Merge binary repos
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..766d224
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+
+# Standard ignores
+*.a
+*.la
+*.lo
+*.o
+*.pyc
+*.so
+*.cmd
+*.swp
+*.tgz
+*.ko
+*.mod.c
+*~
+
+# Ignore DEPS
+build
+wlan_src/.tmp_versions
+wlan_src/Module.markers
+wlan_src/Module.symvers
+wlan_src/modules.order
+io/sdio/syskt/modules.order
diff --git a/FwImage/sd8787.bin b/FwImage/sd8787.bin
new file mode 100644
index 0000000..4041ece
--- /dev/null
+++ b/FwImage/sd8787.bin
Binary files differ
diff --git a/README.chromium b/README.chromium
index 1dd5f1f..ac39238 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,5 +1,4 @@
URL: http://www.marvell.com
-
Version: SD8787 v14.64.2.p47
License: Marvell International Ltd.
License File: sd8787_license.txt
diff --git a/bt_src/Makefile b/bt_src/Makefile
new file mode 100755
index 0000000..5f8f7d5
--- /dev/null
+++ b/bt_src/Makefile
@@ -0,0 +1,144 @@
+# File: Makefile
+# Copyright (C) 2007-2008, Marvell International Ltd.
+#
+
+CC= $(CROSS_COMPILE)gcc
+LD= $(CROSS_COMPILE)ld
+
+BACKUP= /root/backup
+YMD= `date +%Y%m%d%H%M`
+
+#############################################################################
+# Configuration Options
+#############################################################################
+
+# Debug Option
+# DEBUG LEVEL n/1:
+# n: NO DEBUG
+# 1: PRINTM(MSG,...), PRINTM(FATAL,...), PRINTM(WARN,...) and PRINTM(INFO,...)
+CONFIG_DEBUG=1
+
+CONFIG_PXA3XX_DMA_ALIGN=y
+
+#############################################################################
+# Select Platform Tools
+#############################################################################
+
+MODEXT = ko
+
+# KERNELDIR point to the installed kernel directory
+# for PXA3XX BSP.
+# KERNELDIR can be set on the command line
+# make KERNELDIR=/usr/src/arm/<arch-bsp-path>
+# Alternatively KERNELDIR can be set in the environment.
+# Default value for KERNELDIR is set below.
+KERNELDIR ?= /usr/src/arm/linux-2.6.25-pxa9xx
+
+# CROSS_COMPILE specify the prefix used for all executables used
+# during compilation. Only gcc and related bin-utils executables
+# CROSS_COMPILE can be set on the command line
+# make CROSS_COMPILE=</usr/local/arm/4.1.1/bin/>arm-linux-
+# Alternatively CROSS_COMPILE can be set in the environment.
+# Default value for CROSS_COMPILE is set below.
+CROSS_COMPILE ?= /usr/local/arm/4.1.1/bin/arm-linux-
+
+# INSTALLDIR specify the path to install the kernel module after
+# succesful compilation.
+# INSTALLDIR can be set on the command line
+# make INSTALLDIR=/tftpboot/<rootfs>
+# Alternatively INSTALLDIR can be set in the environment.
+# Default value for INSTALL is set below.
+INSTALLDIR ?= /tftpboot/pxa3xx/root
+
+# ARCH specifies the architecture of the target processor, this kernel
+# module will run.
+# ARCH can be set on the command line
+# make ARCH=<arm/i386>
+# Alternatively ARCH can be set in the environment
+# Default values of ARCH for specific platform are set below.
+ARCH ?= arm
+
+
+
+EXTRA_CFLAGS += -I$(KERNELDIR)/include
+EXTRA_CFLAGS += -I$(PWD)/bt
+LD += -S
+
+BINDIR = ../bin_sd8787_bt
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+ EXTRA_CFLAGS += -DFPNUM='"64"'
+
+ifeq ($(CONFIG_DEBUG),1)
+ EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_PXA3XX_DMA_ALIGN),y)
+ EXTRA_CFLAGS += -DPXA3XX_DMA_ALIGN
+endif
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifneq ($(KERNELRELEASE),)
+
+BTOBJS = bt/bt_main.o bt/bt_sdiommc.o bt/bt_proc.o
+
+obj-m := bt8xxx.o
+bt8xxx-objs := $(BTOBJS)
+
+
+
+# Otherwise we were called directly from the command line; invoke the kernel build system.
+else
+default:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
+endif
+
+###############################################################
+
+export CC LD EXTRA_CFLAGS KERNELDIR
+
+echo:
+
+build: echo default
+
+ @if [ ! -d $(BINDIR) ]; then \
+ mkdir $(BINDIR); \
+ fi
+ cp -f bt8xxx.$(MODEXT) $(BINDIR)/bt8787.$(MODEXT)
+
+
+ cp -f README $(BINDIR)
+
+clean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -find . -name "*.symvers" -exec rm {} \;
+ -find . -name "modules.order" -exec rm {} \;
+ -rm -rf .tmp_versions
+
+
+
+install: default
+
+distclean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.orig" -exec rm {} \;
+ -find . -name "*.swp" -exec rm {} \;
+ -find . -name "*.*~" -exec rm {} \;
+ -find . -name "*~" -exec rm {} \;
+ -find . -name "*.d" -exec rm {} \;
+ -find . -name "*.a" -exec rm {} \;
+ -find . -name "tags" -exec rm {} \;
+ -find . -name ".*" -exec rm -rf 2> /dev/null \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -rm -rf .tmp_versions
+# End of file;
diff --git a/bt_src/README b/bt_src/README
new file mode 100755
index 0000000..203faaf
--- /dev/null
+++ b/bt_src/README
@@ -0,0 +1,104 @@
+===============================================================================
+ U S E R M A N U A L
+
+ Copyright (C) 2003-2008, Marvell International Ltd.
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License"). You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the gpl.txt file or by writing to
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ this warranty disclaimer.
+
+===============================================================================
+
+1) FOR DRIVER BUILD
+
+ Goto source code directory src_xxxx.
+ make [clean] build
+ The driver binaries can be found in ../bin_xxxx_bt directory.
+
+2) FOR DRIVER INSTALL
+
+ a) Copy sd8790.bin | sd8787.bin | ... to /lib/firmware/mrvl/ directory,
+ create the directory if it doesn't exist.
+ b) Install bluetooth driver,
+ insmod bt8688.ko | bt8790.ko | ...
+ c) Uninstall bluetooth driver and sdio bus driver,
+ hciconfig hciX down
+ rmmod bt8xxx
+
+3) cat /proc/mbt/hcix/config
+ This command is used to get the current driver settings.
+
+4) cat /proc/mbt/hcix/status
+ This command is used to get driver status
+
+5) proc commands to config bluetooth parameters.
+
+drvdbg=[n]
+ This command is used to set the bit masks of driver debug message control.
+
+ bit 0: MSG PRINTM(MSG,...)
+ bit 1: FATAL PRINTM(FATAL,...)
+ bit 2: ERROR PRINTM(ERROR,...)
+ bit 3: CMD PRINTM(CMD,...)
+ bit 27: DATA DBG_HEXDUMP(DBG_DATA,...)
+ bit 28: ENTRY PRINTM(ENTRY,...), ENTER(), LEAVE()
+ bit 29: WARN PRINTM(WARN,...)
+ bit 30: INFO PRINTM(INFO,...)
+
+ Usage:
+ echo "drvdbg=0x7" > /proc/mbt/hcix/config #enable MSG,FATAL,ERROR messages
+
+gpio_gap=[n]
+ This command is used to configure the host sleep parameters.
+ bit 8:0 -- Gap
+ bit 16:8 -- GPIO
+
+ where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid
+ GPIO pin# (e.g. 0-7) or 0xff (Interface, e.g. SDIO will be used instead).
+
+ where Gap is the gap in milli seconds between wakeup signal and wakeup event
+ or 0xff for special setting.
+ Usage:
+ echo "gpio_gap=0xff80" > /proc/mbt/hcix/config # use Interface (e.g. SDIO)
+ echo "hscfgcmd=1" > /proc/mbt/hcix/config # gap = 0x80
+
+ echo "gpio_gap=0x03ff" > /proc/mbt/hcix/config # use gpio 3
+ echo "hscfgcmd=1" > /proc/mbt/hcix/config # and special host sleep mode
+
+psmode=[n]
+ This command is used to enable/disable auto sleep mode
+
+ where the option is:
+ 1 -- Enable auto sleep mode
+ 0 -- Disable auto sleep mode
+ Usage:
+ echo "psmode=1" > /proc/mbt/hcix/config #enable power save mode
+ echo "pscmd=1" > /proc/mbt/hcix/config
+
+ echo "psmode=0" > /proc/mbt/hcix/config #disable power save mode
+ echo "pscmd=1" > /proc/mbt/hcix/config
+
+
+
+6)Use hcitool to issue raw hci command, refer to hcitool manual
+
+ Usage: Hcitool cmd <ogf> <ocf> [Parameters]
+
+ 1.Interface Control Command
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface
+
+==============================================================================
diff --git a/bt_src/bt/bt_drv.h b/bt_src/bt/bt_drv.h
new file mode 100755
index 0000000..825a1a0
--- /dev/null
+++ b/bt_src/bt/bt_drv.h
@@ -0,0 +1,435 @@
+/** @file bt_drv.h
+ * @brief This header file contains global constant/enum definitions,
+ * global variable declaration.
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _BT_DRV_H_
+#define _BT_DRV_H_
+
+#ifndef BIT
+/** BIT definition */
+#define BIT(x) (1UL << (x))
+#endif
+
+/** Debug level : Message */
+#define DBG_MSG BIT(0)
+/** Debug level : Fatal */
+#define DBG_FATAL BIT(1)
+/** Debug level : Error */
+#define DBG_ERROR BIT(2)
+/** Debug level : Command */
+#define DBG_CMD BIT(3)
+/** Debug level : Data */
+#define DBG_DATA BIT(27)
+/** Debug level : Entry */
+#define DBG_ENTRY BIT(28)
+/** Debug level : Warning */
+#define DBG_WARN BIT(29)
+/** Debug level : Informative */
+#define DBG_INFO BIT(30)
+
+#ifdef DEBUG_LEVEL1
+extern u32 drvdbg;
+
+/** Print informative message */
+#define PRINTM_INFO(msg...) do {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);} while(0)
+/** Print warning message */
+#define PRINTM_WARN(msg...) do {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);} while(0)
+/** Print entry message */
+#define PRINTM_ENTRY(msg...) do {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);} while(0)
+/** Print command message */
+#define PRINTM_CMD(msg...) do {if (drvdbg & DBG_CMD) printk(KERN_DEBUG msg);} while(0)
+/** Print erro message */
+#define PRINTM_ERROR(msg...) do {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);} while(0)
+/** Print fatal message */
+#define PRINTM_FATAL(msg...) do {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);} while(0)
+/** Print message */
+#define PRINTM_MSG(msg...) do {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);} while(0)
+
+/** Print message with required level */
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+/** Debug dump buffer length */
+#define DBG_DUMP_BUF_LEN 64
+/** Maximum number of dump per line */
+#define MAX_DUMP_PER_LINE 16
+/** Maximum data dump length */
+#define MAX_DATA_DUMP_LEN 48
+
+static inline void
+hexdump(char *prompt, u8 * buf, int len)
+{
+ int i;
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+ char *ptr = dbgdumpbuf;
+
+ printk(KERN_DEBUG "%s: len=%d\n", prompt, len);
+ for (i = 1; i <= len; i++) {
+ ptr += sprintf(ptr, "%02x ", *buf);
+ buf++;
+ if (i % MAX_DUMP_PER_LINE == 0) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ ptr = dbgdumpbuf;
+ }
+ }
+ if (len % MAX_DUMP_PER_LINE) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ }
+}
+
+/** Debug hexdump of debug data */
+#define DBG_HEXDUMP_DBG_DATA(x,y,z) do {if (drvdbg & DBG_DATA) hexdump(x,y,z);} while(0)
+
+/** Debug hexdump */
+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
+
+/** Mark entry point */
+#define ENTER() PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
+ __FILE__, __LINE__)
+/** Mark exit point */
+#define LEAVE() PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
+ __FILE__, __LINE__)
+#else
+/** Do nothing */
+#define PRINTM(level,msg...) do {} while (0);
+/** Do nothing */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0);
+/** Do nothing */
+#define ENTER() do {} while (0);
+/** Do nothing */
+#define LEAVE() do {} while (0);
+#endif /* DEBUG_LEVEL1 */
+
+/** Length of device name */
+#define DEV_NAME_LEN 32
+/** Bluetooth upload size */
+#define BT_UPLD_SIZE 2312
+/** Bluetooth status success */
+#define BT_STATUS_SUCCESS (0)
+/** Bluetooth status failure */
+#define BT_STATUS_FAILURE (-1)
+
+#ifndef TRUE
+/** True value */
+#define TRUE 1
+#endif
+#ifndef FALSE
+/** False value */
+#define FALSE 0
+#endif
+
+/** Set thread state */
+#define OS_SET_THREAD_STATE(x) set_current_state(x)
+/** Time to wait until Host Sleep state change in millisecond */
+#define WAIT_UNTIL_HS_STATE_CHANGED 5000
+/** Time to wait cmd resp in millisecond */
+#define WAIT_UNTIL_CMD_RESP 5000
+
+/** Sleep until a condition gets true or a timeout elapses */
+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
+ wait_event_interruptible_timeout(waitq, cond, ((timeout) * HZ / 1000))
+
+typedef struct
+{
+ /** Task */
+ struct task_struct *task;
+ /** Queue */
+ wait_queue_head_t waitQ;
+ /** PID */
+ pid_t pid;
+ /** Private structure */
+ void *priv;
+} bt_thread;
+
+static inline void
+bt_activate_thread(bt_thread * thr)
+{
+ /** Record the thread pid */
+ thr->pid = current->pid;
+
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->waitQ);
+}
+
+static inline void
+bt_deactivate_thread(bt_thread * thr)
+{
+ thr->pid = 0;
+ return;
+}
+
+static inline void
+bt_create_thread(int (*btfunc) (void *), bt_thread * thr, char *name)
+{
+ thr->task = kthread_run(btfunc, thr, "%s", name);
+}
+
+static inline int
+bt_terminate_thread(bt_thread * thr)
+{
+ /* Check if the thread is active or not */
+ if (!thr->pid)
+ return -1;
+
+ kthread_stop(thr->task);
+ return 0;
+}
+
+static inline void
+os_sched_timeout(u32 millisec)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout((millisec * HZ) / 1000);
+}
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+/** Data structure for the Marvell Bluetooth device */
+typedef struct _bt_dev
+{
+ /** device name */
+ char name[DEV_NAME_LEN];
+ /** card pointer */
+ void *card;
+ /** IO port */
+ u32 ioport;
+ /** HCI device */
+ struct hci_dev *hcidev;
+
+ /** Tx download ready flag */
+ u8 tx_dnld_rdy;
+ /** Function */
+ u8 fn;
+ /** Rx unit */
+ u8 rx_unit;
+ /** Power Save mode */
+ u8 psmode;
+ /** Power Save command */
+ u8 pscmd;
+ /** Host Sleep mode */
+ u8 hsmode;
+ /** Host Sleep command */
+ u8 hscmd;
+ /** Low byte is gap, high byte is GPIO */
+ u16 gpio_gap;
+ /** Host Sleep configuration command */
+ u8 hscfgcmd;
+ /** Host Send Cmd Flag */
+ u8 sendcmdflag;
+ /** Device Type */
+ u8 devType;
+} bt_dev_t, *pbt_dev_t;
+
+typedef struct _bt_adapter
+{
+ /** Chip revision ID */
+ u8 chip_rev;
+ /** Surprise removed flag */
+ u8 SurpriseRemoved;
+ /** IRQ number */
+ int irq;
+ /** Interrupt counter */
+ u32 IntCounter;
+ /** Tx packet queue */
+ struct sk_buff_head tx_queue;
+ /** Power Save mode */
+ u8 psmode;
+ /** Power Save state */
+ u8 ps_state;
+ /** Host Sleep state */
+ u8 hs_state;
+ /** Number of wakeup tries */
+ u8 WakeupTries;
+ /** Host Sleep wait queue */
+ wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__;
+ /** Host Cmd complet state */
+ u8 cmd_complete;
+ /** last irq recv */
+ u8 irq_recv;
+ /** last irq processed */
+ u8 irq_done;
+ /** tx pending */
+ u32 skb_pending;
+} bt_adapter, *pbt_adapter;
+
+/** Private structure for the MV device */
+typedef struct _bt_private
+{
+ /** Bluetooth device */
+ bt_dev_t bt_dev;
+ /** Adapter */
+ bt_adapter *adapter;
+ /** Firmware helper */
+ const struct firmware *fw_helper;
+ /** Firmware */
+ const struct firmware *firmware;
+ /** Hotplug device */
+ struct device *hotplug_device;
+ /** thread to service interrupts */
+ bt_thread MainThread;
+ /** Proc directory entry */
+ struct proc_dir_entry *proc_entry;
+ /** Proc mbt directory entry */
+ struct proc_dir_entry *proc_mbt;
+ /** Driver lock */
+ spinlock_t driver_lock;
+ /** Driver lock flags */
+ ulong driver_flags;
+} bt_private, *pbt_private;
+
+/** Disable interrupt */
+#define OS_INT_DISABLE spin_lock_irqsave(&priv->driver_lock, priv->driver_flags)
+/** Enable interrupt */
+#define OS_INT_RESTORE spin_unlock_irqrestore(&priv->driver_lock, priv->driver_flags); \
+ priv->driver_lock = SPIN_LOCK_UNLOCKED
+
+/** BT_AMP flag for device type */
+#define HCI_BT_AMP 0x80
+/** Device type of AMP */
+#define DEV_TYPE_AMP 0x01
+/** Marvell vendor packet */
+#define MRVL_VENDOR_PKT 0xFE
+/** Bluetooth command : Sleep mode */
+#define BT_CMD_AUTO_SLEEP_MODE 0x23
+/** Bluetooth command : Host Sleep configuration */
+#define BT_CMD_HOST_SLEEP_CONFIG 0x59
+/** Bluetooth command : Host Sleep enable */
+#define BT_CMD_HOST_SLEEP_ENABLE 0x5A
+/** Bluetooth command : Module Configuration request */
+#define BT_CMD_MODULE_CFG_REQ 0x5B
+/** Sub Command: Module Bring Up Request */
+#define MODULE_BRINGUP_REQ 0xF1
+/** Sub Command: Module Shut Down Request */
+#define MODULE_SHUTDOWN_REQ 0xF2
+/** Module already up */
+#define MODULE_CFG_RESP_ALREADY_UP 0x0c
+/** Sub Command: Host Interface Control Request */
+#define MODULE_INTERFACE_CTRL_REQ 0xF5
+
+/** Bluetooth event : Power State */
+#define BT_EVENT_POWER_STATE 0x20
+
+/** Bluetooth Power State : Enable */
+#define BT_PS_ENABLE 0x02
+/** Bluetooth Power State : Disable */
+#define BT_PS_DISABLE 0x03
+/** Bluetooth Power State : Sleep */
+#define BT_PS_SLEEP 0x01
+/** Bluetooth Power State : Awake */
+#define BT_PS_AWAKE 0x02
+
+/** OGF */
+#define OGF 0x3F
+
+/** Host Sleep activated */
+#define HS_ACTIVATED 0x01
+/** Host Sleep deactivated */
+#define HS_DEACTIVATED 0x00
+
+/** Power Save sleep */
+#define PS_SLEEP 0x01
+/** Power Save awake */
+#define PS_AWAKE 0x00
+
+/** bt header length */
+#define BT_HEADER_LEN 4
+
+#ifndef MAX
+/** Return maximum of two */
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/** This is for firmware specific length */
+#define EXTRA_LEN 36
+
+/** Command buffer size for Marvell driver */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Bluetooth Rx packet buffer size for Marvell driver */
+#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \
+ (HCI_MAX_FRAME_SIZE + EXTRA_LEN)
+
+/** Buffer size to allocate */
+#define ALLOC_BUF_SIZE (((MAX(MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \
+ MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+ + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES 100
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active when multiple interface is present */
+#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active. (polling the scratch register). */
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+typedef struct _BT_CMD
+{
+ /** OCF OGF */
+ u16 ocf_ogf;
+ /** Length */
+ u8 length;
+ /** Data */
+ u8 data[4];
+} __ATTRIB_PACK__ BT_CMD;
+
+typedef struct _BT_EVENT
+{
+ /** Event Counter */
+ u8 EC;
+ /** Length */
+ u8 length;
+ /** Data */
+ u8 data[4];
+} BT_EVENT;
+
+void check_evtpkt(bt_private * priv, struct sk_buff *skb);
+
+/* Prototype of global function */
+bt_private *bt_add_card(void *card);
+int bt_remove_card(void *card);
+void bt_interrupt(struct hci_dev *hdev);
+
+int bt_proc_init(bt_private * priv);
+void bt_proc_remove(bt_private * priv);
+int bt_process_event(bt_private * priv, struct sk_buff *skb);
+int bt_enable_hs(bt_private * priv);
+int bt_prepare_command(bt_private * priv);
+
+int *sbi_register(void);
+void sbi_unregister(void);
+int sbi_register_dev(bt_private * priv);
+int sbi_unregister_dev(bt_private * priv);
+int sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb);
+int sbi_enable_host_int(bt_private * priv);
+int sbi_disable_host_int(bt_private * priv);
+int sbi_dowload_fw(bt_private * priv);
+int sbi_get_int_status(bt_private * priv, u8 * ireg);
+int sbi_wakeup_firmware(bt_private * priv);
+#endif /* _BT_DRV_H_ */
diff --git a/bt_src/bt/bt_main.c b/bt_src/bt/bt_main.c
new file mode 100755
index 0000000..64253f5
--- /dev/null
+++ b/bt_src/bt/bt_main.c
@@ -0,0 +1,868 @@
+/** @file bt_main.c
+ *
+ * @brief This file contains the major functions in BlueTooth
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/**
+ * @mainpage M-BT Linux Driver
+ *
+ * @section overview_sec Overview
+ *
+ * The M-BT is a Linux reference driver for Marvell SDIO Bluetooth chipset.
+ *
+ * @section copyright_sec Copyright
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ */
+#include "include.h"
+
+/** Version */
+#define VERSION "1.42"
+
+/** Driver version */
+char driver_version[] = "sd8787-" VERSION "-(" "FP" FPNUM ")" " ";
+
+/** Bluetooth device private structure */
+bt_private *btpriv = NULL;
+/** Firmware flag */
+int fw = 1;
+
+#ifdef DEBUG_LEVEL1
+u32 drvdbg = DBG_MSG | DBG_FATAL | DBG_ERROR;
+#endif
+
+/**
+ * @brief This function verify the received event pkt
+ *
+ * @param priv A pointer to bt_private structure
+ * @param skb A pointer to rx skb
+ * @return N/A
+ */
+void
+check_evtpkt(bt_private * priv, struct sk_buff *skb)
+{
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
+ struct hci_ev_cmd_complete *ec;
+ u16 opcode, ocf;
+ ENTER();
+ if (hdr->evt == HCI_EV_CMD_COMPLETE) {
+ ec = (struct hci_ev_cmd_complete *) (skb->data + HCI_EVENT_HDR_SIZE);
+ opcode = __le16_to_cpu(ec->opcode);
+ ocf = hci_opcode_ocf(opcode);
+ if ((ocf == BT_CMD_MODULE_CFG_REQ) &&
+ (priv->bt_dev.sendcmdflag == TRUE)) {
+ priv->bt_dev.sendcmdflag = FALSE;
+ priv->adapter->cmd_complete = TRUE;
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function verify the received acl loopback pkt
+ *
+ * @param priv A pointer to bt_private structure
+ * @param skb A pointer to rx skb
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_process_event(bt_private * priv, struct sk_buff *skb)
+{
+ u8 ret = BT_STATUS_SUCCESS;
+ BT_EVENT *pEvent;
+ ENTER();
+ pEvent = (BT_EVENT *) skb->data;
+ if (pEvent->EC != 0xff) {
+ PRINTM(CMD, "Not Marvell Event=%x\n", pEvent->EC);
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ switch (pEvent->data[0]) {
+ case BT_CMD_AUTO_SLEEP_MODE:
+ if (pEvent->data[2] == BT_STATUS_SUCCESS) {
+ if (pEvent->data[1] == BT_PS_ENABLE)
+ priv->adapter->psmode = 1;
+ else
+ priv->adapter->psmode = 0;
+ PRINTM(CMD, "PS Mode:%s\n",
+ (priv->adapter->psmode) ? "Enable" : "Disable");
+ } else
+ PRINTM(CMD, "PS Mode Command Fail\n");
+ break;
+ case BT_CMD_HOST_SLEEP_CONFIG:
+ if (pEvent->data[3] == BT_STATUS_SUCCESS) {
+ PRINTM(CMD, "gpio=%x,gap=%x\n", pEvent->data[1], pEvent->data[2]);
+ } else
+ PRINTM(CMD, "HSCFG Command Fail\n");
+ break;
+ case BT_CMD_HOST_SLEEP_ENABLE:
+ if (pEvent->data[1] == BT_STATUS_SUCCESS) {
+ priv->adapter->hs_state = HS_ACTIVATED;
+ if (priv->adapter->psmode)
+ priv->adapter->ps_state = PS_SLEEP;
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ PRINTM(CMD, "HS ACTIVATED!\n");
+ } else
+ PRINTM(CMD, "HS Enable Fail\n");
+ break;
+ case BT_CMD_MODULE_CFG_REQ:
+ if ((priv->bt_dev.sendcmdflag == TRUE) &&
+ ((pEvent->data[1] == MODULE_BRINGUP_REQ)
+ || (pEvent->data[1] == MODULE_SHUTDOWN_REQ))) {
+ if (pEvent->data[1] == MODULE_BRINGUP_REQ) {
+ PRINTM(CMD, "EVENT:%s\n",
+ (pEvent->data[2] &&
+ (pEvent->data[2] !=
+ MODULE_CFG_RESP_ALREADY_UP)) ? "Bring up Fail" :
+ "Bring up success");
+ priv->bt_dev.devType = pEvent->data[3];
+ PRINTM(CMD, "devType:%s\n",
+ (pEvent->data[3] ==
+ 1) ? "AMP controller" : "BR/EDR controller");
+
+ }
+ if (pEvent->data[1] == MODULE_SHUTDOWN_REQ) {
+ PRINTM(CMD, "EVENT:%s\n",
+ (pEvent->
+ data[2]) ? "Shut down Fail" : "Shut down success");
+ }
+ if (pEvent->data[2]) {
+ priv->bt_dev.sendcmdflag = FALSE;
+ priv->adapter->cmd_complete = TRUE;
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ }
+ } else {
+ PRINTM(CMD, "BT_CMD_MODULE_CFG_REQ resp for APP\n");
+ ret = BT_STATUS_FAILURE;
+ }
+ break;
+ case BT_EVENT_POWER_STATE:
+ if (pEvent->data[1] == BT_PS_SLEEP)
+ priv->adapter->ps_state = PS_SLEEP;
+ PRINTM(CMD, "EVENT:%s\n",
+ (priv->adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");
+ break;
+ default:
+ PRINTM(CMD, "Unknown Event=%d\n", pEvent->data[0]);
+ ret = BT_STATUS_FAILURE;
+ break;
+ }
+ exit:
+ if (ret == BT_STATUS_SUCCESS)
+ kfree_skb(skb);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function send module cfg cmd to firmware
+ *
+ * @param priv A pointer to bt_private structure
+ * @param subcmd sub command
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_send_module_cfg_cmd(bt_private * priv, int subcmd)
+{
+ struct sk_buff *skb = NULL;
+ u8 ret = BT_STATUS_SUCCESS;
+ BT_CMD *pCmd;
+ ENTER();
+ skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+ if (skb == NULL) {
+ PRINTM(WARN, "No free skb\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ pCmd = (BT_CMD *) skb->tail;
+ pCmd->ocf_ogf = (OGF << 10) | BT_CMD_MODULE_CFG_REQ;
+ pCmd->length = 1;
+ pCmd->data[0] = subcmd;
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+ skb_put(skb, sizeof(BT_CMD));
+ skb->dev = (void *) priv->bt_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+ priv->bt_dev.sendcmdflag = TRUE;
+ priv->adapter->cmd_complete = FALSE;
+ PRINTM(CMD, "Queue module cfg Command\n");
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ /*
+ On some Adroind platforms certain delay is needed for HCI daemon to
+ remove this module and close itself gracefully. Otherwise it hangs. This
+ 10ms delay is a workaround for such platforms as the root cause has not
+ been found yet. */
+ mdelay(10);
+ if (!os_wait_interruptible_timeout
+ (priv->adapter->cmd_wait_q, priv->adapter->cmd_complete,
+ WAIT_UNTIL_CMD_RESP)) {
+ ret = BT_STATUS_FAILURE;
+ PRINTM(MSG, "module_cfg_cmd(%x): timeout sendcmdflag=%d\n", subcmd,
+ priv->bt_dev.sendcmdflag);
+ }
+ PRINTM(CMD, "module cfg Command done\n");
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function enable host sleep
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_enable_hs(bt_private * priv)
+{
+ struct sk_buff *skb = NULL;
+ u8 ret = BT_STATUS_SUCCESS;
+ BT_CMD *pCmd;
+ ENTER();
+ skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+ if (skb == NULL) {
+ PRINTM(WARN, "No free skb\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ pCmd = (BT_CMD *) skb->tail;
+ pCmd->ocf_ogf = (OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE;
+ pCmd->length = 0;
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+ skb_put(skb, sizeof(BT_CMD));
+ skb->dev = (void *) priv->bt_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+ PRINTM(CMD, "Queue hs enable Command\n");
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ if (!os_wait_interruptible_timeout
+ (priv->adapter->cmd_wait_q, priv->adapter->hs_state,
+ WAIT_UNTIL_HS_STATE_CHANGED)) {
+ ret = BT_STATUS_FAILURE;
+ PRINTM(MSG, "bt_enable_hs: timeout: %d, %d,%d\n",
+ priv->adapter->hs_state, priv->adapter->ps_state,
+ priv->adapter->WakeupTries);
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function used to send command to firmware
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+bt_prepare_command(bt_private * priv)
+{
+ struct sk_buff *skb = NULL;
+ u8 ret = BT_STATUS_SUCCESS;
+ BT_CMD *pCmd;
+ ENTER();
+ if (priv->bt_dev.hscfgcmd) {
+ priv->bt_dev.hscfgcmd = 0;
+ skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+ if (skb == NULL) {
+ PRINTM(WARN, "No free skb\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ pCmd = (BT_CMD *) skb->tail;
+ pCmd->ocf_ogf = (OGF << 10) | BT_CMD_HOST_SLEEP_CONFIG;
+ pCmd->length = 2;
+ pCmd->data[0] = (priv->bt_dev.gpio_gap & 0xff00) >> 8;
+ pCmd->data[1] = (u8) (priv->bt_dev.gpio_gap & 0x00ff);
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+ skb_put(skb, sizeof(BT_CMD));
+ skb->dev = (void *) priv->bt_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+ PRINTM(CMD, "Queue HSCFG Command,gpio=%x,gap=%x\n", pCmd->data[0],
+ pCmd->data[1]);
+ }
+ if (priv->bt_dev.pscmd) {
+ priv->bt_dev.pscmd = 0;
+ skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+ if (skb == NULL) {
+ PRINTM(WARN, "No free skb\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ pCmd = (BT_CMD *) skb->tail;
+ pCmd->ocf_ogf = (OGF << 10) | BT_CMD_AUTO_SLEEP_MODE;
+ pCmd->length = 1;
+ if (priv->bt_dev.psmode)
+ pCmd->data[0] = BT_PS_ENABLE;
+ else
+ pCmd->data[0] = BT_PS_DISABLE;
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+ skb_put(skb, sizeof(BT_CMD));
+ skb->dev = (void *) priv->bt_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+ PRINTM(CMD, "Queue PSMODE Command:%d\n", pCmd->data[0]);
+ }
+ if (priv->bt_dev.hscmd) {
+ priv->bt_dev.hscmd = 0;
+ if (priv->bt_dev.hsmode)
+ ret = bt_enable_hs(priv);
+ else {
+ ret = sbi_wakeup_firmware(priv);
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ }
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function processes a single packet
+ *
+ * @param priv A pointer to bt_private structure
+ * @param skb A pointer to skb which includes TX packet
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+SendSinglePacket(bt_private * priv, struct sk_buff *skb)
+{
+ u8 ret;
+ ENTER();
+ if (!skb || !skb->data)
+ return BT_STATUS_FAILURE;
+ if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) {
+ PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
+ BT_UPLD_SIZE);
+ return BT_STATUS_FAILURE;
+ }
+ /* This is SDIO specific header length: byte[3][2][1], type: byte[0]
+ (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
+ skb_push(skb, BT_HEADER_LEN);
+ skb->data[0] = (skb->len & 0x0000ff);
+ skb->data[1] = (skb->len & 0x00ff00) >> 8;
+ skb->data[2] = (skb->len & 0xff0000) >> 16;
+ skb->data[3] = bt_cb(skb)->pkt_type;
+ ret = sbi_host_to_card(priv, skb->data, skb->len);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the adapter structure
+ * and set default value to the member of adapter.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return n/a
+ */
+static void
+bt_init_adapter(bt_private * priv)
+{
+ ENTER();
+ skb_queue_head_init(&priv->adapter->tx_queue);
+ priv->adapter->ps_state = PS_AWAKE;
+ init_waitqueue_head(&priv->adapter->cmd_wait_q);
+ LEAVE();
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+bt_init_fw(bt_private * priv)
+{
+ int ret = BT_STATUS_SUCCESS;
+ ENTER();
+ if (fw == 0) {
+ sbi_enable_host_int(priv);
+ goto done;
+ }
+ sbi_disable_host_int(priv);
+ if (sbi_dowload_fw(priv)) {
+ PRINTM(ERROR, "FW failed to be download!\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ mdelay(100);
+ sbi_enable_host_int(priv);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of adapter
+ *
+ * @param priv A pointer to bt_private structure
+ * @return n/a
+ */
+static void
+bt_free_adapter(bt_private * priv)
+{
+ bt_adapter *Adapter = priv->adapter;
+ ENTER();
+ skb_queue_purge(&priv->adapter->tx_queue);
+ /* Free the adapter object itself */
+ kfree(Adapter);
+ priv->adapter = NULL;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handle the ioctl
+ *
+ * @param hev A pointer to hci_dev structure
+ * @cmd ioctl cmd
+ * @arg
+ * @return -ENOIOCTLCMD
+ */
+static int
+bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+ ENTER();
+ LEAVE();
+ return -ENOIOCTLCMD;
+}
+
+/**
+ * @brief This function handle destruct
+ *
+ * @param hev A pointer to hci_dev structure
+ *
+ * @return n/a
+ */
+static void
+bt_destruct(struct hci_dev *hdev)
+{
+ ENTER();
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handle the transmit
+ *
+ * @param skb A pointer to sk_buffer structure
+ *
+ * @return BT_STATUS_SUCCESS or other
+ */
+static int
+bt_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ bt_private *priv = NULL;
+
+ ENTER();
+ PRINTM(INFO, "bt_send_frame: Type=%d, len=%d\n", skb->pkt_type, skb->len);
+ DBG_HEXDUMP(DBG_DATA, "bt_send_frame", skb->data, skb->len);
+ if (!hdev || !hdev->driver_data) {
+ PRINTM(ERROR, "Frame for unknown HCI device (hdev=NULL)\n");
+ LEAVE();
+ return -ENODEV;
+ }
+ priv = (bt_private *) hdev->driver_data;
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ PRINTM(ERROR, "Fail test HCI_RUNING,flag=%lx\n", hdev->flags);
+ LEAVE();
+ return -EBUSY;
+ }
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+ skb_queue_tail(&priv->adapter->tx_queue, skb);
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function flush the transmit queue
+ *
+ * @param hev A pointer to hci_dev structure
+ *
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+bt_flush(struct hci_dev *hdev)
+{
+ bt_private *priv = (bt_private *) hdev->driver_data;
+ ENTER();
+ skb_queue_purge(&priv->adapter->tx_queue);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function close the bluetooth device
+ *
+ * @param hev A pointer to hci_dev structure
+ *
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+bt_close(struct hci_dev *hdev)
+{
+ bt_private *priv = (bt_private *) hdev->driver_data;
+ ENTER();
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ }
+ skb_queue_purge(&priv->adapter->tx_queue);
+ module_put(THIS_MODULE);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function open the bluetooth device
+ *
+ * @param hev A pointer to hci_dev structure
+ *
+ * @return BT_STATUS_SUCCESS or other
+ */
+static int
+bt_open(struct hci_dev *hdev)
+{
+ ENTER();
+ if (try_module_get(THIS_MODULE) == 0)
+ return BT_STATUS_FAILURE;
+ set_bit(HCI_RUNNING, &hdev->flags);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the major job in bluetooth driver.
+ * it handles the event generated by firmware, rx data received
+ * from firmware and tx data sent from kernel.
+ *
+ * @param data A pointer to bt_thread structure
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+bt_service_main_thread(void *data)
+{
+ bt_thread *thread = data;
+ bt_private *priv = thread->priv;
+ bt_adapter *Adapter = priv->adapter;
+ wait_queue_t wait;
+ u8 ireg = 0;
+ struct sk_buff *skb;
+ ENTER();
+ bt_activate_thread(thread);
+ init_waitqueue_entry(&wait, current);
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&thread->waitQ, &wait);
+ OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+ if (priv->adapter->WakeupTries ||
+ ((!priv->adapter->IntCounter) &&
+ (!priv->bt_dev.tx_dnld_rdy ||
+ skb_queue_empty(&priv->adapter->tx_queue)))) {
+ PRINTM(INFO, "Main: Thread sleeping...\n");
+ schedule();
+ }
+ OS_SET_THREAD_STATE(TASK_RUNNING);
+ remove_wait_queue(&thread->waitQ, &wait);
+ if (kthread_should_stop() || Adapter->SurpriseRemoved) {
+ PRINTM(INFO, "main-thread: break from main thread: "
+ "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
+ break;
+ }
+
+ PRINTM(INFO, "Main: Thread waking up...\n");
+ if (priv->adapter->IntCounter) {
+ OS_INT_DISABLE;
+ Adapter->IntCounter = 0;
+ OS_INT_RESTORE;
+ sbi_get_int_status(priv, &ireg);
+ } else if ((priv->adapter->ps_state == PS_SLEEP) &&
+ !skb_queue_empty(&priv->adapter->tx_queue)) {
+ priv->adapter->WakeupTries++;
+ sbi_wakeup_firmware(priv);
+ continue;
+ }
+ if (priv->adapter->ps_state == PS_SLEEP)
+ continue;
+ if (priv->bt_dev.tx_dnld_rdy == TRUE) {
+ if (!skb_queue_empty(&priv->adapter->tx_queue)) {
+ skb = skb_dequeue(&priv->adapter->tx_queue);
+ if (skb) {
+ if (SendSinglePacket(priv, skb))
+ priv->bt_dev.hcidev->stat.err_tx++;
+ else
+ priv->bt_dev.hcidev->stat.byte_tx += skb->len;
+ kfree_skb(skb);
+ }
+ }
+ }
+ }
+ bt_deactivate_thread(thread);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the interrupt. it will change PS
+ * state if applicable. it will wake up main_thread to handle
+ * the interrupt event as well.
+ *
+ * @param hdev A pointer to hci_dev structure
+ * @return n/a
+ */
+void
+bt_interrupt(struct hci_dev *hdev)
+{
+ bt_private *priv = (bt_private *) hdev->driver_data;
+ ENTER();
+ priv->adapter->ps_state = PS_AWAKE;
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ priv->adapter->WakeupTries = 0;
+ priv->adapter->IntCounter++;
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ LEAVE();
+
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the bt_priv and initialize the device.
+ *
+ * @param card A pointer to card
+ * @return A pointer to bt_private structure
+ */
+
+bt_private *
+bt_add_card(void *card)
+{
+ struct hci_dev *hdev = NULL;
+ bt_private *priv = NULL;
+ int ret;
+
+ ENTER();
+
+ priv = kzalloc(sizeof(bt_private), GFP_KERNEL);
+ if (!priv) {
+ PRINTM(FATAL, "Can not allocate priv\n");
+ LEAVE();
+ return NULL;
+ }
+ /* allocate buffer for bt_adapter */
+ if (!(priv->adapter = kzalloc(sizeof(bt_adapter), GFP_KERNEL))) {
+ PRINTM(FATAL, "Allocate buffer for bt_adapter failed!\n");
+ goto err_kmalloc;
+ }
+
+ bt_init_adapter(priv);
+
+ /* Register to HCI Core */
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ PRINTM(FATAL, "Can not allocate HCI device\n");
+ goto err_kmalloc;
+ }
+
+ PRINTM(INFO, "Starting kthread...\n");
+ priv->MainThread.priv = priv;
+ spin_lock_init(&priv->driver_lock);
+
+ bt_create_thread(bt_service_main_thread, &priv->MainThread,
+ "bt_main_service");
+
+ /* wait for mainthread to up */
+ while (!priv->MainThread.pid) {
+ os_sched_timeout(1);
+ }
+ priv->bt_dev.hcidev = hdev;
+ priv->bt_dev.card = card;
+ btpriv = priv;
+ hdev->driver_data = priv;
+ ((struct sdio_mmc_card *) card)->priv = priv;
+ /*
+ * Register the device. Fillup the private data structure with
+ * relevant information from the card and request for the required
+ * IRQ.
+ */
+ if (sbi_register_dev(priv) < 0) {
+ PRINTM(FATAL, "Failed to register bt device!\n");
+ goto err_registerdev;
+ }
+ if (bt_init_fw(priv)) {
+ PRINTM(FATAL, "Firmware Init Failed\n");
+ goto err_init_fw;
+ }
+ priv->bt_dev.tx_dnld_rdy = TRUE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+ hdev->type = HCI_SDIO;
+#else
+ hdev->type = HCI_PCCARD;
+#endif
+
+ hdev->open = bt_open;
+ hdev->close = bt_close;
+ hdev->flush = bt_flush;
+ hdev->send = bt_send_frame;
+ hdev->destruct = bt_destruct;
+ hdev->ioctl = bt_ioctl;
+
+ hdev->owner = THIS_MODULE;
+ bt_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+ priv->bt_dev.pscmd = TRUE;
+ priv->bt_dev.psmode = TRUE;
+ bt_prepare_command(priv);
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ if (priv->bt_dev.devType == DEV_TYPE_AMP)
+ hdev->type |= HCI_BT_AMP;
+ ret = hci_register_dev(hdev);
+ if (ret < 0) {
+ PRINTM(FATAL, "Can not register HCI device\n");
+ goto err_init_fw;
+ }
+ bt_proc_init(priv);
+
+ LEAVE();
+ return priv;
+
+ err_init_fw:
+ sbi_unregister_dev(priv);
+ err_registerdev:
+ ((struct sdio_mmc_card *) card)->priv = NULL;
+ /* Stop the thread servicing the interrupts */
+ priv->adapter->SurpriseRemoved = TRUE;
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ while (priv->MainThread.pid) {
+ os_sched_timeout(1);
+ }
+ err_kmalloc:
+ if (hdev)
+ hci_free_dev(hdev);
+ bt_free_adapter(priv);
+ kfree(priv);
+ btpriv = NULL;
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes the card.
+ *
+ * @param card A pointer to card
+ * @return BT_STATUS_SUCCESS
+ */
+
+int
+bt_remove_card(void *card)
+{
+ struct hci_dev *hdev;
+ bt_private *priv = ((struct sdio_mmc_card *) card)->priv;
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ }
+ hdev = priv->bt_dev.hcidev;
+ /* Disable interrupts on the card */
+ sbi_disable_host_int(priv);
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ priv->adapter->SurpriseRemoved = TRUE;
+ wake_up_interruptible(&priv->MainThread.waitQ);
+ while (priv->MainThread.pid) {
+ os_sched_timeout(1);
+ }
+ bt_proc_remove(priv);
+ PRINTM(INFO, "unregester dev\n");
+ sbi_unregister_dev(priv);
+
+ /* UnRegister to HCI Core */
+ if (hci_unregister_dev(hdev) < 0)
+ PRINTM(ERROR, "Can not unregister HCI device %s\n", hdev->name);
+ hci_free_dev(hdev);
+ priv->bt_dev.hcidev = NULL;
+ bt_free_adapter(priv);
+ kfree(priv);
+ btpriv = NULL;
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes module.
+ *
+ * @param n/a A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+bt_init_module(void)
+{
+ int ret = BT_STATUS_SUCCESS;
+ ENTER();
+ if (sbi_register() == NULL) {
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans module
+ *
+ * @param priv n/a
+ * @return n/a
+ */
+static void
+bt_exit_module(void)
+{
+ ENTER();
+ if (btpriv) {
+ bt_send_module_cfg_cmd(btpriv, MODULE_SHUTDOWN_REQ);
+ btpriv->adapter->SurpriseRemoved = TRUE;
+ }
+ sbi_unregister();
+ LEAVE();
+}
+
+module_init(bt_init_module);
+module_exit(bt_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell Bluetooth Driver Ver. " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+module_param(fw, int, 1);
+MODULE_PARM_DESC(fw, "0: Skip firmware download; otherwise: Download firmware");
diff --git a/bt_src/bt/bt_proc.c b/bt_src/bt/bt_proc.c
new file mode 100755
index 0000000..f38e738
--- /dev/null
+++ b/bt_src/bt/bt_proc.c
@@ -0,0 +1,479 @@
+/** @file bt_proc.c
+ *
+ * @brief This file handle the functions for proc files
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include "include.h"
+
+/** proc diretory root */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define PROC_DIR NULL
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define PROC_DIR &proc_root
+#else
+#define PROC_DIR proc_net
+#endif
+
+/** Driver version */
+extern char driver_version[];
+
+struct proc_data
+{
+ /** Read length */
+ int rdlen;
+ /** Read buffer */
+ char *rdbuf;
+ /** Write length */
+ int wrlen;
+ /** Maximum write length */
+ int maxwrlen;
+ /** Write buffer */
+ char *wrbuf;
+ void (*on_close) (struct inode *, struct file *);
+};
+
+struct item_data
+{
+ /** Name */
+ char name[32];
+ /** Size */
+ u32 size;
+ /** Address */
+ u32 addr;
+ /** Offset */
+ u32 offset;
+ /** Flag */
+ u32 flag;
+};
+
+struct proc_private_data
+{
+ /** Name */
+ char name[32];
+ /** File flag */
+ u32 fileflag;
+ /** Buffer size */
+ u32 bufsize;
+ /** Number of items */
+ u32 num_items;
+ /** Item data */
+ struct item_data *pdata;
+ /** Private structure */
+ bt_private *pbt;
+ /** File operations */
+ struct file_operations *fops;
+};
+
+/** Default file permission */
+#define DEFAULT_FILE_PERM 0644
+
+/** Bluetooth device offset */
+#define OFFSET_BT_DEV 0x01
+/** Bluetooth adapter offset */
+#define OFFSET_BT_ADAPTER 0x02
+/** Show integer */
+#define SHOW_INT 0x10
+/** Show hex */
+#define SHOW_HEX 0x20
+/** Show string */
+#define SHOW_STRING 0x40
+
+/** Device size */
+#define item_dev_size(n) (sizeof ((bt_dev_t *)0)->n)
+/** Device address */
+#define item_dev_addr(n) ((u32) &((bt_dev_t *)0)->n)
+
+/** Adapter size */
+#define item_adapter_size(n) (sizeof ((bt_adapter *)0)->n)
+/** Adapter address */
+#define item_adapter_addr(n) ((u32) &((bt_adapter *)0)->n)
+static struct item_data config_items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(u32), (u32) & drvdbg, 0, SHOW_HEX}
+ ,
+#endif
+ {"psmode", item_dev_size(psmode), 0, item_dev_addr(psmode),
+ OFFSET_BT_DEV | SHOW_INT}
+ ,
+ {"pscmd", item_dev_size(pscmd), 0, item_dev_addr(pscmd),
+ OFFSET_BT_DEV | SHOW_INT}
+ ,
+ {"hsmode", item_dev_size(hsmode), 0, item_dev_addr(hsmode),
+ OFFSET_BT_DEV | SHOW_INT}
+ ,
+ {"hscmd", item_dev_size(hscmd), 0, item_dev_addr(hscmd),
+ OFFSET_BT_DEV | SHOW_INT}
+ ,
+ {"gpio_gap", item_dev_size(gpio_gap), 0, item_dev_addr(gpio_gap),
+ OFFSET_BT_DEV | SHOW_HEX}
+ ,
+ {"hscfgcmd", item_dev_size(hscfgcmd), 0, item_dev_addr(hscfgcmd),
+ OFFSET_BT_DEV | SHOW_INT}
+ ,
+};
+
+static struct item_data status_items[] = {
+ {"version", 0, (u32) driver_version, 0, SHOW_STRING},
+ {"tx_dnld_rdy", item_dev_size(tx_dnld_rdy), 0, item_dev_addr(tx_dnld_rdy),
+ OFFSET_BT_DEV | SHOW_INT},
+ {"psmode", item_adapter_size(psmode), 0, item_adapter_addr(psmode),
+ OFFSET_BT_ADAPTER | SHOW_INT},
+ {"hs_state", item_adapter_size(hs_state), 0, item_adapter_addr(hs_state),
+ OFFSET_BT_ADAPTER | SHOW_INT},
+ {"ps_state", item_adapter_size(ps_state), 0, item_adapter_addr(ps_state),
+ OFFSET_BT_ADAPTER | SHOW_INT},
+ {"irq_recv", item_adapter_size(irq_recv), 0, item_adapter_addr(irq_recv),
+ OFFSET_BT_ADAPTER | SHOW_INT},
+ {"irq_done", item_adapter_size(irq_done), 0, item_adapter_addr(irq_done),
+ OFFSET_BT_ADAPTER | SHOW_INT},
+ {"skb_pending", item_adapter_size(skb_pending), 0,
+ item_adapter_addr(skb_pending), OFFSET_BT_ADAPTER | SHOW_INT},
+};
+
+/**
+ * @brief convert string to number
+ *
+ * @param s pointer to numbered string
+ * @return converted number from string s
+ */
+int
+string_to_number(char *s)
+{
+ int r = 0;
+ int base = 0;
+ int pn = 1;
+
+ if (strncmp(s, "-", 1) == 0) {
+ pn = -1;
+ s++;
+ }
+ if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0)) {
+ base = 16;
+ s += 2;
+ } else
+ base = 10;
+
+ for (s = s; *s != 0; s++) {
+ if ((*s >= '0') && (*s <= '9'))
+ r = (r * base) + (*s - '0');
+ else if ((*s >= 'A') && (*s <= 'F'))
+ r = (r * base) + (*s - 'A' + 10);
+ else if ((*s >= 'a') && (*s <= 'f'))
+ r = (r * base) + (*s - 'a' + 10);
+ else
+ break;
+ }
+
+ return (r * pn);
+}
+
+/**
+ * @brief This function handle generic proc file close
+ *
+ * @param inode A pointer to inode structure
+ * @param file A pointer to file structure
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+proc_close(struct inode *inode, struct file *file)
+{
+ struct proc_data *pdata = file->private_data;
+ ENTER();
+ if (pdata) {
+ if (pdata->on_close != NULL)
+ pdata->on_close(inode, file);
+ if (pdata->rdbuf)
+ kfree(pdata->rdbuf);
+ if (pdata->wrbuf)
+ kfree(pdata->wrbuf);
+ kfree(pdata);
+ }
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle generic proc file read
+ *
+ * @param file A pointer to file structure
+ * @param buffer A pointer to output buffer
+ * @param len number of byte to read
+ * @param offset A pointer to offset of file
+ * @return number of output data
+ */
+static ssize_t
+proc_read(struct file *file, char __user * buffer, size_t len, loff_t * offset)
+{
+ loff_t pos = *offset;
+ struct proc_data *pdata = (struct proc_data *) file->private_data;
+ if ((!pdata->rdbuf) || (pos < 0))
+ return -EINVAL;
+ if (pos >= pdata->rdlen)
+ return 0;
+ if (len > pdata->rdlen - pos)
+ len = pdata->rdlen - pos;
+ if (copy_to_user(buffer, pdata->rdbuf + pos, len))
+ return -EFAULT;
+ *offset = pos + len;
+ return len;
+}
+
+/**
+ * @brief This function handle generic proc file write
+ *
+ * @param file A pointer to file structure
+ * @param buffer A pointer to input buffer
+ * @param len number of byte to write
+ * @param offset A pointer to offset of file
+ * @return number of input data
+ */
+static ssize_t
+proc_write(struct file *file,
+ const char __user * buffer, size_t len, loff_t * offset)
+{
+ loff_t pos = *offset;
+ struct proc_data *pdata = (struct proc_data *) file->private_data;
+
+ if (!pdata->wrbuf || (pos < 0))
+ return -EINVAL;
+ if (pos >= pdata->maxwrlen)
+ return 0;
+ if (len > pdata->maxwrlen - pos)
+ len = pdata->maxwrlen - pos;
+ if (copy_from_user(pdata->wrbuf + pos, buffer, len))
+ return -EFAULT;
+ if (pos + len > pdata->wrlen)
+ pdata->wrlen = len + file->f_pos;
+ *offset = pos + len;
+ return len;
+}
+
+/**
+ * @brief This function handle the generic file close
+ *
+ * @param inode A pointer to inode structure
+ * @param file A pointer to file structure
+ * @return BT_STATUS_SUCCESS or other
+ */
+static void
+proc_on_close(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *entry = PDE(inode);
+ struct proc_private_data *priv = entry->data;
+ struct proc_data *pdata = file->private_data;
+ char *line;
+ int i;
+ ENTER();
+ if (!pdata->wrlen)
+ return;
+ line = pdata->wrbuf;
+ while (line[0]) {
+ for (i = 0; i < priv->num_items; i++) {
+ if (!strncmp
+ (line, priv->pdata[i].name, strlen(priv->pdata[i].name))) {
+ line += strlen(priv->pdata[i].name) + 1;
+ if (priv->pdata[i].size == 1)
+ *((u8 *) priv->pdata[i].addr) = (u8) string_to_number(line);
+ else if (priv->pdata[i].size == 2)
+ *((u16 *) priv->pdata[i].addr) =
+ (u16) string_to_number(line);
+ else if (priv->pdata[i].size == 4)
+ *((u32 *) priv->pdata[i].addr) =
+ (u32) string_to_number(line);
+ }
+ }
+ while (line[0] && line[0] != '\n')
+ line++;
+ if (line[0])
+ line++;
+ }
+ if (priv->pbt->bt_dev.hscmd || priv->pbt->bt_dev.pscmd
+ || priv->pbt->bt_dev.hscfgcmd) {
+ bt_prepare_command(priv->pbt);
+ wake_up_interruptible(&priv->pbt->MainThread.waitQ);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handle the generic file open
+ *
+ * @param inode A pointer to inode structure
+ * @param file A pointer to file structure
+ * @return BT_STATUS_SUCCESS or other
+ */
+static int
+proc_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *entry = PDE(inode);
+ struct proc_private_data *priv = entry->data;
+ struct proc_data *pdata;
+ int i;
+ char *p;
+ u32 val = 0;
+ ENTER();
+ priv->pbt->adapter->skb_pending =
+ skb_queue_len(&priv->pbt->adapter->tx_queue);
+ if ((file->private_data =
+ kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) {
+ PRINTM(ERROR, "Can not alloc mem for proc_data\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+ pdata = (struct proc_data *) file->private_data;
+ if ((pdata->rdbuf = kmalloc(priv->bufsize, GFP_KERNEL)) == NULL) {
+ PRINTM(ERROR, "Can not alloc mem for rdbuf\n");
+ kfree(file->private_data);
+ LEAVE();
+ return -ENOMEM;
+ }
+ if (priv->fileflag == DEFAULT_FILE_PERM) {
+ if ((pdata->wrbuf = kzalloc(priv->bufsize, GFP_KERNEL)) == NULL) {
+ PRINTM(ERROR, "Can not alloc mem for wrbuf\n");
+ kfree(pdata->rdbuf);
+ kfree(file->private_data);
+ return -ENOMEM;
+ }
+ pdata->maxwrlen = priv->bufsize;
+ pdata->on_close = proc_on_close;
+ }
+ p = pdata->rdbuf;
+ for (i = 0; i < priv->num_items; i++) {
+ if (priv->pdata[i].size == 1)
+ val = *((u8 *) priv->pdata[i].addr);
+ else if (priv->pdata[i].size == 2)
+ val = *((u16 *) priv->pdata[i].addr);
+ else if (priv->pdata[i].size == 4)
+ val = *((u32 *) priv->pdata[i].addr);
+ if (priv->pdata[i].flag & SHOW_INT)
+ p += sprintf(p, "%s=%d\n", priv->pdata[i].name, val);
+ else if (priv->pdata[i].flag & SHOW_HEX)
+ p += sprintf(p, "%s=0x%x\n", priv->pdata[i].name, val);
+ else if (priv->pdata[i].flag & SHOW_STRING)
+ p += sprintf(p, "%s=%s\n", priv->pdata[i].name,
+ (char *) priv->pdata[i].addr);
+ }
+ pdata->rdlen = strlen(pdata->rdbuf);
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+static struct file_operations proc_read_ops = {
+ .read = proc_read,
+ .open = proc_open,
+ .release = proc_close
+};
+
+static struct file_operations proc_rw_ops = {
+ .read = proc_read,
+ .write = proc_write,
+ .open = proc_open,
+ .release = proc_close
+};
+
+static struct proc_private_data proc_files[] = {
+ {"status", S_IRUGO, 1024, sizeof(status_items) / sizeof(status_items[0]),
+ &status_items[0], NULL, &proc_read_ops}
+ ,
+ {"config", DEFAULT_FILE_PERM, 512,
+ sizeof(config_items) / sizeof(config_items[0]), &config_items[0], NULL,
+ &proc_rw_ops}
+ ,
+};
+
+/**
+ * @brief This function init proc entry
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+bt_proc_init(bt_private * priv)
+{
+ u8 ret = BT_STATUS_SUCCESS;
+ struct proc_dir_entry *entry;
+ int i, j;
+ ENTER();
+ if (!priv->proc_mbt) {
+ priv->proc_mbt = proc_mkdir("mbt", PROC_DIR);
+ if (!priv->proc_mbt) {
+ PRINTM(ERROR, "Could not mkdir mbt!\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ priv->proc_entry =
+ proc_mkdir(priv->bt_dev.hcidev->name, priv->proc_mbt);
+ if (!priv->proc_entry) {
+ PRINTM(ERROR, "Could not mkdir %s!\n", priv->bt_dev.hcidev->name);
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ for (j = 0; j < sizeof(proc_files) / sizeof(proc_files[0]); j++) {
+ for (i = 0; i < proc_files[j].num_items; i++) {
+ if (proc_files[j].pdata[i].flag & OFFSET_BT_DEV)
+ proc_files[j].pdata[i].addr =
+ proc_files[j].pdata[i].offset + (u32) & priv->bt_dev;
+ if (proc_files[j].pdata[i].flag & OFFSET_BT_ADAPTER)
+ proc_files[j].pdata[i].addr =
+ proc_files[j].pdata[i].offset + (u32) priv->adapter;
+ }
+ proc_files[j].pbt = priv;
+ entry =
+ create_proc_entry(proc_files[j].name,
+ S_IFREG | proc_files[j].fileflag,
+ priv->proc_entry);
+ if (entry) {
+ entry->data = &proc_files[j];
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ entry->owner = THIS_MODULE;
+#endif
+ entry->proc_fops = proc_files[j].fops;
+ }
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief remove proc file
+ *
+ * @param priv pointer wlan_private
+ * @return N/A
+ */
+void
+bt_proc_remove(bt_private * priv)
+{
+ int j;
+ ENTER();
+ if (priv->proc_mbt) {
+ if (priv->proc_entry) {
+ for (j = 0; j < sizeof(proc_files) / sizeof(proc_files[0]); j++)
+ remove_proc_entry(proc_files[j].name, priv->proc_entry);
+ }
+ remove_proc_entry(priv->bt_dev.hcidev->name, priv->proc_mbt);
+ remove_proc_entry("mbt", PROC_DIR);
+ priv->proc_entry = NULL;
+ priv->proc_mbt = NULL;
+ }
+ LEAVE();
+ return;
+}
diff --git a/bt_src/bt/bt_sdio.h b/bt_src/bt/bt_sdio.h
new file mode 100755
index 0000000..bf464ef
--- /dev/null
+++ b/bt_src/bt/bt_sdio.h
@@ -0,0 +1,236 @@
+/** @file bt_sdio.h
+ * @brief This file contains SDIO (interface) module
+ * related macros, enum, and structure.
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _BT_SDIO_H_
+#define _BT_SDIO_H_
+
+/** IRQ return type */
+typedef irqreturn_t IRQ_RET_TYPE;
+/** IRQ return */
+#define IRQ_RET return IRQ_HANDLED
+/** ISR notifier function */
+typedef IRQ_RET_TYPE(*isr_notifier_fn_t) (s32 irq, void *dev_id,
+ struct pt_regs * reg);
+
+/** SDIO header length */
+#define SDIO_HEADER_LEN 4
+
+/* SD block size can not bigger than 64 due to buf size limit in firmware */
+/** define SD block size for data Tx/Rx */
+#define SD_BLOCK_SIZE 64
+/** define SD block size for firmware download */
+#define SD_BLOCK_SIZE_FW_DL 256
+
+/** Number of blocks for firmware transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/** Firmware ready */
+#define FIRMWARE_READY 0xfedc
+
+/* Bus Interface Control Reg 0x07 */
+/** SD BUS width 1 */
+#define SD_BUS_WIDTH_1 0x00
+/** SD BUS width 4 */
+#define SD_BUS_WIDTH_4 0x02
+/** SD BUS width mask */
+#define SD_BUS_WIDTH_MASK 0x03
+/** Asynchronous interrupt mode */
+#define ASYNC_INT_MODE 0x20
+/* Host Control Registers */
+/** Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG 0x78
+/** Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG 0x79
+/** Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG 0x7A
+
+/** Host Control Registers : Configuration */
+#define CONFIGURATION_REG 0x00
+/** Host Control Registers : Host without Command 53 finish host*/
+#define HOST_TO_CARD_EVENT (0x1U << 3)
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/** Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG 0x02
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/** Enable Host interrupt mask */
+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/** Disable Host interrupt mask */
+#define HIM_DISABLE 0xff
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INTSTATUS_REG 0x03
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/** Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG 0x01
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG 0x28
+/** Host Control Registers : Upload CRC error */
+#define UP_LD_CRC_ERR (0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/* Card Control Registers */
+/** Card Control Registers : Read SQ base address A0 register */
+#define SQ_READ_BASE_ADDRESS_A0_REG 0x40
+/** Card Control Registers : Read SQ base address A1 register */
+#define SQ_READ_BASE_ADDRESS_A1_REG 0x41
+/** Card Control Registers : Read SQ base address A2 register */
+#define SQ_READ_BASE_ADDRESS_A2_REG 0x42
+/** Card Control Registers : Read SQ base address A3 register */
+#define SQ_READ_BASE_ADDRESS_A3_REG 0x43
+/** Card Control Registers : Read SQ base address B0 register */
+#define SQ_READ_BASE_ADDRESS_B0_REG 0x44
+/** Card Control Registers : Read SQ base address B1 register */
+#define SQ_READ_BASE_ADDRESS_B1_REG 0x45
+/** Card Control Registers : Read SQ base address B2 register */
+#define SQ_READ_BASE_ADDRESS_B2_REG 0x46
+/** Card Control Registers : Read SQ base address B3 register */
+#define SQ_READ_BASE_ADDRESS_B3_REG 0x47
+
+/** Card Control Registers : Card status register */
+#define CARD_STATUS_REG 0x30
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/** Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG 0x34
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/** Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG 0x38
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/** Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG 0x3c
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/** Card Control Registers : Debug 0 register */
+#define DEBUG_0_REG 0x70
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0 (0x1U)
+/** Card Control Registers : Debug 1 register */
+#define DEBUG_1_REG 0x71
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1 (0x1U)
+/** Card Control Registers : Debug 2 register */
+#define DEBUG_2_REG 0x72
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2 (0x1U)
+/** Card Control Registers : Debug 3 register */
+#define DEBUG_3_REG 0x73
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3 (0x1U)
+/** Card Control Registers : Card OCR 0 register */
+#define CARD_OCR_0_REG 0x68
+/** Card Control Registers : Card OCR 1 register */
+#define CARD_OCR_1_REG 0x69
+/** Card Control Registers : Card OCR 3 register */
+#define CARD_OCR_3_REG 0x6A
+/** Card Control Registers : Card config register */
+#define CARD_CONFIG_REG 0x6B
+/** Card Control Registers : Card revision register */
+#define CARD_REVISION_REG 0x5c
+/** Card Control Registers : Command 53 finish G BUS */
+#define CMD53_FINISH_GBUS (0x1U << 1)
+/** Card Control Registers : SD negative edge */
+#define SD_NEG_EDGE (0x1U << 0)
+
+/* Special registers in function 0 of the SDxx card */
+/** Special register in function 0 of the SDxxx card : Scratch 0 */
+#define SCRATCH_0_REG 0x80fe
+/** Special register in function 0 of the SDxxx card : Scratch 1 */
+#define SCRATCH_1_REG 0x80ff
+/** Host F1 read base 0 */
+#define HOST_F1_RD_BASE_0 0x0040
+/** Host F1 read base 1 */
+#define HOST_F1_RD_BASE_1 0x0041
+/** Host F1 card ready */
+#define HOST_F1_CARD_RDY 0x0020
+
+/** Chip Id Register 0 */
+#define CARD_CHIP_ID_0_REG 0x801c
+/** Chip Id Register 1 */
+#define CARD_CHIP_ID_1_REG 0x801d
+/** Firmware status 0 register */
+#define CARD_FW_STATUS0_REG 0x60
+/** Firmware status 1 register */
+#define CARD_FW_STATUS1_REG 0x61
+/** Rx length register */
+#define CARD_RX_LEN_REG 0x62
+/** Rx unit register */
+#define CARD_RX_UNIT_REG 0x63
+
+struct sdio_mmc_card
+{
+ /** sdio_func structure pointer */
+ struct sdio_func *func;
+ /** bt_private structure pointer */
+ bt_private *priv;
+};
+#ifdef PXA3XX_DMA_ALIGN
+/** DMA alignment value for PXA3XX platforms */
+#define PXA3XX_DMA_ALIGNMENT 8
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1))
+#endif /* !PXA3XX */
+#endif /* _BT_SDIO_H_ */
diff --git a/bt_src/bt/bt_sdiommc.c b/bt_src/bt/bt_sdiommc.c
new file mode 100755
index 0000000..b176fb4
--- /dev/null
+++ b/bt_src/bt/bt_sdiommc.c
@@ -0,0 +1,1214 @@
+/** @file bt_sdiommc.c
+ * @brief This file contains SDIO IF (interface) module
+ * related functions.
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include "include.h"
+
+/** define marvell vendor id */
+#define MARVELL_VENDOR_ID 0x02df
+
+/** Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY 2
+/** Firmware name */
+char *fw_name = NULL;
+/** Default firmware name */
+#define DEFAULT_FW_NAME "mrvl/sd8787.bin"
+
+/** Function number 2 */
+#define FN2 2
+/** SD 8790 BT device ID */
+#define SD_DEVICE_ID_8790_BT 0x911D
+/** SD 8688 BT device ID */
+#define SD_DEVICE_ID_8688_BT 0x9105
+/** Device ID for SD8787 */
+#define SD_DEVICE_ID_8787_BT 0x911A
+
+static const struct sdio_device_id bt_ids[] = {
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8790_BT)},
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8688_BT)},
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8787_BT)},
+ {}
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+/**Interrupt status */
+static u8 sd_ireg = 0;
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function get rx_unit value
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_get_rx_unit(bt_private * priv)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u8 reg;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+ if (ret == BT_STATUS_SUCCESS)
+ priv->bt_dev.rx_unit = reg;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function reads fwstatus registers
+ *
+ * @param priv A pointer to bt_private structure
+ * @param dat A pointer to keep returned data
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_read_firmware_status(bt_private * priv, u16 * dat)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u8 fws0;
+ u8 fws1;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+ if (ret < 0) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+
+ fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+ if (ret < 0) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+
+ *dat = (((u16) fws1) << 8) | fws0;
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads rx length
+ *
+ * @param priv A pointer to bt_private structure
+ * @param dat A pointer to keep returned data
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_read_rx_len(bt_private * priv, u16 * dat)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u8 reg;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+ if (ret == BT_STATUS_SUCCESS)
+ *dat = (u16) reg << priv->bt_dev.rx_unit;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function enables the host interrupts mask
+ *
+ * @param priv A pointer to bt_private structure
+ * @param mask the interrupt mask
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+sd_enable_host_int_mask(bt_private * priv, u8 mask)
+{
+ int ret = BT_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+ if (ret) {
+ PRINTM(WARN, "Unable to enable the host interrupt!\n");
+ ret = BT_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function disables the host interrupts mask.
+ *
+ * @param priv A pointer to bt_private structure
+ * @param mask the interrupt mask
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_disable_host_int_mask(bt_private * priv, u8 mask)
+{
+ int ret = BT_STATUS_FAILURE;
+ u8 host_int_mask;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ /* Read back the host_int_mask register */
+ host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+ if (ret)
+ goto done;
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~mask;
+ sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+ if (ret < 0) {
+ PRINTM(WARN, "Unable to diable the host interrupt!\n");
+ goto done;
+ }
+ ret = BT_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function polls the card status register.
+ *
+ * @param priv A pointer to bt_private structure
+ * @param bits the bit mask
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_poll_card_status(bt_private * priv, u8 bits)
+{
+ int tries;
+ int rval;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+ u8 cs;
+
+ ENTER();
+
+ for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
+ cs = sdio_readb(card->func, CARD_STATUS_REG, &rval);
+ if (rval != 0)
+ break;
+ if (rval == 0 && (cs & bits) == bits) {
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ }
+ udelay(1);
+ }
+ PRINTM(WARN, "mv_sdio_poll_card_status: FAILED!:%d\n", rval);
+
+ LEAVE();
+ return BT_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function probe the card
+ *
+ * @param func A pointer to sdio_func structure.
+ * @param id A pointer to structure sd_device_id
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_probe_card(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret = BT_STATUS_SUCCESS;
+ bt_private *priv = NULL;
+ struct sdio_mmc_card *card = NULL;
+
+ ENTER();
+
+ PRINTM(INFO, "vendor=%x,device=%x,class=%d,fn=%d\n", id->vendor, id->device,
+ id->class, func->num);
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ card->func = func;
+ priv = bt_add_card(card);
+ if (!priv) {
+ ret = BT_STATUS_FAILURE;
+ kfree(card);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param priv A pointer to bt_private structure
+ * @param pollnum Number of times to polling fw status
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_verify_fw_download(bt_private * priv, int pollnum)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u16 firmwarestat;
+ int tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (sd_read_firmware_status(priv, &firmwarestat) < 0)
+ continue;
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = BT_STATUS_SUCCESS;
+ break;
+ } else {
+ mdelay(10);
+ ret = BT_STATUS_FAILURE;
+ }
+ }
+ if (ret < 0)
+ goto done;
+
+ ret = BT_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware image to the card.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_download_firmware_w_helper(bt_private * priv)
+{
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+ const struct firmware *fw_firmware = NULL;
+ u8 *firmware = NULL;
+ int firmwarelen;
+ u8 base0;
+ u8 base1;
+ int ret = BT_STATUS_SUCCESS;
+ int offset;
+ void *tmpfwbuf = NULL;
+ int tmpfwbufsz;
+ u8 *fwbuf;
+ u16 len;
+ int txlen = 0;
+ int tx_blocks = 0;
+ int i = 0;
+ int tries = 0;
+#ifdef FW_DOWNLOAD_SPEED
+ u32 tv1, tv2;
+#endif
+
+ ENTER();
+
+ if ((ret =
+ request_firmware(&fw_firmware, fw_name, priv->hotplug_device)) < 0) {
+ PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
+ goto done;
+ }
+
+ if (fw_firmware) {
+ firmware = (u8 *) fw_firmware->data;
+ firmwarelen = fw_firmware->size;
+ } else {
+ PRINTM(MSG, "No firmware image found! Terminating download\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
+
+#ifdef FW_DOWNLOAD_SPEED
+ tv1 = get_utimeofday();
+#endif
+
+#ifdef PXA3XX_DMA_ALIGN
+ tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
+#else /* PXA3XX_DMA_ALIGN */
+ tmpfwbufsz = BT_UPLD_SIZE;
+#endif
+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+ if (!tmpfwbuf) {
+ PRINTM(ERROR,
+ "Unable to allocate buffer for firmware. Terminating download\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ memset(tmpfwbuf, 0, tmpfwbufsz);
+#ifdef PXA3XX_DMA_ALIGN
+ /* Ensure 8-byte aligned firmware buffer */
+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT);
+#else /* PXA3XX_DMA_ALIGN */
+ fwbuf = (u8 *) tmpfwbuf;
+#endif
+
+ /* Perform firmware data transfer */
+ offset = 0;
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+ ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret < 0) {
+ PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n",
+ offset);
+ goto done;
+ }
+
+ /* More data? */
+ if (offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+ if (ret) {
+ PRINTM(WARN, "Dev BASE0 register read failed:"
+ " base0=0x%04X(%d). Terminating download\n", base0,
+ base0);
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+ if (ret) {
+ PRINTM(WARN, "Dev BASE1 register read failed:"
+ " base1=0x%04X(%d). Terminating download\n", base1,
+ base1);
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ len = (((u16) base1) << 8) | base0;
+
+ if (len != 0)
+ break;
+ udelay(10);
+ }
+
+ if (len == 0)
+ break;
+ else if (len > BT_UPLD_SIZE) {
+ PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(FATAL,
+ "FW download failure @ %d, over max retry count\n",
+ offset);
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(ERROR, "FW CRC error indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n", len, txlen);
+ len &= ~BIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking for last block */
+ if (firmwarelen - offset < txlen)
+ txlen = firmwarelen - offset;
+
+ PRINTM(INFO, ".");
+
+ tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;
+
+ /* Copy payload to buffer */
+ memcpy(fwbuf, &firmware[offset], txlen);
+ }
+
+ /* Send data */
+ ret =
+ sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf,
+ tx_blocks * SD_BLOCK_SIZE_FW_DL);
+
+ if (ret < 0) {
+ PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
+ offset);
+ sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
+ if (ret)
+ PRINTM(ERROR, "write ioreg failed (CFG)\n");
+ }
+
+ offset += txlen;
+ } while (TRUE);
+
+ PRINTM(INFO, "\nFW download over, size %d bytes\n", offset);
+
+ ret = BT_STATUS_SUCCESS;
+ done:
+#ifdef FW_DOWNLOAD_SPEED
+ tv2 = get_utimeofday();
+ PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
+ (tv1 % 1000000) / 1000, tv1 % 1000);
+ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
+ (tv2 % 1000000) / 1000, tv2 % 1000);
+ tv2 -= tv1;
+ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
+ (tv2 % 1000000) / 1000, tv2 % 1000);
+#endif
+ if (tmpfwbuf)
+ kfree(tmpfwbuf);
+ if (fw_firmware)
+ release_firmware(fw_firmware);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function reads data from the card.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_card_to_host(bt_private * priv)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u16 buf_len = 0;
+ int buf_block_len;
+ int blksz;
+ struct sk_buff *skb = NULL;
+ u32 type;
+ u8 *payload = NULL;
+ struct hci_dev *hdev = priv->bt_dev.hcidev;
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ PRINTM(ERROR, "card or function is NULL!\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Read the length of data to be transferred */
+ ret = sd_read_rx_len(priv, &buf_len);
+ if (ret < 0) {
+ PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Allocate buffer */
+ blksz = SD_BLOCK_SIZE;
+ buf_block_len = (buf_len + blksz - 1) / blksz;
+ if (buf_len <= BT_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+ PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ skb =
+ bt_skb_alloc(buf_block_len * blksz + PXA3XX_DMA_ALIGNMENT, GFP_ATOMIC);
+ if (skb == NULL) {
+ PRINTM(WARN, "No free skb\n");
+ goto exit;
+ }
+ if ((u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1)) {
+ skb_put(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
+ skb_pull(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
+ }
+
+ payload = skb->tail;
+ ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
+ ret = BT_STATUS_FAILURE;
+ goto exit;
+ }
+ DBG_HEXDUMP(DBG_DATA, "SDIO Blk Rd", payload, blksz * buf_block_len);
+ /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
+ (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
+ buf_len = payload[0];
+ buf_len |= (u16) payload[1] << 8;
+ type = payload[3];
+ switch (type) {
+ case HCI_ACLDATA_PKT:
+ case HCI_SCODATA_PKT:
+ case HCI_EVENT_PKT:
+ bt_cb(skb)->pkt_type = type;
+ skb->dev = (void *) hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, BT_HEADER_LEN);
+ if (type == HCI_EVENT_PKT)
+ check_evtpkt(priv, skb);
+ hci_recv_frame(skb);
+ hdev->stat.byte_rx += buf_len;
+ break;
+ case MRVL_VENDOR_PKT:
+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
+ skb->dev = (void *) hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, BT_HEADER_LEN);
+ if (BT_STATUS_SUCCESS != bt_process_event(priv, skb))
+ hci_recv_frame(skb);
+ hdev->stat.byte_rx += buf_len;
+ break;
+ default:
+ /* Driver specified event and command resp should be handle here */
+ PRINTM(INFO, "Unknow PKT type:%d\n", type);
+ kfree_skb(skb);
+ skb = NULL;
+ break;
+ }
+ exit:
+ if (ret) {
+ hdev->stat.err_rx++;
+ if (skb)
+ kfree_skb(skb);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef CONFIG_PM
+/**
+ * @brief This function handle the suspend function
+ *
+ * @param func A pointer to sdio_func structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+sd_suspend(struct sdio_func *func)
+{
+ struct hci_dev *hcidev;
+ struct sdio_mmc_card *card;
+ bt_private *priv = NULL;
+
+ ENTER();
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card)
+ priv = card->priv;
+ }
+ if (!priv) {
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ }
+ if (priv->adapter->hs_state != HS_ACTIVATED) {
+ if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ }
+ hcidev = priv->bt_dev.hcidev;
+ hci_suspend_dev(hcidev);
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle the resume function
+ *
+ * @param func A pointer to sdio_func structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+sd_resume(struct sdio_func *func)
+{
+ struct hci_dev *hcidev;
+ struct sdio_mmc_card *card;
+ bt_private *priv = NULL;
+
+ ENTER();
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card)
+ priv = card->priv;
+ }
+ if (!priv) {
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ }
+ hcidev = priv->bt_dev.hcidev;
+ hci_resume_dev(hcidev);
+ /* if (is_bt_the_wakeup_src()){ */
+ {
+ PRINTM(MSG, "WAKEUP SRC: BT\n");
+ if ((priv->bt_dev.gpio_gap & 0x00ff) == 0xff) {
+ sbi_wakeup_firmware(priv);
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ }
+ }
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function removes the card
+ *
+ * @param func A pointer to sdio_func structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static void
+sd_remove_card(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ bt_remove_card(card);
+ kfree(card);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param func A pointer to sdio_func structure
+ * @return n/a
+ */
+static void
+sd_interrupt(struct sdio_func *func)
+{
+ bt_private *priv;
+ struct hci_dev *hcidev;
+ struct sdio_mmc_card *card;
+ int ret = BT_STATUS_SUCCESS;
+ u8 ireg = 0;
+
+ ENTER();
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->priv) {
+ PRINTM(INFO, "%s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
+ __FUNCTION__, func, card);
+ LEAVE();
+ return;
+ }
+ priv = card->priv;
+ hcidev = priv->bt_dev.hcidev;
+
+ ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ PRINTM(WARN, "sdio_read_ioreg: read int status register failed\n");
+ goto done;
+ }
+ if (ireg != 0) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register and re-enable the interrupt
+ */
+ PRINTM(INFO, "sdio_ireg = 0x%x\n", ireg);
+ priv->adapter->irq_recv = ireg;
+ sdio_writeb(card->func,
+ ~(ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS),
+ HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ PRINTM(WARN,
+ "sdio_write_ioreg: clear int status register failed\n");
+ goto done;
+ }
+ }
+ OS_INT_DISABLE;
+ sd_ireg |= ireg;
+ OS_INT_RESTORE;
+ bt_interrupt(hcidev);
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interfaces are present
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ * UPON BT_STATUS_SUCCESS the calling interface
+ * is winner
+ */
+int
+sd_check_winner_status(bt_private * priv)
+{
+
+ int ret = BT_STATUS_SUCCESS;
+ u8 winner_status = 0;
+ struct sdio_mmc_card *cardp = (struct sdio_mmc_card *) priv->bt_dev.card;
+
+ ENTER();
+
+ winner_status = sdio_readb(cardp->func, CARD_FW_STATUS0_REG, &ret);
+ if (ret != BT_STATUS_SUCCESS) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ if (winner_status != 0)
+ ret = BT_STATUS_FAILURE;
+ else
+ ret = BT_STATUS_SUCCESS;
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+static struct sdio_driver sdio_bt = {
+ .name = "sdio_bt",
+ .id_table = bt_ids,
+ .probe = sd_probe_card,
+ .remove = sd_remove_card,
+/*
+#ifdef CONFIG_PM
+ .suspend = sd_suspend,
+ .resume = sd_resume,
+#endif
+*/
+};
+
+/**
+ * @brief This function registers the bt module in bus driver.
+ *
+ * @return An int pointer that keeps returned value
+ */
+int *
+sbi_register(void)
+{
+ int *ret;
+
+ ENTER();
+
+ if (sdio_register_driver(&sdio_bt) != 0) {
+ PRINTM(FATAL, "SD Driver Registration Failed \n");
+ LEAVE();
+ return NULL;
+ } else
+ ret = (int *) 1;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the bt module in bus driver.
+ *
+ * @return n/a
+ */
+void
+sbi_unregister(void)
+{
+ ENTER();
+ sdio_unregister_driver(&sdio_bt);
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the device.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_register_dev(bt_private * priv)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u8 reg;
+ u8 chiprev;
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ struct sdio_func *func;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ PRINTM(ERROR, "Error: card or function is NULL!\n");
+ goto failed;
+ }
+ func = card->func;
+ priv->hotplug_device = &func->dev;
+ if (fw_name == NULL)
+ fw_name = DEFAULT_FW_NAME;
+
+ /* Initialize the private structure */
+ strncpy(priv->bt_dev.name, "bt_sdio0", sizeof(priv->bt_dev.name));
+ priv->bt_dev.ioport = 0;
+ priv->bt_dev.fn = func->num;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ PRINTM(FATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+ goto release_host;
+ }
+ ret = sdio_claim_irq(func, sd_interrupt);
+ if (ret) {
+ PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+ goto disable_func;
+ }
+ ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
+ if (ret) {
+ PRINTM(FATAL, "%s: cannot set SDIO block size\n", __FUNCTION__);
+ goto release_irq;
+ }
+
+ /* read Revision Register to get the chip revision number */
+ chiprev = sdio_readb(func, CARD_REVISION_REG, &ret);
+ if (ret) {
+ PRINTM(FATAL, "cannot read CARD_REVISION_REG\n");
+ goto release_irq;
+ }
+ priv->adapter->chip_rev = chiprev;
+ PRINTM(INFO, "revision=%#x\n", chiprev);
+
+ /* Read the IO port */
+ reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+ if (ret < 0)
+ goto release_irq;
+ else
+ priv->bt_dev.ioport |= reg;
+
+ reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+ if (ret < 0)
+ goto release_irq;
+ else
+ priv->bt_dev.ioport |= (reg << 8);
+
+ reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+ if (ret < 0)
+ goto release_irq;
+ else
+ priv->bt_dev.ioport |= (reg << 16);
+
+ PRINTM(INFO, "SDIO FUNC%d IO port: 0x%x\n", priv->bt_dev.fn,
+ priv->bt_dev.ioport);
+ sdio_set_drvdata(func, card);
+ sdio_release_host(func);
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+ release_irq:
+ sdio_release_irq(func);
+ disable_func:
+ sdio_disable_func(func);
+ release_host:
+ sdio_release_host(func);
+ failed:
+
+ LEAVE();
+ return BT_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function de-registers the device.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+sbi_unregister_dev(bt_private * priv)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+
+ ENTER();
+
+ if (card && card->func) {
+ sdio_claim_host(card->func);
+ sdio_release_irq(card->func);
+ sdio_disable_func(card->func);
+ sdio_release_host(card->func);
+ sdio_set_drvdata(card->func, NULL);
+ }
+
+ LEAVE();
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS
+ */
+int
+sbi_enable_host_int(bt_private * priv)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ int ret;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ sdio_claim_host(card->func);
+ ret = sd_enable_host_int_mask(priv, HIM_ENABLE);
+ sd_get_rx_unit(priv);
+ sdio_release_host(card->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_disable_host_int(bt_private * priv)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ int ret;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ sdio_claim_host(card->func);
+ ret = sd_disable_host_int_mask(priv, HIM_DISABLE);
+ sdio_release_host(card->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param priv A pointer to bt_private structure
+ * @param payload A pointer to the data/cmd buffer
+ * @param nb the length of data/cmd
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ int ret = BT_STATUS_SUCCESS;
+ int buf_block_len;
+ int blksz;
+ int i = 0;
+ u8 *buf = NULL;
+#ifdef PXA3XX_DMA_ALIGN
+ void *tmpbuf = NULL;
+ int tmpbufsz;
+#endif
+
+ ENTER();
+
+ if (!card || !card->func) {
+ PRINTM(ERROR, "card or function is NULL!\n");
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ buf = payload;
+#ifdef PXA3XX_DMA_ALIGN
+ if ((u32) payload & (PXA3XX_DMA_ALIGNMENT - 1)) {
+ tmpbufsz = ALIGN_SZ(nb, PXA3XX_DMA_ALIGNMENT);
+ tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
+ memset(tmpbuf, 0, tmpbufsz);
+ /* Ensure 8-byte aligned CMD buffer */
+ buf = (u8 *) ALIGN_ADDR(tmpbuf, PXA3XX_DMA_ALIGNMENT);
+ memcpy(buf, payload, nb);
+ }
+#endif
+ /* Allocate buffer and copy payload */
+ blksz = SD_BLOCK_SIZE;
+ buf_block_len = (nb + blksz - 1) / blksz;
+ sdio_claim_host(card->func);
+#define MAX_WRITE_IOMEM_RETRY 2
+ do {
+ /* Transfer data to card */
+ ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ i++;
+ PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+ ret);
+ ret = BT_STATUS_FAILURE;
+ if (i > MAX_WRITE_IOMEM_RETRY)
+ goto exit;
+ } else {
+ DBG_HEXDUMP(DBG_DATA, "SDIO Blk Wr", payload, nb);
+ }
+ } while (ret == BT_STATUS_FAILURE);
+ priv->bt_dev.tx_dnld_rdy = FALSE;
+ exit:
+ sdio_release_host(card->func);
+#ifdef PXA3XX_DMA_ALIGN
+ if (tmpbuf)
+ kfree(tmpbuf);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_dowload_fw(bt_private * priv)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ int ret = BT_STATUS_SUCCESS;
+ int poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ PRINTM(ERROR, "card or function is NULL!\n");
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ sdio_claim_host(card->func);
+ if (BT_STATUS_SUCCESS == sd_verify_fw_download(priv, 1)) {
+ PRINTM(INFO, "Firmware already downloaded!\n");
+ goto done;
+ }
+ /* Check if other interface is downloading */
+ ret = sd_check_winner_status(priv);
+ if (ret == BT_STATUS_FAILURE) {
+ PRINTM(INFO, "winner interface already running! Skip FW download\n");
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+
+ /* Download the main firmware via the helper firmware */
+ if (sd_download_firmware_w_helper(priv)) {
+ PRINTM(INFO, "Bluetooth FW download failed!\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ poll_fw:
+ /* check if the fimware is downloaded successfully or not */
+ if (sd_verify_fw_download(priv, poll_num)) {
+ PRINTM(INFO, "FW failed to be active in time!\n");
+ ret = BT_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ sdio_release_host(card->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and handle it accordingly.
+ *
+ * @param priv A pointer to bt_private structure
+ * @param ireg A pointer to variable that keeps returned value
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_get_int_status(bt_private * priv, u8 * ireg)
+{
+ int ret = BT_STATUS_SUCCESS;
+ u8 sdio_ireg = 0;
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+
+ ENTER();
+
+ *ireg = 0;
+ OS_INT_DISABLE;
+ sdio_ireg = sd_ireg;
+ sd_ireg = 0;
+ OS_INT_RESTORE;
+
+ sdio_claim_host(card->func);
+ priv->adapter->irq_done = sdio_ireg;
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT */
+ if (priv->bt_dev.tx_dnld_rdy) { /* tx_done already received */
+ PRINTM(INFO,
+ "warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
+ priv->bt_dev.tx_dnld_rdy, sdio_ireg);
+ } else {
+ priv->bt_dev.tx_dnld_rdy = TRUE;
+ }
+ }
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+ sd_card_to_host(priv);
+
+ *ireg = sdio_ireg;
+ ret = BT_STATUS_SUCCESS;
+ sdio_release_host(card->func);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function wakeup firmware
+ *
+ * @param priv A pointer to bt_private structure
+ * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_wakeup_firmware(bt_private * priv)
+{
+ struct sdio_mmc_card *card = priv->bt_dev.card;
+ int ret = BT_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!card || !card->func) {
+ PRINTM(ERROR, "card or function is NULL!\n");
+ LEAVE();
+ return BT_STATUS_FAILURE;
+ }
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ sdio_release_host(card->func);
+ PRINTM(CMD, "wake up firmware\n");
+
+ LEAVE();
+ return ret;
+}
+
+module_param(fw_name, charp, 0);
+MODULE_PARM_DESC(fw_name, "Firmware name");
diff --git a/bt_src/bt/include.h b/bt_src/bt/include.h
new file mode 100755
index 0000000..4aa360b
--- /dev/null
+++ b/bt_src/bt/include.h
@@ -0,0 +1,43 @@
+/** @file include.h
+ * @brief This file contains all the necessary include file.
+ *
+ * Copyright (C) 2007-2008, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _INCLUDE_H_
+#define _INCLUDE_H_
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <linux/version.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include "bt_drv.h"
+#include "bt_sdio.h"
+#endif /* _INCLUDE_H_ */
diff --git a/bt_src/gpl.txt b/bt_src/gpl.txt
new file mode 100755
index 0000000..f90922e
--- /dev/null
+++ b/bt_src/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..cbe0747
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+export KERNELDIR=$PWD/../../build/kernels/kernel-i386-intel-menlow/linux-2.6.31.4/
+export CROSS_COMPILE=
+export ARCH=i386
+
+# The number of jobs to pass to tools that can run in parallel (such as make
+# and dpkg-buildpackage
+NUM_JOBS=`cat /proc/cpuinfo | grep processor | awk '{a++} END {print a}'`
+
+BUILDDIR=$PWD/build
+rm -rf $BUILDDIR
+mkdir -p $BUILDDIR
+
+pushd wlan_src
+make clean || true
+make -j$NUM_JOBS KERNELDIR=$KERNELDIR CROSS_COMPILE=$CROSS_COMPILE ARCH=$ARCH
+make KERNELDIR=$KERNELDIR ARCH=$ARCH INSTALLDIR=$BUILDDIR install
+popd
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..f9797a4
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+marvell-8787 (0.1) karmic; urgency=low
+
+ * Initial import
+
+ -- The Chromium OS Authors <chromium-os-dev@googlegroups.com> Tue, 11 Aug 2009 06:56:24 +0000
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..f41d045
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+Source: marvell-8787
+Section: unknown
+Priority: extra
+Maintainer: The Chromium OS Authors <chromium-os-dev@googlegroups.com>
+Build-Depends: debhelper (>= 7)
+Standards-Version: 3.8.0
+
+Package: marvell-8787
+Architecture: any
+Depends:
+Description: mrvl8787
+ Marvell driver for 8787 WiFi+BT+FM radio part.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..78790c5
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1,8 @@
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+lib/firmware
+lib/firmware/mrvl
+etc
+etc/modprobe.d
diff --git a/debian/postinst b/debian/postinst
new file mode 100644
index 0000000..b84fc8b
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# postinst script for marvell-8787
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ configure)
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..dba398e
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,98 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+flavour=chromeos-intel-menlow
+ARCH=i386
+CROSS_COMPILE=
+KERNELDIR=~/trunk/src/build/kernels/kernel-${flavour}/debian/build/build-${flavour}
+
+MRVL_MAKE=$(MAKE) KERNELDIR=$(KERNELDIR) CROSS_COMPILE=$(CROSS_COMPILE) \
+ ARCH=$(ARCH)
+
+INSTALL_DIR=$(CURDIR)/debian/marvell-8787
+MODULES_DIR=lib/modules/2.6.31-0-${flavour}/vendor/marvell
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # nothing to do to configure package
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+ # NB: $(MAKE) -C wlan_src fails 'cuz $(PWD) is set wrong
+ cd wlan_src; $(MRVL_MAKE)
+ touch $@
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+ $(MRVL_MAKE) -C wlan_src clean
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_prep
+ dh_installdirs
+
+ mkdir -p $(INSTALL_DIR)/$(MODULES_DIR)
+ # NB: $(MAKE) -C wlan_src fails 'cuz $(PWD) is set wrong
+ cd wlan_src; $(MRVL_MAKE) INSTALLDIR=$(INSTALL_DIR)/$(MODULES_DIR) \
+ install
+
+ mkdir -p $(INSTALL_DIR)
+ cp marvell_8787.conf $(INSTALL_DIR)/etc/modprobe.d
+
+ mkdir -p $(INSTALL_DIR)/lib/firmware/mrvl
+ cp FwImage/sd8787.bin $(INSTALL_DIR)/lib/firmware/mrvl
+
+# Build architecture-independent files here.
+binary-indep: install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: install
+ dh_testdir
+ dh_testroot
+# dh_installchangelogs
+# dh_installdocs
+# dh_installexamples
+# dh_install
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_python
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+# dh_installman
+# dh_link
+# dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/io/sdio/syskt/Makefile b/io/sdio/syskt/Makefile
new file mode 100755
index 0000000..ff07bd5
--- /dev/null
+++ b/io/sdio/syskt/Makefile
@@ -0,0 +1,58 @@
+# File: Makefile
+#
+# Copyright (C) 2003-2009, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+# Things that need to export symbols
+# export-objs := sdiobus.o
+
+
+# Objects to compile in this module
+#
+STDHOSTOBJS = sdiobus.o \
+ stdhost.o \
+ skisr.o
+
+
+obj-m += mrvlsdio.o
+mrvlsdio-objs := $(STDHOSTOBJS)
+
+
+# EXTRA_CFLAGS += -DDBG
+# EXTRA_CFLAGS += -DSDIO_API_INTERNAL
+# EXTRA_CFLAGS += -DSDIO_BUS_DRIVER
+EXTRA_CFLAGS += -DSDIO_ALTERNATIVE_IRQ
+EXTRA_CFLAGS += -I$(PWD)
+
+#
+# Make target rules
+#
+all: mrvlsdio.o
+ifeq ($(KVER),2.6)
+ @echo "Finished Making Marvell SDIO Stdhost Linux Driver for Kernel 2.6"
+else
+ @echo "Finished Making Marvell SDIO Stdhost Linux Driver for Kernel 2.4"
+endif
+
+mrvlsdio.o: $(STDHOSTOBJS)
+ $(LD) -r $^ -o $@
+
+clean:
+ find . -name "*.o" -exec rm {} \;
+ find . -name "*.*~" -exec rm {} \;
+ find . -name "*.d" -exec rm {} \;
+ find . -name "*.mod.c" -exec rm {} \;
+ find . -name "*.ko" -exec rm {} \;
+ find . -name ".*.cmd" -exec rm {} \;
diff --git a/io/sdio/syskt/diagvers.h b/io/sdio/syskt/diagvers.h
new file mode 100644
index 0000000..2d93c64
--- /dev/null
+++ b/io/sdio/syskt/diagvers.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Name: diagvers.h_
+ * Project: Wireless LAN, SDIO Bus driver
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:23:14 $
+ * Purpose: SDIO bus driver version control
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: diagvers.h,v $
+ * Revision 1.1 2007/01/18 09:23:14 pweber
+ * Put under CVS control
+ *
+ *
+ ******************************************************************************/
+
+// #define SK_SIGNON_MSG "___OEM_SIGNONMSG__"
+#define SK_SIGNON_MSG "Marvell SD Standard Host Driver V.2.0.0.0"
diff --git a/io/sdio/syskt/gpl.txt b/io/sdio/syskt/gpl.txt
new file mode 100755
index 0000000..f90922e
--- /dev/null
+++ b/io/sdio/syskt/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/io/sdio/syskt/h/sdio.h b/io/sdio/syskt/h/sdio.h
new file mode 100644
index 0000000..ed938c4
--- /dev/null
+++ b/io/sdio/syskt/h/sdio.h
@@ -0,0 +1,133 @@
+/**
+ *
+ * Name: sdio.h
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: Bus driver for SDIO interface definitions
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+#ifndef _SDIO_H_
+#define _SDIO_H_
+
+#include <linux/types.h>
+#include "sdio_spec.h"
+
+/* CMD53 parameter*/
+//mode
+#define BLOCK_MODE 0x1
+#define BYTE_MODE 0x0
+//opcode
+#define FIXED_ADDRESS 0x0
+#define INCREMENTAL_ADDRESS 0x1
+
+/*****************************************************************/
+/* New Multifunction SDIO Bus Driver API */
+/*****************************************************************/
+
+#define SD_CLASS_ANY (0xFFFF)
+#define SD_FUNCTION_ANY (0xFFFF)
+#define SD_VENDOR_ANY (0xFFFF)
+#define SD_DEVICE_ANY (0xFFFF)
+
+#define SD_VENDOR_MARVELL 0x02df
+
+#define SD_CLASS_BT_A 0x02
+#define SD_CLASS_BT_B 0x03
+#define SD_CLASS_WLAN 0x07
+
+typedef struct _sd_device_id
+{
+ u16 vendor; /* vendor id */
+ u16 device; /* device id */
+ u16 class; /* class id */
+ u16 fn; /* function number: 1-7 */
+ u16 blocksize; /* block size */
+} sd_device_id, *psd_device_id;
+
+#define COMPARE_DEVICE_ID(dev_id_1,dev_id_2) \
+(((sd_device_id *)(dev_id_1)->vendor == (sd_device_id *)(dev_id_2)->vendor) && \
+ ((sd_device_id *)(dev_id_1)->device == (sd_device_id *)(dev_id_2)->device) && \
+ ((sd_device_id *)(dev_id_1)->class == (sd_device_id *)(dev_id_2)->class) && \
+ ((sd_device_id *)(dev_id_1)->fn == (sd_device_id *)(dev_id_2)->fn))
+
+#define MAX_SDIO_FUNCTIONS 8
+typedef void (*sd_int_handler) (void *dev, sd_device_id * id, void *context);
+
+typedef struct _sd_function
+{
+ u16 class; /* class id */
+ sd_int_handler int_handler; /* interrupt handler per function */
+ void *context; /* private context per function, will be
+ passed back to the int_handler */
+} sd_function, *psd_function;
+
+struct _sd_device
+{
+ struct _sd_driver *drv; /* pointer to the SD client driver */
+ sd_function functions[MAX_SDIO_FUNCTIONS]; /* All supported functions */
+ void *sd_bus; /* Pointer to bus driver's private data */
+ psd_device_id pCurrent_Ids; /* pointer to current ids */
+ u8 chiprev;
+ u32 *cisptr;
+ u8 supported_functions;
+ struct device *dev; /* generic device interface for hotplug */
+ u8 probe_called;
+ u8 remove_called;
+ void *priv;
+};
+
+struct _sd_driver
+{
+ const char *name; /* name of client */
+ sd_device_id *ids; /* ids for this client driver */
+ int (*probe) (struct _sd_device * dev, sd_device_id * id); /* client
+ driver probe
+ handler */
+ int (*remove) (struct _sd_device * dev); /* client driver remove handler
+ */
+ int (*suspend) (struct _sd_device * dev); /* client driver suspend
+ handler */
+ int (*resume) (struct _sd_device * dev); /* client driver resume handler
+ */
+};
+
+typedef struct _sd_driver sd_driver, *psd_driver;
+typedef struct _sd_device sd_device, *psd_device;
+
+/* Functions exported out for WLAN Layer */
+int sd_driver_register(sd_driver * drv);
+int sd_driver_unregister(sd_driver * drv);
+int sd_request_int(sd_device * dev, sd_device_id * id, sd_function * function);
+int sd_release_int(sd_device * dev, sd_device_id * id);
+int sd_unmask(sd_device * dev, sd_device_id * id);
+int sd_enable_int(sd_device * dev, sd_device_id * id);
+int sd_disable_int(sd_device * dev, sd_device_id * id);
+int sd_set_buswidth(sd_device * dev, int width);
+int sd_set_busclock(sd_device * dev, int clock);
+int sd_set_clock_on(sd_device * dev, int on);
+int sd_start_clock(sd_device * dev);
+int sd_stop_clock(sd_device * dev);
+int sd_set_gpo(sd_device * dev, int on);
+int sdio_read_ioreg(sd_device * dev, u8 fn, u32 reg, u8 * dat);
+int sdio_write_ioreg(sd_device * dev, u8 fn, u32 reg, u8 dat);
+int sdio_read_iomem(sd_device * dev, u8 fn, u32 address, u8 blkmode, u8 opcode,
+ u32 blkcnt, u32 blksz, u8 * buffer);
+int sdio_write_iomem(sd_device * dev, u8 fn, u32 address, u8 blkmode, u8 opcode,
+ u32 blkcnt, u32 blksz, u8 * buffer);
+#endif /* sdio.h */
diff --git a/io/sdio/syskt/h/sdio_spec.h b/io/sdio/syskt/h/sdio_spec.h
new file mode 100644
index 0000000..9a0762a
--- /dev/null
+++ b/io/sdio/syskt/h/sdio_spec.h
@@ -0,0 +1,238 @@
+/**
+ * File : sdio_spec.h
+ * Addresses defined by SDIO Specifications
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _SDIOSPEC_H_
+#define _SDIOSPEC_H_
+
+#define MAX_SDIO_TUPLE_BODY_LEN 255
+
+/* CCCR (Card Common Control Registers) */
+#define CCCR_SDIO_REV_REG 0x00
+#define CCCR_FORMAT_VERSION(reg) (((reg) & 0xf0 >> 4))
+#define SDIO_SPEC_REVISION(reg) (((reg) & 0x0f))
+
+#define SD_SPEC_REV_REG 0x01
+#define SD_PHYS_SPEC_VERSION(reg) (((reg) & 0x0f))
+
+#define IO_ENABLE_REG 0x02
+#define IOE(x) (0x1U << (x))
+#define IOE_1 IOE(1)
+#define IOE_2 IOE(2)
+#define IOE_3 IOE(3)
+#define IOE_4 IOE(4)
+#define IOE_5 IOE(5)
+#define IOE_6 IOE(6)
+#define IOE_7 IOE(7)
+
+#define IO_READY_REG 0x03
+#define IOR(x) (0x1U << (x))
+#define IOR_1 IOR(1)
+#define IOR_2 IOR(2)
+#define IOR_3 IOR(3)
+#define IOR_4 IOR(4)
+#define IOR_5 IOR(5)
+#define IOR_6 IOR(6)
+#define IOR_7 IOR(7)
+
+#define INT_ENABLE_REG 0x04
+#define IENM 0x1
+#define IEN(x) (0x1U << (x))
+#define IEN_1 IEN(1)
+#define IEN_2 IEN(2)
+#define IEN_3 IEN(3)
+#define IEN_4 IEN(4)
+#define IEN_5 IEN(5)
+#define IEN_6 IEN(6)
+#define IEN_7 IEN(7)
+
+#define INT_PENDING_REG 0x05
+#define INT(x) (0x1U << (x))
+#define INT_1 INT(1)
+#define INT_2 INT(2)
+#define INT_3 INT(3)
+#define INT_4 INT(4)
+#define INT_5 INT(5)
+#define INT_6 INT(6)
+#define INT_7 INT(7)
+
+#define IO_ABORT_REG 0x06
+#define AS(x) ((x) & 0x7)
+#define AS_1 AS(1)
+#define AS_2 AS(2)
+#define AS_3 AS(3)
+#define AS_4 AS(4)
+#define AS_5 AS(5)
+#define AS_6 AS(6)
+#define AS_7 AS(7)
+
+#define RES (0x00)
+
+#define BUS_INTERFACE_CONTROL_REG 0x07
+#define BUS_WIDTH(reg) ((reg) & 0x3)
+#define CD_DISABLE (0x1U << 7)
+
+#define CARD_CAPABILITY_REG 0x08
+#define SDC (0x1U << 0)
+#define SMB (0x1U << 1)
+#define SRW (0x1U << 2)
+#define SBS (0x1U << 3)
+#define S4MI (0x1U << 4)
+#define E4MI (0x1U << 5)
+#define LSC (0x1U << 6)
+#define S4BLS (0x1U << 7)
+
+#define COMMON_CIS_POINTER_0_REG 0x09
+
+#define COMMON_CIS_POINTER_1_REG 0x0a
+
+#define COMMON_CIS_POINTER_2_REG 0x0b
+
+#define BUS_SUSPEND_REG 0x0c
+#define BUS_STATUS (0x1U << 0)
+#define BUS_REL_REQ_STATUS (0x1U << 1)
+
+#define FUNCTION_SELECT_REG 0x0d
+#ifdef FS
+#undef FS
+#endif
+#define FS(x) ((x) & 0xf)
+#define FS_1 FS(1)
+#define FS_2 FS(2)
+#define FS_3 FS(3)
+#define FS_4 FS(4)
+#define FS_5 FS(5)
+#define FS_6 FS(6)
+#define FS_7 FS(7)
+#define FS_MEM FS(8)
+#define DF (0x1U << 7)
+
+#define EXEC_FLAGS_REG 0x0e
+#define EXM 0x0
+#define EX(x) (0x1U << (x))
+#define EX_1 EX(1)
+#define EX_2 EX(2)
+#define EX_3 EX(3)
+#define EX_4 EX(4)
+#define EX_5 EX(5)
+#define EX_6 EX(6)
+#define EX_7 EX(7)
+
+#define READY_FLAGS_REG 0x0f
+#define RFM 0x0
+#define RF(x) (0x1U << (x))
+#define RF_1 RF(1)
+#define RF_2 RF(2)
+#define RF_3 RF(3)
+#define RF_4 RF(4)
+#define RF_5 RF(5)
+#define RF_6 RF(6)
+#define RF_7 IEN(7)
+
+/* FBR (Function Basic Registers) */
+#define FN_CSA_REG(x) (0x100 * (x) + 0x00)
+#define FN_CIS_POINTER_0_REG(x) (0x100 * (x) + 0x09)
+#define FN_CIS_POINTER_1_REG(x) (0x100 * (x) + 0x0a)
+#define FN_CIS_POINTER_2_REG(x) (0x100 * (x) + 0x0b)
+#define FN_CSA_DAT_REG(x) (0x100 * (x) + 0x0f)
+#define FN_BLOCK_SIZE_0_REG(x) (0x100 * (x) + 0x10)
+#define FN_BLOCK_SIZE_1_REG(x) (0x100 * (x) + 0x11)
+
+/* Function 0 -- duplicate, see the CCRC section */
+#define FN0_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(1)
+#define FN0_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(1)
+#define FN0_CIS_POINTER_2_REG FN_CIS_POINTER_1_REG(1)
+#define FN0_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(1)
+#define FN0_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(1)
+/* Function 1 */
+#define FN1_CSA_REG FN_CSA_REG(1)
+#define FN1_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(1)
+#define FN1_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(1)
+#define FN1_CIS_POINTER_2_REG FN_CIS_POINTER_1_REG(1)
+#define FN1_CSA_DAT_REG FN_CSA_DAT_REG(1)
+#define FN1_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(1)
+#define FN1_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(1)
+/* Function 2 */
+#define FN2_CSA_REG FN_CSA_REG(2)
+#define FN2_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(2)
+#define FN2_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(2)
+#define FN2_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(2)
+#define FN2_CSA_DAT_REG FN_CSA_DAT_REG(2)
+#define FN2_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(2)
+#define FN2_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(2)
+/* Function 3 */
+#define FN3_CSA_REG FN_CSA_REG(3)
+#define FN3_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(3)
+#define FN3_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(3)
+#define FN3_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(3)
+#define FN3_CSA_DAT_REG FN_CSA_DAT_REG(3)
+#define FN3_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(3)
+#define FN3_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(3)
+/* Function 4 */
+#define FN4_CSA_REG FN_CSA_REG(4)
+#define FN4_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(4)
+#define FN4_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(4)
+#define FN4_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(4)
+#define FN4_CSA_DAT_REG FN_CSA_DAT_REG(4)
+#define FN4_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(4)
+#define FN4_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(4)
+/* Function 5 */
+#define FN5_CSA_REG FN_CSA_REG(5)
+#define FN5_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(5)
+#define FN5_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(5)
+#define FN5_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(5)
+#define FN5_CSA_DAT_REG FN_CSA_DAT_REG(5)
+#define FN5_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(5)
+#define FN5_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(5)
+/* Function 6 */
+#define FN6_CSA_REG FN_CSA_REG(6)
+#define FN6_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(6)
+#define FN6_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(6)
+#define FN6_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(6)
+#define FN6_CSA_DAT_REG FN_CSA_DAT_REG(6)
+#define FN6_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(6)
+#define FN6_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(6)
+/* Function 7 */
+#define FN7_CSA_REG FN_CSA_REG(7)
+#define FN7_CIS_POINTER_0_REG FN_CIS_POINTER_0_REG(7)
+#define FN7_CIS_POINTER_1_REG FN_CIS_POINTER_1_REG(7)
+#define FN7_CIS_POINTER_2_REG FN_CIS_POINTER_2_REG(7)
+#define FN7_CSA_DAT_REG FN_CSA_DAT_REG(7)
+#define FN7_BLOCK_SIZE_0_REG FN_BLOCK_SIZE_0_REG(7)
+#define FN7_BLOCK_SIZE_1_REG FN_BLOCK_SIZE_1_REG(7)
+
+/* FBR bit definitions */
+#define FN_IODEV_INTERFACE_CODE(reg) ((reg) & 0xf)
+#define FN_SUPPORTS_CSA (0x1U << 6)
+#define FN_CSA_ENABLE (0x1U << 7)
+
+/* Misc. helper definitions */
+#define FN(x) (x)
+#define FN0 FN(0)
+#define FN1 FN(1)
+#define FN2 FN(2)
+#define FN3 FN(3)
+#define FN4 FN(4)
+#define FN5 FN(5)
+#define FN6 FN(6)
+#define FN7 FN(7)
+
+#endif /* __SDIO_SPEC__H */
diff --git a/io/sdio/syskt/h/sdiobus.h b/io/sdio/syskt/h/sdiobus.h
new file mode 100644
index 0000000..0cbfa5f
--- /dev/null
+++ b/io/sdio/syskt/h/sdiobus.h
@@ -0,0 +1,268 @@
+/**
+ *
+ * Name: sdiobus.h
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: Bus driver for SDIO interface definitions
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: sdiobus.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ ******************************************************************************/
+#ifndef SDIOBUS_H
+#define SDIOBUS_H
+
+#include "sdio.h"
+
+#define USE_SDIO_IF_SEMA
+
+#ifdef USE_SDIO_IF_SEMA
+#ifdef DEBUG_SDIO_IF_SEMA
+#define GET_IF_SEMA() \
+ printk(">>>> %s@%d: SEMA DOWN\n",__FUNCTION__,__LINE__);\
+ if ( down_interruptible(&sd_if_sema)) return -ERESTARTSYS;
+#define GET_IF_SEMA_NO_RC() \
+ printk(">>>> %s@%d: SEMA DOWN\n",__FUNCTION__,__LINE__);\
+ if ( down_interruptible(&sd_if_sema)) return;
+#else
+#define GET_IF_SEMA() \
+ if ( down_interruptible(&sd_if_sema)) return -ERESTARTSYS;
+#define GET_IF_SEMA_NO_RC() \
+ if ( down_interruptible(&sd_if_sema)) return;
+#endif
+
+#ifdef DEBUG_SDIO_IF_SEMA
+#define REL_IF_SEMA() \
+ printk("<<<< %s@%d: SEMA UP\n",__FUNCTION__,__LINE__);\
+ up(&sd_if_sema)
+#else
+#define REL_IF_SEMA() \
+ up(&sd_if_sema)
+#endif
+#else
+#define GET_IF_SEMA()
+#define GET_IF_SEMA_NO_RC()
+#define REL_IF_SEMA()
+#endif
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+#define FILE_DEVICE_SDIOBUSENUM 0x2A // same as for Windows
+#define SDIOBUSENUM_IOCTL(_index_) \
+ _IOWR(FILE_DEVICE_SDIOBUSENUM, _index_, unsigned int )
+
+#define IOCTL_SDIOBUSENUM_PLUGIN_HARDWARE SDIOBUSENUM_IOCTL (0x0)
+#define IOCTL_SDIOBUSENUM_UNPLUG_HARDWARE SDIOBUSENUM_IOCTL (0x1)
+#define IOCTL_SDIOBUSENUM_EJECT_HARDWARE SDIOBUSENUM_IOCTL (0x2)
+#define IOCTL_SDIOBUS_DONT_DISPLAY_IN_UI_DEVICE SDIOBUSENUM_IOCTL (0x3)
+// IOCTL for FPGA Configuration GUI
+#define IOCTL_SDIOBUSENUM_SET_VOLTAGE SDIOBUSENUM_IOCTL (0x4)
+#define IOCTL_SDIOBUSENUM_SET_BUSTYPE SDIOBUSENUM_IOCTL (0x5)
+#define IOCTL_SDIOBUSENUM_SET_BUSWIDTH SDIOBUSENUM_IOCTL (0x6)
+#define IOCTL_SDIOBUSENUM_SET_CLKSPEED SDIOBUSENUM_IOCTL (0x7)
+#define IOCTL_SDIOBUSENUM_GET_BOARDREV SDIOBUSENUM_IOCTL (0x8)
+#define IOCTL_SDIOBUSENUM_GET_JUMPER SDIOBUSENUM_IOCTL (0x9)
+
+#define _SLEEP_MS( pDev, millisecs ) mdelay(millisecs)
+
+#define MMC_TYPE_HOST 1
+#define MMC_TYPE_CARD 2
+#define MMC_REG_TYPE_USER 3
+
+#define SD_BLOCK_SIZE 32
+
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+
+/* FBR (Function Basic Registers) */
+#define FN_CSA_REG(x) (0x100 * (x) + 0x00)
+#define FN_CIS_POINTER_0_REG(x) (0x100 * (x) + 0x09)
+#define FN_CIS_POINTER_1_REG(x) (0x100 * (x) + 0x0a)
+#define FN_CIS_POINTER_2_REG(x) (0x100 * (x) + 0x0b)
+#define FN_CSA_DAT_REG(x) (0x100 * (x) + 0x0f)
+#define FN_BLOCK_SIZE_0_REG(x) (0x100 * (x) + 0x10)
+#define FN_BLOCK_SIZE_1_REG(x) (0x100 * (x) + 0x11)
+
+/* The following defines function 1 registers of SD25 */
+/* Ref.: SD-25 SDIO Interface Specification Rev. 2.0. */
+/* Marvell Semiconductor, Inc. */
+
+/* SDIO Interface Registers */
+#define IO_ENABLE_REG 0x02
+#define IO_READY_REG 0x03
+#define INT_ENABLE_REG 0x04
+#define INT_PENDING_REG 0x05
+#define IO_ABORT_REG 0x06
+#define BUS_INTERFACE_CONTROL_REG 0x07
+#define CARD_CAPABILITY_REG 0x08
+#define FUNCTION_SELECT_REG 0x0d
+#define EXEC_FLAGS_REG 0x0e
+#define READY_FLAGS_REG 0x0f
+#define HIGH_SPEED_REG 0x13
+#define SHS BIT_0
+#define EHS BIT_1
+
+#define CARD_ADD_EVENT 1
+#define CARD_REMOVED_EVENT 2
+
+#define SDIOBUS_COMPATIBLE_IDS L"SDIOBUS\\MrvlCompatibleSDIOBus\0"
+#define SDIOBUS_COMPATIBLE_IDS_LENGTH sizeof(SDIOBUS_COMPATIBLE_IDS)
+
+#define SDIOBUS_POOL_TAG (ULONG) 'lvrM'
+
+#define WAIT_SDIO_CMD_RESPONSE() UDELAY(2)
+
+#define MILLI_SECOND 10000
+
+#define SDIO_BUS_TYPE 1
+#define SDIO_SPI_TYPE 2
+
+#define SDIO_1_BIT 1
+#define SDIO_4_BIT 4
+
+#define DMA_WR_SUPPORT 0x01
+#define DMA_RD_SUPPORT 0x02
+ /*--- mmoser 8/29/2006 ---*/
+typedef struct _SDHOST_EVENT
+{
+ long event;
+ wait_queue_head_t wq;
+} SDHOST_EVENT;
+
+//
+// A common header for the device extensions of the PDOs and FDO
+//
+
+#define DEVICE_NAME_LENGTH 256
+typedef struct _SD_CLIENT
+{
+ struct list_head sd_client_list_entry;
+ struct _sd_driver *drv; /* pointer to the SD client driver */
+} SD_CLIENT, *PSD_CLIENT;
+
+typedef struct _SD_DEVICE_DATA
+{
+ struct list_head sd_dev_list_entry;
+
+#ifdef SYSKT_DMA_MALIGN_TEST
+ SK_U32 dma_rx_malign;
+ SK_U32 dma_tx_malign;
+ SK_U32 dma_start_malign;
+ SK_U8 dma_rbuff[1024 * 8]; // __attribute__((aligned(4)));
+ SK_U8 dma_tbuff[1024 * 8]; // __attribute__((aligned(4)));
+ // struct sk_buff *dma_skb;
+#endif
+ sd_device sd_dev[MAX_SDIO_FUNCTIONS]; /* API to client driver */
+ sd_device_id sd_ids[MAX_SDIO_FUNCTIONS]; /* sd ids for this device */
+ sd_device *irq_device_cache[MAX_SDIO_FUNCTIONS]; /* cache for speed up
+ irq response */
+ u32 cisptr[MAX_SDIO_FUNCTIONS];
+
+ u8 number_of_functions;
+
+ spinlock_t sd_dev_lock;
+ unsigned long sd_dev_lock_flags;
+
+ int thread_id;
+ int stop_thread;
+
+ // mmoser 2005-11-28
+ atomic_t card_add_event;
+ atomic_t card_remove_event;
+
+ /*--- mmoser 8/29/2006 ---*/
+ SDHOST_EVENT trans_complete_evt;
+ SDHOST_EVENT cmd_complete_evt;
+ SDHOST_EVENT thread_started_evt;
+ struct workqueue_struct *workqueue;
+
+ struct work_struct irq_work;
+ struct work_struct card_out_work;
+ SK_BOOL isRemoving;
+
+ /*--- mmoser 10/11/2006 ---*/
+ struct pci_dev *dev;
+
+ SK_U32 ioport;
+
+ // IOBase Addresses
+ SK_U32 *IOBase[2];
+ SK_U32 IOBaseLength[2];
+ SK_U32 IOBaseIx;
+ SK_U32 Interrupt;
+ SK_U32 Affinity;
+ SK_U32 InterruptMode;
+ SK_U32 lastIntStatus;
+ SK_U8 lastCardIntStatus;
+ SK_U8 MACEvent;
+ SK_U8 DeviceName[2 * (DEVICE_NAME_LENGTH + 1)];
+ SK_U32 DeviceNameLength;
+
+ SK_BOOL dump;
+ SK_U32 ClockSpeed;
+ SK_BOOL initialized;
+ /*--- mmoser 13.09.2005 ---*/
+ SK_BOOL SurpriseRemoved;
+
+ atomic_t if_lock;
+
+ SK_U8 dnlType;
+ SK_U8 CmdInProgress;
+
+ SK_U16 lastIRQSignalMask;
+ SK_U16 currentIRQSignalMask;
+ SK_U16 lastErrorIRQSignalMask;
+ SK_U8 baseClockFreq;
+ SK_U8 maxSupplyVoltage;
+ SK_U16 max_block_size;
+ SK_U32 debug_flags;
+ SK_U32 sdio_voltage;
+
+ SK_U32 errorOccured;
+
+ SK_U32 bus_errors;
+ SK_U32 bus_width;
+ SK_U32 bus_type;
+ SK_U32 crc_len;
+
+ SK_U8 dma_support;
+
+ SK_U8 PsState; // pweber 17.08.2005
+
+ SK_BOOL CardIn;
+} SD_DEVICE_DATA, *PSD_DEVICE_DATA;
+
+BOOLEAN SDIOBus_CardPluggedIn(PSD_DEVICE_DATA SdData);
+BOOLEAN SDIOBus_CardRemoved(PSD_DEVICE_DATA SdData);
+
+#endif
diff --git a/io/sdio/syskt/h/skdebug.h b/io/sdio/syskt/h/skdebug.h
new file mode 100644
index 0000000..c868c79
--- /dev/null
+++ b/io/sdio/syskt/h/skdebug.h
@@ -0,0 +1,147 @@
+/**
+ *
+ * Name: skdebug.h
+ * Project: Wireless LAN SDIO bus driver
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose:
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*****************************************************************************
+*
+* History:
+* $Log: skdebug.h,v $
+* Revision 1.1 2007/01/18 09:26:19 pweber
+* Put under CVS control
+*
+*
+*****************************************************************************/
+
+#ifndef _SKDEBUG_H_
+#define _SKDEBUG_H_
+
+// #define DEBUG_VERBOSE 1
+
+#define DBG_NONE 0x00000000 // No debug - all off.
+#define DBG_ERROR 0x00000001 // Debug for ERRORS
+#define DBG_WARNING 0x00000002 // Debug for Warnings.
+#define DBG_LOAD 0x00000004 // Debug for driver load
+#define DBG_PNP 0x00000008
+#define DBG_PWR 0x00000010
+#define DBG_IOCTL 0x00000020
+#define DBG_PDO 0x00000040
+#define DBG_IRQ 0x00000080
+#define DBG_W528D 0x00000100
+#define DBG_W528D_CMD52 0x00000200
+#define DBG_W528D_CMD53 0x00000400
+#define DBG_API 0x00000800
+
+#define DBG_T1 0x01000000 // Our various time stamps.. up to 6.
+#define DBG_T2 0x02000000 // ||
+#define DBG_T3 0x04000000 // ||
+#define DBG_T4 0x08000000 // ||
+#define DBG_T5 0x10000000 // ||
+#define DBG_T6 0x20000000 // \/
+#define DBG_ALL 0xffffffff // All debug enabled.
+
+#define DBG_TIMESTAMPS ( DBG_T1 | DBG_T2 | DBG_T3 | DBG_T4 | DBG_T5 | DBG_T6 )
+
+#undef KERN_DEBUG
+#define KERN_DEBUG
+
+#define DBG_DEFAULT (DBG_NONE \
+| DBG_ERROR \
+| DBG_WARNING \
+| DBG_W528D \
+| DBG_LOAD \
+)
+/***
+| DBG_W528D_CMD52 \
+| DBG_W528D_CMD53 \
+| DBG_TIMESTAMPS \
+| DBG_PNP \
+| DBG_IRQ \
+| DBG_PDO \
+| DBG_PWR \
+| DBG_W528D \
+| DBG_LOAD \
+| DBG_IOCTL \
+| DBG_ERROR \
+| DBG_WARNING \
+
+****/
+
+#ifdef DBG
+extern unsigned char lptRegImage1;
+extern unsigned char lptRegImage2;
+extern ULONG stdDebugLevel;
+#endif // #ifdef DBG
+
+#ifdef DBG
+
+#define DBG_CRLF 0x00000000 // add some cr lfs before this message.
+#define DBG_RAW 0x00000000 // raw debug output
+#define DBG_DONTCARE (DBG_RAW | DBG_CRLF) // either of these by
+ // themselves should not cause
+ // debug to print.
+
+/**
+#define LED_ON(x){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<(16+(x)));\
+ ___ulVal |= ___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
+#define LED_OFF(x){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<(16+(x)));\
+ ___ulVal &= ~___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
+**/
+
+#define BUGPRINT(Str) DbgPrint Str
+
+#define ENTER() DBGPRINT(DBG_LOAD,( KERN_DEBUG "Enter: %s, %s:%i\n", __FUNCTION__, \
+ __FILE__, __LINE__))
+#define LEAVE() DBGPRINT(DBG_LOAD,( KERN_DEBUG "Exit: %s, %s:%i\n", __FUNCTION__, \
+ __FILE__, __LINE__))
+
+#define PrintMacro printk
+
+#define INITDEBUG()
+
+#define DBGPRINT(lvl, Str) \
+ { \
+ ULONG __lvl = lvl; \
+ if (stdDebugLevel & (__lvl & ~DBG_DONTCARE)) \
+ { \
+ PrintMacro Str ; \
+ }}
+
+#else
+#define DBGPRINT(lvl,Str)
+#define INITDEBUG()
+#define ENTER()
+#define LEAVE()
+#endif
+#endif
diff --git a/io/sdio/syskt/h/skdrv1st.h b/io/sdio/syskt/h/skdrv1st.h
new file mode 100644
index 0000000..286eb78
--- /dev/null
+++ b/io/sdio/syskt/h/skdrv1st.h
@@ -0,0 +1,95 @@
+/**
+ *
+ * Name: skdrv1st.h
+ * Project: Wireless LAN, SDIO bus driver
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: Contains all defines system specific definitions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ *
+ * This Module contains Proprietary Information of Marvell
+ * and should be treated as Confidential.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of Marvell.
+ * Such users have the right to use, modify, and incorporate this code
+ * into products for purposes authorized by the license agreement
+ * provided they include this notice and the associated copyright notice
+ * with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ * $Log: skdrv1st.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+#define SDIO_BUS_DRIVER
+
+// Linux specific stuff
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <linux/sched.h> // kernel_thread
+#include <linux/mm.h> // memory manager
+#include <linux/stat.h>
+#include <linux/wait.h>
+
+// kernel specific inludes ++++++++++++++++++++++
+
+#include <linux/workqueue.h> /* for struct work_queue */
+#include <linux/timer.h>
+
+// defines ++++++++++++++++++++
+
+// #define UDELAY udelay
+#define UDELAY(x)
+
+#define INTERLOCKED_INC(x) (atomic_inc((x)),atomic_read((x)))
+#define INTERLOCKED_DEC(x) (atomic_dec((x)),atomic_read((x)))
+#define ZERO_MEMORY( pBuf,len) memset((pBuf),0,(len));
+
+#include "sktypes.h"
+// #include "../h/sdio.h"
+
+#define MRVL_DEVICE_NAME "MrvlSdioBus"
+
+/* defines ********************************************************************/
+/* typedefs *******************************************************************/
+/* function prototypes ********************************************************/
+
+#endif /* __INC_SKDRV1ST_H */
diff --git a/io/sdio/syskt/h/skdrv2nd.h b/io/sdio/syskt/h/skdrv2nd.h
new file mode 100644
index 0000000..27e80b1
--- /dev/null
+++ b/io/sdio/syskt/h/skdrv2nd.h
@@ -0,0 +1,54 @@
+/**
+ *
+ * Name: skdrv2nd.h
+ * Project: Wireless LAN SDIO Bus driver
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: Contains all defines system specific definitions
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: skdrv2nd.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "skdebug.h"
+
+#include "sdiobus.h"
+#include "stdhost.h"
+#include "skisr.h"
+// #include "../h/sdio.h"
+
+/* defines ********************************************************************/
+
+/* function prototypes ********************************************************/
+/* Macros ************************************************************/
+
+#endif /* __INC_SKDRV2ND_H */
diff --git a/io/sdio/syskt/h/skisr.h b/io/sdio/syskt/h/skisr.h
new file mode 100644
index 0000000..19fc304
--- /dev/null
+++ b/io/sdio/syskt/h/skisr.h
@@ -0,0 +1,40 @@
+/**
+ *
+ * Name: skisr.h
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: This module handles the interrupts.
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: skisr.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ *
+ ******************************************************************************/
+
+void SDIOBus_Dpc(unsigned long arg);
+
+irqreturn_t SDIOBus_Isr(int irq, void *dev_id, struct pt_regs *regs);
diff --git a/io/sdio/syskt/h/sktypes.h b/io/sdio/syskt/h/sktypes.h
new file mode 100644
index 0000000..2689823
--- /dev/null
+++ b/io/sdio/syskt/h/sktypes.h
@@ -0,0 +1,80 @@
+/**
+ *
+ * Name: sktypes.h
+ * Project: Wireless LAN, SDIO Bus driver
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: Define data types for SDIO bus driver
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: sktypes.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+/* defines ********************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8 s8
+#define SK_U8 u8
+#define SK_I16 s16
+#define SK_U16 u16
+#define SK_I32 s32
+#define SK_U32 u32
+#define SK_U64 u64
+
+#define SK_UPTR SK_U32 /* casting pointer <-> integral */
+
+#define SK_CONSTI64(x) (x##L)
+#define SK_CONSTU64(x) (x##UL)
+/*
+ * Boolean type.
+ */
+#define SK_BOOL SK_U8
+#define SK_FALSE (SK_BOOL)0
+#define SK_TRUE (SK_BOOL)(!SK_FALSE)
+
+#define VOID void
+#define PVOID VOID*
+#define ULONG SK_U32
+#define USHORT SK_U16
+#define UCHAR SK_U8
+#define PUCHAR SK_U8*
+#define BOOLEAN SK_BOOL
+#define IN
+#define OUT
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif /* __INC_SKTYPES_H */
diff --git a/io/sdio/syskt/h/stdhost.h b/io/sdio/syskt/h/stdhost.h
new file mode 100644
index 0000000..5a012b3
--- /dev/null
+++ b/io/sdio/syskt/h/stdhost.h
@@ -0,0 +1,576 @@
+/**
+ *
+ * Name: stdhost.h
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:26:19 $
+ * Purpose: This module handles the SDIO Standard Host Interface.
+ *
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: stdhost.h,v $
+ * Revision 1.1 2007/01/18 09:26:19 pweber
+ * Put under CVS control
+ *
+ *
+ ******************************************************************************/
+
+// pweber 17.08.2005 taken from eagledev.h
+typedef enum
+{
+ // card is in full power
+ PS_STATE_FULL_POWER,
+ // PS mode, but card is ready for TX
+ PS_STATE_WAKEUP,
+ // PS Mode, card is not ready for TX
+ PS_STATE_SLEEP,
+ // SLEEP event is already received, but have not sent confirm yet
+ PS_STATE_SLEEP_PENDING,
+} PS_STATE;
+
+#define MAX_BUS_ERRORS 10
+
+// #define SD_BLOCK_SIZE 32
+
+#define DEBUG_BREAK_CMD53_RD 0x00000001
+#define DEBUG_BREAK_CMD53_WR 0x00000002
+#define DEBUG_DISABLE_HW_WORKAROUND_RD 0x00000004
+#define DEBUG_DISABLE_HW_WORKAROUND_WR 0x00000008
+#define DEBUG_SHOW_REG_10_14 0x00000010
+#define DEBUG_USE_RD_DMA 0x00000100
+#define DEBUG_USE_WR_DMA 0x00000200
+#define DEBUG_BREAK_START_FDO 0x80000000
+
+// SDIO CMD Macros
+#define MAKE_SDIO_OFFSET(x) ((SK_U32)((SK_U32)(x)<<9))
+#define MAKE_SDIO_OP_CODE(x) ((SK_U32)((SK_U32)(x)<<26))
+#define MAKE_SDIO_BLOCK_MODE(x) ((SK_U32)((SK_U32)(x)<<27))
+#define MAKE_SDIO_FUNCTION(x) ((SK_U32)((SK_U32)(x)<<28))
+#define MAKE_SDIO_DIR(x) ((SK_U32)((SK_U32)(x)<<31))
+
+// SD Host Standard Register
+#define DMA_16K_BOUNDARY (0x2 << 12)
+#define STDHOST_SYSTEM_ADDRESS 0x00 // System
+ // Address
+ // 4
+ // bytes
+#define STDHOST_BLOCK_SIZE 0x04 // 2
+ // bytes
+#define STDHOST_BLOCK_COUNT 0x06 // 2
+ // bytes
+#define STDHOST_CMD_ARGUMENT 0x08 // 4
+ // bytes
+ // ->
+ // bit
+ // 39
+ // -
+ // 8
+ // of
+ // SDIO
+ // CMD
+#define STDHOST_TRANSFER_MODE 0x0C // 2
+ // bytes
+#define STDHOST_MULTI_BLOCK_SELECT (1<<5)
+#define STDHOST_READ_DIR_SELECT (1<<4)
+#define STDHOST_AUTO_CMD12_ENA (1<<2)
+#define STDHOST_BLOCK_COUNT_ENA (1<<1)
+#define STDHOST_DMA_ENA (1<<0)
+
+#define STDHOST_COMMAND 0x0E // 2
+ // bytes
+#define STDHOST_CMD_TYPE_NORMAL 0x00
+#define STDHOST_CMD_TYPE_SUSPEND 0x01
+#define STDHOST_CMD_TYPE_RESUME 0x02
+#define STDHOST_CMD_TYPE_ABORT 0x03
+#define STDHOST_CMD_TYPE_MASK 0x03
+#define MK_CMD_TYPE(x) ((x)<<6)
+#define MK_CMD(x) ((x)<<8)
+#define MAX_WAIT_COMMAND_COMPLETE 1000
+
+#define STDHOST_CMD_DATA_PRESENT (1<<5)
+#define STDHOST_CMD_INDEX_CHK_ENA (1<<4)
+#define STDHOST_CMD_CRC_CHK_ENA (1<<3)
+#define STDHOST_RESP_TYPE_NONE 0x00
+#define STDHOST_RESP_TYPE_R2 0x01
+#define STDHOST_RESP_TYPE_R1 0x02
+#define STDHOST_RESP_TYPE_R3 0x02
+#define STDHOST_RESP_TYPE_R4 0x02
+#define STDHOST_RESP_TYPE_R5 0x02
+#define STDHOST_RESP_TYPE_R6 0x02
+#define STDHOST_RESP_TYPE_R1b 0x03
+#define STDHOST_RESP_TYPE_R5b 0x03
+
+#define STDHOST_RESP_BITS_31_0 0x10 // 4
+ // bytes
+#define STDHOST_RESP_BITS_63_32 0x14 // 4
+ // bytes
+#define STDHOST_RESP_BITS_95_64 0x18 // 4
+ // bytes
+#define STDHOST_RESP_BITS_127_96 0x1C // 4
+ // bytes
+
+#define GET_BITS_135_128(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_127_120(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_119_112(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_111_104(x) ((SK_U8)(x))
+#define GET_BITS_103_96(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_95_88(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_87_80(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_79_72(x) ((SK_U8)(x))
+#define GET_BITS_71_64(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_63_56(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_55_48(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_47_40(x) ((SK_U8)(x))
+#define GET_BITS_39_32(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_31_24(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_23_16(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_15_08(x) ((SK_U8)(x))
+
+/*
+#define GET_BITS_135_128(x) ((SK_U8)(x))
+#define GET_BITS_127_120(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_119_112(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_111_104(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_103_96(x) ((SK_U8)(x))
+#define GET_BITS_95_88(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_87_80(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_79_72(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_71_64(x) ((SK_U8)(x))
+#define GET_BITS_63_56(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_55_48(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_47_40(x) ((SK_U8)((SK_U32)(x)>>24))
+#define GET_BITS_39_32(x) ((SK_U8)(x))
+#define GET_BITS_31_24(x) ((SK_U8)((SK_U32)(x)>>8))
+#define GET_BITS_23_16(x) ((SK_U8)((SK_U32)(x)>>16))
+#define GET_BITS_15_08(x) ((SK_U8)((SK_U32)(x)>>24))
+*/
+
+/* CIS Tuples*/
+#define CISTPL_VERS_1 0x15
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_NULL 0x00
+#define CISTPL_END 0xFF
+
+#define STDHOST_DATA_PORT 0x20 // 4
+ // bytes
+
+#define STDHOST_PRESENT_STATE 0x24 // 4
+ // bytes
+#define STDHOST_STATE_CMD_LINE_LVL (1<<24)
+#define STDHOST_STATE_DAT3_LINE_LVL (1<<23)
+#define STDHOST_STATE_DAT2_LINE_LVL (1<<22)
+#define STDHOST_STATE_DAT1_LINE_LVL (1<<21)
+#define STDHOST_STATE_DAT0_LINE_LVL (1<<20)
+#define STDHOST_STATE_WRITE_PROTECT_LVL (1<<19)
+#define STDHOST_STATE_CARD_DETECT_LVL (1<<18)
+#define STDHOST_STATE_CARD_STATE_STABLE (1<<17)
+#define STDHOST_STATE_CARD_INSERTED (1<<16)
+#define STDHOST_STATE_BUFFER_RD_ENABLE (1<<11)
+#define STDHOST_STATE_BUFFER_WR_ENABLE (1<<10)
+#define STDHOST_STATE_RD_TRANSFER_ACTIVE (1<<9)
+#define STDHOST_STATE_WR_TRANSFER_ACTIVE (1<<8)
+#define STDHOST_STATE_DAT_LINE_ACTIVE (1<<2)
+#define STDHOST_STATE_CMD_INHIB_DAT (1<<1)
+#define STDHOST_STATE_CMD_INHIB_CMD (1<<0)
+#define MAX_WAIT_COMMAND_INHIBIT 1000
+
+#define STDHOST_HOST_CTRL 0x28 // 1
+ // byte
+#define STDHOST_HIGH_SPEED_ENA (1<<2)
+#define STDHOST_4_BIT_ENA (1<<1)
+#define STDHOST_LED_ON (1<<0)
+
+#define STDHOST_POWER_CTRL 0x29 // 1
+ // byte
+#define STDHOST_VOLTAGE_3_3_V 0x07
+#define STDHOST_VOLTAGE_3_0_V 0x06
+#define STDHOST_VOLTAGE_1_8_V 0x05
+#define MK_VOLTAGE(x) ((x)<<1)
+#define STDHOST_POWER_ON (1<<0)
+
+#define STDHOST_BLOCK_GAP_CTRL 0x2A // 1
+ // byte
+#define STDHOST_WAKEUP_CTRL 0x2B // 1
+ // byte
+#define STDHOST_WAKEUP_ON_CARD_REMOVE 0x04
+#define STDHOST_WAKEUP_ON_CARD_INSERT 0x02
+#define STDHOST_WAKEUP_ON_CARD_IRQ 0x01
+
+#define STDHOST_CLOCK_CTRL 0x2C // 2
+ // byte
+#define STDHOST_CLOCK_DIV_BASE_CLK 0x00
+#define STDHOST_CLOCK_DIV_2 0x01
+#define STDHOST_CLOCK_DIV_4 0x02
+#define STDHOST_CLOCK_DIV_8 0x04
+#define STDHOST_CLOCK_DIV_16 0x08
+#define STDHOST_CLOCK_DIV_32 0x10
+#define STDHOST_CLOCK_DIV_64 0x20
+#define STDHOST_CLOCK_DIV_128 0x40
+#define STDHOST_CLOCK_DIV_256 0x80
+#define MK_CLOCK(x) ((x)<<8)
+#define STDHOST_CLOCK_ENA (1<<2)
+#define STDHOST_INTERNAL_CLK_STABLE (1<<1)
+#define STDHOST_INTERNAL_CLK_ENA (1<<0)
+#define MAX_WAIT_CLOCK_STABLE 1000
+
+#define STDHOST_TIMEOUT_CTRL 0x2E // 1
+ // byte
+#define STDHOST_SW_RESET 0x2F // 1
+ // byte
+#define STDHOST_SW_RESET_DAT_LINE (1<<2)
+#define STDHOST_SW_RESET_CMD_LINE (1<<1)
+#define STDHOST_SW_RESET_ALL (1<<0)
+
+#define STDHOST_NORMAL_IRQ_STATUS 0x30 // 2
+ // byte
+#define STDHOST_NORMAL_IRQ_ERROR (1<<15)
+#define STDHOST_NORMAL_IRQ_CARD (1<<8)
+#define STDHOST_NORMAL_IRQ_CARD_OUT (1<<7)
+#define STDHOST_NORMAL_IRQ_CARD_IN (1<<6)
+#define STDHOST_NORMAL_IRQ_BUF_RD_RDY (1<<5)
+#define STDHOST_NORMAL_IRQ_BUF_WR_RDY (1<<4)
+#define STDHOST_NORMAL_IRQ_DMA (1<<3)
+#define STDHOST_NORMAL_IRQ_BLOCK_GAP (1<<2)
+#define STDHOST_NORMAL_IRQ_TRANS_COMPLETE (1<<1)
+#define STDHOST_NORMAL_IRQ_CMD_COMPLETE (1<<0)
+
+#define STDHOST_ERROR_IRQ_STATUS 0x32 // 2
+ // byte
+#define STDHOST_ERROR_IRQ_VENDOR (0x0F<<12)
+#define STDHOST_ERROR_IRQ_GPI_1 (1<<15)
+#define STDHOST_ERROR_IRQ_GPI_0 (1<<14)
+#define STDHOST_ERROR_IRQ_AUTO_CMD12 (1<<8)
+#define STDHOST_ERROR_IRQ_CURRENT_LIMIT (1<<7)
+#define STDHOST_ERROR_IRQ_DATA_END_BIT (1<<6)
+#define STDHOST_ERROR_IRQ_DATA_CRC (1<<5)
+#define STDHOST_ERROR_IRQ_DATA_TIMEOUT (1<<4)
+#define STDHOST_ERROR_IRQ_CMD_INDEX (1<<3)
+#define STDHOST_ERROR_IRQ_CMD_END_BIT (1<<2)
+#define STDHOST_ERROR_IRQ_CMD_CRC (1<<1)
+#define STDHOST_ERROR_IRQ_CMD_TIMEOUT (1<<0)
+
+#define STDHOST_NORMAL_IRQ_STATUS_ENABLE 0x34 // 2 byte
+#define STDHOST_NORMAL_IRQ_CARD_ENA (1<<8)
+#define STDHOST_NORMAL_IRQ_CARD_OUT_ENA (1<<7)
+#define STDHOST_NORMAL_IRQ_CARD_IN_ENA (1<<6)
+#define STDHOST_NORMAL_IRQ_BUF_RD_RDY_ENA (1<<5)
+#define STDHOST_NORMAL_IRQ_BUF_WR_RDY_ENA (1<<4)
+#define STDHOST_NORMAL_IRQ_DMA_ENA (1<<3)
+#define STDHOST_NORMAL_IRQ_BLOCK_GAP_ENA (1<<2)
+#define STDHOST_NORMAL_IRQ_TRANS_COMPLETE_ENA (1<<1)
+#define STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA (1<<0)
+
+#define STDHOST_ERROR_IRQ_STATUS_ENABLE 0x36 // 2 byte
+#define STDHOST_ERROR_IRQ_VENDOR_ENA (0x0F<<12)
+#define STDHOST_ERROR_IRQ_AUTO_CMD12_ENA (1<<8)
+#define STDHOST_ERROR_IRQ_CURRENT_LIMIT_ENA (1<<7)
+#define STDHOST_ERROR_IRQ_DATA_END_BIT_ENA (1<<6)
+#define STDHOST_ERROR_IRQ_DATA_CRC_ENA (1<<5)
+#define STDHOST_ERROR_IRQ_DATA_TIMEOUT_ENA (1<<4)
+#define STDHOST_ERROR_IRQ_CMD_INDEX_ENA (1<<3)
+#define STDHOST_ERROR_IRQ_CMD_END_BIT_ENA (1<<2)
+#define STDHOST_ERROR_IRQ_CMD_CRC_ENA (1<<1)
+#define STDHOST_ERROR_IRQ_CMD_TIMEOUT_ENA (1<<0)
+
+#define STDHOST_NORMAL_IRQ_SIGNAL_ENABLE 0x38 // 2 byte
+#define STDHOST_NORMAL_IRQ_ALL_SIG_ENA 0xFFFF
+#define STDHOST_NORMAL_IRQ_CARD_SIG_ENA (1<<8)
+#define STDHOST_NORMAL_IRQ_CARD_OUT_SIG_ENA (1<<7)
+#define STDHOST_NORMAL_IRQ_CARD_IN_SIG_ENA (1<<6)
+#define STDHOST_NORMAL_IRQ_BUF_RD_RDY_SIG_ENA (1<<5)
+#define STDHOST_NORMAL_IRQ_BUF_WR_RDY_SIG_ENA (1<<4)
+#define STDHOST_NORMAL_IRQ_DMA_SIG_ENA (1<<3)
+#define STDHOST_NORMAL_IRQ_BLOCK_GAP_SIG_ENA (1<<2)
+#define STDHOST_NORMAL_IRQ_TRANS_COMPLETE_SIG_ENA (1<<1)
+#define STDHOST_NORMAL_IRQ_CMD_COMPLETE_SIG_ENA (1<<0)
+
+/*
+#define STDHOST_NORMAL_IRQ_CARD_ALL_ENA ( STDHOST_NORMAL_IRQ_CARD_OUT_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_CARD_IN_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_CARD_SIG_ENA)
+*/
+
+/*
+#define STDHOST_NORMAL_IRQ_CARD_ALL_ENA ( STDHOST_NORMAL_IRQ_CARD_OUT_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_CARD_IN_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_CARD_SIG_ENA)
+*/
+ /**/ extern int intmode;
+#define STDHOST_GPIO_IRQ_CARD_ALL_ENA ( \
+ STDHOST_NORMAL_IRQ_CARD_OUT_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_CARD_IN_SIG_ENA | \
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE_SIG_ENA)
+
+#define STDHOST_NORMAL_IRQ_CARD_ALL_ENA \
+ ((intmode == 0) ? (STDHOST_GPIO_IRQ_CARD_ALL_ENA | STDHOST_NORMAL_IRQ_CARD_SIG_ENA) : \
+ (STDHOST_GPIO_IRQ_CARD_ALL_ENA))
+ /**/
+#define STDHOST_ERROR_IRQ_SIGNAL_ENABLE 0x3A // 2 byte
+#define STDHOST_ERROR_IRQ_VENDOR_SIG_ENA (0x0F<<12)
+#define STDHOST_ERROR_IRQ_AUTO_CMD12_SIG_ENA (1<<8)
+#define STDHOST_ERROR_IRQ_CURRENT_LIMIT_SIG_ENA (1<<7)
+#define STDHOST_ERROR_IRQ_DATA_END_BIT_SIG_ENA (1<<6)
+#define STDHOST_ERROR_IRQ_DATA_CRC_SIG_ENA (1<<5)
+#define STDHOST_ERROR_IRQ_DATA_TIMEOUT_SIG_ENA (1<<4)
+#define STDHOST_ERROR_IRQ_CMD_INDEX_SIG_ENA (1<<3)
+#define STDHOST_ERROR_IRQ_CMD_END_BIT_SIG_ENA (1<<2)
+#define STDHOST_ERROR_IRQ_CMD_CRC_SIG_ENA (1<<1)
+#define STDHOST_ERROR_IRQ_CMD_TIMEOUT_SIG_ENA (1<<0)
+#define STDHOST_AUTO_CMD12_ERROR_STATUS 0x3C // 2 byte
+#define STDHOST_CAPABILITIES 0x40 // 4
+ // byte
+#define STDHOST_CAP_VOLTAGE_1_8 (1<<26)
+#define STDHOST_CAP_VOLTAGE_3_0 (1<<25)
+#define STDHOST_CAP_VOLTAGE_3_3 (1<<24)
+#define STDHOST_CAP_SUSPENSE_RESUME (1<<23)
+#define STDHOST_CAP_DMA (1<<22)
+#define STDHOST_CAP_HIGH_SPEED (1<<21)
+#define STDHOST_CAP_MAX_BLOCK_LEN (0x03<<16)
+#define STDHOST_CAP_MAX_BLOCK_512 (0x00<<16)
+#define STDHOST_CAP_MAX_BLOCK_1024 (0x01<<16)
+#define STDHOST_CAP_MAX_BLOCK_2048 (0x02<<16)
+#define STDHOST_CAP_BASE_CLOCK_FREQ (0x3F<<8)
+#define GET_CAP_BASE_CLOCK_FREQ(x) (SK_U8)(((x)>>8)&0x000000FF)
+#define STDHOST_CAP_TIMEOUT_CLOCK_UNIT (1<<7)
+#define STDHOST_CAP_TIMEOUT_CLOCK_UNIT_MHZ (1<<7)
+#define STDHOST_CAP_TIMEOUT_CLOCK_FREQ 0x3F
+#define STDHOST_CAPABILITIES_RESERVED 0x44 // 4 byte
+#define STDHOST_MAX_CURRENT_CAP 0x48 // 4
+ // byte
+#define STDHOST_MAX_CURRENT_CAP_1_8_V (0xFF<<16)
+#define GET_MAX_CURRENT_CAP_1_8_V(x) (((x)>>16)&0x000000FF)
+#define STDHOST_MAX_CURRENT_CAP_3_0_V (0xFF<<8)
+#define GET_MAX_CURRENT_CAP_3_0_V(x) (((x)>>8)&0x000000FF)
+#define STDHOST_MAX_CURRENT_CAP_3_3_V 0xFF
+#define GET_MAX_CURRENT_CAP_3_3_V(x) ((x)&0x000000FF)
+#define CALC_MAX_CURRENT_IN_MA(x) ((x)*4)
+#define STDHOST_MAX_CURRENT_CAP_RESERVED 0x4C // 4 byte
+#define STDHOST_SLOT_IRQ_STATUS 0xFC // 2
+ // byte
+#define STDHOST_SLOT_IRQ_SLOT_0 0x01
+#define STDHOST_SLOT_IRQ_SLOT_1 0x02
+#define STDHOST_SLOT_IRQ_SLOT_2 0x04
+#define STDHOST_SLOT_IRQ_SLOT_3 0x08
+#define STDHOST_SLOT_IRQ_SLOT_4 0x10
+#define STDHOST_SLOT_IRQ_SLOT_5 0x20
+#define STDHOST_SLOT_IRQ_SLOT_6 0x40
+#define STDHOST_SLOT_IRQ_SLOT_7 0x80
+#define STDHOST_HOST_CONTROLLER_VERSION 0xFE // 2 byte
+#define GET_VENDOR_VERSION_NR(x) ((x)>>8)
+#define GET_SPEC_VERSION_NR(x) ((x)&0x00FF)
+// FPGA specific registers
+#define FPGA_CORE_CTRL_REG 0x200
+#define FPGA_RAISING_EDGE (1 << 8)
+#define FPGA_CARD_REVISION 0x210
+#define FPGA_CARD_REV_1_0 0x10
+#define FPGA_CARD_REV_1_1 0x11
+#define FPGA_CHIP_REVISION 0x211
+#define FPGA_CHIP_REV_1_0 0x10 // SDIO/SPI
+#define FPGA_CHIP_REV_1_1 0x11 // SDIO/SPI/G-SPI
+#define FPGA_CHIP_REV_2_0 0x20 // SDIO/SPI/G-SPI/DMA
+#define FPGA_CONFIG_ID 0x212
+#define FPGA_CONFIG_3_3_V (1<<0)
+#define FPGA_CONFIG_2_5_V (1<<1)
+#define FPGA_CONFIG_1_8_V (1<<2)
+#define FPGA_POWER_REG_DATA 0x20C
+#define FPGA_POWER_REG_3_3_V 0xEF
+#define FPGA_POWER_REG_2_5_V 0xDC
+#define FPGA_POWER_REG_1_8_V 0xCC
+#define FPGA_POWER_REG_CMD 0x20D
+#define FPGA_POWER_REG_CMD_START 0x80
+#define FPGA_POWER_REG_STATUS 0x20E
+#define FPGA_POWER_REG_STABLE (1<<0)
+#define FPGA_POWER_REG_1_8_V_MIN 0xBC // 1.54 V
+#define FPGA_POWER_REG_1_8_V_MAX 0xD9 // 2.31 V
+#define FPGA_POWER_REG_2_5_V_MIN 0xCF // 1.98 V
+#define FPGA_POWER_REG_2_5_V_MAX 0xEC // 3.08 V
+#define FPGA_POWER_REG_3_3_V_MIN 0xE8 // 2.70 V
+#define FPGA_POWER_REG_3_3_V_MAX 0xEF // 3.30 V
+#define FPGA_POWER_REG_0_7_V 0x88 // 0.72 V
+#define FPGA_POWER_REG_0_8_V 0x8B // 0.78 V
+#define FPGA_POWER_REG_0_9_V 0x98 // 0.90 V
+#define FPGA_POWER_REG_1_0_V 0x9B // 0.97 V
+#define FPGA_POWER_REG_1_1_V 0xA8 // 1.08 V
+#define FPGA_POWER_REG_1_2_V 0xAB // 1.17 V
+#define FPGA_POWER_REG_1_2_5_V 0xAC // 1.23 V
+#define FPGA_POWER_REG_1_3_V 0xAF // 1.32 V
+#define FPGA_POWER_REG_1_4_V 0xBA // 1.42 V
+#define FPGA_POWER_REG_1_5_V 0xBC // 1.53 V
+#define FPGA_POWER_REG_1_6_V 0xC8 // 1.62 V
+#define FPGA_POWER_REG_1_8_V 0xCC // 1.84 V
+#define FPGA_POWER_REG_2_0_V 0xCF // 1.98 V
+#define FPGA_POWER_REG_2_2_V 0xD8 // 2.25 V
+#define FPGA_POWER_REG_2_4_V 0xDB // 2.43 V
+#define FPGA_POWER_REG_2_6_V 0xDD // 2.62 V
+#define FPGA_POWER_REG_2_7_V 0xDF // 2.75 V
+#define FPGA_POWER_REG_2_9_V 0xEB // 2.92 V
+#define FPGA_POWER_REG_3_1_V 0xED // 3.15 V
+#define FPGA_POWER_REG_3_3_V 0xEF // 3.30 V
+#define FPGA_POWER_STEPS 20
+//[mb] 300 is a good value for 3.3V
+#define FPGA_POWER_RAMP_DELAY 300
+#define FPGA_POWER_VAL_ENUM { \
+ FPGA_POWER_REG_0_7_V, \
+ FPGA_POWER_REG_0_8_V, \
+ FPGA_POWER_REG_0_9_V, \
+ FPGA_POWER_REG_1_0_V, \
+ FPGA_POWER_REG_1_1_V, \
+ FPGA_POWER_REG_1_2_V, \
+ FPGA_POWER_REG_1_2_5_V, \
+ FPGA_POWER_REG_1_3_V, \
+ FPGA_POWER_REG_1_4_V, \
+ FPGA_POWER_REG_1_5_V, \
+ FPGA_POWER_REG_1_6_V, \
+ FPGA_POWER_REG_1_8_V, \
+ FPGA_POWER_REG_2_0_V, \
+ FPGA_POWER_REG_2_2_V, \
+ FPGA_POWER_REG_2_4_V, \
+ FPGA_POWER_REG_2_6_V, \
+ FPGA_POWER_REG_2_7_V, \
+ FPGA_POWER_REG_2_9_V, \
+ FPGA_POWER_REG_3_1_V, \
+ FPGA_POWER_REG_3_3_V}
+#define SK_SLOT_0 0
+#define SK_SLOT_1 1
+#define SK_BAR( _pObj, _nr ) ((PSD_DEVICE_DATA)(_pObj)->IOBase[_nr])
+//
+// PCI memory mapped I/O access routines
+//
+#define MEM_WRITE_UCHAR(_pObj,_base, _offset, _value) *(SK_U8 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U8)(_value)
+#define MEM_WRITE_USHORT(_pObj,_base, _offset, _value) *(SK_U16 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U16)(_value)
+#define MEM_WRITE_ULONG(_pObj,_base, _offset, _value) *(SK_U32 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U32)(_value)
+/*
+#define MEM_WRITE_UCHAR(_pObj,_base, _offset, _value)\
+ printk("wr-uc:%p=0x%2.02X\n",(SK_U8 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)),(SK_U8)(_value));\
+ *(SK_U8 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U8)(_value)
+
+#define MEM_WRITE_USHORT(_pObj,_base, _offset, _value)\
+ printk("wr-us:%p=0x%4.04X\n",(SK_U16 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)),(SK_U16)(_value));\
+ *(SK_U16 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U16)(_value)
+
+#define MEM_WRITE_ULONG(_pObj,_base, _offset, _value)\
+ printk("wr-ul:%p=0x%8.08X\n",(SK_U32 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)),(SK_U32)(_value));\
+ *(SK_U32 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset)) = (SK_U32)(_value)
+*/
+#define MEM_READ_UCHAR(_pObj,_base, _offset, _pBuf) *(SK_U8 *)(_pBuf) = *(volatile SK_U8 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset))
+#define MEM_READ_USHORT(_pObj,_base, _offset, _pBuf) *(SK_U16 *)(_pBuf) = *(volatile SK_U16 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset))
+#define MEM_READ_ULONG(_pObj,_base, _offset, _pBuf) *(SK_U32 *)(_pBuf) = *(volatile SK_U32 *)(((SK_U32)(SK_BAR((_pObj),(_base))))+(_offset))
+void SDHost_Init(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_isCardPresent(PSD_DEVICE_DATA pDev);
+SK_BOOL isCmdFailed(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_InitializeCard(PSD_DEVICE_DATA pDev);
+VOID SDHost_EnableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask);
+VOID SDHost_DisableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask);
+VOID SDHost_if_EnableInterrupt(PSD_DEVICE_DATA pDev);
+VOID SDHost_if_DisableInterrupt(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_ReadOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr);
+SK_BOOL SDHost_SendCmd(PSD_DEVICE_DATA pDev, SK_U8 cmd, SK_U32 arg,
+ SK_U16 transferMode, SK_U32 * pulResp);
+VOID SDHost_SetCardOutEvent(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_WriteOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr);
+SK_BOOL SDHost_ReadRCA(PSD_DEVICE_DATA pDev, SK_U8 * pRca);
+SK_BOOL SDHost_SendAbort(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_CMD52_Write(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 Data);
+SK_BOOL SDHost_CMD52_Read(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 * pReturnData);
+SK_BOOL SDHost_ReadCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number,
+ SK_U8 cistpl, SK_U8 * pBuf, SK_U32 * length);
+SK_BOOL SDHost_CMD53_Write(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 mode, SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+SK_BOOL SDHost_CMD53_Write_DMA(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 mode, SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+SK_BOOL SDHost_CMD53_Read(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 mode, SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+SK_BOOL SDHost_CMD53_Read_DMA(PSD_DEVICE_DATA pDev, SK_U32 Offset,
+ SK_U8 function_number, SK_U8 mode, SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+
+SK_BOOL SDHost_CMD53_WriteEx(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+
+SK_BOOL SDHost_CMD53_ReadEx(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode,
+ SK_U8 * pData, SK_U32 Count, SK_U32 blksz);
+
+SK_BOOL SDHost_disable_host_int(PSD_DEVICE_DATA pDev, SK_U8 function_number,
+ SK_U8 mask);
+SK_BOOL SDHost_enable_host_int(PSD_DEVICE_DATA pDev, SK_U8 function_number,
+ SK_U8 mask);
+SK_U32 SDHost_send_cmd(PSD_DEVICE_DATA pDev, SK_U8 * payload, SK_U32 length,
+ SK_BOOL wait_status);
+VOID SDHost_ErrorRecovery(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_lockInterface(PSD_DEVICE_DATA pDev);
+VOID SDHost_unlockInterface(PSD_DEVICE_DATA pDev);
+VOID SDHost_SetLed(PSD_DEVICE_DATA pDev, SK_U8 led, SK_U8 on);
+VOID SDHost_PsState(PSD_DEVICE_DATA pDev, SK_U8 State); // pweber 17.08.2005
+SK_BOOL SDHost_SetGPO(PSD_DEVICE_DATA pDev, SK_U8 on); // mmoser 2007-02-20
+SK_U32 SDHost_wait_event(PSD_DEVICE_DATA pDev, SDHOST_EVENT * pEvt, SK_U32 to);
+VOID SDHost_SetClock(PSD_DEVICE_DATA pDev, SK_U8 on);
+SK_BOOL SDHost_SetBusWidth(PSD_DEVICE_DATA pDev, SK_U8 width);
+VOID SDHost_SetClockSpeed(PSD_DEVICE_DATA pDev, SK_U32 bus_freq);
+SK_BOOL SDHost_Enable_HighSpeedMode(PSD_DEVICE_DATA pDev);
+SK_BOOL SDHost_Disable_HighSpeedMode(PSD_DEVICE_DATA pDev);
+
+#define LED_ON(x){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<(16+(x)));\
+ ___ulVal |= ___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
+#define LED_OFF(x){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<(16+(x)));\
+ ___ulVal &= ~___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
+
+#define GPO_ON(){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<24);\
+ ___ulVal |= ___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
+#define GPO_OFF(){\
+SK_U32 ___ulVal,___ulMask;\
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &___ulVal);\
+ ___ulMask = (1<<24);\
+ ___ulVal &= ~___ulMask;\
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, ___ulVal);\
+}
diff --git a/io/sdio/syskt/sdiobus.c b/io/sdio/syskt/sdiobus.c
new file mode 100644
index 0000000..ecb7107
--- /dev/null
+++ b/io/sdio/syskt/sdiobus.c
@@ -0,0 +1,2022 @@
+/**
+ *
+ * Name: sdiobus.c
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:21:35 $
+ * Purpose: Bus driver for SDIO interface
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: sdiobus.c,v $
+ * Revision 1.1 2007/01/18 09:21:35 pweber
+ * Put under CVS control
+ *
+ * Revision 1.2 2005/12/08 12:01:00 ebauer
+ * Driver ckecks AND update voltage registry value if not correct
+ *
+ * Revision 1.1 2005/10/07 08:43:47 jschmalz
+ * Put SDIO with FPGA under CVS control
+ *
+ *
+ ******************************************************************************/
+#ifndef _lint
+static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) Marvell ";
+#endif /* !_lint */
+
+#include "diagvers.h" /* diag version control */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+#include <linux/proc_fs.h> // proc filesystem
+
+#ifdef DBG
+SK_U32 stdDebugLevel = DBG_DEFAULT;
+#endif // #ifdef DBG
+
+#define USE_DEBOUNCE_CARD_IN
+ /*--- mmoser 12/21/2006 ---*/
+#define MAX_DEBOUNCE_TIME 100
+
+DECLARE_MUTEX(sd_if_sema);
+DECLARE_MUTEX(sd_client_sema);
+
+static int sdio_major = 0;
+
+int mrvlsdio_open(struct inode *inode, struct file *filp);
+int mrvlsdio_release(struct inode *inode, struct file *filp);
+int SDIOBus_IoCtl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+static void call_client_probe(PSD_DEVICE_DATA pDev, int fn);
+//
+// Module parameters
+//
+
+static int bus_type = SDIO_BUS_TYPE;
+static int bus_width = SDIO_1_BIT;
+int block_size = SD_BLOCK_SIZE;
+int dma_support = 1;
+static int clock_speed = 0;
+static int gpi_0_mode = 1; // edge triggered
+static int gpi_0_level = 1; // high->low
+static int gpi_1_mode = 1; // edge triggered
+static int gpi_1_level = 1; // high-->low
+#define INTMODE_SDIO 0
+#define INTMODE_GPIO 1
+int intmode = 0; // GPIO intmode enabled
+int gpiopin = 0; // GPIO pin number for SDIO alternative IRQ
+EXPORT_SYMBOL(intmode);
+EXPORT_SYMBOL(gpiopin);
+
+//static int debug_flags = 0;
+static int debug_flags = 0x0c;
+
+static int sdio_voltage = FPGA_POWER_REG_3_3_V;
+
+DECLARE_WAIT_QUEUE_HEAD(add_remove_queue);
+
+// kernel 2.6.x
+module_param(bus_type, int, S_IRUGO);
+module_param(bus_width, int, S_IRUGO);
+module_param(block_size, int, S_IRUGO);
+module_param(clock_speed, int, S_IRUGO);
+module_param(dma_support, int, S_IRUGO);
+module_param(debug_flags, int, S_IRUGO);
+module_param(sdio_voltage, int, S_IRUGO);
+module_param(gpi_0_mode, int, S_IRUGO); // 0 = level triggered 1 = edge
+ // triggered
+module_param(gpi_0_level, int, S_IRUGO); // 0 = low->high or low 1 =
+ // high->low or high
+module_param(gpi_1_mode, int, S_IRUGO); // 0 = level triggered 1 = edge
+ // triggered
+module_param(gpi_1_level, int, S_IRUGO); // 0 = low->high or low 1 =
+ // high->low or high
+module_param(intmode, int, S_IRUGO);
+module_param(gpiopin, int, S_IRUGO);
+
+// prototypes
+// for filling the "/proc/mrvsdio" entry
+int mrvlsdio_read_procmem(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+int sd_match_device(sd_driver * drv, PSD_DEVICE_DATA dev);
+
+// static PSD_DEVICE_DATA gSD_dev_data = NULL;
+
+struct list_head sd_dev_list;
+spinlock_t sd_dev_list_lock;
+unsigned long sd_dev_list_lock_flags;
+
+struct list_head sd_client_list;
+spinlock_t sd_client_list_lock;
+unsigned long sd_client_list_lock_flags;
+
+static int SDIOThread(void *data);
+
+static int probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void remove(struct pci_dev *dev);
+
+static DECLARE_COMPLETION(on_exit);
+
+// kernel 2.6
+
+static struct pci_device_id ids[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x8000),},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ids);
+
+/*
+ * The fops
+ */
+
+struct file_operations mrvlsdio_fops = {
+ llseek:NULL,
+ read:NULL,
+ write:NULL,
+ ioctl:SDIOBus_IoCtl,
+ mmap:NULL,
+ open:mrvlsdio_open,
+ release:mrvlsdio_release,
+};
+
+/*
+ * Open and close
+ */
+
+int
+mrvlsdio_open(struct inode *inode, struct file *filp)
+{
+ ENTER();
+
+ if (list_empty(&sd_dev_list)) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio_open: sd_dev_list is empty -> Adapter not in CardBus slot!\n"));
+ return -ENODEV;
+ }
+
+ filp->f_op = &mrvlsdio_fops;
+
+ // Pointer to first device in list
+ // This works ONLY with one CardBus slot and one SDIO2PCI Adapter !!!
+ // With more SDIO2PCI Adapter we need to implement virtual devices
+ filp->private_data = sd_dev_list.next;
+
+ LEAVE();
+ return 0; /* success */
+}
+
+int
+mrvlsdio_release(struct inode *inode, struct file *filp)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+/*
+ * The ioctl() implementation
+ */
+
+int
+SDIOBus_IoCtl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ UCHAR ucValue;
+ ULONG ulValue;
+ ULONG cnt;
+ PSD_DEVICE_DATA sd_dev;
+
+ ENTER();
+
+ sd_dev = (SD_DEVICE_DATA *) filp->private_data;
+ if (sd_dev == NULL) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "SDIOBus_IoCtl : sd_dev= 0x%p !!!!!!!!!!!!!!!!\n",
+ sd_dev));
+ return -ENOTTY;
+ }
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : sd_dev= 0x%p sd_dev->IOBase[0]= 0x%p\n", sd_dev,
+ sd_dev->IOBase[0]));
+
+ switch (cmd) {
+ case IOCTL_SDIOBUSENUM_SET_VOLTAGE:
+ {
+ ret = get_user(ucValue, (int *) arg);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_SET_VOLTAGE: 0x%2.02X\n",
+ ucValue));
+ MEM_WRITE_UCHAR(sd_dev, SK_SLOT_0, FPGA_POWER_REG_DATA, ucValue);
+ MEM_WRITE_UCHAR(sd_dev, SK_SLOT_0, FPGA_POWER_REG_CMD,
+ FPGA_POWER_REG_CMD_START);
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "wait for stable voltage\n"));
+ cnt = 0;
+ do {
+ MEM_READ_UCHAR(sd_dev, SK_SLOT_0, FPGA_POWER_REG_STATUS,
+ &ucValue);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "PowerRegulatorControl: 0x%x\n", ucValue));
+ } while (++cnt < 10000 && (ucValue & FPGA_POWER_REG_STABLE) == 0);
+ DBGPRINT(DBG_LOAD,
+ ("IOCTL_SDIOBUSENUM_SET_VOLTAGE: cnt=%d\n", cnt));
+ break;
+ }
+ case IOCTL_SDIOBUSENUM_GET_BOARDREV:
+ {
+ MEM_READ_ULONG(sd_dev, SK_SLOT_0, FPGA_CARD_REVISION, &ulValue);
+
+ ret = put_user(ulValue, (int *) arg);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_GET_BOARDREV 0x%8.08X\n",
+ ulValue));
+ break;
+ }
+ case IOCTL_SDIOBUSENUM_GET_JUMPER:
+ {
+ DBGPRINT(DBG_LOAD, ("IOCTL_SDIOBUSENUM_GET_JUMPER\n"));
+ MEM_READ_ULONG(sd_dev, SK_SLOT_0, FPGA_CARD_REVISION, &ulValue);
+ ret = put_user(ulValue, (int *) arg);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_GET_JUMPER 0x%8.08X\n",
+ ulValue));
+ break;
+ }
+
+ case IOCTL_SDIOBUSENUM_SET_BUSTYPE:
+ {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_SET_BUSTYPE --> IGNORED!\n"));
+ break;
+ }
+ case IOCTL_SDIOBUSENUM_SET_BUSWIDTH:
+ {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_SET_BUSWIDTH --> IGNORED!\n"));
+ break;
+ }
+ case IOCTL_SDIOBUSENUM_SET_CLKSPEED:
+ {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SDIOBus_IoCtl : IOCTL_SDIOBUSENUM_SET_CLKSPEED --> IGNORED!\n"));
+ break;
+ }
+ default:
+ {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "SDIOBus_IoCtl : invalid cmd=%d (0x%8.08X)!\n",
+ cmd, cmd));
+ return -ENOTTY;
+ }
+ }
+
+ LEAVE();
+ return ret;
+
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void
+card_out_work(PSD_DEVICE_DATA pDev)
+#else
+static void
+card_out_work(struct work_struct *work)
+#endif
+{
+ int j;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
+ PSD_DEVICE_DATA pDev = container_of(work, SD_DEVICE_DATA, card_out_work);
+#endif
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: CARD_REMOVE_EVENT received.\n", __FUNCTION__));
+ for (j = 1; j <= pDev->number_of_functions; j++) {
+ if (down_interruptible(&sd_client_sema))
+ return;
+ if (pDev->sd_dev[j].drv != NULL && pDev->sd_dev[j].drv->remove != NULL) {
+ if (pDev->sd_dev[j].remove_called == 0) {
+ DBGPRINT(DBG_LOAD | DBG_ERROR,
+ (KERN_DEBUG "%s: call remove() handler on fn=%d\n",
+ __FUNCTION__, j));
+
+ pDev->sd_dev[j].probe_called = 0;
+ pDev->sd_dev[j].remove_called = 1;
+ pDev->sd_dev[j].dev = NULL;
+ pDev->sd_dev[j].drv->remove(&pDev->sd_dev[j]);
+ }
+ } else {
+ // If we have no remove() handler at this point, we will never get
+ // one.
+ // So discard the CARD_REMOVE_EVENT to avoid an endless loop.
+ // This situation is considered a bug in the client driver !!!!
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s: no remove() handler installed for fn=%d! Revise client driver!!!\n",
+ __FUNCTION__, j));
+ }
+ up(&sd_client_sema);
+ }
+
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void
+card_irq_work(PSD_DEVICE_DATA pDev)
+#else
+static void
+card_irq_work(struct work_struct *work)
+#endif
+{
+ SK_U32 irq_handler_called;
+ SK_U8 int_pending;
+ SK_U32 ix;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
+ PSD_DEVICE_DATA pDev = container_of(work, SD_DEVICE_DATA, irq_work);
+#endif
+
+ irq_handler_called = 0;
+
+ // Read function specific interrupt information
+ GET_IF_SEMA_NO_RC();
+ if (SDHost_CMD52_Read(pDev, INT_PENDING_REG, 0, &int_pending)) {
+ REL_IF_SEMA();
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "INT Pending = 0x%2.02X\n ", int_pending));
+
+ for (ix = 1; ix <= 7; ix++) {
+ if (int_pending & INT(ix)) {
+ // Function ix interrupt is pending and enabled
+ if (pDev->irq_device_cache[ix] != NULL) {
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG
+ "Call registered interrupt handler for function %d.\n",
+ ix));
+ irq_handler_called++;
+ if (pDev->irq_device_cache[ix]->functions[ix].int_handler !=
+ NULL) {
+ pDev->irq_device_cache[ix]->functions[ix].
+ int_handler(pDev->irq_device_cache[ix],
+ pDev->irq_device_cache[ix]->
+ pCurrent_Ids,
+ pDev->irq_device_cache[ix]->
+ functions[ix].context);
+ }
+ }
+ }
+ }
+ } else
+ REL_IF_SEMA();
+
+ if (irq_handler_called == 0) {
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "No interrupt handler registered. (sd_dev=%p)\n",
+ pDev));
+ SDHost_EnableInterrupt(pDev, pDev->lastIRQSignalMask);
+ }
+
+}
+
+static struct pci_driver mrvlsdio = {
+ .name = "mrvlsdio",
+ .id_table = ids,
+ .probe = probe,
+ .remove = remove,
+};
+
+static int
+probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int i, ret;
+ SK_U8 ucValue;
+ SK_U32 mem;
+ SK_U32 ulValue;
+ PSD_DEVICE_DATA pTmpDev;
+
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "mrvlsdio : probe()\n"));
+
+ if (pci_enable_device(dev)) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: pci_enable_device() failed\n"));
+ return -EIO;
+ }
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: 32-bit PCI DMA not supported"));
+ pci_disable_device(dev);
+ return -EIO;
+ }
+ pci_set_master(dev);
+
+ /*--- mmoser 6/21/2007 ---*/
+ pTmpDev = (PSD_DEVICE_DATA) kmalloc(sizeof(SD_DEVICE_DATA), GFP_KERNEL);
+
+ if (pTmpDev == NULL) {
+ return -ENOMEM;
+ }
+#ifdef SDIO_MEM_TRACE
+ printk(">>> kmalloc(SD_DEVICE_DATA)\n");
+#endif
+
+ memset(pTmpDev, 0, sizeof(SD_DEVICE_DATA));
+
+ pTmpDev->IOBaseIx = 0;
+ /*--- mmoser 10/11/2006 ---*/
+ pTmpDev->dev = dev;
+ pTmpDev->workqueue = create_workqueue("MRVL-SDIO");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK(&pTmpDev->irq_work, (void (*)(void *)) card_irq_work, pTmpDev);
+ INIT_WORK(&pTmpDev->card_out_work, (void (*)(void *)) card_out_work,
+ pTmpDev);
+#else
+ INIT_WORK(&pTmpDev->irq_work, card_irq_work);
+ INIT_WORK(&pTmpDev->card_out_work, card_out_work);
+#endif
+
+ if (pci_request_regions(dev, "MRVL-SDIO")) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: pci_request_regions() failed.\n"));
+ pci_disable_device(dev);
+ return -EIO;
+ }
+
+ for (i = 0; i < 5; i++) {
+ mem = pci_resource_start(dev, i);
+
+ if (mem != 0) {
+ if (IORESOURCE_MEM & pci_resource_flags(dev, i)) {
+ pTmpDev->IOBaseLength[pTmpDev->IOBaseIx] =
+ pci_resource_end(dev, i) - mem + 1;
+ pTmpDev->IOBase[pTmpDev->IOBaseIx] =
+ ioremap_nocache(mem,
+ pTmpDev->IOBaseLength[pTmpDev->IOBaseIx]);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio: IOBase[%d] = 0x%8.08X IOBaseLength = %u\n",
+ i, (SK_U32) pTmpDev->IOBase[pTmpDev->IOBaseIx],
+ pTmpDev->IOBaseLength[pTmpDev->IOBaseIx]));
+ pTmpDev->IOBaseIx++;
+ if (pTmpDev->IOBaseIx >= 2) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio : Too many memory address ranges!\n"));
+ pTmpDev->IOBaseIx = 0;
+ }
+ }
+ }
+ }
+
+ // Dummy read. Function return SUCCESS but value is messy !!!
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE,
+ (SK_U8 *) & pTmpDev->Interrupt);
+
+ for (i = 0; i < 3; i++) {
+ ret =
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE,
+ (SK_U8 *) & pTmpDev->Interrupt);
+ if (ret) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio: Failed to retrieve Interrupt Line (%d) %d ret=%d\n",
+ i, pTmpDev->Interrupt, ret));
+ UDELAY(100);
+ continue;
+ } else {
+ break;
+ }
+ }
+ if (i >= 3) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio: Failed to retrieve Interrupt Line (%d) ret=%d\n",
+ i, ret));
+ return -ENODEV;
+ }
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: Interrupt Line = %d (%d)\n",
+ pTmpDev->Interrupt, i));
+
+ MEM_READ_UCHAR(pTmpDev, SK_SLOT_0, FPGA_CARD_REVISION, &ucValue);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: CardRevision: 0x%X (sd_dev_data=0x%p)\n",
+ ucValue, &pTmpDev));
+
+ pTmpDev->bus_type = bus_type;
+ pTmpDev->bus_width = bus_width;
+ pTmpDev->ClockSpeed = clock_speed;
+ pTmpDev->debug_flags = debug_flags;
+ pTmpDev->sdio_voltage = sdio_voltage;
+
+ pci_read_config_byte(dev, 0x0c, &ucValue);
+
+ if (ucValue == 0)
+ pci_write_config_byte(dev, 0x0c, 2);
+
+ pci_read_config_byte(dev, 0x0c, &ucValue);
+// printk("config[0x0c]=0x%2.02X\n",ucValue);
+ pci_read_config_byte(dev, 0x0d, &ucValue);
+ // printk("config[0x0d]=0x%2.02X\n",ucValue);
+ printk("debug_flags=0x%8.08X\n", debug_flags);
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: bus_type : SDIO%s\n",
+ bus_type == SDIO_BUS_TYPE ? "" : "/SPI"));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: bus_width : %s\n",
+ bus_width == SDIO_4_BIT ? "4-bit" : "1-bit"));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: block_size : %d\n", block_size));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: clock_speed : %d\n", clock_speed));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: debug_flags : 0x%8.08X\n", debug_flags));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: sdio_voltage : %d\n", sdio_voltage));
+
+ /*--- mmoser 3/12/2007 ---*/
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: gpi_0_mode : %s triggered\n",
+ gpi_0_mode == 0 ? "level" : "edge"));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: gpi_0_level : %s\n",
+ gpi_0_level == 0 ? (gpi_0_mode ==
+ 0 ? "low" : "low->high") : (gpi_0_mode ==
+ 0 ? "high" :
+ "high->low")));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: gpi_1_mode : %s triggered\n",
+ gpi_1_mode == 0 ? "level" : "edge"));
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: gpi_1_level : %s\n",
+ gpi_1_level == 0 ? (gpi_1_mode ==
+ 0 ? "low" : "low->high") : (gpi_1_mode ==
+ 0 ? "high" :
+ "high->low")));
+
+ // mmoser 2005-11-29
+ atomic_set(&pTmpDev->card_add_event, 0);
+ atomic_set(&pTmpDev->card_remove_event, 0);
+
+ /*--- mmoser 8/29/2006 ---*/
+ init_waitqueue_head(&pTmpDev->trans_complete_evt.wq);
+ init_waitqueue_head(&pTmpDev->cmd_complete_evt.wq);
+ init_waitqueue_head(&pTmpDev->thread_started_evt.wq);
+
+ /*--- mmoser 3/12/2007 ---*/
+ MEM_READ_ULONG(pTmpDev, SK_SLOT_0, 0x200, &ulValue);
+ ulValue &= 0x0FFFFFFF;
+ ulValue |=
+ ((gpi_1_mode << 3 | gpi_1_level << 2 | gpi_0_mode << 1 | gpi_0_level) <<
+ 28);
+// printk("mrvlsdio: ulValue = 0x%8.08X\n",ulValue);
+ MEM_WRITE_ULONG(pTmpDev, SK_SLOT_0, 0x200, ulValue);
+
+// printk("mrvlsdio: reg[0x200] = 0x%8.08X\n",ulValue);
+
+ spin_lock_init(&pTmpDev->sd_dev_lock);
+
+ spin_lock_irqsave(&sd_dev_list_lock, sd_dev_list_lock_flags);
+ list_add_tail((struct list_head *) pTmpDev, &sd_dev_list);
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s@%d: sd_dev_list=%p sd_dev_list.prev=%p sd_dev_list.next=%p pTmpDev=%p\n",
+ __FUNCTION__, __LINE__, &sd_dev_list, sd_dev_list.prev,
+ sd_dev_list.next, pTmpDev));
+
+ spin_unlock_irqrestore(&sd_dev_list_lock, sd_dev_list_lock_flags);
+
+ SDHost_Init(pTmpDev);
+
+ // mmoser 2005-11-29
+ if (0 != request_irq(pTmpDev->Interrupt,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ SDIOBus_Isr, SA_SHIRQ,
+#else
+ (irq_handler_t) SDIOBus_Isr, IRQF_SHARED,
+#endif
+ MRVL_DEVICE_NAME, (PVOID) pTmpDev)
+ ) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "mrvlsdio: Failed to register interrupt handler\n"));
+ return -ENODEV;
+ }
+
+ if (SDHost_isCardPresent(pTmpDev) == SK_TRUE) {
+ if (SDIOBus_CardPluggedIn(pTmpDev) == SK_TRUE) {
+ pTmpDev->CardIn = SK_TRUE;
+ }
+ SDHost_EnableInterrupt(pTmpDev, (STDHOST_NORMAL_IRQ_CARD_OUT_SIG_ENA |
+ STDHOST_NORMAL_IRQ_CARD_IN_SIG_ENA));
+ }
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pTmpDev->dma_tx_malign = 0;
+ pTmpDev->dma_rx_malign = 0;
+ // pTmpDev->dma_start_malign = 4096 - 32;
+ pTmpDev->dma_start_malign = 0;
+#endif
+
+// mmoser 2005-11-22 start the thread as the last action
+
+// mmoser 2005-11-21
+ pTmpDev->stop_thread = SK_FALSE;
+
+ pTmpDev->thread_id = kernel_thread(SDIOThread,
+ pTmpDev,
+ (CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND));
+
+ if (pTmpDev->thread_id == 0) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "mrvlsdio: Failed to start kernel thread!\n"));
+ return -1;
+ } else {
+
+ if (SDHost_wait_event(pTmpDev, &pTmpDev->thread_started_evt, 1000)) {
+ pTmpDev->stop_thread = SK_TRUE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ kill_pid(find_get_pid(pTmpDev->thread_id), SIGTERM, 1);
+#else
+ kill_proc(pTmpDev->thread_id, SIGTERM, 1);
+#endif
+ pTmpDev->thread_id = 0;
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "%s @ %d: Wait SDIOThread started ---> FAILED !\n",
+ __FUNCTION__, __LINE__));
+ return 0;
+ }
+
+ }
+
+ return 0;
+}
+
+static void
+remove(struct pci_dev *dev)
+{
+ struct list_head *pTmp;
+ struct list_head *pNext;
+ PSD_DEVICE_DATA pTmpDev;
+ int j;
+ SK_U8 ucValue;
+ SK_U32 cnt;
+
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "remove mrvlsdio ... \n"));
+
+ /* clean up any allocated resources and stuff here. like call
+ release_region(); */
+
+ /*
+ * iterate through the device list
+ * call remove() for each client driver
+ * remove device from list
+ * free allocated memory
+ */
+ if (!list_empty(&sd_dev_list)) {
+ pTmp = sd_dev_list.next;
+
+ while (pTmp != &sd_dev_list) {
+ pNext = pTmp->next;
+ pTmpDev = (PSD_DEVICE_DATA) pTmp;
+ if (pTmpDev->dev == dev) {
+ pTmpDev->isRemoving = SK_TRUE;
+ for (j = 1; j <= pTmpDev->number_of_functions; j++) {
+ if (down_interruptible(&sd_client_sema))
+ return;
+ if (pTmpDev->sd_dev[j].drv != NULL &&
+ pTmpDev->sd_dev[j].drv->remove != NULL) {
+ if (pTmpDev->sd_dev[j].remove_called == 0) {
+ pTmpDev->sd_dev[j].probe_called = 0;
+ pTmpDev->sd_dev[j].remove_called = 1;
+ pTmpDev->sd_dev[j].dev = NULL;
+ pTmpDev->sd_dev[j].drv->remove(&pTmpDev->sd_dev[j]);
+ }
+ }
+ up(&sd_client_sema);
+ }
+
+ if (pTmpDev->thread_id) {
+ pTmpDev->stop_thread = SK_TRUE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ kill_pid(find_get_pid(pTmpDev->thread_id), SIGTERM, 1);
+#else
+ kill_proc(pTmpDev->thread_id, SIGTERM, 1);
+#endif
+ wait_for_completion(&on_exit);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: SDIOThread killed ... \n",
+ __FUNCTION__));
+ }
+ // Send I/O Card Reset
+ SDHost_CMD52_Write((PSD_DEVICE_DATA) pTmp, IO_ABORT_REG, FN0,
+ RES);
+ SDHost_DisableInterrupt((PSD_DEVICE_DATA) pTmp,
+ STDHOST_NORMAL_IRQ_ALL_SIG_ENA);
+ SDHost_SetClock((PSD_DEVICE_DATA) pTmp, 0);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ cancel_delayed_work(&pTmpDev->card_out_work);
+ cancel_delayed_work(&pTmpDev->irq_work);
+#endif
+ flush_scheduled_work();
+ destroy_workqueue(pTmpDev->workqueue);
+ pTmpDev->workqueue = NULL;
+
+ // set host power voltage as low as possible
+ // (still need despite "turn off host power" below, b/c
+ // hotplug can reactivate host power independently in HW)
+ MEM_WRITE_UCHAR((PSD_DEVICE_DATA) pTmp, SK_SLOT_0,
+ FPGA_POWER_REG_DATA, FPGA_POWER_REG_0_7_V);
+ MEM_WRITE_UCHAR((PSD_DEVICE_DATA) pTmp, SK_SLOT_0,
+ FPGA_POWER_REG_CMD, FPGA_POWER_REG_CMD_START);
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "wait for stable voltage\n"));
+ cnt = 0;
+ do {
+ MEM_READ_UCHAR((PSD_DEVICE_DATA) pTmp, SK_SLOT_0,
+ FPGA_POWER_REG_STATUS, &ucValue);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "PowerRegulatorControl: 0x%x\n",
+ ucValue));
+ } while (++cnt < 10000 &&
+ (ucValue & FPGA_POWER_REG_STABLE) == 0);
+ DBGPRINT(DBG_LOAD, ("REMOVE_SET_VOLTAGE: cnt=%d\n", cnt));
+
+ // turn off host power
+ MEM_READ_UCHAR((PSD_DEVICE_DATA) pTmp, SK_SLOT_0,
+ STDHOST_POWER_CTRL, &ucValue);
+ MEM_WRITE_UCHAR((PSD_DEVICE_DATA) pTmp, SK_SLOT_0,
+ STDHOST_POWER_CTRL,
+ ucValue & ~STDHOST_POWER_ON);
+
+ // give some time for host power off to settle
+ mdelay(200);
+
+ free_irq(pTmpDev->Interrupt, pTmpDev);
+ for (j = 0; j < pTmpDev->IOBaseIx; j++)
+ iounmap(pTmpDev->IOBase[j]);
+ /*--- mmoser 10/11/2006 ---*/
+ pci_release_regions(pTmpDev->dev);
+
+ list_del((struct list_head *) pTmpDev);
+ kfree(pTmpDev);
+
+#ifdef SDIO_MEM_TRACE
+ printk("<<< kfree(SD_DEVICE_DATA)\n");
+#endif
+
+ return;
+ }
+ pTmp = pNext;
+ }
+ }
+
+}
+
+BOOLEAN
+SDIOBus_CardRemoved(PSD_DEVICE_DATA SdData)
+{
+ SK_U32 ulVal;
+
+ ENTER();
+
+#ifdef USE_DEBOUNCE_CARD_IN
+
+ /*--- mmoser 12/21/2006 ---*/
+ mdelay(MAX_DEBOUNCE_TIME);
+
+ // Read present state register to check whether a SD card is present
+ MEM_READ_ULONG(SdData, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ if ((ulVal & STDHOST_STATE_CARD_INSERTED) == 1) {
+ // There is probably still a card in the socket
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent(): Card is present. (%8.08X)\n",
+ ulVal));
+ return SK_FALSE;
+ }
+#endif // USE_DEBOUNCE_CARD_IN
+
+ SdData->CardIn = SK_FALSE;
+
+ // mmoser 2005-11-29
+ queue_work(SdData->workqueue, &SdData->card_out_work);
+
+ LEAVE();
+ return SK_TRUE;
+}
+
+BOOLEAN
+SDIOBus_CardPluggedIn(PSD_DEVICE_DATA SdData)
+{
+ SK_U32 ulVal;
+
+ ENTER();
+
+#ifdef USE_DEBOUNCE_CARD_IN
+
+ /*--- mmoser 12/21/2006 ---*/
+ mdelay(MAX_DEBOUNCE_TIME);
+
+ // Read present state register to check whether a SD card is present
+ MEM_READ_ULONG(SdData, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ if ((ulVal & STDHOST_STATE_CARD_INSERTED) == 0) {
+ // There is probably no card in the socket
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent(): Card is NOT present. (%8.08X)\n",
+ ulVal));
+ return SK_FALSE;
+ }
+#endif // USE_DEBOUNCE_CARD_IN
+
+ SDHost_Init(SdData);
+
+ if (!SDHost_InitializeCard(SdData)) {
+ SDHost_EnableInterrupt(SdData, SdData->lastIRQSignalMask);
+ return SK_FALSE;
+ }
+ SdData->CardIn = SK_TRUE;
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Device Name : %s\n", SdData->DeviceName));
+
+ // mmoser 2005-11-29
+ atomic_inc(&SdData->card_add_event);
+ LEAVE();
+ return SK_TRUE;
+}
+
+static int
+SDIOThread(void *data)
+{
+ SK_U16 usVal;
+ SK_U32 card_in = 0;
+ SK_U32 card_out = 0;
+ PSD_DEVICE_DATA pDev;
+ int clients_found;
+ int fn = 0;
+ int j;
+ struct list_head *pTmp;
+ PSD_CLIENT pClientTmp;
+ int fn_mask;
+ u8 attached_fn[MAX_SDIO_FUNCTIONS];
+
+ daemonize("SDIOThread");
+ allow_signal(SIGTERM);
+
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDIOThread() started ... \n"));
+
+ if (data == NULL) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDIOThread() data == NULL !\n"));
+ complete_and_exit(&on_exit, 0);
+ return 1;
+ }
+ pDev = (PSD_DEVICE_DATA) data;
+
+ LED_OFF(4);
+
+ if (!test_and_set_bit(0, &pDev->thread_started_evt.event)) {
+ wake_up(&pDev->thread_started_evt.wq);
+ }
+
+ while (pDev != NULL && !pDev->stop_thread) {
+ LED_ON(4);
+
+// mmoser 2005-11-21
+ // Read the Host Controller Version to check if SD Host adapter is
+ // available
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_HOST_CONTROLLER_VERSION,
+ &usVal);
+ if (usVal == 0xFFFF) {
+ // There is probably no SD Host Adapter available
+ printk("%s: SD Host Adapter is NOT present.\n", __FUNCTION__);
+ pDev->SurpriseRemoved = SK_TRUE;
+ pDev->CardIn = SK_FALSE;
+ pDev->thread_id = 0;
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDIOThread terminated ... \n"));
+ complete_and_exit(&on_exit, 0);
+ return -ENODEV;
+ }
+// mmoser 2005-11-29
+ card_in = atomic_read(&pDev->card_add_event);
+ card_out = atomic_read(&pDev->card_remove_event);
+
+ if (card_in == 0 && card_out == 0) {
+ LED_OFF(4);
+ /*--- mmoser 6/21/2006 ---*/
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(10);
+ continue;
+ }
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: card_in=%d card_out=%d\n", __FUNCTION__,
+ card_in, card_out));
+
+ // mmoser 2005-11-29
+ if (card_in > 0) {
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: CARD_ADD_EVENT received.\n",
+ __FUNCTION__));
+
+ // Check whether we have a client driver in the global list for
+ // this device
+ if (!list_empty(&sd_client_list)) {
+ spin_lock_irqsave(&sd_client_list_lock,
+ sd_client_list_lock_flags);
+
+ fn = pDev->number_of_functions + 1;
+
+ clients_found = 0;
+
+ // walk through the list of client drivers
+ list_for_each(pTmp, &sd_client_list) {
+ pClientTmp = (PSD_CLIENT) pTmp;
+ if ((fn_mask = sd_match_device(pClientTmp->drv, pDev)) > 0) {
+ // Matching client driver found
+ // Assign the client driver to the lowest supported
+ // function
+ for (fn = 1; fn <= pDev->number_of_functions; fn++) {
+ if ((fn_mask & (1 << fn)) != 0) {
+ pDev->sd_dev[fn].drv = pClientTmp->drv;
+ pDev->sd_dev[fn].supported_functions = fn_mask;
+ pDev->sd_dev[fn].cisptr = &pDev->cisptr[0];
+ pDev->sd_dev[fn].sd_bus = pDev; // Backpointer
+ // to bus
+ // driver's
+ // device
+ // structure
+ pDev->sd_dev[fn].dev = &pDev->dev->dev; // Generic
+ // device
+ // interface
+ // for
+ // hotplug
+ attached_fn[clients_found] = fn;
+ clients_found++;
+ break;
+ }
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sd_client_list_lock,
+ sd_client_list_lock_flags);
+
+ if (clients_found) {
+ // Call probe() for each previously attached client driver
+ for (j = 0; j < clients_found; j++) {
+ fn = attached_fn[j];
+ if (pDev->sd_dev[fn].drv->probe != NULL) {
+ if (pDev->sd_dev[fn].probe_called == 0) {
+ DBGPRINT(DBG_LOAD | DBG_ERROR,
+ (KERN_DEBUG
+ "%s: call probe() handler on fn=%d\n",
+ __FUNCTION__, fn));
+
+ pDev->SurpriseRemoved = 0;
+ pDev->sd_dev[fn].probe_called = 1;
+ pDev->sd_dev[fn].remove_called = 0;
+ call_client_probe(pDev, fn);
+ }
+ } else {
+ // If we have no probe() handler at this point, we
+ // will never get one.
+ // So discard the CARD_ADD_EVENT to avoid an
+ // endless loop.
+ // This situation is considered a bug in the client
+ // driver !!!!
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s@%d: no probe() handler installed for fn=%d! Revise client driver!!!\n",
+ __FUNCTION__, __LINE__, fn));
+ }
+ }
+ } else {
+ // There is at least one client driver registered with our
+ // bus driver
+ // but the sd_device_ids of this driver does not match the
+ // ids of the inserted card.
+ // We have to wait until a matching driver will be
+ // installed.
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s@%d: no matching client driver installed.\n",
+ __FUNCTION__, __LINE__));
+ }
+ } else {
+ // Until there is no client driver registered with our bus
+ // driver.
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s@%d: no client driver installed.\n",
+ __FUNCTION__, __LINE__));
+ }
+
+ // We can reset the card event here since the association with a
+ // matching client driver
+ // is already done or will be done in sd_register_driver()
+ atomic_set(&pDev->card_add_event, 0);
+
+ }
+ // mmoser 2005-11-29
+ else if (card_out > 0) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: CARD_REMOVE_EVENT received.\n",
+ __FUNCTION__));
+ for (j = 1; j <= pDev->number_of_functions; j++) {
+ if (down_interruptible(&sd_client_sema))
+ return 0;
+ if (pDev->sd_dev[j].drv != NULL &&
+ pDev->sd_dev[j].drv->remove != NULL) {
+ if (pDev->sd_dev[j].remove_called == 0) {
+ DBGPRINT(DBG_LOAD | DBG_ERROR,
+ (KERN_DEBUG
+ "%s: call remove() handler on fn=%d\n",
+ __FUNCTION__, j));
+
+ pDev->sd_dev[j].probe_called = 0;
+ pDev->sd_dev[j].remove_called = 1;
+ pDev->sd_dev[j].dev = NULL;
+ pDev->sd_dev[j].drv->remove(&pDev->sd_dev[j]);
+ }
+ } else {
+ // If we have no remove() handler at this point, we will
+ // never get one.
+ // So discard the CARD_REMOVE_EVENT to avoid an endless
+ // loop.
+ // This situation is considered a bug in the client driver
+ // !!!!
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s: no remove() handler installed for fn=%d! Revise client driver!!!\n",
+ __FUNCTION__, j));
+ }
+ up(&sd_client_sema);
+ }
+ atomic_set(&pDev->card_remove_event, 0);
+ } else {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDIOThread terminated ... \n"));
+ pDev->thread_id = 0;
+ complete_and_exit(&on_exit, 0);
+ return 1;
+ }
+ }
+
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDIOThread terminated ... \n"));
+
+ if (pDev != NULL) {
+ pDev->thread_id = 0;
+ }
+
+ complete_and_exit(&on_exit, 0);
+
+ return 0;
+}
+
+/************************* New SDIO Bus Driver API ************************/
+
+/**
+ * @brief This function matches a client driver with a SDIO device
+ * @param drv pointer to client drivers device IDs
+ * @param dev pointer to SDIO device
+ * @return mask with supported functions -> 0 means no match found
+ *
+ * 76543210
+ * ||||||+-- fn 1 supported
+ * |||||+--- fn 2 supported
+ * ||||+---- fn 3 supported
+ * |||+----- fn 4 supported
+ * ||+------ fn 5 supported
+ * |+------- fn 6 supported
+ * +-------- fn 7 supported
+ *
+ * 0x02 -> fn 1 supported
+ * 0x06 -> fn 1 and 2 supported
+ * 0x12 -> fn 1 and 4 supported
+*/
+int
+sd_match_device(sd_driver * drv, PSD_DEVICE_DATA dev)
+{
+ psd_device_id pIds;
+ int i;
+ int matched_fn = 0;
+ int fn_mask = 0;
+
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG
+ "%s: drv-name: %s device: vendor=0x%4.04X device=0x%4.04X\n",
+ __FUNCTION__, drv->name, dev->sd_ids[0].vendor,
+ dev->sd_ids[0].device));
+
+ for (pIds = drv->ids; pIds->device != 0 ||
+ pIds->vendor != 0 || pIds->class != 0 || pIds->fn != 0; pIds++) {
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG
+ "vendor=0x%4.04X device=0x%4.04X class=0x%4.04X fn=0x%4.04X\n",
+ pIds->vendor, pIds->device, pIds->class, pIds->fn));
+ if ((pIds->vendor != SD_VENDOR_ANY) &&
+ (pIds->vendor != dev->sd_ids[0].vendor)) {
+ continue;
+ }
+ if (pIds->device != SD_DEVICE_ANY) {
+ matched_fn = 0;
+ for (i = 0; i <= dev->number_of_functions; i++) {
+ if (pIds->device == dev->sd_ids[i].device) {
+ matched_fn = i;
+ fn_mask |= (1 << matched_fn);
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG "driver matches with function %d\n",
+ i));
+ break;
+ }
+ }
+ if (matched_fn == 0) {
+ continue;
+ }
+ }
+ if (pIds->class != SD_CLASS_ANY) {
+ matched_fn = 0;
+ for (i = 1; i <= dev->number_of_functions; i++) {
+// printk("fn[%d] class-id=0x%4.04X\n",i,dev->sd_ids[i].class);
+ if (pIds->class == dev->sd_ids[i].class) {
+ matched_fn = i;
+ fn_mask |= (1 << matched_fn);
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG "driver matches with function %d\n",
+ i));
+ break;
+ }
+ }
+ if (matched_fn == 0) {
+ continue;
+ }
+ } else {
+ // At this point vendor==ANY && device==ANY && class==ANY
+ // Now we have to check whether the card supports the desired
+ // function number
+ if (pIds->fn > 0 && pIds->fn <= dev->number_of_functions) {
+ matched_fn = pIds->fn;
+ fn_mask |= (1 << matched_fn);
+ }
+ }
+
+ if ((pIds->fn != SD_FUNCTION_ANY) && (pIds->fn != matched_fn)) {
+ continue;
+ }
+ }
+
+ printk("%s: supported function mask = 0x%2.02X\n", __FUNCTION__, fn_mask);
+ return (fn_mask);
+}
+
+/**
+ * @brief This function registers a client driver with the bus driver using device IDs
+ * @param drv pointer to client drivers device IDs and call backs
+ * @return 0 : Success < 0: Failed
+*/
+int
+sd_driver_register(sd_driver * drv)
+{
+ struct list_head *pTmp;
+ PSD_CLIENT pClientTmp;
+ PSD_DEVICE_DATA pDevTmp;
+ int fn_mask;
+ int fn;
+
+ GET_IF_SEMA();
+
+ ENTER();
+
+ pClientTmp = (PSD_CLIENT) kmalloc(sizeof(SD_CLIENT), GFP_KERNEL);
+
+ if (pClientTmp == NULL) {
+ REL_IF_SEMA();
+ LEAVE();
+ return -ENOMEM;
+ }
+#ifdef SDIO_MEM_TRACE
+ printk(">>> kmalloc(SD_CLIENT)\n");
+#endif
+
+ memset(pClientTmp, 0, sizeof(SD_CLIENT));
+
+ pClientTmp->drv = drv;
+
+ // Check whether there is a SDIO device available
+ if (!list_empty(&sd_dev_list)) {
+ list_for_each(pTmp, &sd_dev_list) {
+ pDevTmp = (PSD_DEVICE_DATA) pTmp;
+
+ spin_lock_irqsave(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ if ((fn_mask = sd_match_device(drv, pDevTmp)) > 0) {
+ // Assign the client driver to the lowest supported function
+ for (fn = 1; fn <= pDevTmp->number_of_functions; fn++) {
+ if ((fn_mask & (1 << fn)) != 0) {
+ break;
+ }
+ }
+ if (fn <=
+ MIN(pDevTmp->number_of_functions, MAX_SDIO_FUNCTIONS - 1)) {
+ if (pDevTmp->sd_dev[fn].drv == NULL) {
+ pDevTmp->sd_dev[fn].drv = drv;
+ pDevTmp->sd_dev[fn].supported_functions = fn_mask;
+ pDevTmp->sd_dev[fn].cisptr = &pDevTmp->cisptr[0];
+ pDevTmp->sd_dev[fn].sd_bus = pDevTmp; // Backpointer
+ // to bus
+ // driver's
+ // device
+ // structure
+ pDevTmp->sd_dev[fn].dev = &pDevTmp->dev->dev; // Generic
+ // device
+ // interface
+ // for
+ // hotplug
+
+ spin_unlock_irqrestore(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG
+ "%s: Driver registered: %s for functions 0x%2.02X\n",
+ __FUNCTION__, pDevTmp->sd_dev[fn].drv->name,
+ fn_mask));
+
+ if (pDevTmp->sd_dev[fn].drv->probe != NULL) {
+ pDevTmp->sd_dev[fn].probe_called = 1;
+ pDevTmp->sd_dev[fn].remove_called = 0;
+
+ DBGPRINT(DBG_LOAD | DBG_ERROR,
+ (KERN_DEBUG
+ "%s: call probe() handler on fn=%d\n",
+ __FUNCTION__, fn));
+ REL_IF_SEMA();
+ call_client_probe(pDevTmp, fn);
+ GET_IF_SEMA();
+ } else {
+ // If we have no probe() handler at this point, we
+ // will never get one.
+ // This situation is considered a bug in the client
+ // driver !!!!
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "%s@%d: no probe() handler installed for fn=%d! Revise client driver!!!\n",
+ __FUNCTION__, __LINE__, fn));
+ }
+ break;
+ } else {
+ spin_unlock_irqrestore(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ continue;
+ }
+ }
+ } else {
+ spin_unlock_irqrestore(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ continue;
+ }
+
+ }
+ DBGPRINT(DBG_API,
+ (KERN_ERR
+ "%s: There are already drivers registered for all devices!\n",
+ __FUNCTION__));
+ }
+ // Add driver to global client list
+ spin_lock_irqsave(&sd_client_list_lock, sd_client_list_lock_flags);
+ list_add_tail((struct list_head *) pClientTmp, &sd_client_list);
+ spin_unlock_irqrestore(&sd_client_list_lock, sd_client_list_lock_flags);
+
+ REL_IF_SEMA();
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function unregisters a client driver from the bus driver
+ * @param drv pointer to client drivers device IDs and call backs
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_driver_unregister(sd_driver * drv)
+{
+ struct list_head *pTmp;
+ PSD_CLIENT pClientTmp;
+ PSD_DEVICE_DATA pDevTmp;
+ int j;
+
+ ENTER();
+
+ if (drv == NULL) {
+ printk("%s INVALID ARGS: drv==NULL!\n", __FUNCTION__);
+ LEAVE();
+ return -1;
+ }
+
+ if (down_interruptible(&sd_client_sema))
+ return 0;
+ // Delete any association with this client driver
+ spin_lock_irqsave(&sd_dev_list_lock, sd_dev_list_lock_flags);
+ if (!list_empty(&sd_dev_list)) {
+ list_for_each(pTmp, &sd_dev_list) {
+ pDevTmp = (PSD_DEVICE_DATA) pTmp;
+ spin_unlock_irqrestore(&sd_dev_list_lock, sd_dev_list_lock_flags);
+ for (j = 0; j < MAX_SDIO_FUNCTIONS; j++) {
+ if (pDevTmp->sd_dev[j].drv == drv) {
+
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG
+ "%s: Driver unregistered: %s on fn = %d\n",
+ __FUNCTION__, pDevTmp->sd_dev[j].drv->name, j));
+
+ if (drv != NULL && drv->remove != NULL) {
+ if (pDevTmp->sd_dev[j].remove_called == 0) {
+ pDevTmp->sd_dev[j].probe_called = 0;
+ pDevTmp->sd_dev[j].remove_called = 1;
+ if (pDevTmp->SurpriseRemoved == SK_TRUE)
+ pDevTmp->sd_dev[j].dev = NULL;
+ pDevTmp->sd_dev[j].drv->remove(&pDevTmp->sd_dev[j]);
+ }
+ }
+
+ spin_lock_irqsave(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ pDevTmp->sd_dev[j].drv = NULL;
+ spin_unlock_irqrestore(&pDevTmp->sd_dev_lock,
+ pDevTmp->sd_dev_lock_flags);
+ }
+ }
+ }
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: Driver %s is not registered!\n", __FUNCTION__,
+ drv->name));
+ } else {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: SDIO Device List is empty!\n", __FUNCTION__));
+ spin_unlock_irqrestore(&sd_dev_list_lock, sd_dev_list_lock_flags);
+ }
+ up(&sd_client_sema);
+
+ GET_IF_SEMA();
+ // Remove the client driver from global client list
+ if (!list_empty(&sd_client_list)) {
+ spin_lock_irqsave(&sd_client_list_lock, sd_client_list_lock_flags);
+
+ list_for_each(pTmp, &sd_client_list) {
+ pClientTmp = (PSD_CLIENT) pTmp;
+ if (pClientTmp->drv != drv) {
+ continue;
+ }
+
+ list_del(pTmp);
+ kfree(pClientTmp);
+
+#ifdef SDIO_MEM_TRACE
+ printk("<<< kfree(SD_CLIENT)\n");
+#endif
+
+ break;
+ }
+
+ spin_unlock_irqrestore(&sd_client_list_lock, sd_client_list_lock_flags);
+ } else {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: SDIO Client Driver List is empty!\n",
+ __FUNCTION__));
+ REL_IF_SEMA();
+ LEAVE();
+ return -1;
+ }
+
+ REL_IF_SEMA();
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Register an interrupt handler with a card function
+ * @param dev bus driver's device structure
+ * @param id sd_device_ids (contains function number)
+ * @param function interrupt handler
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_request_int(sd_device * dev, sd_device_id * id, sd_function * function)
+{
+ PSD_DEVICE_DATA pDev;
+
+ if (dev == NULL || id == NULL || function == NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: missing parameters: dev=%p id=%p function=%p\n",
+ __FUNCTION__, dev, id, function));
+ return -1;
+ }
+
+ if (id->fn < 1 || id->fn > 7) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: illegal function number: %d\n", __FUNCTION__,
+ id->fn));
+ return -1;
+ }
+ if (dev->functions[id->fn].int_handler != NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR
+ "%s: There is already an interrupt handler registered with function %d\n",
+ __FUNCTION__, id->fn));
+ return -1;
+ }
+
+ GET_IF_SEMA();
+
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG "%s: FN%d handler=%p context=%p\n", __FUNCTION__,
+ id->fn, function->int_handler, function->context));
+
+ pDev = (PSD_DEVICE_DATA) dev->sd_bus;
+
+ SDHost_DisableInterrupt((PSD_DEVICE_DATA) dev->sd_bus,
+ STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+ dev->functions[id->fn].int_handler = function->int_handler;
+ dev->functions[id->fn].context = function->context;
+
+ // cache the device to speed up irq response
+ pDev->irq_device_cache[id->fn] = dev;
+ SDHost_EnableInterrupt((PSD_DEVICE_DATA) dev->sd_bus,
+ pDev->lastIRQSignalMask);
+
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Remove an interrupt handler from a card function
+ * @param dev bus driver's device structure
+ * @param id sd_device_ids (contains function number)
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_release_int(sd_device * dev, sd_device_id * id)
+{
+ PSD_DEVICE_DATA pDev;
+
+ if (dev == NULL || id == NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: missing parameters: dev=%p id=%p\n",
+ __FUNCTION__, dev, id));
+ return -1;
+ }
+ if (id->fn < 1 || id->fn > 7) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: illegal function number: %d\n", __FUNCTION__,
+ id->fn));
+ return -1;
+ }
+
+ GET_IF_SEMA();
+
+ pDev = (PSD_DEVICE_DATA) dev->sd_bus;
+
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s: FN%d\n", __FUNCTION__, id->fn));
+
+ SDHost_DisableInterrupt((PSD_DEVICE_DATA) dev->sd_bus,
+ STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+ dev->functions[id->fn].int_handler = NULL;
+ dev->functions[id->fn].context = NULL;
+
+ pDev->irq_device_cache[id->fn] = NULL;
+ SDHost_EnableInterrupt((PSD_DEVICE_DATA) dev->sd_bus,
+ pDev->lastIRQSignalMask);
+
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Enable interrupt of function id->fn
+ * @param dev bus driver's device structure
+ * @param id sd_device_ids (contains function number)
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_unmask(sd_device * dev, sd_device_id * id)
+{
+ PSD_DEVICE_DATA pDev;
+ if (dev == NULL || id == NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: missing parameters: dev=%p id=%p\n",
+ __FUNCTION__, dev, id));
+ return 1;
+ }
+ if (id->fn < 1 || id->fn > 7) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: illegal function number: %d\n", __FUNCTION__,
+ id->fn));
+ return -1;
+ }
+
+ GET_IF_SEMA();
+
+ pDev = dev->sd_bus;
+ SDHost_EnableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Enable interrupt of function id->fn
+ * @param dev bus driver's device structure
+ * @param id sd_device_ids (contains function number)
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_enable_int(sd_device * dev, sd_device_id * id)
+{
+ PSD_DEVICE_DATA pDev;
+ SK_U8 R;
+
+ if (dev == NULL || id == NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: missing parameters: dev=%p id=%p\n",
+ __FUNCTION__, dev, id));
+ return 1;
+ }
+ if (id->fn < 1 || id->fn > 7) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: illegal function number: %d\n", __FUNCTION__,
+ id->fn));
+ return -1;
+ }
+
+ GET_IF_SEMA();
+
+ pDev = dev->sd_bus;
+
+ // Set global interrupt enable
+ if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R)) {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ R |= (1 << id->fn);
+ if (SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, R)) {
+ if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R)) {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG "%s:FN0 : INT Enable Register: 0x%2.02X\n",
+ __FUNCTION__, R));
+ } else {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ SDHost_EnableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Disable interrupt of function id->fn
+ * @param dev bus driver's device structure
+ * @param id sd_device_ids (contains function number)
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_disable_int(sd_device * dev, sd_device_id * id)
+{
+ PSD_DEVICE_DATA pDev;
+ SK_U8 R;
+
+ if (dev == NULL || id == NULL) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: missing parameters: dev=%p id=%p\n",
+ __FUNCTION__, dev, id));
+ return -1;
+ }
+ if (id->fn < 1 || id->fn > 7) {
+ DBGPRINT(DBG_API,
+ (KERN_ERR "%s: illegal function number: %d\n", __FUNCTION__,
+ id->fn));
+ return -1;
+ }
+
+ GET_IF_SEMA();
+
+ pDev = dev->sd_bus;
+
+ // Set global interrupt enable
+ if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R)) {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ R &= ~(1 << id->fn);
+ if (SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, R)) {
+ if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R)) {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ DBGPRINT(DBG_API,
+ (KERN_DEBUG "%s:FN0 : INT Disable Register: 0x%2.02X\n",
+ __FUNCTION__, R));
+ } else {
+ REL_IF_SEMA();
+ return -1;
+ }
+
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Set SDIO bus width
+ * @param dev bus driver's device structure
+ * @param with SDIO bus with 1 or 4
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_set_buswidth(sd_device * dev, int width)
+{
+ SK_BOOL rc;
+ GET_IF_SEMA();
+
+ if (width == 1 || width == 4) {
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s: width = %d\n", __FUNCTION__, width));
+ rc = SDHost_SetBusWidth((PSD_DEVICE_DATA) dev->sd_bus, width);
+ REL_IF_SEMA();
+ return (rc ? 0 : -1);
+ } else {
+ REL_IF_SEMA();
+ return -1;
+ }
+}
+
+/**
+ * @brief Set GPO on or off
+ * @param dev bus driver's device structure
+ * @param on 1: turn GPO on 0: turn GPO off
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_set_gpo(sd_device * dev, int on)
+{
+ SK_BOOL rc;
+
+ GET_IF_SEMA();
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s: on = %d\n", __FUNCTION__, on));
+ rc = SDHost_SetGPO((PSD_DEVICE_DATA) dev->sd_bus, on);
+
+ REL_IF_SEMA();
+ return (rc ? 0 : -1);
+}
+
+/**
+ * @brief Set SDIO bus clock on
+ * @param dev bus driver's device structure
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_start_clock(sd_device * dev)
+{
+ GET_IF_SEMA();
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s\n", __FUNCTION__));
+ SDHost_SetClock((PSD_DEVICE_DATA) dev->sd_bus, 1);
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Set SDIO bus clock on
+ * @param dev bus driver's device structure
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_stop_clock(sd_device * dev)
+{
+ GET_IF_SEMA();
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s\n", __FUNCTION__));
+ SDHost_SetClock((PSD_DEVICE_DATA) dev->sd_bus, 0);
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Set SDIO bus clock
+ * @param dev bus driver's device structure
+ * @param clock SDIO bus clock frequency
+ * @return 0 : Success -1: Failed
+*/
+int
+sd_set_busclock(sd_device * dev, int clock)
+{
+ GET_IF_SEMA();
+ DBGPRINT(DBG_API, (KERN_DEBUG "%s: clock = %d\n", __FUNCTION__, clock));
+ SDHost_SetClockSpeed((PSD_DEVICE_DATA) dev->sd_bus, clock);
+ REL_IF_SEMA();
+ return 0;
+}
+
+/**
+ * @brief Read a byte from SDIO device
+ * @param dev bus driver's device structure
+ * @param fn function number 0..7
+ * @param reg register offset
+ * @param dat pointer to return value
+ * @return 0 : Success -1: Failed
+*/
+int
+sdio_read_ioreg(sd_device * dev, u8 fn, u32 reg, u8 * dat)
+{
+ GET_IF_SEMA();
+ if (SDHost_CMD52_Read((PSD_DEVICE_DATA) dev->sd_bus, reg, fn, dat)) {
+// printk("%s: dev=%p fn=%d reg=0x%8.08X dat=0x%2.02x\n",__FUNCTION__,dev,fn,reg,*dat);
+ REL_IF_SEMA();
+ return 0;
+ } else {
+ printk("%s: dev=%p fn=%d reg=0x%8.08X FAILED!\n", __FUNCTION__, dev, fn,
+ reg);
+ REL_IF_SEMA();
+ return -1;
+ }
+
+}
+
+/**
+ * @brief Write a byte to SDIO device
+ * @param dev bus driver's device structure
+ * @param fn function number 0..7
+ * @param reg register offset
+ * @param dat value
+ * @return 0 : Success -1: Failed
+*/
+int
+sdio_write_ioreg(sd_device * dev, u8 fn, u32 reg, u8 dat)
+{
+ GET_IF_SEMA();
+ if (SDHost_CMD52_Write((PSD_DEVICE_DATA) dev->sd_bus, reg, fn, dat)) {
+// printk("%s: dev=%p fn=%d reg=0x%8.08X dat=0x%2.02x\n",__FUNCTION__,dev,fn,reg,dat);
+ REL_IF_SEMA();
+ return 0;
+ } else {
+ printk("%s: dev=%p fn=%d reg=0x%8.08X FAILED!\n", __FUNCTION__, dev, fn,
+ reg);
+ REL_IF_SEMA();
+ return -1;
+ }
+}
+
+/**
+ * @brief Read multiple bytes from SDIO device
+ * @param dev bus driver's device structure
+ * @param fn function number 0..7
+ * @param address offset
+ * @param blkmode block or byte mode
+ * @param opcode fixed or auto-inc address
+ * @param blkcnt number of bytes or blocks (depends on blkmode)
+ * @param blksz size of block
+ * @param buffer pointer to data buffer
+ * @return 0 : Success -1: Failed
+*/
+int
+sdio_read_iomem(sd_device * dev, u8 fn, u32 address, u8 blkmode, u8 opcode,
+ u32 blkcnt, u32 blksz, u8 * buffer)
+{
+// printk("%s: dev=%p fn=%d address=0x%8.08X blockcnt=%d blocksize=%d\n",__FUNCTION__,dev,fn,address,blkcnt,blksz);
+
+ GET_IF_SEMA();
+ if (SDHost_CMD53_ReadEx
+ ((PSD_DEVICE_DATA) dev->sd_bus, address, fn, blkmode, opcode, buffer,
+ blkcnt, blksz)) {
+ REL_IF_SEMA();
+ return 0;
+ } else {
+ printk("%s: dev=%p fn=%d FAILED!\n", __FUNCTION__, dev, fn);
+ REL_IF_SEMA();
+ return -1;
+ }
+}
+
+/**
+ * @brief Write multiple bytes to SDIO device
+ * @param dev bus driver's device structure
+ * @param fn function number 0..7
+ * @param address offset
+ * @param blkmode block or byte mode
+ * @param opcode fixed or auto-inc address
+ * @param blkcnt number of bytes or blocks (depends on blkmode)
+ * @param blksz size of block
+ * @param buffer pointer to data buffer
+ * @return 0 : Success -1: Failed
+*/
+int
+sdio_write_iomem(sd_device * dev, u8 fn, u32 address, u8 blkmode, u8 opcode,
+ u32 blkcnt, u32 blksz, u8 * buffer)
+{
+// printk("%s: dev=%p fn=%d address=0x%8.08X blockcnt=%d blocksize=%d\n",__FUNCTION__,dev,fn,address,blkcnt,blksz);
+ GET_IF_SEMA();
+ if (SDHost_CMD53_WriteEx
+ ((PSD_DEVICE_DATA) dev->sd_bus, address, fn, blkmode, opcode, buffer,
+ blkcnt, blksz)) {
+ REL_IF_SEMA();
+ return 0;
+ } else {
+ printk("%s: dev=%p fn=%d FAILED!\n", __FUNCTION__, dev, fn);
+ REL_IF_SEMA();
+ return -1;
+ }
+}
+
+// for filling the "/proc/mrvsdio" entry
+int
+mrvlsdio_read_procmem(char *buf,
+ char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ PSD_DEVICE_DATA pDevTmp;
+ int len = 0;
+
+ if (!list_empty(&sd_dev_list)) {
+ pDevTmp = (PSD_DEVICE_DATA) sd_dev_list.next;
+
+ // after probe-event, we have "good" data in /proc/mrvsdio
+ len =
+ sprintf(buf,
+ "mrvlsdio is running with:\nbus_type = 0x%x\nbus_with = 0x%x\nclock_speed = 0x%x\ndebug_flags = 0x%x\nsdio_voltage = 0x%x\n",
+ pDevTmp->bus_type, pDevTmp->bus_width, pDevTmp->ClockSpeed,
+ pDevTmp->debug_flags, pDevTmp->sdio_voltage);
+ } else {
+ // not probed yet
+ len = sprintf(buf, "mrvlsdio is up and waiting for card\n");
+ }
+
+ *eof = 1;
+ return (len);
+}
+
+static void
+call_client_probe(PSD_DEVICE_DATA pDev, int fn)
+{
+
+ if (down_interruptible(&sd_client_sema))
+ return;
+ if (pDev->sd_dev[fn].drv->probe != NULL) {
+ pDev->sd_dev[fn].drv->probe(&pDev->sd_dev[fn], &pDev->sd_ids[fn]);
+ }
+ up(&sd_client_sema);
+}
+
+static int
+mrvlsdio_init_module(void)
+{
+ int ret;
+
+ ENTER();
+
+ // generate /proc/ entry
+ create_proc_read_entry("mrvlsdio", // entry in "/proc/mrvlsdio"
+ 0, // file attributes
+ NULL, // parent dir
+ mrvlsdio_read_procmem, // name of function
+ NULL); // client data
+
+ DBGPRINT(DBG_ALL, ("*** mrvlsdio ***\n"));
+ DBGPRINT(DBG_ALL, ("*** multifunction API ***\n"));
+ DBGPRINT(DBG_ALL, ("*** Built on %s %s ***\n", __DATE__, __TIME__));
+
+ /*--- mmoser 6/21/2007 ---*/
+ INIT_LIST_HEAD(&sd_dev_list);
+ spin_lock_init(&sd_dev_list_lock);
+
+ INIT_LIST_HEAD(&sd_client_list);
+ spin_lock_init(&sd_client_list_lock);
+
+ ret = register_chrdev(sdio_major, "mrvlsdio", &mrvlsdio_fops);
+ if (ret < 0) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_WARNING "mrvlsdio: can't get major %d ret=%d\n",
+ sdio_major, ret));
+ } else {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "mrvlsdio: major %d\n", ret));
+ }
+ if (sdio_major == 0)
+ sdio_major = ret; /* dynamic */
+
+ /** from 2.4 kernel source:
+ * pci_register_driver - register a new pci driver
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration. The driver remains registered even if the
+ * return value is zero.
+ */
+
+ ret = pci_register_driver(&mrvlsdio);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: pci_register_driver with %d\n", __FILE__, ret));
+
+ LEAVE();
+// return (ret);
+ return 0;
+}
+
+static void
+mrvlsdio_exit_module(void)
+{
+ PSD_DEVICE_DATA pTmpDev;
+ PSD_CLIENT pTmpClient;
+
+ // remove proc entry
+ remove_proc_entry("mrvlsdio", NULL);
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Module mrvlsdio exit\n"));
+
+ unregister_chrdev(sdio_major, "mrvlsdio");
+ pci_unregister_driver(&mrvlsdio);
+
+ // Clean up device list
+
+ while (!list_empty(&sd_dev_list)) {
+ pTmpDev = (PSD_DEVICE_DATA) sd_dev_list.next;
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s@%d: pTmpDev=%p\n", __FUNCTION__, __LINE__,
+ pTmpDev));
+ list_del((struct list_head *) pTmpDev);
+ kfree(pTmpDev);
+
+#ifdef SDIO_MEM_TRACE
+ printk("<<< kfree(SD_DEVICE_DATA)\n");
+#endif
+
+ }
+
+ // Clean up client list
+ while (!list_empty(&sd_client_list)) {
+ pTmpClient = (PSD_CLIENT) sd_client_list.next;
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s@%d: pTmpClient=%p\n", __FUNCTION__, __LINE__,
+ pTmpClient));
+ list_del((struct list_head *) pTmpClient);
+ kfree(pTmpClient);
+#ifdef SDIO_MEM_TRACE
+ printk("<<< kfree(SD_CLIENT)\n");
+#endif
+
+ }
+}
+
+module_init(mrvlsdio_init_module);
+module_exit(mrvlsdio_exit_module);
+
+EXPORT_SYMBOL(sd_driver_register);
+EXPORT_SYMBOL(sd_driver_unregister);
+EXPORT_SYMBOL(sd_request_int);
+EXPORT_SYMBOL(sd_release_int);
+EXPORT_SYMBOL(sd_unmask);
+EXPORT_SYMBOL(sd_enable_int);
+EXPORT_SYMBOL(sd_disable_int);
+EXPORT_SYMBOL(sd_set_buswidth);
+EXPORT_SYMBOL(sd_set_busclock);
+EXPORT_SYMBOL(sd_start_clock);
+EXPORT_SYMBOL(sd_stop_clock);
+EXPORT_SYMBOL(sd_set_gpo);
+EXPORT_SYMBOL(sdio_read_ioreg);
+EXPORT_SYMBOL(sdio_write_ioreg);
+EXPORT_SYMBOL(sdio_read_iomem);
+EXPORT_SYMBOL(sdio_write_iomem);
+
+MODULE_DESCRIPTION("Marvell SDIO Bus Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/io/sdio/syskt/skisr.c b/io/sdio/syskt/skisr.c
new file mode 100644
index 0000000..934720a
--- /dev/null
+++ b/io/sdio/syskt/skisr.c
@@ -0,0 +1,290 @@
+/**
+ *
+ * Name: skisr.c
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:21:35 $
+ * Purpose: This module handles the interrupts.
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: skisr.c,v $
+ * Revision 1.1 2007/01/18 09:21:35 pweber
+ * Put under CVS control
+ *
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+static void (*gpio_int_callback) (void *) = NULL;
+static void *gpio_int_callback_arg = NULL;
+
+int
+request_gpio_irq_callback(void (*callback) (void *), void *arg)
+{
+ if (!gpio_int_callback && !gpio_int_callback_arg) {
+ gpio_int_callback = callback;
+ gpio_int_callback_arg = arg;
+ return 0;
+ }
+ return -1;
+}
+
+EXPORT_SYMBOL(request_gpio_irq_callback);
+
+int
+release_gpio_irq_callback(void (*callback) (void *), void *arg)
+{
+ if ((callback == gpio_int_callback)
+ && (arg == gpio_int_callback_arg)) {
+ gpio_int_callback = NULL;
+ gpio_int_callback_arg = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+EXPORT_SYMBOL(release_gpio_irq_callback);
+
+DECLARE_TASKLET(SDIOBus_tasklet, SDIOBus_Dpc, 0);
+
+void
+SDIOBus_Dpc(unsigned long arg)
+{
+ SK_U32 irq_status, status;
+ SK_U16 errorIRQ_status = 0;
+ PSD_DEVICE_DATA pDev;
+
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "SDIOBUS_Dpc startet ....\n"));
+
+ if (arg == 0) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "SDIOBUS_Dpc : arg == NULL !\n"));
+ return;
+ }
+
+ pDev = (PSD_DEVICE_DATA) arg;
+
+ if (pDev == NULL) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "SDIOBUS_Dpc : pDev == NULL !\n"));
+ return;
+ }
+
+ irq_status = pDev->lastIntStatus;
+
+ if ((irq_status & STDHOST_NORMAL_IRQ_ERROR) != 0) {
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS,
+ &errorIRQ_status);
+ if ((errorIRQ_status & STDHOST_ERROR_IRQ_GPI_0) != 0) {
+ if ((pDev->lastErrorIRQSignalMask & STDHOST_ERROR_IRQ_GPI_0) != 0) {
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS,
+ STDHOST_ERROR_IRQ_GPI_0);
+ // Fake a SDIO card interrupt
+ irq_status |= STDHOST_NORMAL_IRQ_CARD;
+ }
+ }
+ if ((errorIRQ_status & STDHOST_ERROR_IRQ_GPI_1) != 0) {
+ if ((pDev->lastErrorIRQSignalMask & STDHOST_ERROR_IRQ_GPI_1) != 0) {
+ printk("GPI-1 interrupt fired (0x%4.04X)\n", errorIRQ_status);
+ /*--- mmoser 3/12/2007 ---*/
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS,
+ STDHOST_ERROR_IRQ_GPI_1);
+
+ SDHost_SetClock(pDev, 1);
+ if (gpio_int_callback && gpio_int_callback_arg)
+ gpio_int_callback(gpio_int_callback_arg);
+ }
+ }
+ }
+
+ if ((irq_status & STDHOST_NORMAL_IRQ_CARD_OUT) ==
+ STDHOST_NORMAL_IRQ_CARD_OUT) {
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_CARD_OUT);
+
+ /*--- mmoser 14.09.2005 ---*/
+ if (pDev->initialized) {
+ DBGPRINT(DBG_IRQ | DBG_W528D,
+ (KERN_DEBUG "SDIOBUS_Dpc : NORMAL_IRQ_CARD_OUT\n"));
+
+ /*--- mmoser 10.08.2005 ---*/
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "CARD REMOVED\n"));
+ SDIOBus_CardRemoved(pDev);
+
+ /*--- mmoser 3/31/2006 ---*/
+ pDev->SurpriseRemoved = SK_TRUE;
+ }
+ SDHost_EnableInterrupt(pDev, pDev->lastIRQSignalMask);
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Dpc finished.(line=%d)\n", __LINE__));
+ return;
+ }
+ if ((irq_status & STDHOST_NORMAL_IRQ_CARD_IN) == STDHOST_NORMAL_IRQ_CARD_IN) {
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_CARD_IN);
+
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "SDIOBUS_Dpc : NORMAL_IRQ_CARD_IN\n"));
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "CARD PLUGGED IN\n"));
+ SDIOBus_CardPluggedIn(pDev);
+ SDHost_EnableInterrupt(pDev, pDev->lastIRQSignalMask);
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Dpc finished.(line=%d)\n", __LINE__));
+ return;
+ }
+
+ if ((irq_status & STDHOST_NORMAL_IRQ_CARD) == STDHOST_NORMAL_IRQ_CARD) {
+ status = (irq_status << 16);
+ if (pDev->number_of_functions > 1) {
+ queue_work(pDev->workqueue, &pDev->irq_work);
+ } else {
+ if (pDev->irq_device_cache[1]->functions[1].int_handler != NULL) {
+ pDev->irq_device_cache[1]->functions[1].int_handler(pDev->
+ irq_device_cache
+ [1],
+ pDev->
+ irq_device_cache
+ [1]->
+ pCurrent_Ids,
+ pDev->
+ irq_device_cache
+ [1]->
+ functions
+ [1].
+ context);
+ } else {
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "No interrupt handler registered.\n"));
+ SDHost_EnableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "SDIOBUS_Dpc finished.\n"));
+ return;
+ }
+ }
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Dpc finished.(line=%d)\n", __LINE__));
+ return;
+ }
+
+ if (irq_status & (STDHOST_NORMAL_IRQ_ERROR |
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE |
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE)) {
+ if (((irq_status & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) &&
+ (pDev->lastIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE)) ||
+ ((irq_status & STDHOST_NORMAL_IRQ_CMD_COMPLETE) &&
+ (pDev->lastIRQSignalMask & STDHOST_NORMAL_IRQ_CMD_COMPLETE)) ||
+ ((errorIRQ_status & STDHOST_ERROR_IRQ_GPI_1) &&
+ (pDev->lastErrorIRQSignalMask & STDHOST_ERROR_IRQ_GPI_1))
+
+ )
+ {
+ SDHost_EnableInterrupt(pDev, pDev->lastIRQSignalMask);
+ }
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Dpc finished.(line=%d)\n", __LINE__));
+ return;
+ } else {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "SDIOBus_Dpc(): Unhandled IRQ : 0x%8.08X.\n",
+ irq_status));
+ }
+
+ SDHost_EnableInterrupt(pDev, pDev->lastIRQSignalMask);
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Dpc finished.(line=%d)\n", __LINE__));
+}
+
+irqreturn_t
+SDIOBus_Isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ SK_U32 tmp;
+ SK_U16 tmpsig;
+ PSD_DEVICE_DATA pDev;
+
+ if (dev_id == NULL) {
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "SDIOBUS_Isr : dev_id == NULL !\n"));
+ return IRQ_HANDLED;
+ }
+
+ pDev = (PSD_DEVICE_DATA) dev_id;
+
+ if (pDev == NULL) {
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "SDIOBUS_Isr : pDev == NULL !\n"));
+ return IRQ_HANDLED;
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &tmp);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, &tmpsig);
+
+ // Check if interrupt came from our device
+ if (((((tmp & STDHOST_NORMAL_IRQ_ERROR) != 0) &&
+ ((tmpsig & (STDHOST_ERROR_IRQ_GPI_1 | STDHOST_ERROR_IRQ_GPI_0)) != 0))
+ || ((tmp & pDev->currentIRQSignalMask) != 0)) && tmp != 0xFFFFFFFF)
+ {
+ /*--- mmoser 8/29/2006 ---*/
+ if (tmp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE);
+
+ if (!test_and_set_bit(0, &pDev->trans_complete_evt.event)) {
+ wake_up(&pDev->trans_complete_evt.wq);
+ }
+ }
+ }
+
+ if (tmp & STDHOST_NORMAL_IRQ_CMD_COMPLETE) {
+ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_CMD_COMPLETE) {
+ // clear irq bit
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE);
+
+ if (!test_and_set_bit(0, &pDev->cmd_complete_evt.event)) {
+ wake_up(&pDev->cmd_complete_evt.wq);
+ }
+ }
+ }
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ &pDev->lastErrorIRQSignalMask);
+ pDev->lastIntStatus = tmp;
+ DBGPRINT(DBG_IRQ,
+ (KERN_DEBUG "SDIOBUS_Isr (0x%4.04X)\n", pDev->lastIntStatus));
+ SDHost_DisableInterrupt(pDev, STDHOST_NORMAL_IRQ_ALL_SIG_ENA);
+
+ SDIOBus_tasklet.data = (unsigned long) pDev;
+ tasklet_schedule(&SDIOBus_tasklet);
+
+ } else {
+ if (tmp == 0xFFFFFF)
+ pDev->SurpriseRemoved = SK_TRUE;
+ return IRQ_NONE;
+ }
+ return IRQ_HANDLED;
+
+}
diff --git a/io/sdio/syskt/stdhost.c b/io/sdio/syskt/stdhost.c
new file mode 100644
index 0000000..cd79884
--- /dev/null
+++ b/io/sdio/syskt/stdhost.c
@@ -0,0 +1,3974 @@
+/**
+ *
+ * Name: stdhost.c
+ * Project: Wireless LAN, Bus driver for SDIO interface
+ * Version: $Revision: 1.1 $
+ * Date: $Date: 2007/01/18 09:21:35 $
+ * Purpose: This module handles the SDIO Standard Host Interface.
+ *
+ * Copyright (C) 2003-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************************************
+ *
+ * History:
+ *
+ * $Log: stdhost.c,v $
+ * Revision 1.1 2007/01/18 09:21:35 pweber
+ * Put under CVS control
+ *
+ * Revision 1.4 2005/12/08 12:00:27 ebauer
+ * Driver ckecks AND update voltage registry value if not correct
+ *
+ * Revision 1.3 2005/12/07 13:40:19 ebauer
+ * Modify check of registry voltage value
+ *
+ * Revision 1.2 2005/10/31 10:34:59 jschmalz
+ * Bugfixes Chariot (Interface hang)
+ *
+ * Revision 1.1 2005/10/07 08:43:47 jschmalz
+ * Put SDIO with FPGA under CVS control
+ *
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+//define the SD Block Size
+//for SD8381-B0 chip, it could be 32,64,128,256,512
+//for all other chips including SD8381-A0, it must be 32
+#define POLLING_TIMES 2000
+
+#define USE_FPGA_POWER_RAMP
+// #define DMA_SUPPORT_RD
+// #define DMA_SUPPORT_WR
+// #define FIFO_CMD52_DEBUG
+
+SK_U8 ena_func[8] = { 0, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x7E, 0xFE };
+
+SK_BOOL SDHost_DumpCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number,
+ SK_U32 length);
+
+extern int block_size, dma_support;
+
+/******************************************************************************
+ *
+ * SDHost_InitializeCard - Initialize the plugged in SDIO card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * TRUE on success
+ */
+SK_BOOL
+SDHost_InitializeCard(PSD_DEVICE_DATA pDev)
+{
+ SK_U8 OCR[3];
+ SK_U8 RCA[2];
+ SK_U8 Cis[DEVICE_NAME_LENGTH];
+ SK_U16 usVal, ucPowerCurr[FPGA_POWER_STEPS] = FPGA_POWER_VAL_ENUM;
+ SK_U8 ucValue;
+ SK_U8 ucConfigId;
+ SK_U8 ucPowerValue = 0;
+ SK_U8 R;
+ SK_U32 ulArg;
+ SK_U32 j, i, ulValue, ulResponse, cnt;
+ SK_U32 cislength;
+ SK_U32 RegVal;
+ SK_U32 u32Val;
+
+ SDHost_DisableInterrupt(pDev, STDHOST_NORMAL_IRQ_ALL_SIG_ENA);
+
+ _SLEEP_MS(pDev, 100);
+
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "SDHost_InitializeCard()\n"));
+ /*--- mmoser 3/7/2006 ---*/
+ cnt = 0;
+
+ pDev->crc_len = 0;
+
+ ZERO_MEMORY(OCR, 3);
+ ZERO_MEMORY(RCA, 2);
+ ZERO_MEMORY(Cis, DEVICE_NAME_LENGTH);
+
+ // Setup the SD clock
+ if (pDev->baseClockFreq == 0) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "Base clock frequency not available!\n"));
+ return SK_FALSE;
+ }
+ if (pDev->ClockSpeed != 0) {
+ usVal = MK_CLOCK((SK_U16) pDev->ClockSpeed) | STDHOST_INTERNAL_CLK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ } else {
+ SK_U32 ClockSpeed = 1; // set the clock initially to 25MHz
+ usVal = MK_CLOCK((SK_U16) ClockSpeed) | STDHOST_INTERNAL_CLK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ }
+ /* Set the Rx Clock to Rising Edge */
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, FPGA_CORE_CTRL_REG, &u32Val);
+ u32Val |= FPGA_RAISING_EDGE;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, FPGA_CORE_CTRL_REG, u32Val);
+
+ for (j = 0; j < MAX_WAIT_CLOCK_STABLE; j++) {
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal);
+ if ((usVal & STDHOST_INTERNAL_CLK_STABLE) ==
+ STDHOST_INTERNAL_CLK_STABLE) {
+ break;
+ }
+ }
+ if (j >= MAX_WAIT_CLOCK_STABLE) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "SD clock remains unstable!\n"));
+ return SK_FALSE;
+ }
+ // Enable clock to card
+ usVal |= STDHOST_CLOCK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+
+ // enable DMA support depending on ChipRev
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CHIP_REVISION, &ucValue);
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "ChipRevision: 0x%x\n", ucValue));
+ {
+ SK_U8 hi, lo;
+ lo = ucValue & 0x0F;
+ hi = (ucValue >> 4) & 0x0F;
+ printk("\n****************************************************\n");
+ printk("********* FPGA-ChipRevision: %x.%x (0x%2.02X) *********\n",
+ hi, lo, ucValue);
+ printk("****************************************************\n");
+ }
+
+ pDev->dma_support = 0;
+ if ((ucValue >= FPGA_CHIP_REV_2_0) && dma_support) {
+ if ((pDev->debug_flags & DEBUG_USE_RD_DMA) == DEBUG_USE_RD_DMA)
+ pDev->dma_support |= DMA_RD_SUPPORT;
+
+ if ((pDev->debug_flags & DEBUG_USE_WR_DMA) == DEBUG_USE_WR_DMA)
+ pDev->dma_support |= DMA_WR_SUPPORT;
+
+ // pDev->dma_support = DMA_WR_SUPPORT | DMA_RD_SUPPORT;
+ // pDev->dma_support = DMA_RD_SUPPORT;
+ // pDev->dma_support = 0;
+ } else {
+ pDev->dma_support = 0;
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "***************************************************\n"));
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "* CardBus-to-SDIO Adapter FPGA Rev: V0x%x *\n",
+ ucValue));
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "* This FPGA revision does NOT support DMA mode, *\n"));
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "* please update your adapter to Rev 20 or higher *\n"));
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "***************************************************\n"));
+ }
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "DMA_SUPPORT: 0x%x\n", pDev->dma_support));
+ printk
+ ("**************++ DMA_SUPPORT: 0x%x debug_flags=0x%8.08X ++************************\n",
+ pDev->dma_support, pDev->debug_flags);
+ // pweber / tschrobenhauser 03.08.2005
+ // check the power regulator output voltage is stable
+ // WAIT UNTIL ADDR 0x20E, Bit 0 == 1
+
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CARD_REVISION, &ucValue);
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "CardRevision: 0x%x\n", ucValue));
+ if (ucValue == FPGA_CARD_REV_1_1) {
+// SK_U8 ucConfigId;
+// SK_U8 ucPowerValue=0;
+ // LINUX: get voltage value from module parameter 'sdio_voltage'
+ RegVal = pDev->sdio_voltage;
+
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CONFIG_ID, &ucConfigId);
+ if (ucConfigId & FPGA_CONFIG_3_3_V) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 3.3V\n"));
+ // Check if registry value is ok
+ if ((RegVal >= FPGA_POWER_REG_3_3_V_MIN) &&
+ (RegVal <= FPGA_POWER_REG_3_3_V_MAX)) {
+ ucPowerValue = (SK_U8) RegVal;
+ } else {
+ ucPowerValue = FPGA_POWER_REG_3_3_V;
+ }
+ } else if (ucConfigId & FPGA_CONFIG_2_5_V) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 2.5V\n"));
+ // Check if registry value is ok
+ if ((RegVal >= FPGA_POWER_REG_2_5_V_MIN) &&
+ (RegVal <= FPGA_POWER_REG_2_5_V_MAX)) {
+ ucPowerValue = (SK_U8) RegVal;
+ } else {
+ ucPowerValue = FPGA_POWER_REG_2_5_V;
+ }
+ } else if (ucConfigId & FPGA_CONFIG_1_8_V) {
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 1.8V\n"));
+ // Check if registry value is ok
+ if ((RegVal >= FPGA_POWER_REG_1_8_V_MIN) &&
+ (RegVal <= FPGA_POWER_REG_1_8_V_MAX)) {
+ ucPowerValue = (SK_U8) RegVal;
+ } else {
+ ucPowerValue = FPGA_POWER_REG_1_8_V;
+ }
+ }
+ }
+#ifndef USE_FPGA_POWER_RAMP // [fhm] ramp-up SDIO port voltage
+
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_DATA, ucPowerValue);
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_CMD,
+ FPGA_POWER_REG_CMD_START);
+
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "wait for stable voltage\n"));
+ cnt = 0;
+ do {
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_STATUS, &ucValue);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "PowerRegulatorControl: 0x%x\n", ucValue));
+ } while (++cnt < 10000 && (ucValue & FPGA_POWER_REG_STABLE) == 0);
+ DBGPRINT(DBG_ERROR, ("wait for stable voltage: cnt=%d\n", cnt));
+
+ // Turn on highest supplied voltage
+ ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage);
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue);
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "MaxSupplyVoltage: %d\n", pDev->maxSupplyVoltage));
+
+ ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage) | STDHOST_POWER_ON;
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue);
+
+#else
+ _SLEEP_MS(pDev, 100); // [mb] for de-bounce
+ for (i = 0; i < FPGA_POWER_STEPS; i++) {
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_DATA,
+ (SK_U8) ucPowerCurr[i]);
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_CMD,
+ FPGA_POWER_REG_CMD_START);
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "wait for stable voltage (0x%x)\n",
+ ucPowerCurr[i]));
+ cnt = 0;
+ do {
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_STATUS, &ucValue);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "PowerRegulatorControl: 0x%x\n", ucValue));
+ } while (++cnt < 10000 && (ucValue & FPGA_POWER_REG_STABLE) == 0);
+ DBGPRINT(DBG_ERROR, ("wait for stable voltage: cnt=%d\n", cnt));
+ if (cnt == 10000)
+ return SK_FALSE;
+
+ // switch on SDIO port voltage if lowest voltage is stable
+ if (ucPowerCurr[i] == FPGA_POWER_REG_0_7_V) {
+ ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage);
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue);
+ ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage) | STDHOST_POWER_ON;
+//[mb]
+ _SLEEP_MS(pDev, 50); // wait until voltage has reached the
+ // set level
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue);
+ }
+ // leave for loop, if desired power level has been set
+ if (ucPowerCurr[i] == (SK_U16) ucPowerValue)
+ break;
+//[mb]
+ if ((ucPowerCurr[i] < FPGA_POWER_REG_1_2_V) &&
+ (ucPowerCurr[i] > FPGA_POWER_REG_1_0_V))
+ udelay(FPGA_POWER_RAMP_DELAY * 6);
+ else
+ udelay(FPGA_POWER_RAMP_DELAY);
+ if (i < FPGA_POWER_STEPS - 1) {
+ if (ucPowerCurr[i + 1] > (SK_U16) ucPowerValue)
+ ucPowerCurr[i + 1] = (SK_U16) ucPowerValue;
+ }
+ }
+
+#endif // [fhm]
+
+ _SLEEP_MS(pDev, 100); // pweber 03.08.2005
+
+ if (pDev->bus_type == SDIO_SPI_TYPE) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "--------------> SPI-Mode : Send CMD0\n"));
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x200, &ulValue);
+ ulValue |= 0x00000001;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, 0x200, ulValue);
+
+ SDHost_SendCmd(pDev, 0, 0, 0, &ulResponse); // CMD0 for transit to
+ // SPI mode
+ SDHost_SendCmd(pDev, 59, 0, 0, &ulResponse); // CMD59 turn off CRC
+ }
+// _SLEEP_MS( pDev, 100); pweber 03.08.2005
+
+ if (!SDHost_ReadOCR(pDev, OCR)) {
+ DBGPRINT(DBG_W528D | DBG_ERROR, (KERN_DEBUG "ReadOCR failed!\n"));
+ return SK_FALSE;
+ }
+ // check if our supply voltage is supported
+
+ if ((OCR[0] & 0xE0) == 0) // Support for 3.3 - 3.6 V
+ {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG "Card does not support our supply voltage!\n"));
+ return SK_FALSE;
+ }
+
+ if (!SDHost_WriteOCR(pDev, OCR)) {
+ DBGPRINT(DBG_W528D | DBG_ERROR, (KERN_DEBUG "WriteOCR failed!\n"));
+ return SK_FALSE;
+ }
+
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ // Send CMD3 ident -> standby
+ if (!SDHost_ReadRCA(pDev, RCA)) {
+ return SK_FALSE;
+ }
+
+ if (RCA[0] == 0 && RCA[1] == 0) {
+ // Try to get new RCA
+ if (!SDHost_ReadRCA(pDev, RCA)) {
+ return SK_FALSE;
+ }
+ if (RCA[0] == 0 && RCA[1] == 0) {
+ // Failed to get a valid RCA
+ return SK_FALSE;
+ }
+ }
+ ulArg = RCA[0] << 24 | RCA[1] << 16;
+ // CMD7 to select card and go to transfer state.
+ if (!SDHost_SendCmd(pDev, 7, ulArg, 0, &ulResponse)) {
+ if (++pDev->bus_errors > MAX_BUS_ERRORS) {
+ SDHost_SetCardOutEvent(pDev);
+ }
+ return SK_FALSE;
+ }
+ }
+
+ j = 0;
+ while (j++ < 5) {
+ // IO Enable all supported functions
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "IO Enable all supported functions: 0x%2.02X\n",
+ ena_func[pDev->number_of_functions]));
+ SDHost_CMD52_Write(pDev, IO_ENABLE_REG, 0,
+ ena_func[pDev->number_of_functions]);
+ if (SDHost_CMD52_Read(pDev, IO_ENABLE_REG, 0, &R)) {
+ break;
+ }
+ }
+
+ if (j >= 5) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "FN0 : I/O Enable FAILED!!!!!!!!!!!!\n"));
+ return SK_FALSE;
+ }
+
+ /*--- mmoser 3/22/2006 ---*/
+ j = 0;
+ while (j++ < 5) {
+ // INT Enable function 0
+ if (SDHost_CMD52_Write
+ (pDev, INT_ENABLE_REG, 0,
+ ena_func[pDev->number_of_functions] | IENM)) {
+ SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R);
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "FN0 : INT Enable 0x%2.02X\n", R));
+ break;
+ }
+ }
+
+ if (j >= 5) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "FN0 : INT Enable FAILED!!!!!!!!!!!!\n"));
+ return SK_FALSE;
+ }
+
+ // IO Ready function 1
+ if (SDHost_CMD52_Read(pDev, IO_READY_REG, 0, &R)) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "I/O Ready(R/O) 0x%2.02X\n", R));
+ }
+ // Read Card Capability
+ if (SDHost_CMD52_Read(pDev, CARD_CAPABILITY_REG, 0, &R)) {
+#ifdef DBG
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "Card Capability\n"));
+ if (R & 0x01) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " SDC:CMD52 supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " SDC:CMD52 not supported\n"));
+ }
+ if (R & 0x02) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " SMB:CMD53 supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " SMB:CMD53 not supported\n"));
+ }
+ if (R & 0x04) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " SRW:Read Wait supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " SRW:Read Wait not supported\n"));
+ }
+ if (R & 0x08) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " SBS supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " SBD not supported\n"));
+ }
+ if (R & 0x10) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " S4MI supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " S4MI not supported\n"));
+ }
+ if (R & 0x20) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " E4MI supported(R/W)\n"));
+ } else {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " E4MI not supported(R/W)\n"));
+ }
+ if (R & 0x40) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " LSC supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " LSC not supported\n"));
+ }
+ if (R & 0x80) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " 4BLS supported\n"));
+ } else {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG " 4BLS not supported\n"));
+ }
+#endif
+ }
+ if (SDHost_CMD52_Read(pDev, FUNCTION_SELECT_REG, 0, &R)) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "Card Function Selected for Suspend/Resume(R/W) 0x%2.02X!\n",
+ R));
+ }
+ // Exec Flags
+ if (SDHost_CMD52_Read(pDev, EXEC_FLAGS_REG, 0, &R)) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "Exec Flags(R/O)0x%2.02X\n", R));
+ }
+ // Ready Flags
+ if (SDHost_CMD52_Read(pDev, READY_FLAGS_REG, 0, &R)) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "Ready Flags(R/O)0x%2.02X\n", R));
+ }
+
+ if (pDev->bus_width == SDIO_4_BIT) {
+ SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x82); // 0x80:CD
+ // disable,1
+ // bit;0x82:CD
+ // disable,4
+ // bit
+ } else {
+ SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x80); // 0x80:CD
+ // disable,1
+ // bit;0x82:CD
+ // disable,4
+ // bit
+ }
+
+ SDHost_CMD52_Read(pDev, BUS_INTERFACE_CONTROL_REG, 0, &R);
+
+ switch (R & 0x0F) {
+ case 0x02:
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "4 bit mode,"));
+ break;
+ case 0x00:
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "1 bit mode,"));
+ break;
+ default:
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "1 or 4 bit mode error,"));
+ }
+ if ((R & 0xF0) == 0x80) {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "CD Disable!\n"));
+ } else {
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "CD Enable!\n"));
+ }
+
+ SDHost_Enable_HighSpeedMode(pDev);
+
+ // set function 0-7 block size
+ for (i = 0; i <= pDev->number_of_functions; i++) {
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(i), 0,
+ (SK_U8) (block_size & 0x00ff));
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(i), 0,
+ (SK_U8) (block_size >> 8));
+ pDev->sd_ids[i].blocksize = block_size;
+ }
+
+/*
+ for (i=0;i<8;i++)
+ {
+ SDHost_DumpCIS(pDev, i, 512 );
+ }
+*/
+
+ for (i = 0; i <= pDev->number_of_functions; i++) {
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(i), 0, &R)) {
+ break;
+ }
+ pDev->cisptr[i] = R;
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(i), 0, &R)) {
+ pDev->cisptr[i] = 0;
+ }
+ pDev->cisptr[i] |= (R << 8);
+ }
+
+ cislength = DEVICE_NAME_LENGTH;
+ if (!SDHost_ReadCIS(pDev, 0, CISTPL_VERS_1, Cis, &cislength)) {
+ return SK_FALSE;
+ }
+ if (cislength > 0) {
+ memcpy(pDev->DeviceName, "SDIOBus\\", 8);
+ for (i = 0, j = 8; i < cislength; i++) {
+ pDev->DeviceName[j++] = (Cis[i] == ' ' ? '_' : Cis[i]);
+ }
+ pDev->DeviceName[j++] = 0;
+ pDev->DeviceNameLength = j;
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG " DeviceName (len=%d): %s\n",
+ pDev->DeviceNameLength, pDev->DeviceName));
+ }
+
+ cislength = 4;
+ if (!SDHost_ReadCIS(pDev, 0, CISTPL_MANFID, Cis, &cislength)) {
+ return SK_FALSE;
+ }
+ if (cislength > 0) {
+ unsigned short vendor, device;
+ vendor = *((short *) Cis);
+ device = *((short *) &Cis[2]);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: vendor=0x%4.04X device=0x%4.04X\n",
+ __FUNCTION__, vendor, device));
+ for (i = 0; i <= pDev->number_of_functions; i++) {
+ pDev->sd_ids[i].vendor = vendor;
+ pDev->sd_ids[i].device = device;
+ pDev->sd_ids[i].fn = i;
+ if (i > 0) {
+ if (SDHost_ReadCIS(pDev, i, CISTPL_MANFID, Cis, &cislength)) {
+ if (cislength > 0) {
+ pDev->sd_ids[i].vendor = *((short *) Cis);
+ pDev->sd_ids[i].device = *((short *) &Cis[2]);
+ }
+ }
+ SDHost_CMD52_Read(pDev, FN_CSA_REG(i), 0, &R);
+ pDev->sd_ids[i].class = R;
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "fn%d: class=0x%4.04X vendor=0x%4.04X,device=0x%4.04X\n",
+ i, pDev->sd_ids[i].class, pDev->sd_ids[i].vendor,
+ pDev->sd_ids[i].device));
+ } else {
+ pDev->sd_ids[i].class = 0;
+ }
+ }
+ }
+ // Clear irq status bits
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF);
+
+ /*--- mmoser 08.09.2005 ---*/
+ pDev->initialized = SK_TRUE;
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_Init - Initialize the FPGA SDIO/CardBus interface
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+void
+SDHost_Init(PSD_DEVICE_DATA pDev)
+{
+ SK_U32 ulVal;
+ SK_U8 ucHostCtrl = 0;
+ SK_U16 usVal;
+
+ ENTER();
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "SDHost_Init(pDev=0x%p, IOBase=0x%p)\n", pDev,
+ pDev->IOBase[0]));
+
+ /*--- mmoser 4/4/2006 ---*/
+ pDev->SurpriseRemoved = 0;
+
+ // issue software reset
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, STDHOST_SW_RESET_ALL);
+
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDHost_Init() line=%d\n", __LINE__));
+
+ // Read the Host Controller Version
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_HOST_CONTROLLER_VERSION, &usVal);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG
+ "SD Host Spec Version 0x%2.02X - Vendor Version 0x%2.02x\n",
+ GET_SPEC_VERSION_NR(usVal), GET_VENDOR_VERSION_NR(usVal)));
+
+ if (pDev->bus_type == SDIO_BUS_TYPE && pDev->bus_width == SDIO_4_BIT) {
+ ucHostCtrl |= STDHOST_4_BIT_ENA;
+ }
+ // Read capabilities
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_CAPABILITIES, &ulVal);
+
+ if ((ulVal & STDHOST_CAP_VOLTAGE_1_8) == STDHOST_CAP_VOLTAGE_1_8) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "1.8V supported\n"));
+ pDev->maxSupplyVoltage = STDHOST_VOLTAGE_1_8_V;
+ }
+ if ((ulVal & STDHOST_CAP_VOLTAGE_3_0) == STDHOST_CAP_VOLTAGE_3_0) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "3.0V supported\n"));
+ pDev->maxSupplyVoltage = STDHOST_VOLTAGE_3_0_V;
+ }
+ if ((ulVal & STDHOST_CAP_VOLTAGE_3_3) == STDHOST_CAP_VOLTAGE_3_3) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "3.3V supported\n"));
+ pDev->maxSupplyVoltage = STDHOST_VOLTAGE_3_3_V;
+ }
+ if ((ulVal & STDHOST_CAP_SUSPENSE_RESUME) == STDHOST_CAP_SUSPENSE_RESUME) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Suspense/resume supported\n"));
+ }
+ if ((ulVal & STDHOST_CAP_DMA) == STDHOST_CAP_DMA) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "DMA supported\n"));
+ }
+ if ((ulVal & STDHOST_CAP_HIGH_SPEED) == STDHOST_CAP_HIGH_SPEED) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "High speed supported\n"));
+ ucHostCtrl |= STDHOST_HIGH_SPEED_ENA;
+ }
+ pDev->max_block_size = SD_BLOCK_SIZE;
+ if ((ulVal & STDHOST_CAP_MAX_BLOCK_512) == STDHOST_CAP_MAX_BLOCK_512) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 512\n"));
+ pDev->max_block_size = 512;
+ } else if ((ulVal & STDHOST_CAP_MAX_BLOCK_1024) ==
+ STDHOST_CAP_MAX_BLOCK_1024) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 1024\n"));
+ pDev->max_block_size = 1024;
+ } else if ((ulVal & STDHOST_CAP_MAX_BLOCK_2048) ==
+ STDHOST_CAP_MAX_BLOCK_2048) {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 2048\n"));
+ pDev->max_block_size = 2048;
+ }
+ if (block_size > pDev->max_block_size)
+ block_size = pDev->max_block_size;
+
+ pDev->baseClockFreq = GET_CAP_BASE_CLOCK_FREQ(ulVal);
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "Base clock : %d MHz\n", pDev->baseClockFreq));
+
+ if ((ulVal & STDHOST_CAP_TIMEOUT_CLOCK_UNIT_MHZ) ==
+ STDHOST_CAP_TIMEOUT_CLOCK_UNIT_MHZ) {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "Timeout clock : %d MHz\n",
+ (ulVal & STDHOST_CAP_TIMEOUT_CLOCK_FREQ)));
+ } else {
+ DBGPRINT(DBG_LOAD, (KERN_DEBUG "Timeout clock : %d kHz\n",
+ (ulVal & STDHOST_CAP_TIMEOUT_CLOCK_FREQ)));
+ }
+
+ // Read the max current capabilities
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_MAX_CURRENT_CAP, &ulVal);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "Max. current @1.8V=%dmA @3.0V=%dmA @3.3V=%dmA\n",
+ CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_1_8_V(ulVal)),
+ CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_3_0_V(ulVal)),
+ CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_3_3_V(ulVal))));
+
+ // Setup host control register
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl);
+
+ /*--- mmoser 14.09.2005 ---*/
+ // Reset all pending irq bits
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF);
+
+ // Enable error irq status
+ usVal = 0xFFFF;
+ // usVal = STDHOST_ERROR_IRQ_VENDOR_SIG_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS_ENABLE, usVal);
+
+ /*--- mmoser 1/2/2007 ---*/
+ // Enable GPI interrupts
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ STDHOST_ERROR_IRQ_VENDOR_SIG_ENA);
+
+ // Enable card detect
+ usVal = 0xFFFF;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, usVal);
+ usVal = STDHOST_NORMAL_IRQ_CARD_ALL_ENA;
+ usVal &= ~STDHOST_NORMAL_IRQ_CARD_SIG_ENA; // Don't enable card interrupt
+ // at this point!
+ pDev->lastIRQSignalMask = 0;
+ pDev->currentIRQSignalMask = usVal;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, usVal);
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "SDHost_Init() : present state=0x%8.08X\n", ulVal));
+
+ /*--- mmoser 12.09.2005 ---*/
+ pDev->initialized = SK_TRUE;
+
+ LEAVE();
+
+}
+
+/******************************************************************************
+ *
+ * SDHost_isCardPresent - checks whether a SDIO card is in the SDIO socket
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE card is in socket
+ * SK_FALSE no card in socket
+ *
+ */
+SK_BOOL
+SDHost_isCardPresent(PSD_DEVICE_DATA pDev)
+{
+ SK_U32 ulVal;
+ SK_U16 usVal;
+
+// mmoser 2005-11-21
+ /*--- mmoser 13.09.2005 ---*/
+ if (pDev->SurpriseRemoved) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent: Surprise Removal of Card!\n"));
+ return SK_FALSE;
+ }
+
+ if (pDev->initialized == SK_FALSE) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent(): SD Host Adapter is NOT initialized. (%d)\n",
+ pDev->initialized));
+ return SK_FALSE;
+ }
+ // Read the Host Controller Version to check if SD Host adapter is
+ // available
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_HOST_CONTROLLER_VERSION, &usVal);
+ if (usVal == 0xFFFF) {
+ // There is probably no SD Host Adapter available
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent(): SD Host Adapter is NOT present. (%4.04X)\n",
+ usVal));
+ return SK_FALSE;
+ }
+ // Read present state register to check whether a SD card is present
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ if ((ulVal & STDHOST_STATE_CARD_INSERTED) == 0) {
+ // There is probably no card in the socket
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_isCardPresent(): Card is NOT present. (%8.08X)\n",
+ ulVal));
+ return SK_FALSE;
+ }
+
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_SendCmd - Send a SDIO command to the card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ */
+SK_BOOL
+SDHost_SendCmd(PSD_DEVICE_DATA pDev, SK_U8 cmd, SK_U32 arg, SK_U16 transferMode,
+ SK_U32 * pulResp)
+{
+ SK_U32 retry, max_retry;
+ SK_U32 ulVal;
+ SK_U16 usCmd;
+ SK_U32 ulIrq;
+ SK_U16 usSigEna;
+
+ // max_retry depends on actual bus clock speed
+ max_retry =
+ MAX_WAIT_COMMAND_INHIBIT * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ // Read present state register to check whether Command Inhibit (CMD) = 0
+ for (retry = 0; retry < max_retry; retry++) {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ if (cmd == 53) {
+ if ((ulVal & STDHOST_STATE_CMD_INHIB_DAT) == 0) {
+ break;
+ }
+ } else {
+ if ((ulVal & STDHOST_STATE_CMD_INHIB_CMD) == 0) {
+ break;
+ }
+ }
+ /*--- mmoser 3/7/2006 ---*/
+ if (retry & 0xFFFFFFFE)
+ UDELAY(1);
+ }
+ if (retry >= max_retry) {
+ if (cmd == 53) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_SendCmd() : Command Inhibit DAT remains busy! (max_retry=%d)\n",
+ max_retry));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ UDELAY(10); // wait until reset is complete
+
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, 0);
+ } else {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_SendCmd() : Command Inhibit CMD remains busy! (max_retry=%d)\n",
+ max_retry));
+ // reset the cmd line
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_CMD_LINE);
+ UDELAY(10); // wait until reset is complete
+
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, 0);
+ }
+ return SK_FALSE;
+ }
+ // clear irq bit
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF0000 | // ERROR_IRQ_STATUS
+ STDHOST_NORMAL_IRQ_ERROR |
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE |
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE);
+
+ usCmd = MK_CMD(cmd) | MK_CMD_TYPE(STDHOST_CMD_TYPE_NORMAL);
+
+ switch (cmd) {
+ case 0:
+ {
+ usCmd |= STDHOST_RESP_TYPE_NONE;
+ break;
+ }
+ case 3:
+ {
+ usCmd |= STDHOST_CMD_INDEX_CHK_ENA |
+ STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R6;
+ break;
+ }
+ case 5:
+ {
+ usCmd |= STDHOST_RESP_TYPE_R4;
+ break;
+ }
+ case 7:
+ {
+ usCmd |= STDHOST_CMD_INDEX_CHK_ENA |
+ STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R1b;
+ break;
+ }
+ case 52:
+ case 53:
+ {
+ usCmd |= STDHOST_CMD_INDEX_CHK_ENA |
+ STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R5;
+ break;
+ }
+ case 59:
+ {
+ usCmd |= STDHOST_RESP_TYPE_NONE;
+ break;
+ }
+ default:
+ {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_SendCmd() : Command 0x%2.02X not supported!\n",
+ cmd));
+ return SK_FALSE;
+ }
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal);
+
+ clear_bit(0, &pDev->cmd_complete_evt.event);
+
+ // mmoser 2007-06-08 : Ensure that CMD_COMPLETE signal is enabled
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &usSigEna);
+ usSigEna |= STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ usSigEna);
+
+ pDev->errorOccured = 0;
+
+ // initiate the cmd
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_CMD_ARGUMENT, arg);
+ ulVal = (usCmd << 16) | transferMode;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, ulVal);
+
+#ifdef DBG
+ if ((pDev->debug_flags & DEBUG_SHOW_REG_10_14) == DEBUG_SHOW_REG_10_14) {
+ if (cmd == 53) {
+ for (retry = 0; retry < 10; retry++) {
+ SK_U32 ulR1, ulR2;
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulR1);
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_63_32, &ulR2);
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "retry=%d 63-32 : 0x%8.08X 31-0 : 0x%8.08X\n", retry,
+ ulR2, ulR1));
+ }
+ }
+ }
+#endif
+
+ /**/ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_CMD_COMPLETE) {
+//printk("%s @ %d: Wait CMD complete\n",__FUNCTION__,__LINE__);
+ if (SDHost_wait_event(pDev, &pDev->cmd_complete_evt, 100)) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "%s @ %d: Wait CMD complete ---> FAILED !\n",
+ __FUNCTION__, __LINE__));
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->cmd_complete_evt.event);
+ } else
+ /**/ {
+ max_retry =
+ MAX_WAIT_COMMAND_COMPLETE * 10 * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+ // Wait for end of command
+ for (retry = 0; retry < max_retry; retry++) {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulIrq);
+ if ((ulIrq & STDHOST_NORMAL_IRQ_CMD_COMPLETE) ==
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE) {
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE);
+
+ break;
+ }
+ /*--- mmoser 3/7/2006 ---*/
+ if (retry & 0xFFFFFFFE)
+ UDELAY(1);
+ }
+ if (retry >= max_retry) {
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &usCmd);
+// printk("status_enable=0x%4.04X\n",usCmd);
+ if ((usCmd & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0) {
+ usCmd |= STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0,
+ STDHOST_NORMAL_IRQ_STATUS_ENABLE, usCmd);
+ MEM_READ_USHORT(pDev, SK_SLOT_0,
+ STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usCmd);
+// printk("RESTORED:status_enable=0x%4.04X\n",usCmd);
+ }
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_SendCmd() : Command not completed! (max_retry=%d)\n",
+ max_retry));
+// printk("#");
+ return SK_FALSE;
+ }
+
+ }
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, pulResp);
+
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_SendAbort - Aborts an SDIO CMD53 block transfer
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ */
+SK_BOOL
+SDHost_SendAbort(PSD_DEVICE_DATA pDev)
+{
+
+// return SDHost_CMD52_Write(pDev, IO_ABORT_REG, 0, 0x03);
+
+//#ifdef __XXX__
+ SK_U32 retry, max_retry;
+ SK_U32 ulVal;
+ SK_U32 ulArg;
+ SK_U16 usCmd;
+// SK_U32 ulIrq;
+
+ ulArg = MAKE_SDIO_OFFSET(IO_ABORT_REG) | MAKE_SDIO_FUNCTION(0x00) | 0x07;
+
+ // max_retry depends on actual bus clock speed
+ max_retry =
+ MAX_WAIT_COMMAND_INHIBIT * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ // clear irq bit
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE |
+ STDHOST_NORMAL_IRQ_CMD_COMPLETE);
+
+ /*--- mmoser 3/7/2006 ---*/
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal);
+
+ usCmd = MK_CMD(52) |
+ MK_CMD_TYPE(STDHOST_CMD_TYPE_ABORT) |
+ STDHOST_CMD_INDEX_CHK_ENA |
+ STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R5;
+
+ // initiate the cmd
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_CMD_ARGUMENT, ulArg);
+
+ ulVal = (usCmd << 16) | STDHOST_READ_DIR_SELECT;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, ulVal);
+
+ // Read present state register to check whether Command Inhibit (CMD) = 0
+ for (retry = 0; retry < max_retry; retry++) {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ if (((ulVal & STDHOST_STATE_CMD_INHIB_DAT) == 0) &&
+ ((ulVal & STDHOST_STATE_CMD_INHIB_CMD) == 0)) {
+ break;
+ }
+ UDELAY(1);
+ }
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_SendAbort() : Command Inhibit (CMD/DAT) remains busy! (max_retry=%d)\n",
+ max_retry));
+ return SK_FALSE;
+ }
+
+ return SK_TRUE;
+//#endif
+}
+
+/******************************************************************************
+ *
+ * isCmdFailed - checks whether the FPGA reports an error condition
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+isCmdFailed(PSD_DEVICE_DATA pDev)
+{
+ SK_U16 errStatus;
+
+ // Read error status register
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, &errStatus);
+
+ if ((errStatus & 0x00FF) != 0) {
+ printk("%s: 0x%4.04X: ", __FUNCTION__, errStatus);
+ if (errStatus & STDHOST_ERROR_IRQ_CURRENT_LIMIT) {
+ printk("CURRENT_LIMIT ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_DATA_END_BIT) {
+ printk("DATA_END_BIT ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_DATA_CRC) {
+ printk("DATA_CRC ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_DATA_TIMEOUT) {
+ printk("DATA_TIMEOUT ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_CMD_INDEX) {
+ printk("CMD_INDEX ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_CMD_END_BIT) {
+ printk("CMD_END_BIT ");
+ }
+ if (errStatus & STDHOST_ERROR_IRQ_CMD_CRC) {
+ printk("CMD_CRC ");
+ } else if (errStatus & STDHOST_ERROR_IRQ_CMD_TIMEOUT) {
+ printk("CMD_TIMEOUT ");
+ }
+ printk("\n");
+
+ // Reset the error status irq register
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0x00FF);
+ return SK_TRUE;
+ } else {
+ return SK_FALSE;
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD52_Read - Read one byte from the SDIO card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD52_Read(PSD_DEVICE_DATA pDev, SK_U32 Offset, SK_U8 function_number,
+ SK_U8 * pReturnData)
+{
+ SK_U8 Resp;
+ SK_U32 ulResponse;
+ SK_U8 D8, D16;
+ SK_U32 retry, Arg;
+
+ /*--- mmoser 8/8/2007 ---*/
+ SK_U16 lastIRQMask;
+ SK_U16 lastErrorIRQMask;
+
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ printk
+ ("CMD52 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors);
+ return SK_FALSE;
+ }
+
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &lastIRQMask);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ &lastErrorIRQMask);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD)));
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA)));
+
+#ifdef FIFO_CMD52_DEBUG
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0204, &ulResponse);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "(3)RD Fifo Stat : 0x%x \n", ulResponse));
+
+ if (ulResponse != 0x40010000) {
+ SK_U32 tmp;
+ SK_U16 i;
+ printk("(3)RD Fifo Stat : 0x%x \n", ulResponse);
+ for (i = 0; i < (ulResponse & 0x3ff); i++)
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x20, &tmp);
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0208, &ulResponse);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "(3)WR Fifo Stat : 0x%x \n", ulResponse));
+ if (ulResponse != 0x40000000)
+ printk("(3)WR Fifo Stat : 0x%x \n", ulResponse);
+#endif
+
+ Arg = MAKE_SDIO_OFFSET(Offset) | MAKE_SDIO_FUNCTION(function_number);
+
+ retry = 0;
+ while (1) {
+ if (SDHost_SendCmd(pDev, 52, Arg, STDHOST_READ_DIR_SELECT, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+/*
+ if (++pDev->bus_errors > MAX_BUS_ERRORS )
+ {
+ SDHost_SetCardOutEvent(pDev);
+ }
+*/
+ if (!SDHost_isCardPresent(pDev)) {
+ pDev->SurpriseRemoved = SK_TRUE;
+ SDHost_SetCardOutEvent(pDev);
+ }
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ FAILED : fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors));
+ return SK_FALSE;
+ }
+// mmoser 2006-02-22
+ if (retry > 1) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ FAILED : fn=%2.02X reg=%8.08X (bus_errors=%d) retry=%d\n",
+ function_number, Offset, pDev->bus_errors, retry));
+ }
+
+ UDELAY(200);
+ }
+
+ D16 = GET_BITS_23_16(ulResponse);
+
+ Resp = D16;
+
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ // SDIO bus
+
+ // mask 11001011
+ if (Resp & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ fn=%2.02X reg=%8.08X RESP Error:0x%2.02X (0x%8.08X)\n",
+ function_number, Offset, Resp, ulResponse));
+ UDELAY(100);
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ } else if ((Resp & 0x30) == 0) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ fn=%2.02X reg=%8.08X RESP Error,card not selected!:0x%2.02X (0x%8.08X)\n",
+ function_number, Offset, Resp, ulResponse));
+ UDELAY(100);
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ } else {
+ // SPI bus
+
+ if (Resp & 0x5C) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD52 READ RESP Error:0x%.2X\n", Resp));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ }
+ if (isCmdFailed(pDev)) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+
+ D8 = GET_BITS_15_08(ulResponse);
+ *pReturnData = D8;
+
+ if (pDev->bus_errors > 0) {
+ pDev->bus_errors--;
+ }
+
+ DBGPRINT(DBG_W528D_CMD52,
+ (KERN_DEBUG
+ "CMD52 READ : fn=%2.02X reg=%8.08X data=%2.02X (%2.02X %2.02X/%8.08X)\n",
+ function_number, Offset, *pReturnData, D16, D8, ulResponse));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD52_Write - Write one byte from the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD52_Write(PSD_DEVICE_DATA pDev, SK_U32 Offset, SK_U8 function_number,
+ SK_U8 Data)
+{
+ SK_U8 Resp;
+ SK_U32 ulResponse;
+ SK_U32 Arg, retry;
+ /*--- mmoser 8/8/2007 ---*/
+ SK_U16 lastIRQMask;
+ SK_U16 lastErrorIRQMask;
+
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ printk
+ ("CMD52 WRITE : Surprise Removed !!!! fn=%2.02X reg=%8.08X data=%2.02X (bus_errors=%d)\n",
+ function_number, Offset, Data, pDev->bus_errors);
+ return SK_FALSE;
+ }
+
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &lastIRQMask);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ &lastErrorIRQMask);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD)));
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA)));
+
+ DBGPRINT(DBG_W528D_CMD52,
+ (KERN_DEBUG
+ "CMD52 WRITE : fn=%2.02X reg=%8.08X data=%2.02X (bus_errors=%d)\n",
+ function_number, Offset, Data, pDev->bus_errors));
+
+#ifdef FIFO_CMD52_DEBUG
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0204, &ulResponse);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "(4)RD Fifo Stat : 0x%x \n", ulResponse));
+
+ if (ulResponse != 0x40010000) {
+ SK_U32 tmp;
+ SK_U16 i;
+ printk("(4)RD Fifo Stat : 0x%x \n", ulResponse);
+ for (i = 0; i < (ulResponse & 0x3ff); i++)
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x20, &tmp);
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0208, &ulResponse);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "(4)WR Fifo Stat : 0x%x \n", ulResponse));
+
+ if (ulResponse != 0x40000000)
+ printk("(4)WR Fifo Stat : 0x%x \n", ulResponse);
+#endif
+
+ Arg = MAKE_SDIO_OFFSET(Offset) |
+ MAKE_SDIO_FUNCTION(function_number) | MAKE_SDIO_DIR(1) | (SK_U8) Data;
+ retry = 0;
+ while (1) {
+
+ if (SDHost_SendCmd(pDev, 52, Arg, STDHOST_READ_DIR_SELECT, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+ if (!SDHost_isCardPresent(pDev)) {
+ pDev->SurpriseRemoved = SK_TRUE;
+ SDHost_SetCardOutEvent(pDev);
+ }
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 WRITE FAILED : fn=%2.02X reg=%8.08X data=%2.02X\n",
+ function_number, Offset, Data));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ UDELAY(200);
+ }
+
+ Resp = GET_BITS_23_16(ulResponse);
+
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ // SDIO bus
+
+ // mask 11001011
+ if (Resp & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ fn=%2.02X reg=%8.08X RESP Error:0x%2.02X (0x%8.08X)\n",
+ function_number, Offset, Resp, ulResponse));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ } else if ((Resp & 0x30) == 0) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD52 READ fn=%2.02X reg=%8.08X RESP Error,card not selected!:0x%2.02X (0x%8.08X)\n",
+ function_number, Offset, Resp, ulResponse));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ } else {
+ // SPI bus
+
+ if (Resp & 0x5C) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD52 READ RESP Error:0x%.2X\n", Resp));
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ }
+
+ if (isCmdFailed(pDev)) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_FALSE;
+ }
+ if (pDev->bus_errors > 0) {
+ pDev->bus_errors--;
+ }
+
+ /*--- mmoser 8/8/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_ReadRCA - Read the RCA from SDIO card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_ReadRCA(PSD_DEVICE_DATA pDev, SK_U8 * pRca)
+{
+ SK_U8 ucStatus1, ucStatus2;
+ SK_U32 ulResponse;
+
+ // CMD3 to read card RCA.
+ if (!SDHost_SendCmd(pDev, 3, 0, 0, &ulResponse)) {
+ if (++pDev->bus_errors > MAX_BUS_ERRORS) {
+ SDHost_SetCardOutEvent(pDev);
+ }
+ return SK_FALSE;
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulResponse);
+
+ pRca[0] = GET_BITS_39_32(ulResponse);
+ pRca[1] = GET_BITS_31_24(ulResponse);
+
+ ucStatus1 = GET_BITS_23_16(ulResponse);
+ ucStatus2 = GET_BITS_15_08(ulResponse);
+
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ReadRCA: %2.02X%2.02X - CardStatus=%2.02X%2.02X\n",
+ pRca[0], pRca[1], ucStatus1 &= 0xE0, ucStatus2));
+ return SK_TRUE;
+}
+
+SK_BOOL
+is_ValidCISTuple(SK_U8 cistpl)
+{
+ switch (cistpl) {
+ case CISTPL_VERS_1:
+ case CISTPL_MANFID:
+ case CISTPL_FUNCID:
+ case CISTPL_FUNCE:
+ case CISTPL_END:
+ {
+ return SK_TRUE;
+ }
+ default:
+ {
+ return SK_FALSE;
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_ReadCIS - Read element 'cistpl' from the card's CIS
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_ReadCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number, SK_U8 cistpl,
+ SK_U8 * pBuf, SK_U32 * length)
+{
+ SK_U8 R;
+ SK_U8 tuple;
+ SK_U8 tuple_len;
+ SK_U8 tuple_end = 0;
+ SK_U32 _cis = 0;
+
+ if (pBuf == NULL || length == NULL || *length == 0) {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_ReadCIS : Illegal Parameters pBuf=%p length=%d\n",
+ pBuf, *length));
+ return SK_FALSE;
+ }
+
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis = R;
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis |= (R << 8);
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_2_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis |= (R << 16);
+
+ // Search for CISTPL
+ if (_cis != 0) {
+ SK_U32 i = 0;
+ SK_U32 j = 0;
+
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "SDHost_ReadCIS : CIS=%8.08X\n", _cis));
+
+ R = 0;
+ tuple_len = 0;
+ while (R != CISTPL_END) {
+ // Read Tuple
+ SDHost_CMD52_Read(pDev, _cis + j, function_number, &tuple);
+ j++;
+
+ R = tuple;
+ if (!is_ValidCISTuple(R)) {
+ continue;
+ }
+ // Read Tuple Length
+ SDHost_CMD52_Read(pDev, _cis + j, function_number, &tuple_len);
+ j++;
+ R = tuple;
+
+// printk("cistpl=0x%2.02X tuple=0x%2.02X tuple_length=%d j=%d\n",cistpl,tuple,tuple_len,j);
+ if (R != CISTPL_NULL && R != CISTPL_END) {
+ tuple_end = j + tuple_len;
+ }
+
+ if (tuple == cistpl) {
+ switch (cistpl) {
+ case CISTPL_VERS_1:
+ {
+ j += 2;
+ i = 0;
+
+ while (j < tuple_end && i < *length - 1) {
+ SDHost_CMD52_Read(pDev, _cis + j, function_number,
+ &R);
+ j++;
+// printk("%2.02X ",R);
+ pBuf[i++] = (R == 0 ? ' ' : R);
+ }
+ i -= 3;
+ pBuf[i] = 0;
+ *length = i;
+
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ReadCIS : fn=%d cistpl=%2.02X |%s| len=%d\n",
+ function_number, cistpl, pBuf, *length));
+// printk("\nCISTPL_VERS_1 found!\n");
+ return SK_TRUE;
+ break;
+ }
+ case CISTPL_MANFID:
+ case CISTPL_FUNCID:
+ case CISTPL_FUNCE:
+ {
+ i = 0;
+ DBGPRINT(DBG_W528D,
+ ("SDHost_ReadCIS : fn=%d cistpl=%2.02X |",
+ function_number, cistpl));
+ while (j <= tuple_end && i < *length) {
+ SDHost_CMD52_Read(pDev, _cis + j, function_number,
+ &R);
+ j++;
+ pBuf[i++] = R;
+// printk("%2.02X ",R);
+
+ DBGPRINT(DBG_W528D, ("%2.02x ", R));
+ }
+ *length = i;
+
+ DBGPRINT(DBG_W528D, ("| len=%d\n", *length));
+
+// printk("\ncistpl=0x%2.02X found!\n",cistpl);
+
+ return SK_TRUE;
+
+ break;
+ }
+ }
+ } else {
+ j = tuple_end;
+ }
+ }
+ }
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_ReadCIS : fn=%d cistpl=%2.02X |%s| len=%d\n",
+ function_number, cistpl, pBuf, *length));
+
+ *length = 0;
+ return SK_FALSE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_ReadOCR - Read the OCR (supported voltages) from the SDIO card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_ReadOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr)
+{
+ SK_U32 i, j;
+ SK_U32 ulResponse;
+ SK_U8 ucValue = 0;
+// SK_U8 R1,R2,R3,R4,R5,R6;
+ SK_U8 R2, R3, R4, R5;
+
+ R2 = R3 = R4 = R5 = 0;
+ j = 0;
+ while (j++ < 5) {
+ // Wait until power cycle is complete
+ for (i = 0; i < 100; i++) {
+ if (!SDHost_SendCmd(pDev, 5, 0, 0, &ulResponse)) {
+ if (++pDev->bus_errors > MAX_BUS_ERRORS) {
+ SDHost_SetCardOutEvent(pDev);
+ return SK_FALSE;
+ }
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_ReadOCR() retry=%d\n", j));
+
+ continue;
+ }
+
+ R2 = GET_BITS_15_08(ulResponse);
+ R3 = GET_BITS_23_16(ulResponse);
+ R4 = GET_BITS_31_24(ulResponse);
+ R5 = GET_BITS_39_32(ulResponse);
+
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ReadOCR(31-0) retry=%d : 0x%2.02X %2.02X %2.02X %2.02X\n",
+ j, R5, R4, R3, R2));
+
+ pDev->number_of_functions = (R5 >> 4) & 0x07;
+ ucValue = GET_BITS_39_32(ulResponse);
+
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_ReadOCR(%d) : 0x%2.02X\n",
+ pDev->bus_type, ucValue));
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_ReadOCR() : 0x%8.08X\n", ulResponse));
+
+ if (ucValue & 0x80) {
+ // power cycle is complete
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ReadOCR() : power cycle is complete\n"));
+ break;
+ }
+ }
+ if (i == 100) {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_ReadOCR() FAILED : Power cycle not complete after %d retries (0x%2.02X)!\n",
+ i, ucValue));
+ return SK_FALSE;
+ }
+
+ pOcr[0] = R4;
+ pOcr[1] = R3;
+ pOcr[2] = R2;
+
+ if (R4 != 0 || R3 != 0) {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ReadOCR() : PwrCycle:%X,IO_n:%X,Mem_p:%X,OCR:[0x%2.02X%2.02X%2.02X]\n",
+ ucValue & 0x80, ucValue & 0x70, ucValue & 0x40, pOcr[0],
+ pOcr[1], pOcr[2]));
+
+ return SK_TRUE;
+ }
+ }
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "SDHost_ReadOCR() FAILED : Cannot read OCR!\n"));
+ return SK_FALSE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_WriteOCR - Write the OCR (supported voltages) to the SDIO card
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_WriteOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr)
+{
+ SK_U32 ulArg;
+ SK_U32 ulResponse;
+ SK_U8 ucValue;
+ SK_U32 i;
+
+ ulArg = pOcr[0] << 16 | pOcr[1] << 8 | pOcr[2];
+ // Wait until power cycle is complete
+ for (i = 0; i < 100; i++) {
+ if (!SDHost_SendCmd(pDev, 5, ulArg, 0, &ulResponse)) {
+ if (++pDev->bus_errors > MAX_BUS_ERRORS) {
+ SDHost_SetCardOutEvent(pDev);
+ }
+ return SK_FALSE;
+ }
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulResponse);
+
+ ucValue = GET_BITS_39_32(ulResponse);
+
+ if (ucValue & 0x80) {
+ // power cycle is complete
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "I/O Power up status is ready and set new voltage ok!\n"));
+ break;
+ }
+ }
+ if (i == 100) {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_WriteOCR() FAILED : Power cycle not complete after %d retries!\n",
+ i));
+ return SK_FALSE;
+ }
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_WriteOCR() : PwrCycle:%X,IO_n:%X,Mem_p:%X\n",
+ ucValue & 0x80, ucValue & 0x70, ucValue & 0x40));
+
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Read - Read a block of data from the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_Read(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+ SK_U16 uwTransferMode;
+ SK_U32 size;
+ SK_U32 i, blkCnt, Arg;
+ SK_U32 ulResponse, retry, max_retry;
+ SK_U32 *pSrc32;
+ SK_U32 *pDest32;
+ SK_U8 RESP;
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 READ fn=%2.02X reg=%8.08X data=0x%2.0X\n",
+ function_number, Offset, *(pData)));
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors));
+ return SK_FALSE;
+ }
+
+ if (Count > 0x1FF) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count));
+ return SK_FALSE;
+ }
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count));
+
+ if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block
+ // mode
+ {
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0,
+ (SK_U8) (blksz & 0x00ff));
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0,
+ (SK_U8) (blksz >> 8));
+ pDev->sd_ids[function_number].blocksize = blksz;
+ }
+
+ uwTransferMode = STDHOST_READ_DIR_SELECT;
+
+ if (mode == BYTE_MODE) {
+ size = Count;
+
+ blkCnt = 1 << 16 | Count;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt);
+ } else {
+ size = blksz * Count;
+
+/* 20050630 mmoser HW-Workaround */
+ if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_RD) ==
+ DEBUG_DISABLE_HW_WORKAROUND_RD) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ } else {
+ if (Count > 1) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ }
+ }
+ uwTransferMode |= STDHOST_BLOCK_COUNT_ENA;
+
+ blkCnt = Count << 16 | blksz | DMA_16K_BOUNDARY;
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt);
+ }
+
+ Arg = MAKE_SDIO_OFFSET(Offset) |
+ MAKE_SDIO_OP_CODE(opcode) |
+ MAKE_SDIO_BLOCK_MODE(mode) |
+ MAKE_SDIO_FUNCTION(function_number) | (Count & 0x01FF);
+
+ retry = 0;
+ while (1) {
+ if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 READ FAILED : fn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ return SK_FALSE;
+ }
+ UDELAY(5);
+ }
+
+ RESP = GET_BITS_23_16(ulResponse);
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ if (RESP & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG "CMD53 Read RESP Error:0x%.2X\n", RESP));
+ return SK_FALSE;
+ } else if ((RESP & 0x30) == 0) {
+ DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 Read RESP Error,card not selected!:0x%.2X\n",
+ RESP));
+ return SK_FALSE;
+ }
+ } else {
+ if (RESP & 0x5C) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 READ RESP Error:0x%.2X\n", RESP));
+ return SK_FALSE;
+ }
+ }
+
+ pSrc32 =
+ (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) +
+ (STDHOST_DATA_PORT));
+ pDest32 = (SK_U32 *) pData;
+
+ retry = 0;
+ max_retry =
+ MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ i = 0;
+ while (i < size) {
+ if (i % blksz == 0) {
+ retry = 0;
+
+ do {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE,
+ &ulResponse);
+ if ((ulResponse & STDHOST_STATE_BUFFER_RD_ENABLE) ==
+ STDHOST_STATE_BUFFER_RD_ENABLE) {
+ break;
+ }
+
+ /*--- mmoser 3/13/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+ /*--- mmoser 3/3/2006 ---*/
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 READ FAILED : STDHOST_STATE_BUFFER_RD_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+ return SK_FALSE;
+ }
+ }
+ *pDest32 = *pSrc32;
+ pDest32++;
+ i += 4;
+ }
+
+/*
+ {
+ SK_U16 i;
+
+ printk( KERN_DEBUG "\n%s\n", __FUNCTION__ );
+ for( i=0; i<size; i++ ) {
+ if( i % 16 ==0 )
+ printk( "\n");
+
+ printk( "%2.02X ", pData[i] );
+
+ }
+ }
+*/
+
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+ /*--- mmoser 1/5/2007 ---*/
+// STDHOST_NORMAL_IRQ_ERROR is used for GPI interrupts !!!!
+//
+/*
+ MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal);
+ if (ulVal&STDHOST_NORMAL_IRQ_ERROR)
+ {
+ SDHost_ErrorRecovery(pDev);
+ DBGPRINT(DBG_ERROR,( KERN_DEBUG "SDHost_CMD53_Read() : Command Error 0x%8.08X\n",ulVal));
+ return SK_FALSE;
+ }
+*/
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Read_DMA - Read a block of data from the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_Read_DMA(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+ SK_U16 uwTransferMode;
+ SK_U32 size;
+ SK_U32 blkCnt, Arg;
+ SK_U32 ulResponse, retry, max_retry;
+ SK_U8 RESP;
+ SK_U64 PhysAddr;
+ SK_U32 ulResp;
+
+ /*--- mmoser 1/10/2007 ---*/
+ SK_U16 lastIRQMask;
+ SK_U16 lastErrorIRQMask;
+
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ printk
+ ("CMD53 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors);
+ return SK_FALSE;
+ }
+
+ if (Count > 0x1FF) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count));
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &lastIRQMask);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ &lastErrorIRQMask);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD)));
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA)));
+
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count));
+
+ if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block
+ // mode
+ {
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0,
+ (SK_U8) (blksz & 0x00ff));
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0,
+ (SK_U8) (blksz >> 8));
+ pDev->sd_ids[function_number].blocksize = blksz;
+ }
+
+ uwTransferMode = STDHOST_READ_DIR_SELECT;
+
+ if (mode == BYTE_MODE) {
+ size = Count;
+ blkCnt = 1 << 16 | Count;
+ uwTransferMode |= STDHOST_DMA_ENA;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt);
+ } else {
+ size = blksz * Count;
+
+ /* 20050630 mmoser HW-Workaround */
+ if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_RD) ==
+ DEBUG_DISABLE_HW_WORKAROUND_RD) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ } else {
+ if (Count > 1) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ }
+ }
+
+ uwTransferMode |= STDHOST_BLOCK_COUNT_ENA | STDHOST_DMA_ENA;
+
+ blkCnt = Count << 16 | blksz | DMA_16K_BOUNDARY;
+
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "blkCnt: 0x%x \n", blkCnt));
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt);
+ }
+
+ Arg = MAKE_SDIO_OFFSET(Offset) |
+ MAKE_SDIO_OP_CODE(opcode) |
+ MAKE_SDIO_BLOCK_MODE(mode) |
+ MAKE_SDIO_FUNCTION(function_number) | (Count & 0x01FF);
+
+#ifdef SYSKT_DMA_MALIGN_TEST
+ // set the DMA address
+ PhysAddr = (SK_U64) pci_map_page(pDev->dev,
+ virt_to_page(pDev->dma_rbuff),
+ ((unsigned long) (pDev->
+ dma_rbuff) & ~PAGE_MASK),
+ 8192, PCI_DMA_FROMDEVICE);
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,
+ (SK_U32) (PhysAddr + pDev->dma_start_malign +
+ pDev->dma_rx_malign));
+// MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,&ulResp);
+// printk("dma_abuf:0x%p phys:0x%x rx_malign:%d (read-back=0x%x)\n", pDev->dma_rbuff, (SK_U32)PhysAddr, pDev->dma_rx_malign, ulResp );
+#else // SYSKT_DMA_MALIGN_TEST
+
+ // set the DMA address
+ PhysAddr = (SK_U64) pci_map_page(pDev->dev, virt_to_page(pData),
+ ((unsigned long) pData & ~PAGE_MASK),
+ size, PCI_DMA_FROMDEVICE);
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, (SK_U32) PhysAddr);
+ // printk("\n\nCMD53 READ PhysAddr: 0x%x (virt:0x%x)\n",(SK_U32) PhysAddr,
+ // (SK_U32) pData );
+#endif // SYSKT_DMA_MALIGN_TEST
+
+/*
+ DBGPRINT(DBG_ERROR,( KERN_DEBUG "\n\nCMD53 READ PhysAddr: 0x%x (virt:0x%x)\n",(SK_U32) PhysAddr, (SK_U32) pData ) );
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x0204, &ulResp);
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "(1)RD Fifo Stat : 0x%x \n", ulResp ));
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x0208, &ulResp);
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "(1)WR Fifo Stat : 0x%x \n", ulResp ));
+*/
+ pDev->CmdInProgress = 1;
+ clear_bit(0, &pDev->trans_complete_evt.event);
+
+ retry = 0;
+ while (1) {
+
+ if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+ if (!SDHost_isCardPresent(pDev)) {
+ pDev->SurpriseRemoved = SK_TRUE;
+ SDHost_SetCardOutEvent(pDev);
+ }
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 READ FAILED : fn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ UDELAY(5);
+ }
+
+ RESP = GET_BITS_23_16(ulResponse);
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ if (RESP & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG "CMD53 Read RESP Error:0x%.2X\n", RESP));
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ } else if ((RESP & 0x30) == 0) {
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+
+ DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 Read RESP Error,card not selected!:0x%.2X\n",
+ RESP));
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ } else {
+ if (RESP & 0x5C) {
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 READ RESP Error:0x%.2X\n", RESP));
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ }
+ if (isCmdFailed(pDev)) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+
+ retry = 0;
+ max_retry =
+ MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ // wait for DMA to complete
+ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "%s -> SDHost_wait_event trans_complete failed\n",
+ __FUNCTION__));
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ } else {
+ retry = 0;
+ if (test_bit(0, &pDev->trans_complete_evt.event) == 0) {
+ // if ( SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1 ) ) {
+ do {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ &ulResp);
+ if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) ==
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE);
+ break;
+ }
+ /*--- mmoser 3/14/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+ } else {
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ }
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_WARNING | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 Read : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)\n",
+ Count, max_retry));
+ // reset the data line and FIFO
+ }
+ }
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, 0);
+
+#ifdef SYSKT_DMA_MALIGN_TEST
+ {
+ memcpy(pData,
+ (void *) (pDev->dma_rbuff + pDev->dma_start_malign +
+ pDev->dma_rx_malign), size);
+ // pDev->dma_rx_malign++;
+ pDev->dma_rx_malign %= 64;
+ }
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, PCI_DMA_FROMDEVICE);
+#endif
+
+#ifdef WAR_SEND_ABORT
+// Needed for FPGA workaround
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+#endif // WAR_SEND_ABORT
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+/*
+ {
+ int j;
+ for (j=0; j < 64 && j < size; j++)
+ {
+ printk("%2.02X ",pData[j]);
+ if ((j+1)%16 == 0)
+ {
+ printk("\n");
+ }
+ }
+ printk("\n");
+ }
+*/
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Write - Write a block of data to the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_Write(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+ SK_U16 uwTransferMode;
+ SK_U32 Arg;
+ SK_U32 ulResponse;
+ SK_U32 blk_cnt, cnt;
+ SK_U32 *pSrc32, *pEnd32;
+ SK_U32 *pDest32;
+ SK_U8 RESP;
+ SK_U32 retry, max_retry;
+ SK_U32 i;
+
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE fn=%2.02X reg=%8.08X data=0x%2.0X\n",
+ function_number, Offset, *(pData)));
+
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors));
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+
+ if (Count >= 512) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n",
+ function_number, Offset, Count));
+ return SK_FALSE;
+ }
+
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG
+ "CMD53 WRITE %s MODE : fn=%2.02X reg=%8.08X %s=%d block_size=%d\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset,
+ (mode ? "blocks" : "length"), Count, blksz));
+
+ if ((*(pData + 4) == 0x03) && (Count == 2)) {
+ SK_U32 x;
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "\n**** TRIGGER *****\n"));
+ MEM_READ_ULONG(pDev, SK_SLOT_0, 0x200, &x);
+ x |= ((1 << 24) | (1 << 16));
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, 0x200, x);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "**** pData 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+ *(pData + 0), *(pData + 1), *(pData + 2), *(pData + 3),
+ *(pData + 4), *(pData + 5)));
+ }
+
+ if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block
+ // mode
+ {
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0,
+ (SK_U8) (blksz & 0x00ff));
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0,
+ (SK_U8) (blksz >> 8));
+ pDev->sd_ids[function_number].blocksize = blksz;
+ }
+ uwTransferMode = 0;
+
+ if (mode == BYTE_MODE) {
+ cnt = Count;
+
+ blk_cnt = 1 << 16 | Count;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt);
+ } else {
+ cnt = Count * blksz;
+
+/* 20050630 mmoser HW-Workaround */
+ if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_WR) ==
+ DEBUG_DISABLE_HW_WORKAROUND_WR) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ } else {
+ if (Count > 1) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ }
+ }
+
+ uwTransferMode |= STDHOST_BLOCK_COUNT_ENA;
+
+ blk_cnt = Count << 16 | blksz | DMA_16K_BOUNDARY;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt);
+ }
+
+ pSrc32 = (SK_U32 *) pData;
+ pDest32 =
+ (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) +
+ (STDHOST_DATA_PORT));
+
+ Arg = MAKE_SDIO_OFFSET(Offset) |
+ MAKE_SDIO_OP_CODE(opcode) |
+ MAKE_SDIO_BLOCK_MODE(mode) |
+ MAKE_SDIO_FUNCTION(function_number) |
+ MAKE_SDIO_DIR(1) | (Count & 0x01FF);
+
+ max_retry =
+ MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ pEnd32 = (SK_U32 *) ((SK_U32) pSrc32 + cnt);
+
+// #define PREFILL_FIFO
+
+/*** mmoser 2006-03-03 **/
+#ifdef PREFILL_FIFO
+ // --> The whole message is always written to the FIFO! each FIFO has 2K
+ // Fill the FIFO before issuing the command
+ i = 0;
+ while (i < 2000 && pSrc32 < pEnd32) {
+ if (i % blksz == 0) {
+ retry = 0;
+
+ do {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE,
+ &ulResponse);
+ if ((ulResponse & STDHOST_STATE_BUFFER_WR_ENABLE) ==
+ STDHOST_STATE_BUFFER_WR_ENABLE) {
+ break;
+ }
+
+ /*--- mmoser 3/13/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+
+ /*--- mmoser 3/3/2006 ---*/
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE FAILED : STDHOST_STATE_BUFFER_WR_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ return SK_FALSE;
+ }
+ }
+
+ *pDest32 = *pSrc32;
+ pSrc32++;
+ i += 4;
+ }
+#endif // PREFILL_FIFO
+
+ /*--- mmoser 8/29/2006 ---*/
+ clear_bit(0, &pDev->trans_complete_evt.event);
+
+ retry = 0;
+ while (1) {
+
+ if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE FAILED : fn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ return SK_FALSE;
+ }
+ UDELAY(5);
+ }
+
+ RESP = GET_BITS_23_16(ulResponse);
+
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ if (RESP & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ return SK_FALSE;
+ } else if ((RESP & 0x30) == 0) {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE RESP Error,card not selected!:0x%.2X\n",
+ RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ return SK_FALSE;
+ }
+
+ } else {
+ if (RESP & 0x5C) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ return SK_FALSE;
+ }
+ }
+
+#ifndef PREFILL_FIFO
+ i = 0;
+#endif
+
+ // Fill FIFO with remaining data, if any ...
+ while (pSrc32 < pEnd32) {
+ if (i % blksz == 0) {
+ retry = 0;
+
+ do {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE,
+ &ulResponse);
+ if ((ulResponse & STDHOST_STATE_BUFFER_WR_ENABLE) ==
+ STDHOST_STATE_BUFFER_WR_ENABLE) {
+ break;
+ }
+
+ /*--- mmoser 3/13/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+ /*--- mmoser 3/3/2006 ---*/
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE FAILED : STDHOST_STATE_BUFFER_WR_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+ return SK_FALSE;
+ }
+ }
+
+ *pDest32 = *pSrc32;
+ pSrc32++;
+ i += 4;
+ }
+
+ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) {
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ } else {
+ retry = 0;
+ do {
+ SK_U32 ulResp;
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulResp);
+ if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) ==
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE);
+ break;
+ }
+
+ /*--- mmoser 3/14/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_WARNING,
+ (KERN_DEBUG
+ "CMD53 Write : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)\n",
+ Count, max_retry));
+ // reset the data line and FIFO
+ }
+ }
+
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+
+ /*--- mmoser 1/5/2007 ---*/
+// STDHOST_NORMAL_IRQ_ERROR is used for GPI interrupts !!!!
+/*
+ MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal);
+ if (ulVal&STDHOST_NORMAL_IRQ_ERROR)
+ {
+ SDHost_ErrorRecovery(pDev);
+ DBGPRINT(DBG_ERROR,( KERN_DEBUG "SDHost_CMD53_Write() : Command Error 0x%8.08X\n",ulVal));
+ return SK_FALSE;
+ }
+*/
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Write_DMA - Write a block of data to the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_Write_DMA(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+ SK_U16 uwTransferMode;
+ SK_U32 Arg;
+ SK_U32 ulResponse;
+ SK_U32 blk_cnt, cnt;
+ SK_U32 *pSrc32;
+ SK_U32 *pDest32;
+ SK_U8 RESP;
+ SK_U32 retry, max_retry;
+ SK_U32 ulResp;
+ SK_U64 PhysAddr;
+ /*--- mmoser 1/10/2007 ---*/
+ SK_U16 lastIRQMask;
+ SK_U16 lastErrorIRQMask;
+
+ /*--- mmoser 3/31/2006 ---*/
+ if (pDev->SurpriseRemoved == SK_TRUE) {
+ /*--- mmoser 1/10/2007 ---*/
+ printk
+ ("CMD53 WRITE FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n",
+ function_number, Offset, pDev->bus_errors);
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+
+ if (Count >= 512) {
+ /*--- mmoser 1/10/2007 ---*/
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n",
+ function_number, Offset, Count));
+ return SK_FALSE;
+ }
+
+/*
+ if(( *(pData) == 0x3C) && (Count == 2) ) {
+ SK_U32 x;
+ DBGPRINT(DBG_ERROR,( KERN_DEBUG "\n**** TRIGGER *****\n"));
+ MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &x);
+ x |= ((1 << 24) | (1 << 16));
+ MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, x);
+ DBGPRINT(DBG_ERROR,( KERN_DEBUG "**** pData 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+ *(pData+0),*(pData+1),*(pData+2),*(pData+3), *(pData+4), *(pData+5)));
+ }
+*/
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ &lastIRQMask);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ &lastErrorIRQMask);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD)));
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA)));
+
+ DBGPRINT(DBG_W528D_CMD53,
+ (KERN_DEBUG
+ "CMD53 WRITE %s MODE : fn=%2.02X reg=%8.08X %s=%d block_size=%d\n",
+ (mode ? "BLOCK" : "BYTE"), function_number, Offset,
+ (mode ? "blocks" : "length"), Count, blksz));
+
+ if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block
+ // mode
+ {
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0,
+ (SK_U8) (blksz & 0x00ff));
+ SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0,
+ (SK_U8) (blksz >> 8));
+ pDev->sd_ids[function_number].blocksize = blksz;
+ }
+ uwTransferMode = 0;
+
+ if (mode == BYTE_MODE) {
+ cnt = Count;
+
+ blk_cnt = 1 << 16 | Count;
+ uwTransferMode |= STDHOST_DMA_ENA;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt);
+ } else {
+ cnt = Count * blksz;
+
+/* 20050630 mmoser HW-Workaround */
+ if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_WR) ==
+ DEBUG_DISABLE_HW_WORKAROUND_WR) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ } else {
+ if (Count > 1) {
+ uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT;
+ }
+ }
+
+/*
+ {
+ int j;
+ for (j=0; j < 64 && j < cnt; j++)
+ {
+ printk("%2.02X ",pData[j]);
+ if ((j+1)%16 == 0)
+ {
+ printk("\n");
+ }
+ }
+ printk("\n");
+ }
+*/
+ // enable DMA transfer
+ uwTransferMode |= (STDHOST_BLOCK_COUNT_ENA | STDHOST_DMA_ENA);
+
+ blk_cnt = Count << 16 | blksz | DMA_16K_BOUNDARY;
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt);
+ }
+
+ pSrc32 = (SK_U32 *) pData;
+ pDest32 =
+ (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) +
+ (STDHOST_DATA_PORT));
+
+ Arg = MAKE_SDIO_OFFSET(Offset) |
+ MAKE_SDIO_OP_CODE(opcode) |
+ MAKE_SDIO_BLOCK_MODE(mode) |
+ MAKE_SDIO_FUNCTION(function_number) |
+ MAKE_SDIO_DIR(1) | (Count & 0x01FF);
+
+ max_retry =
+ MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed ==
+ 0 ? 1 : pDev->ClockSpeed);
+
+ // max_retry = MAX_WAIT_COMMAND_COMPLETE * 100 * (pDev->ClockSpeed == 0 ? 1
+ // : pDev->ClockSpeed);
+ /*--- mmoser 8/29/2006 ---*/
+
+#ifdef SYSKT_DMA_MALIGN_TEST
+ // set the DMA address
+ PhysAddr = (SK_U64) pci_map_page(pDev->dev,
+ virt_to_page(pDev->dma_tbuff),
+ ((unsigned long) (pDev->
+ dma_tbuff) & ~PAGE_MASK),
+ 8192, PCI_DMA_FROMDEVICE);
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,
+ (SK_U32) (PhysAddr + pDev->dma_start_malign +
+ pDev->dma_tx_malign));
+
+// MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,&ulResp);
+// printk("dma_abuf:0x%p phys:0x%x tx_malign:%d (read-back=0x%x)\n", pDev->dma_tbuff, (SK_U32)PhysAddr, pDev->dma_tx_malign, ulResp );
+ memcpy((void *) (pDev->dma_tbuff + pDev->dma_start_malign +
+ pDev->dma_tx_malign), pData, cnt);
+//printk("TX org: %2.02X %2.02X %2.02X %2.02X ...\n",pData[0],pData[1],pData[2],pData[3]);
+//pTmp = (SK_U8 *)(pDev->dma_tbuff+pDev->dma_start_malign+pDev->dma_tx_malign);
+//printk("TX cp : %2.02X %2.02X %2.02X %2.02X ...\n",pTmp[0],pTmp[1],pTmp[2],pTmp[3]);
+ pDev->dma_tx_malign++;
+ pDev->dma_tx_malign %= 64;
+
+#else // SYSKT_DMA_MALIGN_TEST
+ // set the DMA address
+ PhysAddr = (SK_U64) pci_map_page(pDev->dev, virt_to_page(pData),
+ ((unsigned long) pData & ~PAGE_MASK),
+ cnt, PCI_DMA_TODEVICE);
+
+ MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, (SK_U32) PhysAddr);
+#endif
+
+ pDev->CmdInProgress = 1;
+ clear_bit(0, &pDev->trans_complete_evt.event);
+
+ retry = 0;
+ while (1) {
+
+ if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) {
+ break;
+ }
+ if (retry++ > 5) {
+ if (!SDHost_isCardPresent(pDev)) {
+ pDev->SurpriseRemoved = SK_TRUE;
+ SDHost_SetCardOutEvent(pDev);
+ }
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE FAILED : fn=%2.02X reg=%8.08X\n",
+ function_number, Offset));
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ UDELAY(5);
+ }
+ RESP = GET_BITS_23_16(ulResponse);
+
+ if (pDev->bus_type == SDIO_BUS_TYPE) {
+ if (RESP & 0xCB) {
+ DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ } else if ((RESP & 0x30) == 0) {
+ DBGPRINT(DBG_W528D | DBG_ERROR,
+ (KERN_DEBUG
+ "CMD53 WRITE RESP Error,card not selected!:0x%.2X\n",
+ RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+
+ } else {
+ if (RESP & 0x5C) {
+ DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR,
+ (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP));
+ // reset the data line and FIFO
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ }
+ if (isCmdFailed(pDev)) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ // wait for DMA to complete
+ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "%s -> SDHost_wait_event trans_complete failed\n",
+ __FUNCTION__));
+ /*--- mmoser 1/10/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192,
+ PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt,
+ PCI_DMA_FROMDEVICE);
+#endif
+ return SK_FALSE;
+ }
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ } else {
+ retry = 0;
+ ulResp = 0;
+ if (test_bit(0, &pDev->trans_complete_evt.event) == 0) {
+ do {
+
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ &ulResp);
+ if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) ==
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ STDHOST_NORMAL_IRQ_TRANS_COMPLETE);
+ break;
+ }
+ /*--- mmoser 3/14/2006 ---*/
+ UDELAY(1);
+ } while (++retry < max_retry);
+
+ } // check event
+ else {
+ clear_bit(0, &pDev->trans_complete_evt.event);
+ printk("%s xxx event instead of polling\n", __FUNCTION__);
+ }
+ if (retry >= max_retry) {
+ DBGPRINT(DBG_WARNING,
+ (KERN_DEBUG
+ "CMD53 Write : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)0x%x\n",
+ Count, max_retry, ulResp));
+ // reset the data line and FIFO
+ }
+ }
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, 0);
+
+#ifdef SYSKT_DMA_MALIGN_TEST
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, PCI_DMA_FROMDEVICE);
+#else
+ pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, PCI_DMA_FROMDEVICE);
+#endif
+
+#ifdef WAR_SEND_ABORT
+// Needed for FPGA workaround
+ if (mode) {
+ SDHost_SendAbort(pDev);
+ }
+#endif // WAR_SEND_ABORT
+
+ /*--- mmoser 1/5/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE,
+ lastIRQMask);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ lastErrorIRQMask);
+ pDev->CmdInProgress = 0;
+
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Read - Read a block of data from the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_ReadEx(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+ SK_BOOL rc;
+
+ if (pDev->dma_support & DMA_RD_SUPPORT) {
+ // printk("SDHost_CMD53_ReadEx (DMA): Count=%d
+ // blksz=%d\n",Count,blksz);
+ rc = SDHost_CMD53_Read_DMA(pDev, Offset, function_number, mode, opcode,
+ pData, Count, blksz);
+ } else {
+ // printk("SDHost_CMD53_ReadEx: Count=%d blksz=%d\n",Count,blksz);
+ rc = SDHost_CMD53_Read(pDev, Offset, function_number, mode, opcode,
+ pData, Count, blksz);
+ }
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * SDHost_CMD53_Write - Write a block of data to the SDIO card
+ * -
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ * SK_TRUE on success
+ *
+ */
+SK_BOOL
+SDHost_CMD53_WriteEx(PSD_DEVICE_DATA pDev,
+ SK_U32 Offset,
+ SK_U8 function_number,
+ SK_U8 mode,
+ SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz)
+{
+
+ if (pDev->dma_support & DMA_WR_SUPPORT) {
+ // printk("SDHost_CMD53_WriteEx (DMA): Count=%d
+ // blksz=%d\n",Count,blksz);
+ return SDHost_CMD53_Write_DMA(pDev, Offset, function_number, mode,
+ opcode, pData, Count, blksz);
+ } else {
+ // printk("SDHost_CMD53_WriteEx: Count=%d blksz=%d\n",Count,blksz);
+ return SDHost_CMD53_Write(pDev, Offset, function_number, mode, opcode,
+ pData, Count, blksz);
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_EnableInterrupt - Enable the interrupts on the FPGA
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_EnableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask)
+{
+// SK_U16 usSigEna;
+ pDev->currentIRQSignalMask |= mask;
+
+/*
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna);
+ if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 )
+ {
+ printk("@%d ####################################################################################################\n",__LINE__);
+ }
+*/
+
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "Enable PCI Interrupt (0x%4.04X)\n",
+ pDev->currentIRQSignalMask));
+
+ /*--- mmoser 1/2/2007 ---*/
+ if (pDev->CmdInProgress == 0) {
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE,
+ STDHOST_ERROR_IRQ_VENDOR_SIG_ENA);
+/*
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna);
+ if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 )
+ {
+ printk("@%d ####################################################################################################\n",__LINE__);
+ }
+*/
+ }
+ // save last irq mask
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ &pDev->lastIRQSignalMask);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ pDev->currentIRQSignalMask);
+/*
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna);
+
+ if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 )
+ {
+ printk("@%d #################################################################################################### (mask=0x%4.04X)\n",__LINE__,pDev->currentIRQSignalMask);
+ }
+*/
+}
+
+/******************************************************************************
+ *
+ * SDHost_DisableInterrupt - Disable the interrupts on the FPGA
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_DisableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask)
+{
+
+/*
+{
+ SK_U16 usSigEna;
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna);
+ if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 )
+ {
+ printk("@%d ####################################################################################################\n",__LINE__);
+ }
+
+}
+*/
+
+ // save current irq mask
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ &pDev->currentIRQSignalMask);
+
+ pDev->lastIRQSignalMask = pDev->currentIRQSignalMask;
+
+ DBGPRINT(DBG_IRQ, (KERN_DEBUG "Disable PCI Interrupt (0x%4.04X)\n",
+ pDev->currentIRQSignalMask & ~mask));
+
+ /*--- mmoser 1/2/2007 ---*/
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, 0);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ pDev->currentIRQSignalMask & ~mask);
+/*
+{
+ SK_U16 usSigEna;
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna);
+ if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 )
+ {
+ printk("@%d #################################################################################################### (mask=0x%4.04X)\n",__LINE__,pDev->currentIRQSignalMask & ~mask);
+ }
+}
+*/
+ pDev->currentIRQSignalMask &= ~mask;
+
+}
+
+/******************************************************************************
+ *
+ * SDHost_if_EnableInterrupt - Exported interface function
+ *
+ * Description:
+ * Exported interface function : Enable only card related interrupts
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_if_EnableInterrupt(PSD_DEVICE_DATA pDev)
+{
+ SDHost_EnableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+}
+
+/******************************************************************************
+ *
+ * SDHost_if_DisableInterrupt - Exported interface function
+ *
+ * Description:
+ * Exported interface function : Disable only card related interrupts
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_if_DisableInterrupt(PSD_DEVICE_DATA pDev)
+{
+ SDHost_DisableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA);
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetCardOutEvent - Set the card out event
+ *
+ * Description:
+ *
+ * Notes: WINDOWS only
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_SetCardOutEvent(PSD_DEVICE_DATA pDev)
+{
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_SetCardOutEvent() ---> CARD REMOVED\n"));
+ if (!pDev->isRemoving) {
+ queue_work(pDev->workqueue, &pDev->card_out_work);
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_lockInterface - Lock the SDIO interface
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+SK_BOOL
+SDHost_lockInterface(PSD_DEVICE_DATA pDev)
+{
+#ifdef SK_SDIO_LOCK_INTERFACE
+ if (INTERLOCKED_INC(&pDev->if_lock) > 1) {
+ INTERLOCKED_DEC(&pDev->if_lock);
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "SDHost_lockInterface() FAILED !!! if_lock=%d\n",
+ pDev->if_lock));
+ return SK_FALSE;
+ }
+#endif
+
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_unlockInterface - unlock the SDIO interface
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_unlockInterface(PSD_DEVICE_DATA pDev)
+{
+#ifdef SK_SDIO_LOCK_INTERFACE
+ if (INTERLOCKED_DEC(&pDev->if_lock) < 0) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_unlockInterface() was already zero !!!! --> ignore.\n",
+ pDev->if_lock));
+ INTERLOCKED_INC(&pDev->if_lock);
+ }
+#endif
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetLed - Set the LED on the FPGA interface
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_SetLed(PSD_DEVICE_DATA pDev, SK_U8 led, SK_U8 on)
+{
+ if (on) {
+ LED_ON(led);
+ } else {
+ LED_OFF(led);
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetClockSpeed - Set the SDIO bus clock speed
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_SetClockSpeed(PSD_DEVICE_DATA pDev, SK_U32 bus_freq)
+{
+ SK_U32 freq = 0;
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: set clock to %d\n", __FUNCTION__,
+ bus_freq == 0 ? 25 : bus_freq));
+
+ if (bus_freq == 50) {
+ freq = 0; /* 50 MHz */
+ } else if (bus_freq == 0 || bus_freq == 25) {
+ freq = 1; /* default: 25 MHz */
+ } else if (bus_freq == 12) {
+ freq = 2; /* 12 MHz */
+ } else if (bus_freq == 6) {
+ freq = 4; /* 6 MHz */
+ } else if (bus_freq == 3) {
+ freq = 8; /* 3 MHz */
+ } else if (bus_freq == 2) {
+ freq = 16; /* 1,5 MHz */
+ } else if (bus_freq == 800) {
+ freq = 32; /* 800 kHz */
+ } else if (bus_freq == 300) {
+ freq = 64; /* 300 kHz */
+ } else if (bus_freq == 200) {
+ freq = 128; /* 200 kHz */
+ } else {
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: illegal clock %d\n", __FUNCTION__, bus_freq));
+ return;
+ }
+ pDev->ClockSpeed = freq;
+
+ if (!pDev->ClockSpeed) {
+ SDHost_Enable_HighSpeedMode(pDev);
+ } else {
+
+ SDHost_Disable_HighSpeedMode(pDev);
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetClock - Set the SDIO bus clock on/off
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_SetClock(PSD_DEVICE_DATA pDev, SK_U8 on)
+{
+ SK_U16 usVal;
+ int j;
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal);
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: turn clock %s\n", __FUNCTION__,
+ (on == 1 ? "ON" : "OFF")));
+
+ if (on) {
+ if (usVal & STDHOST_INTERNAL_CLK_ENA) {
+ if (usVal & STDHOST_INTERNAL_CLK_STABLE) {
+ if (usVal & STDHOST_CLOCK_ENA) {
+ // clock is already stable and running
+ return;
+ } else {
+ // Enable clock to card
+ usVal |= STDHOST_CLOCK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL,
+ usVal);
+ return;
+ }
+ }
+ // there is something fishy with the clock.
+ // -> disable internal clock first
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "%s: SD internal clock is unstable!\n",
+ __FUNCTION__));
+ usVal &= ~STDHOST_INTERNAL_CLK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ }
+
+ usVal |= STDHOST_INTERNAL_CLK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ for (j = 0; j < MAX_WAIT_CLOCK_STABLE; j++) {
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal);
+ if ((usVal & STDHOST_INTERNAL_CLK_STABLE) ==
+ STDHOST_INTERNAL_CLK_STABLE) {
+ break;
+ }
+ }
+ if (j >= MAX_WAIT_CLOCK_STABLE) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "%s: SD clock remains unstable!\n",
+ __FUNCTION__));
+ return;
+ }
+ // Enable clock to card
+ usVal |= STDHOST_CLOCK_ENA;
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ } else {
+ // Disable clock to card
+ usVal &= ~(STDHOST_CLOCK_ENA | STDHOST_INTERNAL_CLK_ENA);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ }
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetBusWidth - Set the SDIO bus width
+ *
+ * Description:
+ *
+ * Notes: see Part_A2_Host_Controller.pdf p.61
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+SK_BOOL
+SDHost_SetBusWidth(PSD_DEVICE_DATA pDev, SK_U8 width)
+{
+ SK_U16 usValue, usOrgValue;
+ SK_U8 ucHostCtrl = 0;
+ SK_U8 orgIntEnable;
+
+ if (pDev->bus_type != SDIO_BUS_TYPE) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG "%s: not possible in current bus mode (%d)\n",
+ __FUNCTION__, pDev->bus_type));
+ return SK_FALSE;
+ }
+
+ DBGPRINT(DBG_LOAD,
+ (KERN_DEBUG "%s: bus width = %d\n", __FUNCTION__, width));
+ // save current irq mask
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ &usOrgValue);
+
+ // disable card interrupt
+ usValue = usOrgValue;
+ usValue &= ~STDHOST_NORMAL_IRQ_CARD_SIG_ENA;
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ usValue);
+
+ // Disable Host Interrupt on card
+ if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &orgIntEnable)) {
+ return SK_FALSE;
+ }
+ if (!SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, 0)) {
+ return SK_FALSE;
+ }
+ // Read current host control register
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl);
+
+ if (width == SDIO_4_BIT) {
+ pDev->bus_width = SDIO_4_BIT;
+ if (!SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x82)) // 0x80:CD
+ // disable,1
+ // bit;0x82:CD
+ // disable,4
+ // bit
+ {
+ return SK_FALSE;
+ }
+ ucHostCtrl |= STDHOST_4_BIT_ENA;
+ } else {
+ pDev->bus_width = SDIO_1_BIT;
+ if (!SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x80)) // 0x80:CD
+ // disable,1
+ // bit;0x80:CD
+ // disable,1
+ // bit
+ {
+ return SK_FALSE;
+ }
+ ucHostCtrl &= ~STDHOST_4_BIT_ENA;
+ }
+
+ // Setup host control register
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl);
+
+ // Re-enable Host Interrupt on card
+ if (!SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, orgIntEnable)) {
+ return SK_FALSE;
+ }
+ // Re-enable card interrupt
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE,
+ usOrgValue);
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_SetGPO - Set the GPO on/off
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+SK_BOOL
+SDHost_SetGPO(PSD_DEVICE_DATA pDev, SK_U8 on)
+{
+ if (!pDev->CardIn) {
+ return SK_FALSE;
+ }
+
+ if (on) {
+
+ GPO_ON();
+ } else {
+
+ GPO_OFF();
+ }
+ return SK_TRUE;
+}
+
+/******************************************************************************
+ *
+ * SDHost_PsState - Set the power state of the upper layer driver
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_PsState(PSD_DEVICE_DATA pDev, SK_U8 State)
+{
+ pDev->PsState = State;
+}
+
+/******************************************************************************
+ *
+ * SDHost_ErrorRecovery - SDIO Standard Host Spec conform error recovery
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Context:
+ *
+ * Returns:
+ *
+ */
+VOID
+SDHost_ErrorRecovery(PSD_DEVICE_DATA pDev)
+{
+ SK_U8 ucValue;
+ SK_U16 usValue;
+ SK_U32 j, ulVal, ulDataLineMask;
+
+ // We have to do spec conform error recovery
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, &usValue);
+ DBGPRINT(DBG_ERROR, (KERN_DEBUG "~#~#~#~#\n"));
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "SDHost_ErrorRecovery : ERROR_IRQ_STATUS=0x%4.04X\n",
+ usValue));
+ // 1.) check whether any of bits3-0 are set.
+ if (usValue & 0x000F) {
+ // reset the command line
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_CMD_LINE);
+
+ // wait until CMD line reset is 0
+ j = 0;
+ do {
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, &ucValue);
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ErrorRecovery : CMD-LINE SW_RESET=0x%2.02X\n",
+ ucValue));
+ UDELAY(2);
+ } while ((ucValue & STDHOST_SW_RESET_CMD_LINE) && j++ < 10000);
+ }
+ // 2.) check whether any of bits6-4 are set.
+ if (usValue & 0x0070) {
+
+ // reset the data line
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0,
+ STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE);
+
+ // wait until data line reset is 0
+ j = 0;
+ do {
+
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, &ucValue);
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ErrorRecovery : DAT-LINE SW_RESET=0x%2.02X\n",
+ ucValue));
+ UDELAY(2);
+ } while ((ucValue & STDHOST_SW_RESET_DAT_LINE) && j++ < 10000);
+
+ }
+ // clear error irq bits
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF);
+
+ // wait for more than 40 us
+ UDELAY(100);
+
+ if (pDev->bus_type == SDIO_SPI_TYPE) {
+ ulDataLineMask = STDHOST_STATE_DAT0_LINE_LVL;
+ } else {
+ if (pDev->bus_width == SDIO_1_BIT) {
+ ulDataLineMask = STDHOST_STATE_DAT0_LINE_LVL;
+ } else {
+ ulDataLineMask =
+ (STDHOST_STATE_DAT0_LINE_LVL | STDHOST_STATE_DAT1_LINE_LVL |
+ STDHOST_STATE_DAT2_LINE_LVL | STDHOST_STATE_DAT3_LINE_LVL);
+ }
+ }
+ for (j = 0; j < 50; j++) {
+ MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal);
+ UDELAY(5);
+ if ((ulVal & ulDataLineMask) == ulDataLineMask) {
+ break;
+ }
+ }
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG
+ "SDHost_ErrorRecovery : DAT-LINE=%d %d %d %d CMD-Line=%d\n",
+ ulVal & STDHOST_STATE_DAT3_LINE_LVL ? 1 : 0,
+ ulVal & STDHOST_STATE_DAT2_LINE_LVL ? 1 : 0,
+ ulVal & STDHOST_STATE_DAT1_LINE_LVL ? 1 : 0,
+ ulVal & STDHOST_STATE_DAT0_LINE_LVL ? 1 : 0,
+ ulVal & STDHOST_STATE_CMD_LINE_LVL ? 1 : 0));
+ if (j >= 50) {
+ DBGPRINT(DBG_ERROR,
+ (KERN_DEBUG
+ "SDHost_ErrorRecovery : Present state=8x%8.08X : Non-recoverable error (bad datalines 0x%8.08X)!!!!!!!!!!!!!!!!!!!!\n",
+ ulVal, ulVal & ulDataLineMask));
+ }
+ // clear error irq bits
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF);
+ // clear normal irq bits
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS,
+ ~(pDev->currentIRQSignalMask));
+
+ UDELAY(100);
+}
+
+SK_U32
+SDHost_wait_event(PSD_DEVICE_DATA pDev, SDHOST_EVENT * pEvt, SK_U32 to)
+{
+ SK_U32 timeOut = 0;
+ SK_U32 rc = 0;
+
+ DECLARE_WAITQUEUE(sdwait, current);
+
+ if (to == 0) {
+ timeOut = LONG_MAX;
+ } else {
+ timeOut = to;
+ }
+
+// DBGPRINT(DBG_ALL, (">>> %s: timeout=%d event=%ld\n",__FUNCTION__,timeOut,pEvt->event));
+
+ add_wait_queue(&pEvt->wq, &sdwait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while ((test_bit(0, &pEvt->event) == 0) && timeOut) {
+ timeOut = schedule_timeout(timeOut);
+ if (signal_pending(current)) {
+ rc = 1;
+ DBGPRINT(DBG_ALL, ("%s: Signal pending!\n", __FUNCTION__));
+ break;
+ }
+ }
+
+ if (timeOut <= 0 || (test_bit(0, &pEvt->event) == 0)) {
+ rc = 2;
+ DBGPRINT(DBG_ALL,
+ ("%s: timeout=%d event=%ld\n", __FUNCTION__, timeOut,
+ pEvt->event));
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&pEvt->wq, &sdwait);
+
+ // DBGPRINT(DBG_ALL, ("<<< %s: timeout=%d
+ // event=%ld\n",__FUNCTION__,timeOut,pEvt->event));
+
+ return (rc);
+}
+
+SK_BOOL
+SDHost_DumpCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number, SK_U32 length)
+{
+ SK_U8 R;
+ SK_U32 _cis = 0;
+ SK_U32 j;
+ SK_U32 i = 0;
+ SK_U32 len = 0;
+ SK_U32 state = 0;
+
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis = R;
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis |= (R << 8);
+ if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_2_REG(function_number), 0, &R)) {
+ return SK_FALSE;
+ }
+ _cis |= (R << 16);
+
+ // Search for CISTPL
+ printk("SDHost_DumpCIS : FN=%d CIS=%8.08X\n", function_number, _cis);
+ R = 0;
+
+ if (_cis == 0) {
+ return SK_FALSE;
+ }
+
+ j = 0;
+ while (j < length) {
+ SDHost_CMD52_Read(pDev, _cis + j, function_number, &R);
+ j++;
+ switch (state) {
+ case 0:
+ {
+ printk("%2.02X:", R);
+ state++;
+ if (R == 0xFF) {
+ printk("END\n");
+ return SK_TRUE;
+ }
+ break;
+ }
+ case 1:
+ {
+ printk("len=%2.02X:", R);
+ len = R;
+ i = 0;
+ state++;
+ break;
+ }
+ case 2:
+ {
+ printk("%2.02X ", R);
+ i++;
+ if (i >= len) {
+ printk("\n");
+ state = 0;
+ }
+ break;
+ }
+ }
+ }
+ printk("\n");
+
+ return SK_TRUE;
+}
+
+SK_BOOL
+SDHost_Disable_HighSpeedMode(PSD_DEVICE_DATA pDev)
+{
+ SK_U8 R;
+ SK_U16 usVal;
+ SK_U8 ucHostCtrl = 0;
+
+ // Turn Off Bus Clock
+ SDHost_SetClock(pDev, 0);
+
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal);
+
+ usVal &= 0x00FF;
+ usVal |= MK_CLOCK((SK_U16) pDev->ClockSpeed);
+
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ // Turn On Bus Clock
+ SDHost_SetClock(pDev, 1);
+
+ if (SDHost_CMD52_Read(pDev, HIGH_SPEED_REG, 0, &R) && pDev->ClockSpeed != 0) {
+ if (R & EHS) {
+ // Disable high speed mode if requested bus clock is not 50MHz
+ R &= ~EHS;
+ SDHost_CMD52_Write(pDev, HIGH_SPEED_REG, 0, R);
+ }
+ }
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl);
+
+ if (ucHostCtrl & STDHOST_HIGH_SPEED_ENA) {
+ ucHostCtrl &= ~STDHOST_HIGH_SPEED_ENA;
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl);
+ }
+ return SK_TRUE;
+}
+
+SK_BOOL
+SDHost_Enable_HighSpeedMode(PSD_DEVICE_DATA pDev)
+{
+ SK_U8 R;
+ SK_U16 usVal;
+ SK_U8 ucHostCtrl = 0;
+
+ // Read High Speed register of CCCR
+ if (SDHost_CMD52_Read(pDev, HIGH_SPEED_REG, 0, &R) &&
+ (pDev->ClockSpeed == 0)) {
+ if (R & SHS) {
+ /* Make the clock edge to rising */
+ MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl);
+ ucHostCtrl |= STDHOST_HIGH_SPEED_ENA;
+ MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl);
+
+ DBGPRINT(DBG_W528D, (KERN_DEBUG "High speed mode is supported.\n"));
+
+ // Enable high speed mode if requested bus clock is 50MHz
+ // and card supports high speed mode
+ R |= EHS;
+ SDHost_CMD52_Write(pDev, HIGH_SPEED_REG, 0, R);
+
+ /* Change the Host controller clock to 50MHZ */
+ // Turn Off Bus Clock
+ SDHost_SetClock(pDev, 0);
+ MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal);
+ usVal &= 0x00FF;
+ usVal |= MK_CLOCK((SK_U16) pDev->ClockSpeed);
+ MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal);
+ // Turn On Bus Clock
+ SDHost_SetClock(pDev, 1);
+ } else {
+ DBGPRINT(DBG_W528D,
+ (KERN_DEBUG "High speed mode is not supported.\n"));
+ }
+ }
+ return SK_TRUE;
+}
diff --git a/make_pkg.sh b/make_pkg.sh
new file mode 100755
index 0000000..396102c
--- /dev/null
+++ b/make_pkg.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Builds the .deb package.
+
+# Load common constants. This should be the first executable line.
+# The path to common.sh should be relative to your script's location.
+COMMON_SH="$(dirname "$0")/../../scripts/common.sh"
+. "$COMMON_SH"
+
+# Make the package
+make_pkg_common "marvell-8787" "$@"
diff --git a/marvell_8787.conf b/marvell_8787.conf
new file mode 100644
index 0000000..f998a7a
--- /dev/null
+++ b/marvell_8787.conf
@@ -0,0 +1 @@
+options sd8787 fw_name=mrvl/sd8787.bin
diff --git a/unpack.sh b/unpack.sh
new file mode 100644
index 0000000..d3f8ea4
--- /dev/null
+++ b/unpack.sh
@@ -0,0 +1,8 @@
+# /bin/sh
+
+# unpack vendor drop into git
+
+for i in SD-BT-8787-*.tgz
+do
+ tar xf $i --strip 1
+done
diff --git a/wlan_src/Makefile b/wlan_src/Makefile
new file mode 100755
index 0000000..f8bbdd1
--- /dev/null
+++ b/wlan_src/Makefile
@@ -0,0 +1,262 @@
+# File: Makefile
+#
+# Copyright (C) 2008-2009, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# A copy of the GPL is available in file gpl-2.0.txt accompanying in this
+# deliverables.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+CC= $(CROSS_COMPILE)gcc
+LD= $(CROSS_COMPILE)ld
+BACKUP= /root/backup
+YMD= `date +%Y%m%d%H%M`
+
+#############################################################################
+# Configuration Options
+#############################################################################
+
+# Debug Option
+# DEBUG LEVEL n/1/2:
+# n: NO DEBUG
+# 1: Only PRINTM(MMSG,...), PRINTM(MFATAL,...), ...
+# 2: All PRINTM()
+CONFIG_DEBUG=1
+
+# Proc debug file
+CONFIG_PROC_DEBUG=y
+
+# Re-association in driver
+CONFIG_REASSOCIATION=y
+
+# Manufacturing firmware support
+CONFIG_MFG_CMD_SUPPORT=y
+
+# Big-endian platform
+CONFIG_BIG_ENDIAN=n
+
+# Enable SDIO multi-port Tx aggregation
+CONFIG_SDIO_MULTI_PORT_TX_AGGR=y
+
+# Enable SDIO multi-port Rx aggregation
+CONFIG_SDIO_MULTI_PORT_RX_AGGR=y
+
+
+#############################################################################
+# Select Platform Tools
+#############################################################################
+
+MODEXT = ko
+#EXTRA_CFLAGS += -I$(PWD)/mlan
+EXTRA_CFLAGS += -I$(M)/mlan
+EXTRA_CFLAGS += -DLINUX
+
+# KERNELDIR point to the installed kernel directory.
+# KERNELDIR can be set on the command line,
+# make KERNELDIR=/usr/src/arm/<arch-bsp-path>
+# Alternatively KERNELDIR can be set in the environment.
+# Default value for KERNELDIR is set below.
+KERNELDIR ?= /usr/src/arm/linux-2.6.25-pxa9xx
+
+# CROSS_COMPILE specify the prefix used for all executables used
+# during compilation. Only gcc and related bin-utils executables
+# CROSS_COMPILE can be set on the command line
+# make CROSS_COMPILE=</usr/local/arm/4.1.1/bin/>arm-linux-
+# Alternatively CROSS_COMPILE can be set in the environment.
+# Default value for CROSS_COMPILE is set below.
+CROSS_COMPILE ?= /usr/local/arm/4.1.1/bin/arm-linux-
+
+# INSTALLDIR specify the path to install the kernel module after
+# succesful compilation.
+# INSTALLDIR can be set on the command line
+# make INSTALLDIR=/tftpboot/<rootfs>
+# Alternatively INSTALLDIR can be set in the environment.
+# Default value for INSTALL is set below.
+INSTALLDIR ?= /tftpboot/pxa9xx/root
+
+# ARCH specifies the architecture of the target processor, this kernel
+# module will run.
+# ARCH can be set on the command line
+# make ARCH=<arm/i386>
+# Alternatively ARCH can be set in the environment
+# Default values of ARCH for specific platform are set below.
+ARCH ?= arm
+
+LD += -S
+BINDIR = ../bin_sd8787
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+ EXTRA_CFLAGS += -I$(KERNELDIR)/include
+
+ EXTRA_CFLAGS += -DFPNUM='"64"'
+
+ifeq ($(CONFIG_DEBUG),1)
+ EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_DEBUG),2)
+ EXTRA_CFLAGS += -DDEBUG_LEVEL1
+ EXTRA_CFLAGS += -DDEBUG_LEVEL2
+ DBG= -dbg
+endif
+
+ifeq ($(CONFIG_PROC_DEBUG),y)
+ EXTRA_CFLAGS += -DPROC_DEBUG
+ export CONFIG_PROC_DEBUG
+endif
+
+ifeq ($(CONFIG_REASSOCIATION),y)
+ EXTRA_CFLAGS += -DREASSOCIATION
+endif
+
+ifeq ($(CONFIG_MFG_CMD_SUPPORT),y)
+ EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
+endif
+
+ifeq ($(CONFIG_BIG_ENDIAN),y)
+ EXTRA_CFLAGS += -DBIG_ENDIAN
+endif
+
+ifeq ($(CONFIG_SDIO_MULTI_PORT_TX_AGGR),y)
+ EXTRA_CFLAGS += -DSDIO_MULTI_PORT_TX_AGGR
+endif
+
+ifeq ($(CONFIG_SDIO_MULTI_PORT_RX_AGGR),y)
+ EXTRA_CFLAGS += -DSDIO_MULTI_PORT_RX_AGGR
+endif
+
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifneq ($(KERNELRELEASE),)
+
+MOALOBJS = mlinux/moal_main.o \
+ mlinux/moal_ioctl.o \
+ mlinux/moal_shim.o
+
+MLANOBJS = mlan/mlan_shim.o mlan/mlan_init.o \
+ mlan/mlan_txrx.o \
+ mlan/mlan_cmdevt.o mlan/mlan_misc.o \
+ mlan/mlan_module.o
+
+MLANOBJS += mlan/mlan_wmm.o
+MLANOBJS += mlan/mlan_sdio.o
+MLANOBJS += mlan/mlan_11n_aggr.o
+MLANOBJS += mlan/mlan_11n_rxreorder.o
+MLANOBJS += mlan/mlan_11n.o
+MLANOBJS += mlan/mlan_11d.o
+MLANOBJS += mlan/mlan_scan.o
+MLANOBJS += mlan/mlan_join.o
+MLANOBJS += mlan/mlan_cfp.o \
+ mlan/mlan_sta_ioctl.o \
+ mlan/mlan_sta_rx.o \
+ mlan/mlan_sta_tx.o \
+ mlan/mlan_sta_event.o \
+ mlan/mlan_sta_cmd.o \
+ mlan/mlan_sta_cmdresp.o
+MOALOBJS += mlinux/moal_priv.o \
+ mlinux/moal_wext.o
+MLANOBJS += mlan/mlan_11h.o
+MLANOBJS += mlan/mlan_meas.o
+
+
+ifdef CONFIG_PROC_FS
+MOALOBJS += mlinux/moal_proc.o
+ifeq ($(CONFIG_PROC_DEBUG),y)
+MOALOBJS += mlinux/moal_debug.o
+endif
+endif
+
+obj-m := mlan.o
+mlan-objs := $(MLANOBJS)
+MOALOBJS += mlinux/moal_sdio_mmc.o
+obj-m += sd8xxx.o
+sd8xxx-objs := $(MOALOBJS)
+
+
+# Otherwise we were called directly from the command line; invoke the kernel build system.
+else
+
+default:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
+
+endif
+
+###############################################################
+
+export CC LD EXTRA_CFLAGS KERNELDIR
+
+.PHONY: mapp/mlanconfig mapp/mlan2040coex clean distclean
+ @echo "Finished Making Marvell Wlan Linux Driver"
+
+mapp/mlanconfig:
+ $(MAKE) -C $@
+mapp/mlan2040coex:
+ $(MAKE) -C $@
+
+echo:
+
+build: echo default
+
+ @if [ ! -d $(BINDIR) ]; then \
+ mkdir $(BINDIR); \
+ fi
+ cp -f mlan.$(MODEXT) $(BINDIR)/mlan$(DBG).$(MODEXT)
+ cp -f sd8xxx.$(MODEXT) $(BINDIR)/sd8787$(DBG).$(MODEXT)
+
+ cp -f README $(BINDIR)
+ $(MAKE) -C mapp/mlanconfig $@ INSTALLDIR=$(BINDIR)
+ $(MAKE) -C mapp/mlan2040coex $@ INSTALLDIR=$(BINDIR)
+
+clean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -find . -name "Module.symvers" -exec rm {} \;
+ -find . -name "Module.markers" -exec rm {} \;
+ -find . -name "modules.order" -exec rm {} \;
+ -rm -rf .tmp_versions
+ $(MAKE) -C mapp/mlanconfig $@
+ $(MAKE) -C mapp/mlan2040coex $@
+
+install: default
+
+ cp -f mlan.$(MODEXT) $(INSTALLDIR)/mlan$(DBG).$(MODEXT)
+ cp -f sd8xxx.$(MODEXT) $(INSTALLDIR)/sd8787$(DBG).$(MODEXT)
+ echo "sd8787 Driver Installed"
+
+distclean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.orig" -exec rm {} \;
+ -find . -name "*.swp" -exec rm {} \;
+ -find . -name "*.*~" -exec rm {} \;
+ -find . -name "*~" -exec rm {} \;
+ -find . -name "*.d" -exec rm {} \;
+ -find . -name "*.a" -exec rm {} \;
+ -find . -name "tags" -exec rm {} \;
+ -find . -name ".*" -exec rm -rf 2> /dev/null \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -rm -rf .tmp_versions
+ $(MAKE) -C mapp/mlanconfig $@
+ $(MAKE) -C mapp/mlan2040coex $@
+
+# End of file
diff --git a/wlan_src/README b/wlan_src/README
new file mode 100755
index 0000000..1c70ffe
--- /dev/null
+++ b/wlan_src/README
@@ -0,0 +1,1600 @@
+===============================================================================
+ U S E R M A N U A L
+
+ Copyright (C) 2008-2009, Marvell International Ltd.
+ All Rights Reserved
+
+1) FOR DRIVER BUILD
+
+ Goto source code directory wlan_src/.
+ make [clean] build
+ The driver and utility binaries can be found in ../bin_xxxx directory.
+
+2) FOR DRIVER INSTALL
+
+ a) Copy sd8786.bin | sd8787.bin | ... to /lib/firmware/mrvl/ directory,
+ create the directory if it doesn't exist.
+ b) Install WLAN driver,
+ insmod mlan.ko
+ insmod sd8xxx.ko [helper_name=mrvl/helper_sd.bin] [fw_name=mrvl/sd8xxx.bin]
+ c) Uninstall WLAN driver,
+ ifconfig mlanX down
+ rmmod sd8xxx
+ rmmod mlan
+
+ To load driver with MFG firmware file, use mfg_mode=1 when insmod WLAN driver and
+ specify MFG firmware name if needed.
+
+3) FOR DRIVER PROC & DEBUG
+
+ The following info are provided in /proc/net/mwlan/mlanX/info,
+ on kernel 2.6.24 or later, the entry is /proc/mwlan/mlanX/info.
+
+ driver_name = "wlan"
+ driver_version = <chip id, firmware version and driver version>
+ interface_name = "mlanX"
+ bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
+ media_state = "Disconnected" | "Connected"
+ mac_address = <6-byte adapter MAC address>
+ multicase_count = <multicast address count>
+ essid = <current SSID>
+ bssid = <current BSSID>
+ channel = <current channel>
+ region_code = <current region code>
+ multicasr_address[n] = <multicast address>
+ num_tx_bytes = <number of bytes sent to device>
+ num_rx_bytes = <number of bytes received from device and sent to kernel>
+ num_tx_pkts = <number of packets sent to device>
+ num_rx_pkts = <number of packets received from device and sent to kernel>
+ num_tx_pkts_dropped = <number of Tx packets dropped by driver>
+ num_rx_pkts_dropped = <number of Rx packets dropped by driver>
+ num_tx_pkts_err = <number of Tx packets failed to send to device>
+ num_rx_pkts_err = <number of Rx packets failed to receive from device>
+ carrier "on" | "off"
+ tx queue "stopped" | "started"
+
+ The following debug info are provided in /proc/net/mwlan/mlanX/debug,
+ on kernel 2.6.24 or later, the entry is /proc/mwlan/mlanX/debug.
+
+ int_counter = <interrupt count, cleared when interrupt handled>
+ wmm_ac_vo = <number of packets sent to device from WMM AcVo queue>
+ wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
+ wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
+ wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
+ max_tx_buf_size = <maximum Tx buffer size>
+ tx_buf_size = <current Tx buffer size>
+ ps_mode = <0/1, CAM mode/PS mode>
+ ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
+ is_deep_sleep = <0/1, not deep sleep state/deep sleep state>
+ wakeup_dev_req = <0/1, wakeup device not required/required>
+ wakeup_tries = <wakeup device count, cleared when device awake>
+ hs_configured = <0/1, host sleep not configured/configured>
+ hs_activated = <0/1, extended host sleep not activated/activated>
+ num_tx_timeout = <number of Tx timeout>
+ num_cmd_timeout = <number of timeout commands>
+ timeout_cmd_id = <command id of the last timeout command>
+ timeout_cmd_act = <command action of the last timeout command>
+ last_cmd_id = <command id of the last several commands sent to device>
+ last_cmd_act = <command action of the last several commands sent to device>
+ last_cmd_index = <0 based last command index>
+ last_cmd_resp_id = <command id of the last several command responses received from device>
+ last_cmd_resp_index = <0 based last command response index>
+ last_event = <event id of the last several events received from device>
+ last_event_index = <0 based last event index>
+ num_cmd_h2c_fail = <number of commands failed to send to device>
+ num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
+ num_tx_h2c_fail = <number of data packets failed to send to device>
+ num_evt_deauth = <number of deauthenticated events received from device>
+ num_evt_disassoc = <number of disassociated events received from device>
+ num_evt_link_lost = <number of link lost events received from device>
+ num_cmd_deauth = <number of deauthenticate commands sent to device>
+ num_cmd_assoc_ok = <number of associate commands with success return>
+ num_cmd_assoc_fail = <number of associate commands with failure return>
+ cmd_sent = <0/1, send command resources available/sending command to device>
+ data_sent = <0/1, send data resources available/sending data to device>
+ mp_rd_bitmap = <SDIO multi-port read bitmap>
+ mp_wr_bitmap = <SDIO multi-port write bitmap>
+ cmd_resp_received = <0/1, no cmd response to process/response received and yet to process>
+ event_received = <0/1, no event to process/event received and yet to process>
+ ioctl_pending = <number of ioctl pending>
+ tx_pending = <number of Tx packet pending>
+ rx_pending = <number of Rx packet pending>
+ malloc_count = <number of malloc done>
+ lock_count = <number of lock used>
+
+ Use dmesg or cat /var/log/debug to check driver debug messages.
+
+ Update /proc/sys/kernel/printk to change message log levels.
+ For example,
+ echo 6 > /proc/sys/kernel/printk (messages with a higher priority than 6
+ will be printed to the console)
+ echo 15 > /proc/sys/kernel/printk (all messages will be printed to console)
+
+4) FOR IWPRIV COMMAND
+
+NAME
+ This manual describes the usage of private commands used in Marvell MLAN
+ Linux Driver.
+
+ To use parameters as hex format, a '0x' must precede it for the parameters to
+ be parsed properly.
+
+SYNOPSIS
+ iwpriv <mlanX> <command> [sub-command] ...
+
+ iwpriv mlanX version
+ iwpriv mlanX verext
+ iwpriv mlanX getsignal [m] [n]
+ iwpriv mlanX antcfg [m]
+ iwpriv mlanX regioncode [n]
+ iwpriv mlanX wwscfg [m]
+ iwpriv mlanX esuppmode
+ iwpriv mlanX passphrase <ssid/psk/passphrase>
+ iwpriv mlanX httxcfg <m>
+ iwpriv mlanX htcapinfo <m>
+ iwpriv mlanX addbapara <m> <n> <o>
+ iwpriv mlanX aggrpriotbl <n>
+ iwpriv mlanX addbareject <n>
+ iwpriv mlanX txbufcfg <n>
+ iwpriv mlanx amsduaggrctrl <n>
+ iwpriv mlanX mpactrl [tx_ena] [rx_ena] [tx_size] [rx_size] [tx_ports] [rx_ports]
+ iwpriv mlanX tideligtbl [N0] [N1] [N2] [N3] [N4] [N5] [N6] [N7]
+ iwpriv mlanX atimwindow [n]
+ iwpriv mlanX deepsleep [n] [m]
+ iwpriv mlanX hscfg [condition [[GPIO# [gap]]]]
+ iwpriv mlanX hssetpara condition [GPIO# [gap]]
+ iwpriv mlanX deauth [n]
+ iwpriv mlanX radioctrl
+ iwpriv mlanX reassoctrl [n]
+ iwpriv mlanX adhocaes
+ iwpriv mlanX bandcfg [l] [m] [n]
+ iwpriv mlanX getlog
+ iwpriv mlanX 11dcfg
+ iwpriv mlanX wmmcfg [n]
+ iwpriv mlanX txpowercfg [<RateIndex> [<MinPwr> [<MaxPwr> <step>]]]
+ iwpriv mlanX qoscfg
+ iwpriv mlanX getdatarate
+ iwpriv mlanX txratecfg [n]
+ iwpriv mlanX bcninterval [n]
+ iwpriv mlanX sysclock [clk1] [clk2] [clk3] [clk4]
+ iwpriv mlanX ldocfg [n]
+ iwpriv mlanX drvdbg [n] [m]
+ iwpriv mlanX warmreset
+ iwpriv mlanX regrdwr <type> <offset> [value]
+ iwpriv mlanX rdeeprom <offset> <length>
+ iwpriv mlanX memrdwr <address> [value]
+ iwpriv mlanX inactivityto <n> <m> <l> [k]
+ iwpriv mlanX bcats <traffic_type> [<timeshare_interval> <bt_time>]
+ iwpriv mlanX sdioclock <n>
+ iwpriv mlanX scancfg [t] [m] [p] [s] [a] [b]
+ iwpriv mlanX vsiecfg <action> <id> [<mask> [data1] ... [dataN]]
+ iwpriv mlanX sleeppd [n]
+ iwpriv mlanX pscfg [k] [d] [l] ...
+ iwpriv mlanX sleepparams [<p1> <p2> <p3> <p4> <p5> <p6>]
+ iwpriv mlanX authtype [n]
+
+DESCRIPTION
+ Those commands are used to send additional commands to the Marvell MLAN
+ card via the Linux device driver.
+
+ The mlanX parameter specifies the network device that is to be used to
+ perform this command on. It could be mlan0, mlan1 etc.
+
+version
+ This is used to get the current version of the driver and the firmware.
+
+verext
+ Retrieve and display an extended version string from the firmware
+
+ Usage:
+ iwpriv mlanX verext [#]
+
+ where [#] is an optional argument to retrieve a specific version string,
+ omission of the argument retrieves the 0 indexed string.
+
+getsignal
+ This command gets the last and average value of RSSI, SNR and NF of
+ Beacon and Data.
+ Note: This command is available only when STA is connected.
+
+ where value of m is:
+ 1 -- RSSI (Receive Signal Strength Indication)
+ 2 -- SNR (Signal to Noise Ratio)
+ 3 -- NF (Noise Floor)
+ where value of n is:
+ 1 -- Beacon last
+ 2 -- Beacon average
+ 3 -- Data last
+ 4 -- Data average
+
+ Examples:
+ iwpriv mlan0 getsignal 1 : Get the RSSI info (beacon last, beacon
+ average, data last and data average)
+ iwpriv mlan0 getsignal 3 4 : Get the NF of data average
+ iwpriv mlan0 getsignal 2 1 : Get the SNR of beacon last
+ iwpriv mlan0 getsignal : Get all of the signal info
+ mlan0 getsignal:-32 -33 -35 -36 67 59 63 56 -99 -92 -98 -92
+ RSSI info: beacon last -32, beacon average -33, data last -35, data average -36
+ SNR info: beacon last 67, beacon average 59, data last 63, data average 56
+ NF info: beacon last -99, beacon average -92, data last -98, data average -92
+
+antcfg
+ This command is used to set/get the mode of Tx/Rx antenna.
+
+ where value of m is:
+ 1 -- Tx/Rx antenna 1.
+ 2 -- Tx/Rx antenna 2.
+ 0xFFFF -- Tx/Rx antenna diversity.
+
+ Examples:
+ iwpriv mlan0 antcfg : Get Tx/Rx antenna mode
+ iwpriv mlan0 antcfg 1 : Set Tx/Rx antenna 1
+ iwpriv mlan0 antcfg 0xFFFF : Set Tx/Rx antenna diversity
+
+regioncode
+ This command is used to set/get the region code in the station.
+ Note: This command should be issued at beginning before band/channel selection
+ and association.
+
+ where value is 'region code' for various regions like
+ USA FCC, Canada IC, Europe ETSI, Japan ...
+ The special code (0xff) is used for Japan to support channel 1-14 in B/G/N mode.
+
+ Examples:
+ iwpriv mlan0 regioncode : Get region code
+ iwpriv mlan0 regioncode 0x10 : Set region code to USA (0x10)
+
+wwscfg
+ This command is used to set/get the WWS (World Wide Safe) mode.
+
+ where value of m is:
+ 0 -- Disable WWS mode (default)
+ 1 -- Enable WWS mode
+
+ Examples:
+ iwpriv mlan0 wwscfg : Get WWS mode
+ iwpriv mlan0 wwscfg 1 : Enable WWS mode
+ iwpriv mlan0 wwscfg 0 : Disable WWS mode
+
+esuppmode
+ This command is used to get the current RSN mode and active pairwise/group
+ cipher for WPA/WPA2 mode.
+ Note: This command is available only when STA is connected.
+
+ These are bits settings used to indicate each RSN mode.
+ Bit 0 : No RSN
+ Bit 1-2 : RFU
+ Bit 3 : WPA
+ Bit 4 : WPA-NONE
+ Bit 5 : WPA2
+ Bit 6 : AES CCKM
+ Bit 7-15 : RFU
+
+ These are bits settings used to indicate each pairwise and group cipher.
+ Bit 0 : RFU
+ Bit 1 : RFU
+ Bit 2 : TKIP
+ Bit 3 : AES CCKM
+ Bit 2-7 : RFU
+
+ Example:
+ iwpriv mlan0 esuppmode : Get RSN mode and pairwise/group cipher
+ 8 4 4
+ (The current RSN mode is WPA, active pairwise cipher is TKIP and
+ active group cipher is TKIP.)
+
+passphrase
+ This command is used to set/get passphrase for WPA-PSK/WPA2-PSK mode.
+
+ Where <n>
+ ASCII string for ssid/passphrase/psk.
+
+ 1) "0;<ssid=valid ssid>" - This will get the passphrase, AKMP
+ for specified ssid, if none specified then it will get all.
+
+ Example:
+ iwpriv mlan0 passphrase "0;ssid=marvell"
+
+ 2) "1;<psk=64 byte hexpsk>;<passphrase=1-63 byte passphare>
+ <ssid=valid ssid>" - Passphrase and psk cannot be provided for the same SSID.
+ This command takes only one SSID at a time, If ssid= is present it should contain
+ a passphrase or psk. If no arguments are provided then AKMP=802.1x, and passphrase
+ should be provided after association.
+ End of each parameter should be followed by a ';'(except for the last parameter)
+ as the delimiter. If ';' or '/' has to be used in an SSID then a '/' should be preceded
+ to ';' or '/' as a escape.
+
+ Examples:
+ iwpriv mlan0 passphrase "1;ssid=mrvlAP;passphrase=abcdefgd"
+ iwpriv mlan0 passphrase "1;ssid=mrvl AP;psk=<64 bytes hexpsk>"
+
+ If user wants to input the ssid as "mrvl; AP" then command has to be
+ iwpriv mlan0 passphrase "1;ssid=mrvl/; AP;passphrase=abcdefgh"
+
+ If user wants to input the ssid as "//;" then command has to be
+ iwpriv mlan0 passphrase "1;ssid=/////;;passphrase=abcdefgh"
+
+ 3) "2;<ssid=valid ssid>" - This will clear the passphrase
+ for specified ssid, if none specified then it will clear all.
+
+ Examples:
+ iwpriv mlan0 passphrase "2;ssid=marvell"
+ iwpriv mlan0 passphrase "2" : Clear all profiles and disable embedded supplicant
+
+httxcfg
+ This command is used to configure various 11n specific configration
+ for transmit (such as Short GI, Channel BW and Green field support)
+
+ where <m>
+ This is a bitmap and should be used as following
+ Bit 15-7: Reserved set to 0
+ Bit 6: Short GI in 40 Mhz enable/disable
+ Bit 5: Short GI in 20 Mhz enable/disable
+ Bit 4: Green field enable/disble
+ Bit 3-2: Reserved set to 0
+ Bit 1: 20/40 Mhz enable disable.
+ Bit 0: Reserved set to 0
+
+ When Bit 1 is set then firmware could transmit in 20Mhz or 40Mhz based
+ on rate adaptation. When this bit is reset then firmware will only
+ transmit in 20Mhz.
+
+ iwpriv mlanX httxcfg 0x62
+ This will enable 20/40 and Short GI but will disable Green field.
+
+ iwpriv mlanX httxcfg 0x30
+ This will enable Short GI and Green field.
+
+ The default value is 0x20
+
+ Note:- If 20/40 MHz support is disabled in htcapinfo, device will not transmit
+ in 40 MHz even 20/40 MHz is enabled in httxcfg.
+
+htcapinfo
+ This command is used to configure some of paramters in HTCapInfo IE
+ (such as Short GI, Channel BW, and Green field support)
+
+ where <m>
+ This is a bitmap and should be used as following
+ Bit 29: Green field enable/disable
+ Bit 26: Rx STBC Support enable/disable. (As we support
+ single spatial stream only 1 bit is used for Rx STBC)
+ Bit 24: Short GI in 40 Mhz enable/disable
+ Bit 23: Short GI in 20 Mhz enable/disable
+ Bit 17: 20/40 Mhz enable disable.
+ Bit 8: Enable/disable 40Mhz Intolarent bit in ht capinfo.
+ 0 will reset this bit and 1 will set this bit in
+ htcapinfo attached in assoc request.
+ All others are reserved and should be set to 0.
+
+ Setting of any other bits will return error.
+
+ iwpriv mlanX htcapinfo 0x1820000
+ This will enable Short GI, Channel BW to 20/40 and disable Green field support.
+
+ iwpriv mlanX htcapinfo 0x800000
+ This will enable Short GI, Channel BW to 20 only, No Rx STBC support and disable Green field support.
+
+ The default value is 0x4800000
+
+ Note:- This command can be issued any time but it will only come to effect from
+ next association. (as HTCapInfo is sent only during Association).
+
+addbapara
+ This command can be used to update the default ADDBA parameters.
+
+ where <m> is <timeout>
+ <timeout> - This is the block ack timeout for ADDBA request.
+ 0 : Disable (recommended for throughput test)
+ 1 - 65535 : Block Ack Timeout in us
+
+ where <n> is <txwinsize>
+ <txwinsize> - Window size for ADDBA request. (32 is recommended and default value)
+
+ where <o> is <rxwinsize>
+ <rxwinsize> - Window size for ADDBA response. (16 is recommended value for most APs, 64
+ is recommended for AP85)
+
+ eg:
+ iwpriv mlanX addbapara - This command will get the current addba params
+ iwpriv mlanX addbapara 1000 64 5 (This will change the ADDBA timeout to (1000 * 1024) us,
+ txwinsize to 64 and rxwinsize to 5.
+
+ In case the ADDBA timeout value is updated then a ADDBA is sent for all streams
+ to update the timeout value.
+
+ In case txwinsize and/or rxwinsize is update the effect could only be seen on
+ next ADDBA request/response. The current streams will not be affected with this
+ change.
+
+aggrpriotbl
+ This command is used set/get the priority table for AMPDU/AMSDU traffic per tid.
+ This command can also be used to disable AMPDU/AMSDU for a given tid.
+ In case of AMPDU this priority table will be used to setup block ack (to make
+ sure the highest priority tid always uses AMPDU as we have limited AMPDU streams)
+
+ where <m0> <n0> <m1> <n1> ... <m7> <n7>
+
+ <mx> - This is priority for Tid0 for AMPDU packet. A priority could be any
+ values between 0 - 7, 0xff to disable aggregation.
+ <nx> - This is priority for Tid0 for AMSDU packet. A priority could be any
+ values between 0 - 7, 0xff to disable aggregation.
+
+ eg:
+ iwpriv mlanX aggrpriotbl - This command will get the current Priority table for AMPDU and AMSDU.
+ <2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255>. This is read as
+ <"Prio for AMPDU for Tid0" "Prio for AMSDU for Tid0"
+ "Prio for AMPDU for Tid1" "Prio for AMSDU for Tid1" and so on
+ iwpriv mlanX aggrpriotbl 2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255 -
+ This will set the priority table for AMPDU and AMSDU
+ Priority for Tid0/AMPDU = 2, Tid0/AMSDU = 2, Tid1/AMPDU = 0, Tid1/AMSDU = 0
+ and so on. Aggregation for Tid6 and Tid7 are disabled.
+ Here higher the priority number, higher the priority (i.e. 7
+ has higher priority than 6). Similarly for AMSDU.
+ iwpriv mlanX aggrpriotbl 0xff 2 0xff 0 0xff 1 0xff 3 0xff 4 0xff 5 0xff 0xff 0xff 0xff - This will disable
+ AMPDU for all the TIDs but will still keep AMSDU enabled to Tid0 to Tid5
+
+ A delBA should be seen in case a disable happens on a TID for which AMPDU stream
+ is currently setup.
+
+ Note:- This command should only be issue in disconnected state.
+
+addbareject
+ This command is used set/get the addbareject table for all the TIDs.
+ This command can also be used to enable rejection of ADDBA requests for a given tid.
+
+ where <m0> <m1> ... <m7>
+
+ <mX> - This can be 0/1 for TidX. 1 enables rejection of ADDBA request for TidX and
+ 0 would accept any ADDBAs for TidX.
+
+ eg:
+ iwpriv mlanX addbareject - This command will get the current table.
+ [0 0 0 0 0 0 0 0]. ADDBA would be accepted for all TIDs. This is the default state.
+
+ iwpriv mlanX addbareject 0 0 1 1 0 0 0 0 - This command will accept ADDBA requests for
+ Tid [0,1,4,5,6,7] and reject ADDBA requests for Tid [2,3]
+
+ iwpriv mlanX addbareject 1 1 1 1 1 1 1 1 - This will enable rejection of ADDBA requests for
+ all Tids.
+
+ Note:- This command should only be issue in disconnected state.
+
+txbufcfg
+ This command can be used to set max transmit buffer size of firmware. Increasing this
+ buffer size is recommended for AMSDU packets. (Default is 2048)
+
+ where <n> is <buffer size in byte>
+
+ <buffer size> - This can be 2048/4096/8192.
+
+ eg:
+ iwpriv mlanX txbufcfg - This will display the current buffer size.
+ iwpriv mlanX txbufcfg 8192 - This will change the tx buffer size of 8192.
+
+ For AMSDU for work for multiple packets we may need the max tx buffer size to be
+ 4096/8192.
+
+ Note:- This command should be issue in disconnected state.
+ Otherwise, new setting will be effected in next time associate.
+ The actual tx buf size will depends on AP's capability and max transmit buffer size.
+
+amsduaggrctrl
+ This command could be used to enable/disable a feature where firmware gives feedback to driver
+ regarding the optimal AMSDU buffer size to use with the current rate. Firmware will use the
+ current rate to decide the buffer size we could transmit. The max buffer size will still be
+ limited by buffer size provided in txbufcfg. (i.e. if the txbufcfg is 4K, then we could only transmit
+ 4K/2K AMSDU packets, if the txbufcfg is 8K then we could transmit 8k/4k/2k based on current rate)
+
+ If enabled AMSDU buffer size at various rates will be as follows
+
+ 1. Legacy B/G rate.
+ No AMSDU aggregation.
+
+ 2. BW20 HT Rate:
+ When TX rate goes down,
+ MCS 7, 6, 5, 4:
+ a 8K aggregation size (if TX buffer size is 8K)
+ b 4K aggregation size (if TX buffer size is 4K)
+ c 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 3, 2:
+ a 4K aggregation size (if TX buffer size is 8K/4K)
+ b 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 1, 0:
+ a No aggregation
+
+ When TX rate goes up,
+ MCS 7, 6, 5:
+ a 8K aggregation size (if TX buffer size is 8K)
+ b 4K aggregation size (if TX buffer size is 4K)
+ c 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 4, 3:
+ a 4K aggregation size (if TX buffer size is 8K/4K)
+ b 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 2, 1, 0:
+ a No aggregation
+
+ 3. BW40 HT Rate:
+ When TX rate goes down,
+ MCS 7, 6, 5, 4, 3, 2, 1:
+ a 8K aggregation size (if TX buffer size is 8K)
+ b 4K aggregation size (if TX buffer size is 4K)
+ c 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 0:
+ a No aggregation
+
+ When TX rate goes up,
+ MCS 7, 6, 5, 4, 3:
+ a 8K aggregation size (if TX buffer size is 8K)
+ b 4K aggregation size (if TX buffer size is 4K)
+ c 2K aggregation size (if TX buffer size is 2K)
+
+ MCS 2, 1, 0:
+ a No aggregation
+
+ where <n> is 0/1 (for disable/enable)
+
+ eg:
+ iwpriv mlanx amsduaggrctrl 1 - Enable this feature
+ iwpriv mlanx amsduaggrctrl 0 - Disable this feature
+ iwpriv mlanx amsduaggrctrl (This will get the enable/disable flag
+ and the current AMSDU buffer size). The AMSDU buffer size returned is only
+ valid after association as before association there is no rate info.
+
+ Note:- This command to enable/disable could be given anytime (before/after
+ association). This feature is enabled by default by the driver during
+ initialization.
+
+mpactrl
+ This command is used to set/get the Tx, Rx SDIO aggregation parameters
+ Note: The parameters can be set only in disconnected state.
+
+ Examples:
+ iwpriv mlan0 mpactrl : Get MP aggregation parameters
+ iwpriv mlan0 mpactrl 1 1 2048 2048 5 7
+ : Enable MP aggregation for Tx, Rx
+ : Set Tx, Rx buffer size to 2048 bytes.
+ : Set maximum Tx ports to 5 and maximum Rx ports to 7.
+ default values are 0 0 4096 4096 8 8
+
+tideligtbl
+ This command is used to set/get number of available ports for transfer
+ eligibility for TIDs (TID0-TID7).
+
+ Usage:
+ iwpriv mlanX tideligtbl [N0] [N1] [N2] [N3] [N4] [N5] [N6] [N7]
+
+ The Nx (x=0-7) is for TIDx. For each TIDx, there must be at least Nx
+ number of available ports to transfer the corresponding packet.
+ The Nx could be 1-15, 0 or no input for unchanged.
+
+ Examples:
+ iwpriv mlan0 tideligtbl : Get the TID eligibility table
+ iwpriv mlan0 tideligtbl 6 6 5 4 3 2 1 1
+ : Set the TID eligibility table
+ iwpriv mlan0 tideligtbl 4 0 2 : Set TID table TID0 and TID2,
+ keep the others unchanged
+
+atimwindow
+ This command is used to set/get the ATIM window value in the station.
+ The range of ATIM window is 0 - 50.
+ Note: This command should be issued before ad-hoc start/join and ad-hoc
+ power save on.
+
+ Examples:
+ iwpriv mlan0 atimwindow 20 : Set atimwindow to 20
+ iwpriv mlan0 atimwindow : Get atimwindow
+
+deepsleep
+ This command is used to set/get auto deep sleep mode.
+
+ Usage:
+ iwpriv mlanX deepsleep [n] [m]
+
+ where the parameters are:
+ [n]: Enable/disable auto deep sleep mode (1/0)
+ [m]: Idle time in milliseconds after which firmware will put the device
+ in deep sleep mode. Default value is 100 ms.
+
+ Examples:
+ iwpriv mlan0 deepsleep : Display auto deep sleep mode
+ iwpriv mlan0 deepsleep 1 : Enable auto deep sleep mode, idle time unchanged
+ iwpriv mlan0 deepsleep 0 : Disable auto deep sleep mode
+ iwpriv mlan0 deepsleep 1 500 : Enable auto deep sleep mode with idle time 500 ms
+
+hscfg
+ This command is used to configure the host sleep parameters.
+
+ Usage:
+ iwpriv mlanX hscfg [condition [[GPIO# [gap]]]]
+
+ This command takes one (condition), two (condition and GPIO#) or three
+ (condition, GPIO# and gap) parameters for set. If no paramter provided,
+ get is performed.
+
+ where Condition is:
+ bit 0 = 1 -- broadcast data
+ bit 1 = 1 -- unicast data
+ bit 2 = 1 -- mac event
+ bit 3 = 1 -- multicast packet
+
+ where GPIO is the pin number of GPIO used to wakeup the host. It could be
+ any valid GPIO pin# (e.g. 0-7) or 0xff (interface, e.g. SDIO will be used
+ instead).
+
+ where Gap is the gap in milliseconds between wakeup signal and wakeup event
+ or 0xff for special setting.
+
+ The host sleep mode will be cancelled if condition is set to -1.
+
+ Examples:
+ iwpriv mlan0 hscfg : Get current host sleep mode
+ iwpriv mlan0 hscfg -1 : Cancel host sleep mode
+ iwpriv mlan0 hscfg 3 : Broadcast and unicast data
+ Use GPIO and gap set previously
+ iwpriv mlan0 hscfg 2 3 : Unicast data
+ Use GPIO 3 and gap set previously
+ iwpriv mlan0 hscfg 2 1 0xa0 : Unicast data
+ Use GPIO 1 and gap 160 ms
+ iwpriv mlan0 hscfg 2 0xff : Unicast data
+ Use interface (e.g. SDIO)
+ Use gap set previously
+ iwpriv mlan0 hscfg 4 3 0xff : MAC event
+ Use GPIO 3
+ Special host sleep mode
+ iwpriv mlan0 hscfg 1 0xff 0xff : Broadcast data
+ Use interface (e.g. SDIO)
+ Special host sleep mode
+
+hssetpara
+ This command is used to set host sleep parameters.
+
+ Usage:
+ iwpriv mlanX hssetpara Condition [GPIO# [gap]]
+
+ Note:
+ 1) The usages of parameters are the same as "hscfg" command.
+ 2) The parameters will be saved in the driver and be used when host suspends.
+
+deauth
+ This command is used to send a de-authentication to an arbitrary AP.
+ If [n] is omitted, the driver will deauth the associated AP.
+ If in ad-hoc mode this command is used to stop beacon transmission
+ from the station and go into idle state.
+
+ When <n> is supplied as a MAC address, the driver will deauth the
+ specified AP. If the AP address matches the driver's associated AP,
+ the driver will disconnect. Otherwise, the driver remains connected.
+
+radioctrl
+ This command is used to turn on/off the radio.
+ Note: The radio can be disabled only in disconnected state.
+
+ where value of n is:
+ 0 -- Disable
+ 1 -- Enable
+
+ Examples:
+ iwpriv mlan0 radioctrl 1 : Turn the radio on
+ iwpriv mlan0 radioctrl : Get radio status
+
+reassoctrl
+ This command is used to turn on/off re-association in driver.
+
+ Usage:
+ iwpriv mlanX reassoctrl [n]
+
+ Where value of n is:
+ 0 -- Disable
+ 1 -- Enable
+
+ Examples:
+ iwpriv mlan0 reassoctrl : Get re-association status
+ iwpriv mlan0 reassoctrl 1 : Turn re-association on
+
+adhocaes
+ This command is used to set/get the AES key, when the station is in ad-hoc mode.
+ Note: This command is only available in disconnected state.
+
+ where value can be any 16 byte value.
+
+ Examples:
+ iwpriv mlan0 adhocaes : Get ad-hoc aes key
+ iwpriv mlan0 adhocaes "1;12345678901234567890123456789012"
+ : Set ad-hoc aes key
+ iwpriv mlan0 adhocaes 2 : Clear ad-hoc aes key
+
+bandcfg
+ This command is used to set/get infra/ad-hoc band.
+ Note: This command is only available in disconnected state.
+
+ Usage:
+ iwpriv mlanX bandcfg [l] [m] [n]
+
+ where the parameters:
+ [l]: Infrastructure band
+ bit 0: B
+ bit 1: G
+ bit 2: A
+ bit 3: GN
+ bit 4: AN
+
+ [m]: Ad-hoc start band
+ bit 0: B
+ bit 1: G
+ bit 2: A
+ bit 3: GN
+ bit 4: AN
+ [n]: Ad-hoc start channel
+
+ Examples:
+ iwpriv mlan0 bandcfg : Get infra/ad-hoc band and ad-hoc
+ start channel configurations
+ iwpriv mlan0 bandcfg 1 : Set infra band to B only
+ iwpriv mlan0 bandcfg 3 2 6 : Set infra band to B/G, ad-hoc start band
+ to G and ad-hoc start channel to 6
+
+getlog
+ This command is used to get the statistics available in the station.
+
+11dcfg
+ This command is used to control 11D. No argument is used to get.
+
+ where value of n is:
+ 0 -- Disable
+ 1 -- Enable
+
+ Examples:
+ iwpriv mlan0 11dcfg 1 : Enable 11D
+ iwpriv mlan0 11dcfg : Get 11D status
+
+wmmcfg
+ This command is used to control WMM. No argument is used to get.
+
+ where value of n is:
+ 0 -- Disable
+ 1 -- Enable
+
+ Examples:
+ iwpriv mlan0 wmmcfg 1 : Enable WMM
+ iwpriv mlan0 wmmcfg : Get WMM status
+
+txpowercfg
+ This command is used to get/set the Tx power configuration.
+
+ Where
+ <RateIndex> - Data rate index
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 6 Mbps
+ 5 9 Mbps
+ 6 12 Mbps
+ 7 18 Mbps
+ 8 24 Mbps
+ 9 36 Mbps
+ 10 48 Mbps
+ 11 54 Mbps
+ 12 MCS0 (BW20)
+ 13 MCS1 (BW20)
+ 14 MCS2 (BW20)
+ 15 MCS3 (BW20)
+ 16 MCS4 (BW20)
+ 17 MCS5 (BW20)
+ 18 MCS6 (BW20)
+ 19 MCS7 (BW20)
+ 140 MCS0 (BW40)
+ 141 MCS1 (BW40)
+ 142 MCS2 (BW40)
+ 143 MCS3 (BW40)
+ 144 MCS4 (BW40)
+ 145 MCS5 (BW40)
+ 146 MCS6 (BW40)
+ 147 MCS7 (BW40)
+ 0xff Default
+ <MinPwr> - Minimum power level in dBm
+ <MaxPwr> - Maximum power level in dBm
+ <step> - Power step
+
+ Note: Firmware may adjust the setting if over limit, use get command to
+ check the current setting.
+
+ Examples:
+ iwpriv mlan0 txpowercfg 0xff : Default power configuration
+ iwpriv mlan0 txpowercfg 11 12 : Set power level 12 dBm to data rate 54 Mbps
+ iwpriv mlan0 txpowercfg 7 11 16 1 : Set power level 11 dBm to 16 dBm with
+ step 1 to data rate 18 Mbps
+ iwpriv mlan0 txpowercfg : Get current configuration
+ mlan0 txpowercfg:2 3 13 18 2 1 1 13 18 2 0 0 13 18 2
+ 10 11 13 15 2 8 9 13 16 2 6 7 13 17 2 4 5 13 17 2
+ 17 19 13 15 2 15 16 13 16 2 13 14 13 17 2 12 12 13 17 2
+ 145 147 13 14 1 143 144 13 14 1 141 142 13 14 1 140 140 13 14 1
+
+ 2 -> First rate index is 5.5 Mbps.
+ 3 -> Last rate index is 11 Mbps.
+ 13 -> Min Tx power value is 13 dBm.
+ 18 -> Max Tx power value is 18 dBm.
+ 2 -> Power adjustment step value is 2.
+
+ Similarly
+ 17 -> First rate index is MCS5 (BW20).
+ 19 -> Last rate index is MCS7 (BW20).
+ 13 -> Min Tx power value is 13 dBm.
+ 15 -> Max Tx power value is 15 dBm.
+ 2 -> Power adjustment step value is 2.
+
+ so on...
+
+qoscfg
+ This command sets WMM IE QOS info when an argument is given, and gets current WMM
+ IE QOS info when no argument is given.
+
+ Examples:
+ iwpriv mlan0 qoscfg 0x0f : Set WMM IE QOS info to 0x0f
+ iwpriv mlan0 qoscfg : Get WMM IE QOS info
+
+getdatarate
+ This command is used to get the data rate (index) being used in last Tx
+ packet and last Rx packet.
+
+txratecfg
+ This command is used to set/get the transmit data rate.
+
+ Note:
+ 1) The data rate can be set only after association.
+
+ 2) If the reassoc is OFF driver reset the data rate to auto if the connection state is disconnected.
+ Please note that user has to re-issue the set data rate command if the driver is disconnected.
+
+ 3) If the reassoc is ON driver remembers the data rate set by the user, if the driver is
+ disconnected user does not have to re-issue the set data rate again.
+
+ Where <n>
+ data rate
+ Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 6 Mbps
+ 5 9 Mbps
+ 6 12 Mbps
+ 7 18 Mbps
+ 8 24 Mbps
+ 9 36 Mbps
+ 10 48 Mbps
+ 11 54 Mbps
+ 12 MCS0
+ 13 MCS1
+ 14 MCS2
+ 15 MCS3
+ 16 MCS4
+ 17 MCS5
+ 18 MCS6
+ 19 MCS7
+ 44 MCS32
+ 0xff Auto
+
+ Examples:
+ iwpriv mlan0 txratecfg 3 : Set fixed Tx rate to 11 Mbps
+ iwpriv mlan0 txratecfg 11 : Set fixed Tx rate to 54 Mbps
+ iwpriv mlan0 txratecfg 15 : Set fixed Tx rate to MCS3
+ iwpriv mlan0 txratecfg 0xff : Disable fixed rate and uses auto rate
+ iwpriv mlan0 txratecfg : Read the current data rate setting
+
+bcninterval
+ This command is used to set/get the beacon interval in ad-hoc mode.
+ The valid beacon interval is between 20 - 1000, default beacon
+ interval is 100.
+
+ Where <n>
+ Beacon interval in TU (Time Unit: 1024 us).
+
+ Examples:
+ iwpriv mlan0 bcninterval 200 : Set ad-hoc beacon interval to 200
+ iwpriv mlan0 bcninterval : Get ad-hoc beacon interval
+
+sysclock
+ This command is used to set/get system clocks in MHz.
+ The current system clock, configurable system clocks and all of the
+ supported system clocks will be returned if no parameter provided.
+
+ Examples:
+ iwpriv mlan0 sysclock : Get system clocks
+ 80 80 128 128 128 5 11 16 20 22 32 40 44 64 80 106 128 160
+ (The current system clock is 80 MHz.
+ The configurable system clocks of non-security, security, non-security
+ A-MPDU and security A-MPDU are 80 MHz, 128 MHz, 128 MHz and 128 MHz.
+ The supported system clocks are 5 MHz, 11 MHz, ..., 160 MHz.)
+
+ iwpriv mlanX sysclock 80 : Set system clock in non-security mode
+ to 80 MHz, no change for others
+ iwpriv mlanX sysclock 0 0 128 : Set system clock in non-security A-MPDU
+ mode to 128 MHz, no changes for others
+
+ldocfg
+ This command is used to set/get internal/external core power voltage source.
+ By default firmware uses internal LDO for 1.2V core power supply.
+ The current setting will be returned if no parameter provided.
+
+ Usage:
+ iwpriv mlanX ldocfg [n]
+
+ where the parameter is,
+ 0 -- internal
+ 1 -- external
+
+drvdbg
+ This command is used to set/get the bit masks of driver debug message control.
+
+ Usage:
+ iwpriv mlanX drvdbg [n] [m]
+
+ Where the parameter <n> is the generic debug message control bit mask.
+ The following types of driver debug messages can be dynamically enabled or
+ disabled by setting or clearing the corresponding bits,
+ bit 0: MMSG PRINTM(MMSG,...)
+ bit 1: MFATAL PRINTM(MFATAL,...)
+ bit 2: MERROR PRINTM(MERROR,...)
+ bit 3: MDATA PRINTM(MDATA,...)
+ bit 4: MCMND PRINTM(MCMND,...)
+ bit 5: MEVENT PRINTM(MEVENT,...)
+ bit 6: MINTR PRINTM(MINTR,...)
+ ...
+ bit 16: MDAT_D PRINTM(MDAT_D,...), DBG_HEXDUMP(MDAT_D,...)
+ bit 17: MCMD_D PRINTM(MCMD_D,...), DBG_HEXDUMP(MCMD_D,...)
+ bit 18: MFW_D PRINTM(MFW_D,...)
+ ...
+ bit 28: MENTRY PRINTM(MENTRY,...), ENTER(), LEAVE()
+ bit 29: MWARN PRINTM(MWARN,...)
+ bit 30: MINFO PRINTM(MINFO,...)
+
+ Where the parameter <m> is the extended interface module debug message control
+ bit mask. The following types of debug messages can be controlled.
+
+ bit 0: MIF_D PRINTM(MIF_D,...), DBG_HEXDUMP(MIF_D,...)
+
+ If CONFIG_DEBUG=2, all kinds of debug messages can be configured.
+ By default all debug messages are enabled except for MEVENT and MIF_D.
+
+ If CONFIG_DEBUG=1, all kinds of debug messages can be configured except
+ for MENTRY, MWARN and MINFO. By default MMSG, MFATAL and MERROR are enabled.
+
+ Some special debug messages,
+ '*' // MLAN driver ISR is called (bit 6 MINTR enabled)
+ '|' // PS awake event is received (bit 5 MEVENT enabled)
+ '_' // PS sleep event is received (bit 5 MEVENT enabled)
+ '+' // PS sleep confirm is sent (bit 5 MEVENT enabled)
+
+ Examples:
+ iwpriv mlan0 drvdbg : Get the current driver debug masks
+ iwpriv mlan0 drvdbg 0 0 : Disable all the debug messages
+ iwpriv mlan0 drvdbg 7 : Enable MMSG, MFATAL and MERROR messages,
+ no change for if debug control
+ iwpriv mlan0 drvdbg 3 1 : Enable MMSG and MFATAL messages,
+ enable MIF_D message
+ iwpriv mlan0 drvdbg -1 -1 : Enable all the debug messages
+
+warmreset
+ This command is used for warm reset of the interface.
+
+ Usage:
+ iwpriv mlanX warmreset
+
+regrdwr
+ This command is used to read/write the adapter register.
+
+ Usage:
+ iwpriv mlanX regrdwr <type> <offset> [value]
+
+ where the parameters are,
+ <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
+ <offset>: offset of register
+ [value]: value to be written
+ Note: If highest bit of a 32-bit value needs to be set, use negitive input.
+
+ Examples:
+ iwpriv mlan0 regrdwr 1 0xa060 : Read the MAC register
+ iwpriv mlan0 regrdwr 1 0xa060 0x12 : Write the MAC register
+ iwpriv mlan0 regrdwr 1 0xa794 -0x80000000
+ : Write 0x80000000 to MAC register
+ iwpriv mlan0 regrdwr 1 0xa794 -0x00000001
+ : Write 0xffffffff to MAC register
+
+rdeeprom
+ This command is used to read the EEPROM contents of the card.
+
+ Usage:
+ iwpriv mlanX rdeeprom <offset> <length>
+
+ where the parameters are,
+ <offset>: multiples of 4
+ <length>: 4-20, multiples of 4
+
+ Example:
+ iwpriv mlan0 rdeeprom 0 20 : Read 20 bytes of EEPROM data from offset 0
+
+memrdwr
+ This command is used to read/write the adapter memory.
+
+ Usage:
+ iwpriv mlanX memrdwr <address> [value]
+
+ where the parameters are,
+ <address>: memory address
+ [value]: value to be written
+ Note: If highest bit of a 32-bit value needs to be set, use negitive input.
+
+ Examples:
+ iwpriv mlan0 memrdwr -0x80000000
+ : Read memory address 0x80000000
+ iwpriv mlan0 memrdwr -0x80000000 -0x00000001
+ : Write 0xffffffff to memory address 0x80000000
+
+inactivityto
+ This command is used to set/get the inactivity timeout value, which specifies
+ when WLAN device is put to sleep.
+
+ Usage:
+ iwpriv mlanX inactivityto <n> <m> <l> [k]
+
+ where the parameter are:
+ <n>: timeout unit in microseconds.
+ <m>: Inactivity timeout for unicast data.
+ <l>: Inactivity timeout for multicast data.
+ [k]: Inactivity timeout for new Rx traffic after PS notification to AP.
+
+ Examples:
+ iwpriv mlan0 inactivityto : Get the timeout value
+ iwpriv mlan0 inactivityto 1000 2 3 : Set timeout unit to 1000 us (1 ms),
+ inactivity timeout for unicast data is 2 ms,
+ inactivity timeout for multicast data is 3 ms
+
+bcats
+ This command is used to set/get the BCA timeshare parameters.
+ This command only works after BCA has been enabled.
+
+ Usage:
+ iwpriv mlanX bcats <traffic_type> [<timeshare_interval> <bt_time>]
+
+ where:
+ <traffic_type>: 0 - Wlan and bluetooth are low priority.
+ 1 - Wlan and bluetooth are high priority.
+ 2 - Wlan and bluetooth are medium priority.
+ 3 - Wlan and bluetooth are medium high priority.
+ 0xffff - Reset fairshare.
+
+ If <timeshare_interval> value is not multiple of 10 then floor value
+ is taken and the valid range is <20 ... 60,000> in milliseconds.
+
+ If <bt_time> value is not multiple of 10 then floor value is taken
+ and the valid range is <0 ... timeshare_interval value> in milliseconds.
+
+ Examples:
+ iwpriv mlan0 bcats 1 : Get the BCA timeshare settings when wlan
+ and bluetooth are set to high priority
+ iwpriv mlan0 bcats 0xffff : Reset fairshare, disable all modes above
+ that are running, and restore arbitration
+ table register values to before the user
+ enabled any of the above fairshare modes.
+ iwpriv mlan0 bcats 1 30 20 : Set wlan and bluetooth to high priority,
+ wlan timeshare_interval to 30 ms and
+ bt_time to 20 ms
+
+sdioclock
+ Turn On(1) or Off(0) the SDIO clock.
+
+ Usage:
+ iwpriv mlanX sdioclock 1 (on)
+ iwpriv mlanX sdioclock 0 (off)
+ iwpriv mlanX sdioclock (get the current clock state)
+
+scancfg
+ This command is used to set/get scan configuration parameters.
+
+ Usage:
+ iwpriv mlanX scancfg [t] [m] [p] [s] [a] [b]
+
+ where the parameters:
+ [t]: Scan Type (0: Unchanged, 1: Active, 2: Passive)
+ [m]: Scan Mode (0: Unchanged, 1: BSS, 2: IBSS, 3: Any)
+ [p]: Scan Probes (0: Unchanged, 1-10: Number of probes per channel)
+ [s]: Specific Scan Time (0: Unchanged, n: Value in ms, default 110 ms, max 500 ms)
+ [a]: Active Scan Time (0: Unchanged, n: Value in ms, default 200 ms, max 500 ms)
+ [b]: Passive Scan Time (0: Unchanged, n: Value in ms, default 200 ms, max 2000 ms)
+ No change if the parameter is 0 or the parameter is not provided.
+
+ Examples:
+ iwpriv mlan0 scancfg : Get all the current scan configuration settings
+ iwpriv mlan0 scancfg 1 3 : Set scan type to active and scan mode to any,
+ all the other scan configurations are unchanged
+ iwpriv mlan0 scancfg 0 1 2 200 : Set scan mode to BSS, number of probes to 2 and
+ specific scan time to 200 ms, all the other scan
+ configurations are unchanged
+
+vsiecfg
+ This command is used to get/add/remove vendor specific IE.
+
+ Usage:
+ iwpriv mlanX vsiecfg <action> <id> [<mask> [data1] ... [dataN]]
+
+ where:
+ <action>: 0/1/2: Get/Add/Remove
+ <id>: 0-7: IE index in the driver IE array
+ [mask]: Bit 0: IE for scan
+ Bit 1: IE for associate
+ Bit 2: IE for ad-hoc
+ [data1]...[dataN]: IE data
+
+ Note: The max data length is 254-byte, IE ID (221) and length is not included.
+ The max total length of vendor specific IEs for scan/assoc/ad-hoc is 512-byte.
+
+ Examples:
+ iwpriv mlan0 vsiecfg 0 2 : Get the 3rd IE
+ iwpriv mlan0 vsiecfg 1 0 4 0x12 0x34
+ : Add IE in 1st position for ad-hoc
+ iwpriv mlan0 vsiecfg 1 6 3 0x00 0x50 0x43 0x20 0xFF 0xFE
+ : Add IE in 7th position for scan and associate
+ iwpriv mlan0 vsiecfg 2 1 : Remove the 2nd IE
+
+sleeppd
+ This command is used to configure the sleep period of the WLAN device.
+
+ Usage:
+ iwpriv mlanX sleeppd [<period>]
+
+ Where the parameter is:
+ period: sleep period in milliseconds. Range 10~60. 0 for disable.
+
+ Examples:
+ iwpriv mlan0 sleeppd : Get sleep period configuration
+ iwpriv mlan0 sleeppd 10 : Set sleep period to 10 ms
+
+pscfg
+ This command is used to set/get PS configuration parameters.
+
+ Usage:
+ iwpriv mlanX pscfg [k] [d] [l] ...
+
+ Where the parameters:
+ [k]: Keep alive null packet interval (0: Unchanged, -1: Disable, n: Interval in seconds)
+ [d]: DTIM interval (0: Unchanged, 1-5: Value, 65534: DTIM will be ignored
+ in firmware, listen interval will be used)
+ [l]: Local listen interval (0: Unchanged, n: Interval)
+ [a]: Ad-hoc awake period (0: Unchanged, 1-31: Beacon interval, 255: Firmware
+ will go to sleep after beacon send out)
+ [b]: Beacon miss timeout (0: Unchanged, 1-50: Value in milliseconds, 65535: Disable)
+ [p]: Delay to PS (0-65535: Value in milliseconds)
+ [m]: PS mode (0: Unchanged, 1: Auto mode, 2: PS-Poll mode, 3: PS Null mode)
+ No change if parameters are not provided.
+
+ Examples:
+ iwpriv mlan0 pscfg : Get all the current PS configuration settings
+ iwpriv mlan0 pscfg 3 4 : Set PS keep alive null packet interval to 3 seconds
+ and DTIM interval to 4, all the other configurations
+ are unchanged
+ iwpriv mlan0 pscfg 0 0xfffe 10 0 20
+ : Disable DTIM interval, set local listen interval to
+ 10 beacon intervals and beacon miss interval to 20,
+ all the other configurations are unchanged
+ iwpriv mlan0 pscfg 0 0 0 0 0 50 : Set delay to PS to 50 ms, keep the others unchanged
+
+sleepparams
+ This command is used to set the sleepclock configurations
+
+ Usage:
+ iwpriv mlanX sleepparams [<p1> <p2> <p3> <p4> <p5> <p6>]
+
+ where:
+ p1 is Sleep clock error in ppm (0-65535)
+ p2 is Wakeup offset in usec (0-65535)
+ p3 is Clock stabilization time in usec (0-65535)
+ p4 is Control periodic calibration (0-2)
+ p5 is Control the use of external sleep clock (0-2)
+ p6 is reserved for debug (0-65535)
+
+ Examples:
+ iwpriv mlan0 sleepparams : Get current sleepclock configuration
+ iwpriv mlan0 sleepparams 10 1000 2000 1 0 128 : Set sleepclock configuration
+
+authtype
+ This command is used to set/get authentication type.
+
+ Usage:
+ iwpriv mlanX authtype [n]
+
+ where <n>
+ 0: 802.11 open system authentication.
+ 1: 802.11 shared key authentication.
+ 255: allow open system or shared key authentication.
+
+ Examples:
+ iwpriv mlan0 authtype 0 : use open system authentication
+ iwpriv mlan0 authtype 1 : use shared key authentication
+ iwpriv mlan0 authtype 255 : allow open system or shared key authentication
+ iwpriv mlan0 authtype : get current setting
+
+
+===============================================================================
+ U S E R M A N U A L F O R M L A N C O N F I G
+
+NAME
+mlanconfig - configure the additional parameters available for the Marvell mdriver.
+
+SYNOPSIS
+mlanconfig -v
+mlanconfig <mlanX> <command> [parameters] ...
+
+mlanconfig mlanX hostcmd <bg_scan.conf> bgscfg
+mlanconfig mlanX hostcmd <requesttpc.conf> requesttpc
+mlanconfig mlanX hostcmd <crypto_test.conf> crypto_test
+mlanconfig mlanX hostcmd <subevent.conf> subevent_get
+mlanconfig mlanX hostcmd <subevent.conf> subevent_set
+mlanconfig mlanX hostcmd <auto_tx.conf> auto_tx_get
+mlanconfig mlanX hostcmd <auto_tx.conf> nat_keep_alive
+mlanconfig mlanX hostcmd <auto_tx.conf> auto_tx_unreg
+mlanconfig mlanX hostcmd <txrate_cfg.conf> txrate_cfg_get
+mlanconfig mlanX hostcmd <txrate_cfg.conf> txrate_cfg_set_bg
+mlanconfig mlanX hostcmd <txrate_cfg.conf> txrate_cfg_set_bgn
+mlanconfig mlanX hostcmd <txpwrlimit_cfg.conf> txpwrlimit_cfg_get
+mlanconfig mlanX hostcmd <txpwrlimit_cfg.conf> txpwrlimit_cfg_set
+mlanconfig mlanX hostcmd <11n_2040coex.conf> 2040coex
+mlanconfig mlanX hostcmd <robust_btc.conf> robust_btc_get
+mlanconfig mlanX hostcmd <robust_btc.conf> robust_btc_enable
+mlanconfig mlanX hostcmd <robust_btc.conf> robust_btc_disable
+mlanconfig mlanX arpfilter <arpfilter.conf>
+mlanconfig mlanX mefcfg <mef.conf>
+mlanconfig mlanX cfgdata <register type> <conf file>
+mlanconfig mlanX sdcmd52rw <FN no.> <address> [data]
+mlanconfig mlanX sdcmd53rw <FN no.> <address> <mode> <blksize> <blknum> [data1] ... [dataN]
+mlanconfig mlanX setuserscan [ARGS]
+mlanconfig mlanX getscantable
+mlanconfig mlanX addts <filename.conf> <section# of tspec> <timeout in ms>
+mlanconfig mlanX delts <filename.conf> <section# of tspec>
+mlanconfig mlanX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
+mlanconfig mlanX qconfig get [Queue Id: 0-3]
+mlanconfig mlanX qconfig def [Queue Id: 0-3]
+mlanconfig mlanX qstats on [Queue Id: 0-3]
+mlanconfig mlanX qstats off [Queue Id: 0-3]
+mlanconfig mlanX qstats get [Queue Id: 0-3]
+mlanconfig mlanX qstatus
+mlanconfig mlanX ts_status
+mlanconfig mlanX regrdwr <type> <offset> [value]
+
+DESCRIPTION
+
+Those commands are used in Marvell specific application called mlanconfig.
+
+===========
+-v
+ This command is used to display the version of mlanconfig utility.
+ Usage:
+ mlanconfig -v
+
+hostcmd bgscfg
+ This command is used to configure the various parameters for PPS/UAPSD
+ or normal background scan.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/bg_scan.conf bgscfg
+
+hostcmd requesttpc
+ This command is used to request 802.11H TPC info.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/requesttpc.conf requesttpc
+
+hostcmd crypto_test
+ This command is used to test the encryption/decryption API of the firmware.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/crypto_test.conf crypto_test
+
+hostcmd subevent_get
+hostcmd subevent_set
+ This command is used to get/set the configurations for event descriptor
+ interface command.
+ subsvent_get: get subscribed event parameters
+ subsvent_set: set subscribed event parameters
+
+ Usage:
+ mlanconfig mlanX hostcmd config/subevent.conf subevent_get
+ mlanconfig mlanX hostcmd config/subevent.conf subevent_set
+
+hostcmd auto_tx_get
+hostcmd nat_keep_alive
+hostcmd auto_tx_unreg
+ This command is used to configures the Frame Auto Transmission parameters.
+ auto_tx_get: get auto_tx parameters
+ nat_keep_alive: register to firmware for sending NAT Keep Alive packet
+ auto_tx_unreg: unregister to firmware auto_tx
+
+ Usage:
+ mlanconfig mlanX hostcmd config/auto_tx.conf auto_tx_get
+ mlanconfig mlanX hostcmd config/auto_tx.conf nat_keep_alive
+ mlanconfig mlanX hostcmd config/auto_tx.conf auto_tx_unreg
+
+hostcmd txrate_cfg_get
+hostcmd txrate_cfg_set_bg
+hostcmd txrate_cfg_set_bgn
+ This command is used to set/get the transmit data rate.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/txrate_cfg.conf txrate_cfg_get
+ mlanconfig mlanX hostcmd config/txrate_cfg.conf txrate_cfg_set_bg
+ mlanconfig mlanX hostcmd config/txrate_cfg.conf txrate_cfg_set_bgn
+
+hostcmd txpwrlimit_cfg_get
+hostcmd txpwrlimit_cfg_set
+ This command is used to set/get the configuration data of Tx power limitation.
+ Note: The configuration set should be issued when STA is disconnetced.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/txpwrlimit_cfg.conf txpwrlimit_cfg_get
+ mlanconfig mlanX hostcmd config/txpwrlimit_cfg.conf txpwrlimit_cfg_set
+
+hostcmd 2040coex
+ This command is used to send the 11n 20/40 Coex command to firmware.
+ Firmware will send 11n 20/40 Coex management action frame to AP.
+
+ Usage:
+ mlanconfig mlanX hostcmd config/11n_2040coex.conf 2040coex
+
+hostcmd robust_btc_get
+hostcmd robust_btc_enable
+hostcmd robust_btc_disable
+ This command is used to get/set Robust BT Coex.
+ robust_btc_get: get the current configuration
+ robust_btc_enable: enable and set the Robust BT Coex timing
+ robust_btc_disable: disable the Robust BT Coex
+
+ Usage:
+ mlanconfig mlanX hostcmd config/robust_btc.conf robust_btc_get
+ mlanconfig mlanX hostcmd config/robust_btc.conf robust_btc_enable
+ mlanconfig mlanX hostcmd config/robust_btc.conf robust_btc_disable
+
+arpfilter
+ This command is used to configure the ARP filtering parameters.
+
+ Usage:
+ mlanconfig mlanX arpfilter config/arpfilter.conf
+
+mefcfg
+ This command is used to set MEF settings.
+
+ Usage:
+ mlanconfig mlanX mefcfg config/mef.conf
+
+cfgdata
+ This command is used to set/get the configuration data to/from firmware.
+
+ Usage:
+ mlanconfig mlanX cfgdata <type> <.conf file name>
+ This command is used to set the cfg data in the .conf file to firmware.
+
+ mlanconfig mlanX cfgdata <type>
+ This command is used to get the cfg data from firmware and display
+ on to the console.
+
+ Where the value of <type> field is:
+ 1 -- Optimal Register download and <.conf file name > is or_data.conf
+ 2 -- Cal data download and <.conf file name> is cal_data.conf
+ 3 -- PMIC data download and <.conf file name> is pmic_data.conf
+
+sdcmd52rw
+ This command is used to read/write a controller register in
+ Secure Digital I/O Interfaces.
+
+ Usage:
+ mlanconfig mlanX sdcmd52rw <function number> <register address> [value]
+
+ Examples:
+ mlanconfig mlan0 sdcmd52rw 1 3
+ mlanconfig mlan0 sdcmd52rw 1 1 0x3f
+
+sdcmd53rw
+ This command is used to issue a CMD53 read/write data in
+ Secure Digital I/O Interfaces.
+
+ Usage:
+ mlanconfig mlanX sdcmd53rw <func> <address> <mode> <blksize> <blknum> [data1] ... [dataN]
+
+ where the parameters are,
+ <func>: function number (0/1/2/..)
+ <address>: data address
+ <mode>: byte mode/block mode (0/1)
+ <blksize>: block size (32/64/../512, NA for byte mode)
+ <blknum>: block number or byte number
+ <data1> ... <dataN>: data for write
+
+ Note: The total data length is block size * block number for block mode
+ or byte number for byte mode. The max data length is 2000-byte.
+ For write the data pattern will be duplicated to data buffer.
+
+ Examples:
+ mlanconfig mlan0 sdcmd53rw 0 0x8000 1 64 2
+ mlanconfig mlan0 sdcmd53rw 1 0x10000 0 1 5 0x0a 0x0b 0x0c 0x0d 0x0e
+
+setuserscan
+ Initiate a customized scan and retrieve the results
+
+ Usage:
+ mlanconfig mlanX setuserscan [ARGS]
+
+ Where [ARGS]:
+ ssid="[SSID]" specify a SSID filter for the scan
+ chan=[chan#][band][mode] where band is [a,b,g,n] and mode is
+ blank for active or 'p' for passive
+ bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
+ wc="[WILDCARD SSID]" specify a UNIX pattern matching filter (using *
+ and ?) for SSIDs found in a broadcast probe
+ keep=[0 or 1] keep the previous scan results (1), discard (0)
+ dur=[scan time] time to scan for each channel in milliseconds
+ probes=[#] number of probe requests to send on each chan
+ for each broadcast probe required and each SSID
+ specific probe required (1-10)
+ type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+ Any combination of the above arguments can be supplied on the command line.
+ If the chan token is absent, a full channel scan will be completed by driver.
+ If the dur or probes tokens are absent, the driver default setting will be
+ used. The bssid and ssid fields, if blank, will produce an unfiltered scan.
+ The type field will default to 3 (Any) and the keep field will default to 0
+ (Discard).
+
+ Examples:
+ 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+ setuserscan chan=1g,6g,11g
+
+ 2) Perform a passive scan on channel 11 for 20 ms:
+ setuserscan chan=11gp dur=20
+
+ 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+ channel 36 in the 'a' band:
+ setuserscan chan=1g,6g,11g,36ap
+
+ 4) Perform an active scan on channel 6 and 36 for a specific SSID:
+ setuserscan chan=6g,36a ssid="TestAP"
+
+ 5) Scan all available channels (B/G/N, A bands) for a specific BSSID, keep
+ the current scan table intact, update existing or append new scan data:
+ setuserscan bssid=00:50:43:20:12:82 keep=1
+
+ 6) Scan channel 6, for all infrastructure networks, sending two probe
+ requests. Keep the previous scan table intact. Update any duplicate
+ BSSID/SSID matches with the new scan data:
+ setuserscan chan=6g type=1 probes=2 keep=1
+
+ 7) Scan channel 1 and 6, for all networks matching the Mrvl*AP
+ or AP*Mrvl? patterns and for MrvlTst SSID. Generate 3 broadcast
+ probes for the patterns and 3 SSID specific probes for MrvlTst on
+ both channel 1 and channel 6.
+ setuserscan chan=1g,6g probes=3 wc="Mrvl*AP" wc="AP*Mrvl?" ssid="MrvlTst"
+
+ 8) Scan all the channels for specified band.
+ setuserscan chan=0g
+
+ All entries in the scan table (not just the new scan data when keep=1)
+ will be displayed upon completion by use of the getscantable ioctl.
+
+getscantable
+ Display the current contents of the driver scan table
+
+ Usage:
+ mlanconfig mlanX getscantable
+ mlanconfig mlanX getscantable [#]
+ mlanconfig mlanX getscantable tsf
+ mlanconfig mlanX getscantable help
+
+ 1) Without argument, the entire scantable is displayed.
+ 2) Specifying a # will display detailed information about a specific scan
+ table entry. '0' displays driver cached information regarding the
+ current association (if any).
+ 3) The tsf argument will display the entire scan table with the recorded
+ TSF timestamp for the entry.
+ 4) The help argument will display the legend for the capability field.
+
+addts
+ Send an ADDTS command to the associated AP.
+
+ Process a given conf file for a specific TSPEC data block. Send the
+ TSPEC along with any other IEs to the driver/firmware for transmission
+ in an ADDTS request to the associated AP.
+
+ Return the execution status of the command as well as the ADDTS response
+ from the AP if any.
+
+ Usage:
+ mlanconfig mlanX addts <filename.conf> <section# of tspec> <timeout(ms)>
+
+delts
+ Send a DELTS command to the associated AP.
+
+ Process a given conf file for a specific TSPEC data block. Send the
+ TSPEC along with any other IEs to the driver/firmware for transmission
+ in a DELTS request to the associated AP.
+
+ Return the execution status of the command. There is no response to a
+ DELTS from the AP.
+
+ Usage:
+ mlanconfig mlanX delts <filename.conf> <section# of tspec>
+
+qconfig
+ Send a WMM AC Queue configuration command to get/set/default params
+
+ Configure or get the parameters of a WMM AC queue. The command takes
+ an optional Queue Id as a last parameter. Without the queue id, all
+ queues will be acted upon.
+
+ Usage:
+ mlanconfig mlanX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
+ mlanconfig mlanX qconfig get [Queue Id: 0-3]
+ mlanconfig mlanX qconfig def [Queue Id: 0-3]
+
+qstats
+ Turn on/off or retrieve and clear the queue statistics for an AC
+
+ Turn the queue statistics collection on/off for a given AC or retrieve the
+ current accumulated stats and clear them from the firmware. The command
+ takes an optional Queue Id as a last parameter. Without the queue id,
+ all queues will be acted upon.
+
+ Usage:
+ mlanconfig mlanX qstats on [Queue Id: 0-3]
+ mlanconfig mlanX qstats off [Queue Id: 0-3]
+ mlanconfig mlanX qstats get [Queue Id: 0-3]
+
+qstatus
+ This command retrieves the current status of the WMM queues. If WMM
+ is enabled then it displays the informations for each AC in a table.
+
+ Usage:
+ mlanconfig mlanX qstatus
+
+ts_status
+ This command queries the FW for the status of TSIDs 0 through 7
+ configured via call admission control and displays the results in a
+ table.
+
+ Usage:
+ mlanconfig mlanX ts_status
+
+regrdwr
+ This command is used to read/write the adapter register.
+
+ Usage:
+ mlanconfig mlanX regrdwr <type> <offset> [value]
+
+ where the parameters are,
+ <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
+ <offset>: offset of register
+ [value]: value to be written
+
+ Examples:
+ mlanconfig mlan0 regrdwr 1 0xa060 : Read the MAC register
+ mlanconfig mlan0 regrdwr 1 0xa794 0x80000000
+ : Write 0x80000000 to MAC register
+
+
+===============================================================================
+ U S E R M A N U A L F O R M L A N 2 0 4 0 C O E X
+
+NAME
+mlan2040coex - This application handles the 11n 20/40 coexistence operation for
+ the Marvell mdriver
+
+SYNOPSIS
+mlan2040coex [-i <intfname>] [hvB]
+(If intfname not present then mlan0 assumed)
+ -h = Help
+ -v = Version
+ -B = Run the process in background
+
+===============================================================================
diff --git a/wlan_src/gpl-2.0.txt b/wlan_src/gpl-2.0.txt
new file mode 100755
index 0000000..58ca40e
--- /dev/null
+++ b/wlan_src/gpl-2.0.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+ freedom to share and change it. By contrast, the GNU General Public
+ License is intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users. This
+ General Public License applies to most of the Free Software
+ Foundation's software and to any other program whose authors commit to
+ using it. (Some other Free Software Foundation software is covered by
+ the GNU Lesser General Public License instead.) You can apply it to
+ your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ this service if you wish), that you receive source code or can get it
+ if you want it, that you can change the software or use pieces of it
+ in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+ gratis or for a fee, you must give the recipients all the rights that
+ you have. You must make sure that they, too, receive or can get the
+ source code. And you must show them these terms so they know their
+ rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+ (2) offer you this license which gives you legal permission to copy,
+ distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+ that everyone understands that there is no warranty for this free
+ software. If the software is modified by someone else and passed on, we
+ want its recipients to know that what they have is not the original, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that redistributors of a free
+ program will individually obtain patent licenses, in effect making the
+ program proprietary. To prevent this, we have made it clear that any
+ patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+ a notice placed by the copyright holder saying it may be distributed
+ under the terms of this General Public License. The "Program", below,
+ refers to any such program or work, and a "work based on the Program"
+ means either the Program or any derivative work under copyright law:
+ that is to say, a work containing the Program or a portion of it,
+ either verbatim or with modifications and/or translated into another
+ language. (Hereinafter, translation is included without limitation in
+ the term "modification".) Each licensee is addressed as "you".
+
+ Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of
+ running the Program is not restricted, and the output from the Program
+ is covered only if its contents constitute a work based on the
+ Program (independent of having been made by running the Program).
+ Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+ source code as you receive it, in any medium, provided that you
+ conspicuously and appropriately publish on each copy an appropriate
+ copyright notice and disclaimer of warranty; keep intact all the
+ notices that refer to this License and to the absence of any warranty;
+ and give any other recipients of the Program a copy of this License
+ along with the Program.
+
+ You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+ of it, thus forming a work based on the Program, and copy and
+ distribute such modifications or work under the terms of Section 1
+ above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Program,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Program, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote it.
+
+ Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Program.
+
+ In addition, mere aggregation of another work not based on the Program
+ with the Program (or with a work based on the Program) on a volume of
+ a storage or distribution medium does not bring the other work under
+ the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms of
+ Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+ The source code for a work means the preferred form of the work for
+ making modifications to it. For an executable work, complete source
+ code means all the source code for all modules it contains, plus any
+ associated interface definition files, plus the scripts used to
+ control compilation and installation of the executable. However, as a
+ special exception, the source code distributed need not include
+ anything that is normally distributed (in either source or binary
+ form) with the major components (compiler, kernel, and so on) of the
+ operating system on which the executable runs, unless that component
+ itself accompanies the executable.
+
+ If distribution of executable or object code is made by offering
+ access to copy from a designated place, then offering equivalent
+ access to copy the source code from the same place counts as
+ distribution of the source code, even though third parties are not
+ compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt
+ otherwise to copy, modify, sublicense or distribute the Program is
+ void, and will automatically terminate your rights under this License.
+ However, parties who have received copies, or rights, from you under
+ this License will not have their licenses terminated so long as such
+ parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify or
+ distribute the Program or its derivative works. These actions are
+ prohibited by law if you do not accept this License. Therefore, by
+ modifying or distributing the Program (or any work based on the
+ Program), you indicate your acceptance of this License to do so, and
+ all its terms and conditions for copying, distributing or modifying
+ the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program subject to
+ these terms and conditions. You may not impose any further
+ restrictions on the recipients' exercise of the rights granted herein.
+ You are not responsible for enforcing compliance by third parties to
+ this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot
+ distribute so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you
+ may not distribute the Program at all. For example, if a patent
+ license would not permit royalty-free redistribution of the Program by
+ all those who receive copies directly or indirectly through you, then
+ the only way you could satisfy both it and this License would be to
+ refrain entirely from distribution of the Program.
+
+ If any portion of this section is held invalid or unenforceable under
+ any particular circumstance, the balance of the section is intended to
+ apply and the section as a whole is intended to apply in other
+ circumstances.
+
+ It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system, which is
+ implemented by public license practices. Many people have made
+ generous contributions to the wide range of software distributed
+ through that system in reliance on consistent application of that
+ system; it is up to the author/donor to decide if he or she is willing
+ to distribute software through any other system and a licensee cannot
+ impose that choice.
+
+ This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Program under this License
+ may add an explicit geographical distribution limitation excluding
+ those countries, so that distribution is permitted only in or among
+ countries not thus excluded. In such case, this License incorporates
+ the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+ of the General Public License from time to time. Such new versions will
+ be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and "any
+ later version", you have the option of following the terms and conditions
+ either of that version or of any later version published by the Free
+ Software Foundation. If the Program does not specify a version number of
+ this License, you may choose any version ever published by the Free Software
+ Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the author
+ to ask for permission. For software which is copyrighted by the Free
+ Software Foundation, write to the Free Software Foundation; we sometimes
+ make exceptions for this. Our decision will be guided by the two goals
+ of preserving the free status of all derivatives of our free software and
+ of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+ REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+ to attach them to the start of each source file to most effectively
+ convey the exclusion of warranty; and each file should have at least
+ the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ If the program is interactive, make it output a short notice like this
+ when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+ The hypothetical commands `show w' and `show c' should show the appropriate
+ parts of the General Public License. Of course, the commands you use may
+ be called something other than `show w' and `show c'; they could even be
+ mouse-clicks or menu items--whatever suits your program.
+
+ You should also get your employer (if you work as a programmer) or your
+ school, if any, to sign a "copyright disclaimer" for the program, if
+ necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+ This General Public License does not permit incorporating your program into
+ proprietary programs. If your program is a subroutine library, you may
+ consider it more useful to permit linking proprietary applications with the
+ library. If this is what you want to do, use the GNU Lesser General
+ Public License instead of this License.
diff --git a/wlan_src/mapp/mlan2040coex/Makefile b/wlan_src/mapp/mlan2040coex/Makefile
new file mode 100755
index 0000000..42e643e
--- /dev/null
+++ b/wlan_src/mapp/mlan2040coex/Makefile
@@ -0,0 +1,47 @@
+#
+# File : mlan2040coex/Makefile
+#
+# Copyright (C) 2009, Marvell International Ltd.
+# All Rights Reserved
+
+# Path to the top directory of the mlandriver distribution
+PATH_TO_TOP = ../..
+
+# Determine how we should copy things to the install directory
+ABSPATH := $(filter /%, $(INSTALLDIR))
+RELPATH := $(filter-out /%, $(INSTALLDIR))
+INSTALLPATH := $(ABSPATH)
+ifeq ($(strip $(INSTALLPATH)),)
+INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH)
+endif
+
+# Override CFLAGS for application sources, remove __ kernel namespace defines
+CFLAGS := $(filter-out -D__%, $(EXTRA_CFLAGS))
+
+#
+# List of application executables to create
+#
+libobjs:= mlan2040coex.o mlan2040misc.o
+exectarget=mlan2040coex
+TARGETS := $(exectarget)
+
+#
+# Make target rules
+#
+
+# All rule compiles list of TARGETS using builtin program target from src rule
+all :
+$(exectarget): $(libobjs)
+ $(CC) $(CFLAGS) $(libobjs) -o $(exectarget)
+
+# Update any needed TARGETS and then copy to the install path
+build install: $(TARGETS)
+ @cp -f $(exectarget) $(INSTALLPATH)
+
+clean:
+ @rm -f $(exectarget)
+ @rm -f *.o
+
+distclean: clean
+ @rm -f *~ core
+ @rm -f tags
diff --git a/wlan_src/mapp/mlan2040coex/mlan2040coex.c b/wlan_src/mapp/mlan2040coex/mlan2040coex.c
new file mode 100755
index 0000000..00d3029
--- /dev/null
+++ b/wlan_src/mapp/mlan2040coex/mlan2040coex.c
@@ -0,0 +1,1008 @@
+/** @file mlan2040coex.c
+ *
+ * @brief 11n 20/40 MHz Coex application
+ *
+ * Usage:
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 06/24/2009: initial version
+************************************************************************/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/ethernet.h>
+#include "mlan2040coex.h"
+#include "mlan2040misc.h"
+
+/** coex application's version number */
+#define COEX_VER "M1.0"
+
+/** Initial number of total private ioctl calls */
+#define IW_INIT_PRIV_NUM 128
+/** Maximum number of total private ioctl calls supported */
+#define IW_MAX_PRIV_NUM 1024
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+static t_s8 *usage[] = {
+ "Usage: ",
+ " mlan2040coex [-i <intfname>] [-hvB] ",
+ " -h = help",
+ " -v = version",
+ " -B = run the process in background.",
+ " (if intfname not present then mlan0 assumed)"
+};
+
+t_s32 sockfd = 0; /**< socket descriptor */
+t_s32 nl_sk = 0; /**< netlink socket descriptor */
+t_s8 dev_name[IFNAMSIZ + 1]; /**< device name */
+static struct iw_priv_args *priv_args = NULL; /**< private args */
+static int we_version_compiled = 0;
+ /**< version compiled */
+/** Flag: is 2040coex command required */
+int coex_cmd_req_flag = FALSE;
+/** Flag: is associated */
+int assoc_flag = FALSE;
+/** Flag: is HT AP */
+int is_ht_ap = FALSE;
+/** terminate flag */
+int terminate_flag = FALSE;
+/********************************************************
+ Global Variables
+********************************************************/
+/** OBSS scan parameter of associated AP */
+OBSSScanParam_t cur_obss_scan_param;
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Get private info.
+ *
+ * @param ifname A pointer to net name
+ * @return MLAN_STATUS_SUCCESS--success, otherwise --fail
+ */
+static int
+get_private_info(const t_s8 * ifname)
+{
+ /* This function sends the SIOCGIWPRIV command, which is handled by the
+ kernel and gets the total number of private ioctl's available in the
+ host driver. */
+ struct iwreq iwr;
+ int s, ret = MLAN_STATUS_SUCCESS;
+ struct iw_priv_args *ppriv = NULL;
+ struct iw_priv_args *new_priv;
+ int result = 0;
+ size_t size = IW_INIT_PRIV_NUM;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, ifname, IFNAMSIZ);
+
+ do {
+ /* (Re)allocate the buffer */
+ new_priv = realloc(ppriv, size * sizeof(ppriv[0]));
+ if (new_priv == NULL) {
+ printf("Error: Buffer allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ ppriv = new_priv;
+
+ iwr.u.data.pointer = (caddr_t) ppriv;
+ iwr.u.data.length = size;
+ iwr.u.data.flags = 0;
+
+ if (ioctl(s, SIOCGIWPRIV, &iwr)) {
+ result = errno;
+ ret = MLAN_STATUS_FAILURE;
+ if (result == E2BIG) {
+ /* We need a bigger buffer. Check if kernel gave us any hints. */
+ if (iwr.u.data.length > size) {
+ /* Kernel provided required size */
+ size = iwr.u.data.length;
+ } else {
+ /* No hint from kernel, double the buffer size */
+ size *= 2;
+ }
+ } else {
+ /* ioctl error */
+ perror("ioctl[SIOCGIWPRIV]");
+ break;
+ }
+ } else {
+ /* Success. Return the number of private ioctls */
+ priv_args = ppriv;
+ ret = iwr.u.data.length;
+ break;
+ }
+ } while (size <= IW_MAX_PRIV_NUM);
+
+ if ((ret == MLAN_STATUS_FAILURE) && (ppriv))
+ free(ppriv);
+
+ close(s);
+
+ return ret;
+}
+
+/**
+ * @brief Get Sub command ioctl number
+ *
+ * @param i command index
+ * @param priv_cnt Total number of private ioctls availabe in driver
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+marvell_get_subioctl_no(t_s32 i,
+ t_s32 priv_cnt, int *ioctl_val, int *subioctl_val)
+{
+ t_s32 j;
+
+ if (priv_args[i].cmd >= SIOCDEVPRIVATE) {
+ *ioctl_val = priv_args[i].cmd;
+ *subioctl_val = 0;
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ j = -1;
+
+ /* Find the matching *real* ioctl */
+
+ while ((++j < priv_cnt)
+ && ((priv_args[j].name[0] != '\0') ||
+ (priv_args[j].set_args != priv_args[i].set_args) ||
+ (priv_args[j].get_args != priv_args[i].get_args))) {
+ }
+
+ /* If not found... */
+ if (j == priv_cnt) {
+ printf("%s: Invalid private ioctl definition for: 0x%x\n",
+ dev_name, priv_args[i].cmd);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Save ioctl numbers */
+ *ioctl_val = priv_args[j].cmd;
+ *subioctl_val = priv_args[i].cmd;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get ioctl number
+ *
+ * @param ifname A pointer to net name
+ * @param priv_cmd A pointer to priv command buffer
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+marvell_get_ioctl_no(const t_s8 * ifname,
+ const t_s8 * priv_cmd, int *ioctl_val, int *subioctl_val)
+{
+ t_s32 i;
+ t_s32 priv_cnt;
+ int ret = MLAN_STATUS_FAILURE;
+
+ priv_cnt = get_private_info(ifname);
+
+ /* Are there any private ioctls? */
+ if (priv_cnt <= 0 || priv_cnt > IW_MAX_PRIV_NUM) {
+ /* Could skip this message ? */
+ printf("%-8.8s no private ioctls.\n", ifname);
+ } else {
+ for (i = 0; i < priv_cnt; i++) {
+ if (priv_args[i].name[0] && !strcmp(priv_args[i].name, priv_cmd)) {
+ ret = marvell_get_subioctl_no(i, priv_cnt,
+ ioctl_val, subioctl_val);
+ break;
+ }
+ }
+ }
+
+ if (priv_args) {
+ free(priv_args);
+ priv_args = NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Retrieve the ioctl and sub-ioctl numbers for the given ioctl string
+ *
+ * @param ioctl_name Private IOCTL string name
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+get_priv_ioctl(char *ioctl_name, int *ioctl_val, int *subioctl_val)
+{
+ int retval;
+
+ retval =
+ marvell_get_ioctl_no(dev_name, ioctl_name, ioctl_val, subioctl_val);
+ return retval;
+}
+
+/**
+ * @brief Process OBSS scan table
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_scantable(void)
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ t_u8 *scan_rsp_buf = NULL;
+ char ssid[MRVDRV_MAX_SSID_LENGTH + 1];
+ unsigned int scan_start;
+ int idx, i = 0, j, already_listed, ssid_len, ssid_idx;
+
+ t_u8 *pcurrent;
+ t_u8 *pnext;
+ IEEEtypes_ElementId_e *pelement_id;
+ t_u8 *pelement_len, ht_cap_present, intol_bit_is_set;
+ int bss_info_len, ret = MLAN_STATUS_SUCCESS;
+
+ IEEEtypes_CapInfo_t cap_info = { 0 };
+ t_u8 tsf[8];
+ t_u16 beacon_interval;
+ IEEEtypes_HTCap_t *pht_cap;
+ int scan_result_found;
+
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+
+ scan_rsp_buf = (t_u8 *) malloc(SCAN_RESP_BUF_SIZE);
+ if (scan_rsp_buf == NULL) {
+ printf("Error: allocate memory for scan_rsp_buf failed\n");
+ return -ENOMEM;
+ }
+ prsp_info = (wlan_ioctl_get_scan_table_info *) scan_rsp_buf;
+ memset(leg_ap_chan_list, 0, sizeof(leg_ap_chan_list));
+ num_leg_ap_chan = 0;
+ if (get_priv_ioctl("getscantable",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ scan_result_found = FALSE;
+ scan_start = 1;
+
+ do {
+ prsp_info->scan_number = scan_start;
+
+ /** Set up and execute the ioctl call */
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) prsp_info;
+ iwr.u.data.length = SCAN_RESP_BUF_SIZE;
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ perror("mlan2040coex: getscantable ioctl");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pcurrent = 0;
+ pnext = prsp_info->scan_table_entry_buf;
+
+ for (idx = 0; idx < prsp_info->scan_number; idx++) {
+
+ /*
+ * Set pcurrent to pnext in case pad bytes are at the end
+ * of the last IE we processed.
+ */
+ pcurrent = pnext;
+ prsp_entry = (wlan_ioctl_get_scan_table_entry *) pcurrent;
+ scan_result_found = TRUE;
+ pcurrent += (sizeof(prsp_entry->fixed_field_length) +
+ prsp_entry->fixed_field_length);
+
+ bss_info_len = prsp_entry->bss_info_length;
+ pcurrent += sizeof(prsp_entry->bss_info_length);
+ pnext = pcurrent + prsp_entry->bss_info_length;
+
+ if (bss_info_len >= (sizeof(tsf)
+ + sizeof(beacon_interval) + sizeof(cap_info))) {
+ pcurrent +=
+ (sizeof(tsf) + sizeof(beacon_interval) + sizeof(cap_info));
+ bss_info_len -=
+ (sizeof(tsf) + sizeof(beacon_interval) + sizeof(cap_info));
+ }
+ ht_cap_present = FALSE;
+ intol_bit_is_set = FALSE;
+ while (bss_info_len >= 2) {
+ pelement_id = (IEEEtypes_ElementId_e *) pcurrent;
+ pelement_len = pcurrent + 1;
+ pcurrent += 2;
+
+ switch (*pelement_id) {
+ case SSID:
+ if (*pelement_len &&
+ *pelement_len <= MRVDRV_MAX_SSID_LENGTH) {
+ memcpy(ssid, pcurrent, *pelement_len);
+ ssid_len = *pelement_len;
+ }
+ break;
+
+ case HT_CAPABILITY:
+ pht_cap = (IEEEtypes_HTCap_t *) pelement_id;
+ ht_cap_present = TRUE;
+ if (IS_INTOL_BIT_SET
+ (le16_to_cpu(pht_cap->ht_cap.ht_cap_info))) {
+ intol_bit_is_set = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ pcurrent += *pelement_len;
+ bss_info_len -= (2 + *pelement_len);
+ }
+ if (!ht_cap_present || intol_bit_is_set) {
+ printf("%s AP found on channel number: %-3d ",
+ intol_bit_is_set ? "40 MHZ intolerant" : "Legacy",
+ prsp_entry->fixed_fields.channel);
+ if (ssid_len) {
+ printf("SSID: ");
+ /* Print out the ssid or the hex values if non-printable */
+ for (ssid_idx = 0; ssid_idx < ssid_len; ssid_idx++) {
+ if (isprint(ssid[ssid_idx])) {
+ printf("%c", ssid[ssid_idx]);
+ } else {
+ printf("\\%02x", ssid[ssid_idx]);
+ }
+ }
+ }
+ printf("\n");
+
+ /* Verify that the channel is already listed or not */
+ already_listed = FALSE;
+ for (j = 0; j < i; j++) {
+ if (leg_ap_chan_list[j].chan_num ==
+ prsp_entry->fixed_fields.channel) {
+ already_listed = TRUE;
+ break;
+ }
+ }
+ if (!already_listed) {
+ /* add the channel in list */
+ leg_ap_chan_list[i].chan_num =
+ prsp_entry->fixed_fields.channel;
+ leg_ap_chan_list[i].is_intol_set = intol_bit_is_set;
+ i++;
+ coex_cmd_req_flag = TRUE;
+ num_leg_ap_chan++;
+ }
+ }
+ }
+ scan_start += prsp_info->scan_number;
+ memset(ssid, 0, sizeof(ssid));
+ ssid_len = 0;
+
+ } while (prsp_info->scan_number);
+
+ done:
+ if (scan_rsp_buf)
+ free(scan_rsp_buf);
+ return ret;
+}
+
+/** BSS Mode any (both infra and adhoc) */
+#define BSS_MODE_ANY 3
+
+/**
+ * @brief Issue OBSS scan command
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_setuserscan(void)
+{
+ wlan_ioctl_user_scan_cfg scan_req;
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ coex_cmd_req_flag = FALSE;
+
+ if (get_priv_ioctl("setuserscan",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ scan_req.bss_mode = BSS_MODE_ANY;
+ scan_req.chan_list[0].scan_time =
+ (t_u32) le16_to_cpu(cur_obss_scan_param.obss_scan_active_dwell);
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) & scan_req;
+ iwr.u.data.length = sizeof(scan_req);
+ iwr.u.data.flags = subioctl_val;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ perror("mlan2040coex: setuserscan ioctl");
+ return -EFAULT;
+ }
+ /** process scan results */
+ process_scantable();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief get range
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise --fail
+ */
+static int
+get_range(t_void)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ size_t buf_len;
+
+ buf_len = sizeof(struct iw_range) + 500;
+ range = malloc(buf_len);
+ if (range == NULL) {
+ printf("Error: allocate memory for iw_range failed\n");
+ return -ENOMEM;
+ }
+ memset(range, 0, buf_len);
+ memset(&iwr, 0, sizeof(struct iwreq));
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buf_len;
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+
+ if (ioctl(sockfd, SIOCGIWRANGE, &iwr)) {
+ printf("Get Range Results Failed\n");
+ free(range);
+ return MLAN_STATUS_FAILURE;
+ }
+ we_version_compiled = range->we_version_compiled;
+ printf("Driver build with Wireless Extension %d\n",
+ range->we_version_compiled);
+ free(range);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Display usage
+ *
+ * @return NA
+ */
+static t_void
+display_usage(t_void)
+{
+ t_s32 i;
+ for (i = 0; i < NELEMENTS(usage); i++)
+ fprintf(stderr, "%s\n", usage[i]);
+}
+
+/**
+ * @brief get connection status
+ *
+ * @param data Pointer to the output buffer holding connection status
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+get_connstatus(int *data)
+{
+ struct iwreq iwr;
+ struct sockaddr apaddr;
+ struct ether_addr etherzero = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+
+ if (ioctl(sockfd, SIOCGIWAP, &iwr)) {
+ fprintf(stderr, "mlan2040coex: ioctl SIOCGIWAP failed by %s\n",
+ dev_name);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(&apaddr, 0, sizeof(struct sockaddr));
+ memcpy(&apaddr, &(iwr.u.ap_addr), sizeof(struct sockaddr));
+ if (!memcmp
+ ((struct ether_addr *) apaddr.sa_data, ðerzero,
+ sizeof(struct ether_addr))) {
+ /* not associated */
+ *data = FALSE;
+ } else {
+ /* associated */
+ *data = TRUE;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function parses for IWEVENT events
+ *
+ * @param h Pointer to Netlink message header
+ * @param left Number of bytes to be read
+ * @param evt_conn A pointer to a output buffer. It sets TRUE when it gets
+ * the event CUS_EVT_OBSS_SCAN_PARAM, otherwise FALSE
+ * @return Number of bytes left to be read
+ */
+static int
+drv_iwevt_handler(struct nlmsghdr *h, int left, int *evt_conn)
+{
+ int len, plen, attrlen, nlmsg_len, rta_len;
+ struct ifinfomsg *ifi;
+ struct rtattr *attr;
+
+ *evt_conn = FALSE;
+ while (left >= sizeof(*h)) {
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ /* malformed netlink message */
+ break;
+ }
+ if (plen < sizeof(*ifi)) {
+ break;
+ }
+ ifi = NLMSG_DATA(h);
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0) {
+ break;
+ }
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ struct iw_event *iwe;
+ char *pos = ((char *) attr) + rta_len;
+ char *end = pos + (attr->rta_len - rta_len);
+ unsigned short dlen;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ iwe = (struct iw_event *) pos;
+ if (iwe->len <= IW_EV_LCP_LEN)
+ break;
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ {
+ struct ether_addr *wap;
+ struct ether_addr etherzero =
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+ char buf[32];
+
+ wap = (struct ether_addr *)
+ ((struct sockaddr *) (&iwe->u.ap_addr))->
+ sa_data;
+
+ if (!memcmp
+ (wap, ðerzero, sizeof(struct ether_addr))) {
+ printf("---< Disconnected from AP >---\n");
+ memset(&cur_obss_scan_param, 0,
+ sizeof(cur_obss_scan_param));
+ assoc_flag = FALSE;
+ is_ht_ap = FALSE;
+ } else {
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+ wap->ether_addr_octet[0],
+ wap->ether_addr_octet[1],
+ wap->ether_addr_octet[2],
+ wap->ether_addr_octet[3],
+ wap->ether_addr_octet[4],
+ wap->ether_addr_octet[5]);
+ printf("---< Connected to AP: %s >---\n", buf);
+ /** set TRUE, if connected */
+ assoc_flag = TRUE;
+ }
+ pos += iwe->len;
+ }
+ break;
+ case IWEVCUSTOM:
+ {
+ char *custom;
+ custom = pos + IW_EV_POINT_LEN;
+ if (IW_EV_POINT_LEN ==
+ IW_EV_LCP_LEN + sizeof(struct iw_point)) {
+ dlen = iwe->u.data.length;
+ } else { /* WIRELESS_EXT >= 19 */
+ dlen =
+ *((unsigned short *) (pos + IW_EV_LCP_LEN));
+ }
+ if (custom + dlen > end)
+ break;
+
+ printf("---< %s >---\n", custom);
+ if (!strncmp
+ (CUS_EVT_OBSS_SCAN_PARAM, custom,
+ strlen(CUS_EVT_OBSS_SCAN_PARAM))) {
+ memset(&cur_obss_scan_param, 0,
+ sizeof(cur_obss_scan_param));
+ memcpy(&cur_obss_scan_param,
+ (custom +
+ strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1),
+ sizeof(cur_obss_scan_param));
+ /** set TRUE, since it is an HT AP */
+ is_ht_ap = TRUE;
+ *evt_conn = TRUE;
+ }
+ pos += iwe->len;
+ }
+ break;
+ default:
+ pos += iwe->len;
+ break;
+ }
+ }
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+ return left;
+}
+
+/**
+ * @brief Run the application
+ */
+void
+run_app(void)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int ret = MLAN_STATUS_FAILURE;
+ char msg[1024];
+ int left, evt_conn;
+
+ /* Initialize timeout value */
+ tv.tv_sec = DEFAULT_SCAN_INTERVAL;
+ tv.tv_usec = 0;
+
+ /** Get connection status */
+ if (get_connstatus(&assoc_flag) == MLAN_STATUS_FAILURE)
+ return;
+
+ while (!terminate_flag) {
+ memset(msg, 0, sizeof(msg));
+ /* Setup read fds */
+ FD_ZERO(&rfds);
+ FD_SET(nl_sk, &rfds);
+ /* Wait for event */
+ ret = select(nl_sk + 1, &rfds, NULL, NULL, &tv);
+ if (ret == MLAN_STATUS_FAILURE) {
+ /* Error */
+ tv.tv_sec = DEFAULT_SCAN_INTERVAL;
+ tv.tv_usec = 0;
+ continue;
+ } else if (!ret) {
+ if (assoc_flag && is_ht_ap) {
+ /** Issue OBSS scan */
+ process_setuserscan();
+ /** Invoke 2040coex command, if any legacy AP found or
+ * any AP has 40MHz intolarent bit set */
+ if (coex_cmd_req_flag)
+ invoke_coex_command();
+ }
+ if (assoc_flag && is_ht_ap) {
+ /* Timeout. Try again after BSS channel width triger scan
+ interval when the STA is connected with a HT AP */
+ tv.tv_sec =
+ (t_u32) le16_to_cpu(cur_obss_scan_param.
+ bss_chan_width_trigger_scan_int);
+ } else {
+ /* Timeout. Try again after default duration when the STA is
+ not connected with a HT AP */
+ tv.tv_sec = DEFAULT_SCAN_INTERVAL;
+ }
+ tv.tv_usec = 0;
+ continue;
+ }
+ if (!FD_ISSET(nl_sk, &rfds)) {
+ /* Unexpected error. Try again */
+ tv.tv_sec = DEFAULT_SCAN_INTERVAL;
+ tv.tv_usec = 0;
+ continue;
+ }
+ left = recv(nl_sk, msg, sizeof(msg), MSG_DONTWAIT);
+
+ /* handle only IWEVENT events here */
+ left = drv_iwevt_handler((struct nlmsghdr *) msg, left, &evt_conn);
+ if (assoc_flag && is_ht_ap) {
+ /** If the event is connected with an HT AP then issue OBSS scan immediately */
+ if (evt_conn) {
+ /** Issue OBSS scan */
+ process_setuserscan();
+ /** Invoke 2040coex command, if any legacy AP found or
+ * any AP has 40MHz intolarent bit set */
+ if (coex_cmd_req_flag)
+ invoke_coex_command();
+ }
+ tv.tv_sec =
+ (t_u32) le16_to_cpu(cur_obss_scan_param.
+ bss_chan_width_trigger_scan_int);
+ } else {
+ tv.tv_sec = DEFAULT_SCAN_INTERVAL;
+ }
+ tv.tv_usec = 0;
+ }
+ return;
+}
+
+/**
+ * @brief open netlink socket
+ * @return socket id --success, otherwise--MLAN_STATUS_FAILURE
+ */
+int
+open_netlink(void)
+{
+ int sk;
+ struct sockaddr_nl addr;
+
+ /* Open Netlink socket */
+ sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sk < 0) {
+ printf("ERR:Could not open netlink socket.\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Set source address */
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = RTMGRP_LINK;
+
+ /* Bind socket with source address */
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ printf("ERR:Could not bind socket!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ return sk;
+}
+
+/**
+ * @brief Terminate signal handler
+ */
+static t_void
+terminate_handler(int signal)
+{
+ terminate_flag = TRUE;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Process host command
+ * @param cmd Command
+ * @param chan_list A pointer to a channel list
+ * @param chan_num Number of channels in the channel list
+ * @param reg_class Regulatory class of the channels
+ * @param is_intol_ap_present Flag:is there any 40 MHz intolerant AP is present or not
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_host_cmd(int cmd, t_u8 * chan_list, t_u8 chan_num, t_u8 reg_class,
+ t_u8 is_intol_ap_present)
+{
+ HostCmd_DS_GEN *hostcmd;
+ struct iwreq iwr;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val;
+ t_u8 *buf = NULL;
+
+ if (get_priv_ioctl("hostcmd",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+ buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (buf == NULL) {
+ printf("Error: allocate memory for hostcmd failed\n");
+ return -ENOMEM;
+ }
+
+ switch (cmd) {
+ case CMD_2040COEX:
+ prepare_coex_cmd_buff(buf, chan_list, chan_num, reg_class,
+ is_intol_ap_present);
+ break;
+ default:
+ break;
+ }
+
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (t_u8 *) hostcmd;
+ iwr.u.data.length = le16_to_cpu(hostcmd->size);
+
+ iwr.u.data.flags = 0;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr, "mlan2040coex: MLANHOSTCMD is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ goto _exit_;
+ }
+ ret = process_host_cmd_resp(buf);
+
+ _exit_:
+ if (buf)
+ free(buf);
+ return ret;
+}
+
+/**
+ * @brief Check the STA is 40 MHz intolerant or not
+ * @param intol Flag: TRUE when the STA is 40 MHz intolerant, otherwise FALSE
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+is_intolerant_sta(int *intol)
+{
+ struct iwreq iwr;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val, htcap_info;
+
+ *intol = FALSE;
+ if (get_priv_ioctl("htcapinfo",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = &htcap_info;
+ iwr.u.data.length = 0;
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr,
+ "mlan2040coex: private command 'htcapinfo' is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ if (htcap_info & MBIT(8))
+ *intol = TRUE;
+
+ return ret;
+}
+
+/**
+ * @brief get region code
+ * @param reg_code Pointer to region code
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+get_region_code(int *reg_code)
+{
+ struct iwreq iwr;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("regioncode",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = reg_code;
+ iwr.u.data.length = 0;
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr,
+ "mlan2040coex: private command 'regioncode' is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ return ret;
+}
+
+/** No option */
+#define NO_OPTION -1
+
+/**
+ * @brief Entry function for coex
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+main(int argc, char *argv[])
+{
+ char *ifname = "mlan0";
+ int c, daemonize = FALSE;
+ for (;;) {
+ c = getopt(argc, argv, "Bhi:v");
+ /* check if all command-line options have been parsed */
+ if (c == NO_OPTION)
+ break;
+
+ switch (c) {
+ case 'B':
+ daemonize = TRUE;
+ break;
+ case 'h':
+ display_usage();
+ return MLAN_STATUS_SUCCESS;
+ case 'v':
+ fprintf(stdout, "Marvell 20/40coex application version %s\n",
+ COEX_VER);
+ return MLAN_STATUS_SUCCESS;
+ case 'i':
+ ifname = optarg;
+ break;
+ default:
+ fprintf(stdout, "Invalid argument\n");
+ display_usage();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ strncpy(dev_name, ifname, IFNAMSIZ);
+
+ /* create a socket */
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "mlan2040coex: Cannot open socket.\n");
+ goto done;
+ }
+ if (get_range() != MLAN_STATUS_SUCCESS) {
+ fprintf(stderr, "mlan2040coex: Cannot get range.\n");
+ goto done;
+ }
+ /* create a netlink socket */
+ if ((nl_sk = open_netlink()) == MLAN_STATUS_FAILURE) {
+ fprintf(stderr, "mlan2040coex: Cannot open netlink socket.\n");
+ goto done;
+ }
+
+ signal(SIGHUP, terminate_handler); /* catch hangup signal */
+ signal(SIGTERM, terminate_handler); /* catch kill signal */
+
+ /** Make the process background-process */
+ if (daemonize)
+ daemon(0, 0);
+
+ /** run the application */
+ run_app();
+
+ done:
+ if (sockfd)
+ close(sockfd);
+ if (nl_sk)
+ close(nl_sk);
+
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mapp/mlan2040coex/mlan2040coex.h b/wlan_src/mapp/mlan2040coex/mlan2040coex.h
new file mode 100755
index 0000000..b59fbe8
--- /dev/null
+++ b/wlan_src/mapp/mlan2040coex/mlan2040coex.h
@@ -0,0 +1,125 @@
+/** @file mlan2040coex.h
+ *
+ * @brief This file contains definitions for application
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 06/24/2009: initial version
+************************************************************************/
+#ifndef _COEX_H_
+#define _COEX_H_
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#undef BIG_ENDIAN
+#endif
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+((t_u16)((((t_u16)(x) & 0x00ffU) << 8) | \
+ (((t_u16)(x) & 0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+((t_u32)((((t_u32)(x) & 0x000000ffUL) << 24) | \
+ (((t_u32)(x) & 0x0000ff00UL) << 8) | \
+ (((t_u32)(x) & 0x00ff0000UL) >> 8) | \
+ (((t_u32)(x) & 0xff000000UL) >> 24)))
+
+/** Convert to correct endian format */
+#ifdef BIG_ENDIAN
+/** CPU to little-endian convert for 16-bit */
+#define cpu_to_le16(x) swap_byte_16(x)
+/** CPU to little-endian convert for 32-bit */
+#define cpu_to_le32(x) swap_byte_32(x)
+/** Little-endian to CPU convert for 16-bit */
+#define le16_to_cpu(x) swap_byte_16(x)
+/** Little-endian to CPU convert for 32-bit */
+#define le32_to_cpu(x) swap_byte_32(x)
+#else
+/** Do nothing */
+#define cpu_to_le16(x) (x)
+/** Do nothing */
+#define cpu_to_le32(x) (x)
+/** Do nothing */
+#define le16_to_cpu(x) (x)
+/** Do nothing */
+#define le32_to_cpu(x) (x)
+#endif
+
+/** Character, 1 byte */
+typedef char t_s8;
+/** Unsigned character, 1 byte */
+typedef unsigned char t_u8;
+
+/** Short integer */
+typedef signed short t_s16;
+/** Unsigned short integer */
+typedef unsigned short t_u16;
+
+/** Long integer */
+typedef signed long t_s32;
+/** Unsigned long integer */
+typedef unsigned long t_u32;
+
+/** Long long integer */
+typedef signed long long t_s64;
+/** Unsigned long long integer */
+typedef unsigned long long t_u64;
+
+/** Void pointer (4-bytes) */
+typedef void t_void;
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifndef MIN
+/** Find minimum value */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif /* MIN */
+
+/** Type definition: boolean */
+typedef enum
+{ FALSE, TRUE } boolean;
+
+/** Find number of elements */
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+/** Success */
+#define MLAN_STATUS_SUCCESS (0)
+/** Failure */
+#define MLAN_STATUS_FAILURE (-1)
+
+/** Enumeration for host-command index */
+enum COMMANDS
+{
+ CMD_2040COEX = 1,
+};
+/** Maximum number of channels that can be sent in a setuserscan ioctl */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
+
+/** Structure defination of chan_intol_t*/
+typedef struct _chan_intol_t
+{
+ /** Channel numer */
+ t_u8 chan_num;
+ /** Flag: Is any 40MHz intolerant AP found in this channel */
+ t_u8 is_intol_set;
+} chan_intol_t;
+
+/** Legacy APs channel list */
+chan_intol_t leg_ap_chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+/** Total number of channel present in Legacy APs channel list */
+t_u8 num_leg_ap_chan;
+int get_region_code(int *reg_code);
+int process_host_cmd(int cmd, t_u8 * chan_list, t_u8 chan_num, t_u8 reg_class,
+ t_u8 is_intol_ap_present);
+int is_intolerant_sta(int *intol);
+
+#endif /* _COEX_H_ */
diff --git a/wlan_src/mapp/mlan2040coex/mlan2040misc.c b/wlan_src/mapp/mlan2040coex/mlan2040misc.c
new file mode 100755
index 0000000..c2441cb
--- /dev/null
+++ b/wlan_src/mapp/mlan2040coex/mlan2040misc.c
@@ -0,0 +1,235 @@
+/** @file mlan2040misc.c
+ *
+ * @brief This file contains helper functions for coex application
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 06/24/2009: initial version
+************************************************************************/
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mlan2040coex.h"
+#include "mlan2040misc.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+static class_chan_t us_class_chan_t[] = {
+ {32, {1, 2, 3, 4, 5, 6, 7}, 7},
+ {33, {5, 6, 7, 8, 9, 10, 11}, 7}
+};
+
+static class_chan_t europe_class_chan_t[] = {
+ {11, {1, 2, 3, 4, 5, 6, 7, 8, 9}, 9},
+ {12, {5, 6, 7, 8, 9, 10, 11, 12, 13}, 9}
+};
+
+static class_chan_t japan_class_chan_t[] = {
+ {56, {1, 2, 3, 4, 5, 6, 7, 8, 9}, 9},
+ {57, {5, 6, 7, 8, 9, 10, 11, 12, 13}, 9}
+};
+
+static region_class_chan_t region_class_chan_table[] = {
+ {0x10, us_class_chan_t, sizeof(us_class_chan_t) / sizeof(class_chan_t)}
+ ,
+ {0x30, europe_class_chan_t,
+ sizeof(europe_class_chan_t) / sizeof(class_chan_t)}
+ ,
+ {0x40, japan_class_chan_t, sizeof(japan_class_chan_t) / sizeof(class_chan_t)}
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function prepares the channel list for a particular
+ * regulatory class from channel number for legacy AP
+ * @param cur_class_chan_table A pointer to the class_chan_t
+ * @param num_entry Number of entry in cur_class_chan_table table
+ * @param chan_list A pointer to the output channel list
+ * @param chan_num total number of channel in output channel list
+ * @param reg_domain regulatory domain
+ * @param reg_class regulatory class
+ * @param is_intol_ap_present It sets TRUE when 40MHz intolerant AP is found
+ * otherwise FALSE
+ * @return None
+ */
+static void
+get_channels_for_specified_reg_class(class_chan_t * cur_class_chan_table,
+ int num_entry, t_u8 * chan_list,
+ t_u8 * chan_num, t_u8 reg_domain,
+ t_u8 reg_class, t_u8 * is_intol_ap_present)
+{
+ int i, j, k, idx = 0;
+
+ *is_intol_ap_present = FALSE;
+
+ /* For each regulatory class */
+ for (i = 0; i < num_entry; i++) {
+ if (cur_class_chan_table[i].reg_class == reg_class) {
+ /* For each channel of the regulatory class */
+ for (j = 0; j < cur_class_chan_table[i].total_chan; j++) {
+ for (k = 0; k < num_leg_ap_chan; k++) {
+
+ if (cur_class_chan_table[i].channels[j] ==
+ leg_ap_chan_list[k].chan_num) {
+ *(chan_list + idx) = leg_ap_chan_list[k].chan_num;
+ idx++;
+ if (leg_ap_chan_list[k].is_intol_set)
+ *is_intol_ap_present = TRUE;
+ }
+ }
+ }
+ break;
+ }
+ }
+ /* update the total number of channel */
+ *chan_num = idx--;
+ return;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Prepare 2040 coex command buffer
+ * @param buf A pointer to the command buffer
+ * @param chan_list Channel list
+ * @param num_of_chan Number of channel present in channel list
+ * @param reg_class Regulatory class
+ * @param is_intol_ap_present Flag: is any 40 MHz intolerant AP
+ * is present in these chaanel set
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+void
+prepare_coex_cmd_buff(t_u8 * buf, t_u8 * chan_list, t_u8 num_of_chan,
+ t_u8 reg_class, t_u8 is_intol_ap_present)
+{
+ HostCmd_DS_GEN *hostcmd;
+ MrvlIETypes_2040COEX_t *coex_ie = NULL;
+ MrvlIETypes_2040BssIntolerantChannelReport_t *bss_intol_ie = NULL;
+ t_u8 *pos = NULL;
+ int intol;
+
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_11N_2040COEX);
+ hostcmd->size = S_DS_GEN;
+ pos = buf + S_DS_GEN;
+ {
+ coex_ie = (MrvlIETypes_2040COEX_t *) pos;
+ coex_ie->header.element_id = TLV_ID_2040COEX;
+ coex_ie->header.len = sizeof(coex_ie->coex_elem);
+ /* Check STA is 40 MHz intolerant or not */
+ is_intolerant_sta(&intol);
+ if (intol)
+ coex_ie->coex_elem |= MBIT(1);
+
+ if (is_intol_ap_present)
+ coex_ie->coex_elem |= MBIT(2);
+ pos += sizeof(MrvlIETypes_2040COEX_t);
+ hostcmd->size += sizeof(MrvlIETypes_2040COEX_t);
+ }
+ {
+ bss_intol_ie = (MrvlIETypes_2040BssIntolerantChannelReport_t *) pos;
+ bss_intol_ie->header.element_id = TLV_ID_2040BSS_INTOL_CHAN_REPORT;
+ hostcmd->size +=
+ sizeof(MrvlIETypes_2040BssIntolerantChannelReport_t) -
+ sizeof(bss_intol_ie->chan_num);
+ bss_intol_ie->reg_class = reg_class;
+ memcpy(bss_intol_ie->chan_num, chan_list, num_of_chan);
+ bss_intol_ie->header.len =
+ sizeof(bss_intol_ie->reg_class) + num_of_chan;
+ hostcmd->size += num_of_chan;
+ }
+ hostcmd->size = cpu_to_le16(hostcmd->size);
+ return;
+}
+
+/**
+ * @brief Invoke multiple 2040Coex commands for multiple regulatory classes
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+invoke_coex_command(void)
+{
+ int cur_reg_domain;
+ t_u8 chan_list[MAX_CHAN], is_intol_ap_present;
+ t_u8 num_of_chan;
+ int i, num_entry, ret = MLAN_STATUS_SUCCESS;
+ class_chan_t *cur_class_chan_table = NULL;
+
+ /** get region code */
+ ret = get_region_code(&cur_reg_domain);
+ if (ret != MLAN_STATUS_SUCCESS)
+ return ret;
+ /** Find region_class_chan_table for this region */
+ for (i = 0;
+ i < (sizeof(region_class_chan_table) / sizeof(region_class_chan_t));
+ i++) {
+ if (region_class_chan_table[i].reg_domain == cur_reg_domain) {
+ cur_class_chan_table = region_class_chan_table[i].class_chan_list;
+ num_entry = region_class_chan_table[i].num_class_chan_entry;
+ break;
+ }
+ }
+ if (cur_class_chan_table == NULL) {
+ printf("No region_class_chan table found for this region\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < num_entry; i++) {
+ /** Get channels for the specified regulatory class */
+ get_channels_for_specified_reg_class(cur_class_chan_table, num_entry,
+ chan_list, &num_of_chan,
+ cur_reg_domain,
+ cur_class_chan_table[i].reg_class,
+ &is_intol_ap_present);
+
+ /** If any channel found for this regulatory class, then invoke the 2040coex command */
+ if (num_of_chan > 0) {
+ ret = process_host_cmd(CMD_2040COEX, chan_list, num_of_chan,
+ cur_class_chan_table[i].reg_class,
+ is_intol_ap_present);
+ if (ret)
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief Process host_cmd response
+ * @param buf A pointer to the response buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_host_cmd_resp(t_u8 * buf)
+{
+ HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *) buf;
+ int ret = MLAN_STATUS_SUCCESS;
+
+ hostcmd->command = le16_to_cpu(hostcmd->command);
+ hostcmd->size = le16_to_cpu(hostcmd->size);
+
+ hostcmd->command &= ~HostCmd_RET_BIT;
+ if (!le16_to_cpu(hostcmd->result)) {
+ switch (hostcmd->command) {
+ }
+ } else {
+ printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",
+ le16_to_cpu(hostcmd->command), le16_to_cpu(hostcmd->result));
+ ret = MLAN_STATUS_FAILURE;
+ }
+ return ret;
+}
diff --git a/wlan_src/mapp/mlan2040coex/mlan2040misc.h b/wlan_src/mapp/mlan2040coex/mlan2040misc.h
new file mode 100755
index 0000000..a325c69
--- /dev/null
+++ b/wlan_src/mapp/mlan2040coex/mlan2040misc.h
@@ -0,0 +1,435 @@
+/** @file mlan2040misc.h
+ *
+ * @brief This file contains command definitions for application
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 06/24/2009: initial version
+************************************************************************/
+#ifndef _COEX_MISC_H_
+#define _COEX_MISC_H_
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** TLV Id for 2040Coex IE */
+#define TLV_ID_2040COEX 0x48
+/** TLV Id for 2040BSS intolarent channel report IE */
+#define TLV_ID_2040BSS_INTOL_CHAN_REPORT 0x49
+/** Host-command for 2040coex command */
+#define HostCmd_CMD_11N_2040COEX 0x00e9
+/** Maximum scan response buffer size */
+#define SCAN_RESP_BUF_SIZE 2000
+
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+
+/** Length of ethernet address */
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+/** Default scan interval in second*/
+#define DEFAULT_SCAN_INTERVAL 300
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Check intolerent bit set */
+#define IS_INTOL_BIT_SET(cap_info) (cap_info & MBIT(14))
+
+/** Check OBSS non-HT STAs present bit set */
+#define IS_NON_HT_STA_PRESENT(ht_info) (ht_info.field3 & MBIT(4))
+
+/** Custom event : OBSS scan parameter */
+#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM"
+
+/** IEEE Type definitions */
+typedef enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+ IBSS_PARAM_SET = 6,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+ ERP_INFO = 42,
+ EXTENDED_SUPPORTED_RATES = 50,
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+} __attribute__ ((packed)) IEEEtypes_ElementId_e;
+
+/** HT Capabilities Data */
+typedef struct _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Reserved set to 0 */
+ t_u16 reserved;
+} __attribute__ ((packed)) HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+ /** Reserved set to 0 */
+ t_u16 reserved;
+} __attribute__ ((packed)) HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+ /** Reserve field */
+ t_u8 reserved[3];
+} __attribute__ ((packed)) BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} __attribute__ ((packed)) ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+ /** Reserved Field */
+ t_u16 reserved;
+} __attribute__ ((packed)) OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** IEEEtypes_CapInfo_t structure*/
+typedef struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} __attribute__ ((packed)) IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+
+typedef struct
+{
+ t_u8 chan_number; /**< Channel Number to scan */
+ t_u8 radio_type; /**< Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 scan_type; /**< Scan type: Active = 0, Passive = 1 */
+ t_u8 reserved; /**< Reserved */
+ t_u32 scan_time; /**< Scan duration in milliseconds; if 0 default used */
+} __attribute__ ((packed)) wlan_ioctl_user_scan_chan;
+
+typedef struct
+{
+ char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; /**< SSID */
+ t_u8 max_len; /**< Maximum length of SSID */
+} __attribute__ ((packed)) wlan_ioctl_user_scan_ssid;
+
+typedef struct
+{
+
+ /** Flag set to keep the previous scan table intact */
+ t_u8 keep_previous_scan; /* Do not erase the existing scan results */
+
+ /** BSS mode to be sent in the firmware command */
+ t_u8 bss_mode;
+
+ /** Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+
+ /** Reserved */
+ t_u8 reserved;
+
+ /** BSSID filter sent in the firmware command to limit the results */
+ t_u8 specific_bssid[ETH_ALEN];
+ /** SSID filter list used in the to limit the scan results */
+ wlan_ioctl_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_ioctl_user_scan_chan chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+
+} __attribute__ ((packed)) wlan_ioctl_user_scan_cfg;
+
+/** IEEE IE header */
+typedef struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} __attribute__ ((packed)) IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** HT Capabilities IE */
+typedef struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} __attribute__ ((packed)) IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} __attribute__ ((packed)) IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} __attribute__ ((packed)) IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} __attribute__ ((packed)) IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} __attribute__ ((packed)) IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows starting at bssInfoBuffer
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ t_u8 bss_info_buffer[1];
+} wlan_ioctl_get_scan_table_entry;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/* Define general hostcmd data structure */
+/** HostCmd_DS_GEN */
+typedef struct _HostCmd_DS_GEN
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} __attribute__ ((packed)) HostCmd_DS_GEN;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef struct _MrvlIEtypesHeader
+{
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} __attribute__ ((packed)) MrvlIEtypesHeader_t;
+
+/** _MrvlIETypes_2040BssIntolerantChannelReport_t */
+typedef struct _MrvlIETypes_2040BssIntolerantChannelReport_t
+{
+ /** Header */
+ IEEEtypes_Header_t header;
+ /** regulatory class */
+ t_u8 reg_class;
+ /** channel numbers for legacy AP */
+ t_u8 chan_num[1];
+} __attribute__ ((packed)) MrvlIETypes_2040BssIntolerantChannelReport_t;
+
+/** MrvlIETypes_2040COEX_t */
+typedef struct _MrvlIETypes_2040COEX_t
+{
+ /** Header */
+ IEEEtypes_Header_t header;
+ /** 2040 coex element */
+ t_u8 coex_elem;
+} __attribute__ ((packed)) MrvlIETypes_2040COEX_t;
+
+typedef struct _HostCmd_DS_CMD_11N_2040COEX
+{
+ /** 2040 coex element */
+ MrvlIETypes_2040COEX_t coex;
+ /** 2040 BSS intolerant channel report*/
+ MrvlIETypes_2040BssIntolerantChannelReport_t chan_intol_report;
+} __attribute__ ((packed)) HostCmd_DS_CMD_11N_2040COEX;
+
+/** Maximum number of channel per regulatory class */
+#define MAX_CHAN 20
+typedef struct _class_chan_t
+{
+ /** Regulatory class */
+ t_u8 reg_class;
+ /** Channel numbers */
+ t_u8 channels[MAX_CHAN];
+ /** Total number of channels */
+ t_u8 total_chan;
+} class_chan_t;
+
+typedef struct _region_class_chan_t
+{
+ /** Regulatory domain */
+ int reg_domain;
+ /** Channel numbers */
+ class_chan_t *class_chan_list;
+ /** Number of class channel table entry */
+ int num_class_chan_entry;
+} region_class_chan_t;
+
+int process_host_cmd_resp(t_u8 * buf);
+void prepare_coex_cmd_buff(t_u8 * buf, t_u8 * chan_list, t_u8 num_of_chan,
+ t_u8 reg_class, t_u8 is_intol_ap_present);
+int invoke_coex_command(void);
+
+#endif /* _COEX_MISC_H_ */
diff --git a/wlan_src/mapp/mlanconfig/Makefile b/wlan_src/mapp/mlanconfig/Makefile
new file mode 100755
index 0000000..73666f9
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/Makefile
@@ -0,0 +1,48 @@
+#
+# File : mlanconfig/Makefile
+#
+# Copyright (C) 2008-2009, Marvell International Ltd.
+# All Rights Reserved
+
+# Path to the top directory of the mlandriver distribution
+PATH_TO_TOP = ../..
+
+# Determine how we should copy things to the install directory
+ABSPATH := $(filter /%, $(INSTALLDIR))
+RELPATH := $(filter-out /%, $(INSTALLDIR))
+INSTALLPATH := $(ABSPATH)
+ifeq ($(strip $(INSTALLPATH)),)
+INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH)
+endif
+
+# Override CFLAGS for application sources, remove __ kernel namespace defines
+CFLAGS := $(filter-out -D__%, $(EXTRA_CFLAGS))
+
+#
+# List of application executables to create
+#
+libobjs:= mlanconfig.o mlanhostcmd.o mlanmisc.o
+exectarget=mlanconfig
+TARGETS := $(exectarget)
+
+#
+# Make target rules
+#
+
+# All rule compiles list of TARGETS using builtin program target from src rule
+all :
+$(exectarget): $(libobjs)
+ $(CC) $(CFLAGS) $(libobjs) -o $(exectarget)
+
+# Update any needed TARGETS and then copy to the install path
+build install: $(TARGETS)
+ @cp -f $(exectarget) $(INSTALLPATH)
+ @cp -rf config $(INSTALLPATH)
+
+clean:
+ @rm -f $(exectarget)
+ @rm -f *.o
+
+distclean: clean
+ @rm -f *~ core
+ @rm -f tags
diff --git a/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf b/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf
new file mode 100755
index 0000000..1e8cda7
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf
@@ -0,0 +1,21 @@
+# File : 11n_2040coex.conf
+
+######################### 20/40 Coex command ##################
+2040coex={
+ CmdCode=0x00e9 # do NOT change this line
+
+ 2040CoexTlvType:1=0x48
+ 2040CoexTlvLen:1={
+ 2040CoexElement:1=0x04
+ }
+
+ 2040BssIntlChanTlvType:1=0x49
+ 2040BssIntlChanTlvLen:1={
+ RegulatoryDomain:1=32 # USA: 32 (1-7), 33 (5-11)
+ ChannelNum:1=1
+ ChannelNum:1=2
+ # ...
+ }
+}
+
+##################################################################
diff --git a/wlan_src/mapp/mlanconfig/config/arpfilter.conf b/wlan_src/mapp/mlanconfig/config/arpfilter.conf
new file mode 100755
index 0000000..fe843af
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/arpfilter.conf
@@ -0,0 +1,29 @@
+# File : arpfilter.conf
+
+######################### Host Sleep ARP/IP filtering command ##################
+# add arp filter
+# firmware supports 8 entries of ARP_FILTER. Each entry has 8 bytes.
+# must not exceed 8x8+4=68 bytes
+
+arpfilter={
+ TlvType:2=0x0115
+ TlvLength:2={
+ AddrType:2=3 # multicast
+ EthType:2=0xffff # Any
+ Ipv4Addr:4=0xffffffff # Any
+ AddrType:2=1 # broadcast
+ EthType:2=0x0608 # ARP: 0x0806
+ Ipv4Addr:4=0x6200a8c0 # 192.168.0.98
+ AddrType:2=2 # unicast
+ EthType:2=0xffff # Any
+ Ipv4Addr:4=0xffffffff # Any
+ }
+}
+
+# remove arp filter
+#arpfilter={
+# TlvType:2=0x0115
+# TlvLength:2={
+# }
+#}
+######################### Host Sleep ARP/IP filtering command ##################
diff --git a/wlan_src/mapp/mlanconfig/config/auto_tx.conf b/wlan_src/mapp/mlanconfig/config/auto_tx.conf
new file mode 100755
index 0000000..6c35540
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/auto_tx.conf
@@ -0,0 +1,54 @@
+# File : auto_tx.conf
+
+######################### Auto-TX command ##################
+auto_tx_get={
+ CmdCode=0x0082 # do NOT change this line
+
+ Action:2=0 # GET
+}
+
+auto_tx_unreg={
+ CmdCode=0x0082 # do NOT change this line
+
+ Action:2=1 # SET
+}
+
+nat_keep_alive={
+ CmdCode=0x0082 # do NOT change this line
+
+ Action:2=1 # SET
+
+ AutoTxTlvType:2=0x0118
+ AutoTxTlvLength:2={ # 58 = 6 + 52 (FrameLen)
+ Interval:2=2 # 1 - 3600 seconds
+ Priority:1=7 # Priority, ignored if non-WMM
+ Reserved:1=0
+ FrameLength:2={ # 52 = 6 (DA) + 6 (SA) + 2 + 38 (Length)
+ DestMacAddr:6='0x00,0x40,0xf4,0xbf,0x24,0xee'
+ SrcMacAddr:6='0x00,0x00,0x00,0x00,0x00,0x00'
+ Length:2='0x00,38' # 38 = 8 (SNAP hdr) + 29 (IP) + 1 (padding)
+ DSAP:1=0xaa # SNAP header
+ SSAP:1=0xaa
+ Ctrl:1=0x03
+ SNAP_OUI:3='0x00,0x00,0x00'
+ SNAP_PID:2='0x08,0x00' # IP Packet
+ IPv4:1=0x45
+ IP_TOS:1=0x00
+ IP_LEN:2='0x00,29' # IP hdr 20 + payload 9 = 29
+ IP_ID:2=0xefbe
+ IP_Flag_FragOffset:2=0x0000
+ IP_TTL:1=128
+ IP_Prot:1=17 # UDP protocol
+ IPhdr_cksum:2=0xc5f9 # may need re-calculation if changed
+ IPsrcAddr:4='192,168,0,201' # 192.168.0.201
+ IPdstAddr:4='192,168,0,1' # 192.168.0.1
+ UDPsrcPort:2='0x11,0x94' # 4500
+ UDPdstPort:2='0x11,0x94' # 4500
+ UDPlength:2='0x00,9' # UDP hdr 8 + payload 1 = 9
+ UDPcksum:2=0x985b # may need re-calculation if changed
+ UDPpayload:1=0xff
+ padding:1=0 # MAC Padding for 32bit alignment, set to 0
+ }
+ }
+}
+######################### Auto-TX command ##################
diff --git a/wlan_src/mapp/mlanconfig/config/bg_scan.conf b/wlan_src/mapp/mlanconfig/config/bg_scan.conf
new file mode 100755
index 0000000..270c3cc
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/bg_scan.conf
@@ -0,0 +1,116 @@
+# File : bg_scan.conf
+
+######################### BG Scan Configuration command ##################
+########### Sample configuration for Get BG Scan Configuration #####################
+#bgscfg={
+# CmdCode=0x006b # do NOT change this line
+# Action:1=0 # 0- Get, 1- Set
+# ConfigType:1=0 # 0- normal BG Scan config, 1-PPS or UAPSD BG Scan config
+# Enable:1=1 # 0- Disable, 1-Enable
+# BssType:1=0 # 1 - Infrastructure,2 - IBSS,3 - Any
+# ChannelsPerScan:1=0 # Number of Channel to scan at one scan; maximum 14
+# Reserved1:3=0
+# ScanInterval:4=0 # Interval between consecutive scan (in milliseconds)
+# Reserved2:4=0
+# ReportConditions:4=0 # bit0 - SSID match
+ # bit1 - SNR above SNR threshold
+ # bit2 - RSSI above RSSI threshold
+ # bit31 - All channels scanned at least once
+# Reserved3:2=0
+#}
+
+########### SET BG Scan Configuration #####################
+bgscfg={
+ CmdCode=0x006b # do NOT change this line
+ Action:1=1 # 0- Get, 1- Set
+ ConfigType:1=0 # 0- normal BG Scan config, 1-PPS or UAPSD BG Scan config
+ Enable:1=1 # 0- Disable, 1-Enable
+ BssType:1=3 # 1 - Infrastructure,2 - IBSS,3 - Any
+ ChannelsPerScan:1=14 # Number of Channel to scan at one scan; maximum 14
+ Reserved1:3=0
+ ScanInterval:4=1000 # Interval between consecutive scan (in milliseconds)
+ Reserved2:4=0
+ ReportConditions:4=1 # bit0 - SSID match
+ # bit1 - SNR above SNR threshold
+ # bit2 - RSSI above RSSI threshold
+ # bit31 - All channels scanned at least once
+ Reserved3:2=0
+
+ # SSID entries:
+ #
+ # 1. SSID="" - to denote NULL SSID, which is considered
+ # as SSID with length 0.
+ # 2. SSID="AP_NAME" - to mention a specific SSID to match.
+ # 3. SSID="AP_NAME",maxlen - AP_NAME will be use to base match
+ # the SSID, and SSID's max length is max length
+
+ SSIDHeaderType:2=0x0112
+ SSIDHeaderLen:2={
+ MaxSSIDLen:1=0x00
+ SSID:9="MarvellAP"
+ }
+# SSIDHeaderType:2=0x0112
+# SSIDHeaderLen:2={
+# MaxSSIDLen:1=0x00
+# SSID:10="MarvellAP2"
+# }
+
+ # Number Probe requests to be sent for broadcast and
+ # for each SSID specific scan required.
+ #
+ # Set to 0 to use global scan probes setting
+ #
+ ProbeHeaderType:2=0x0102
+ ProbeHeaderLen:2={
+ NumProbes:2=2
+ }
+
+ # ChannelList contains the channels to scan
+ # The ChannelList should be specified in the form of
+ #
+ # RadioType, ChanNumber, ScanType, MinScanTime, ScanTime;
+ #
+ # RadioType - 0 [B/G Band], 1 [A Band]
+ # ScanType - 2 [Active], 3 [Passive]
+ #
+
+ ChannHeaderType:2=0x0101
+ ChannHeaderLen:2={
+ Chan1_RadioType:1=0
+ Chan1_ChanNumber:1=10
+ Chan1_ScanType:1=2
+ Chan1_MinScanTime:2=10
+ Chan1_ScanTime:2=100
+
+ Chan2_RadioType:1=0
+ Chan2_ChanNumber:1=6
+ Chan2_ScanType:1=3
+ Chan2_MinScanTime:2=10
+ Chan2_ScanTime:2=100
+ }
+
+ # SNR threshold used when ReportConditions bit1 is set
+ SNRHeaderType:2=0x0105
+ SNRHeaderLen:2={
+ SNRValue:1=40 #SNR Thereshold Value
+ SNRFreq:1=0
+ }
+
+ # RSSI threshold used when ReportConditions bit2 is set
+ #
+ # Threshold is absolute value and match value would
+ # therefore be less than or equal to trigger a report
+ RSSIHeaderType:2=0x0104
+ RSSIHeaderLen:2={
+ RSSIValue:1=50 #RSSI Thereshold Value
+ RSSIFreq:1=0
+ }
+
+ # StartLaterValue: 0 - BGScan start immediately
+ # 1 - BGScan will start later after "Scan Interval"
+ StartLaterHeaderType:2=0x011e
+ StartLaterHeaderLen:2={
+ StartLaterValue:2=0
+ }
+}
+######################### BG Scan Configuration command ##################
diff --git a/wlan_src/mapp/mlanconfig/config/cal_data.conf b/wlan_src/mapp/mlanconfig/config/cal_data.conf
new file mode 100755
index 0000000..e37f674
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/cal_data.conf
@@ -0,0 +1,42 @@
+01 00 0c 00 58 02
+00 40 68 0c 00 00 00 40 00 00 00 00 00 11 00 00
+00 11 00 10 00 00 00 00 00 00 00 00 00 00 00 00
+10 12 00 10 10 86 40 89 01 03 02 00 01 02 05 00
+01 03 05 00 17 17 00 05 00 00 00 00 00 00 00 00
+00 30 1f 11 00 00 00 70 00 00 00 00 13 00 1e 01
+00 1e 5e 15 29 5e 15 13 5c 1d 0d 0b 1d 0d 0b 29
+0d 0b 29 5c 0b 29 5c 1d 00 5c 1d 0d 00 00 00 00
+00 5c c0 0e 00 00 00 cc 00 5f 00 00 07 01 04 00
+00 00 0e 0d 00 00 00 00 00 00 00 00 00 00 00 ff
+00 00 00 01 00 00 00 00 00 00 00 ff 00 00 00 01
+00 00 00 00 00 00 00 ff 00 00 00 01 00 00 00 00
+00 00 00 ff 00 00 00 01 00 00 00 00 06 3c 06 3d
+00 00 00 00 00 00 00 00 00 00 00 00
+00 5c dc 25 00 00 01 28 00 6f 00 00 07 01 04 00
+00 00 0e 0d 00 00 00 00 00 00 00 00 00 08 00 07
+00 00 00 09 00 00 00 00 00 08 00 07 00 00 00 09
+00 00 00 00 00 08 00 07 00 00 00 09 00 00 00 00
+00 08 00 07 00 00 00 09 00 00 00 00 06 3c 06 3d
+00 00 00 00 00 00 00 00 00 00 00 00
+00 14 9f 1f 00 00 01 3c 03 00 00 00 00 f1 0a f1
+00 fb 0d fb
+00 20 dd 28 00 00 01 5c 08 86 00 88 ff 06 b1 05
+24 24 3c 42 00 00 24 18 a4 24 bc bc 3d 00 a0 8f
+00 14 00 2a 00 00 01 70 00 00 30 00 01 05 1b 00
+00 00 00 01
+00 74 2c 10 00 00 01 e4 00 00 00 00 09 6a 09 b0
+0b 12 00 6c 04 0a 00 6c 03 03 00 6c 03 03 00 6c
+3f ff ff 00 3f ff ff 01 3f ff ff 02 3f ff ff 03
+15 00 00 04 17 00 00 05 19 00 00 06 1b 00 00 07
+1d 00 00 08 1f 00 00 09 21 00 00 0a 23 00 00 0b
+25 00 00 0c 28 00 00 0d 2a 00 00 0e 2d 00 00 0f
+2f 00 00 10 32 00 00 11 34 00 00 12 3f ff ff 13
+3f ff ff 14
+00 74 84 10 ff ff ff ff 01 00 00 00 09 b0 09 ba
+0a 0f 00 6c 04 09 00 6c 03 03 00 6c 03 03 00 6c
+3f ff ff 00 3f ff ff 01 3f ff ff 02 3f ff ff 03
+15 00 00 04 17 00 00 05 1a 00 00 06 1c 00 00 07
+1f 00 00 08 21 00 00 09 23 00 00 0a 26 00 00 0b
+2a 00 00 0c 2d 00 00 0d 31 00 00 0e 34 00 00 0f
+3f ff ff 10 3f ff ff 11 3f ff ff 12 3f ff ff 13
+3f ff ff 14
diff --git a/wlan_src/mapp/mlanconfig/config/crypto_test.conf b/wlan_src/mapp/mlanconfig/config/crypto_test.conf
new file mode 100755
index 0000000..609366c
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/crypto_test.conf
@@ -0,0 +1,57 @@
+# File : crypto_test.conf
+
+######################### crypto_test command configuration ##################
+
+crypto_test={
+ CmdCode=0x0078 # do NOT change this line
+ #EncDec: 0-Decrypt, 1-Encrypt
+ EncDec:2=0
+ #Algorithm: 1-RC4, 2-AES, 3-AES_KEY_WRAP
+ Algorithm:2=1
+ #KeyIVLength: Length of KeyIV (bytes)
+ KeyIVLength:2=8
+ #KeyIV: Key IV
+ KeyIV:32='0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11'
+ #KeyLength: Length of Key (bytes)
+ KeyLength:2=16
+ #Key: Key
+ Key:32='0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22'
+ #DataType: DataType
+ DataType:2=0x0111
+ #DataLength: Data Length
+ DataLength:2={
+ #Data: Data
+ Data:8='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33'
+ }
+}
+
+#####Sample crypto_test command configuration for AES-CCM algorithm #########
+
+#crypto_test={
+# CmdCode=0x0078 # do NOT change this line
+# #EncDec: 0-Decrypt, 1-Encrypt
+# EncDec:2=1
+# #Algorithm: 4-AES-CCM
+# Algorithm:2=4
+# #KeyLength: Length of Key (bytes)
+# KeyLength:2=16
+# #Key: Key
+# Key:32='0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22'
+# #NonceLength: Length of Nonce (bytes)
+# NonceLength:2=10
+# #Nonce: Nonce
+# Nonce:14='0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11'
+# #AADLength: Length of AAD (bytes)
+# AADLength:2=12
+# #AAD: AAD
+# AAD:32='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33'
+# #DataType: DataType
+# DataType:2=0x0111
+# #DataLength: Data Length
+# DataLength:2={
+# #Data: Data
+# Data:8='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33'
+# }
+#}
+
+######################### End of crypto_test configuration command ##################
diff --git a/wlan_src/mapp/mlanconfig/config/mef.conf b/wlan_src/mapp/mlanconfig/config/mef.conf
new file mode 100755
index 0000000..873fce5
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/mef.conf
@@ -0,0 +1,136 @@
+# File : mef.conf
+
+######################### MEF Configuration command ##################
+mefcfg={
+ #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast
+ Criteria=2 # Unicast frames are received during hostsleepmode
+ NumEntries=1 # Number of activated MEF entries
+ #mef_entry_0: example filters to match TCP destination port 80 send by 192.168.0.88 pkt or magic pkt.
+ mef_entry_0={
+ #mode: bit0--hostsleep mode, bit1--non hostsleep mode
+ mode=1 # HostSleep mode
+ #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host
+ action=3 # Allow and Wake host
+ filter_num=3 # Number of filter
+ #RPN only support "&&" and "||" operator,space can not be removed between operator.
+ RPN=Filter_0 && Filter_1 || Filter_2
+ #Byte comparion filter's type is 0x41,Decimal comparion filter's type is 0x42,
+ #Bit comparion filter's type is 0x43
+ #Filter_0 is decimal comparion filter, it always with type=0x42
+ #Decimal filter always has type, pattern, offset, numbyte 4 field
+ #Filter_0 will match rx pkt with TCP destination port 80
+ Filter_0={
+ type=0x42 # decimal comparion filter
+ pattern=80 # 80 is the decimal constant to be compared
+ offset=44 # 44 is the byte offset of the field in RX pkt to be compare
+ numbyte=2 # 2 is the number of bytes of the field
+ }
+ #Filter_1 is Byte comparion filter, it always with type=0x41
+ #Byte filter always has type, byte, repeat, offset 4 filed
+ #Filter_1 will match rx pkt send by IP address 192.168.0.88
+ Filter_1={
+ type=0x41 # Byte comparion filter
+ repeat=1 # 1 copies of 'c0:a8:00:58'
+ byte=c0:a8:00:58 # 'c0:a8:00:58' is the byte sequence constant with each byte
+ # in hex format, with ':' as delimiter between two byte.
+ offset=34 # 34 is the byte offset of the equal length field of rx'd pkt.
+ }
+ #Filter_2 is Magic packet, it will looking for 16 contiguous copies of '00:50:43:20:01:02' from
+ # the rx pkt's offset 14
+ Filter_2={
+ type=0x41 # Byte comparion filter
+ repeat=16 # 16 copies of '00:50:43:20:01:02'
+ byte=00:50:43:20:01:02 # '00:50:43:20:01:02' is the byte sequence constant
+ offset=14 # 14 is the byte offset of the equal length field of rx'd pkt.
+ }
+ }
+}
+
+
+#--------------------------examples for MEF filters--------------------------------
+# example: filters to match ARP packet with protocol addr 192.168.0.104
+# mef_entry_0={
+# mode=1 # HostSleep mode
+# action=3 # Allow and Wake host
+# filter_num=3 # Number of filter
+# RPN=Filter_0 && Filter_1 && Filter_2
+# #Filter_0 looking for rx pkt with DA is broadcast address
+# Filter_0={
+# type=0x41
+# repeat=6
+# byte=ff
+# offset=0
+# }
+# #Filter_1 looking for rx pkt with EtherType is 0x0806(ARP)
+# Filter_1={
+# type=0x41
+# repeat=1
+# byte=08:06
+# offset=20
+# }
+# #Filter_2 looking for rx pkt with ARP target protocol addr 192.168.0.104
+# Filter_2={
+# type=0x41
+# repeat=1
+# byte=c0:a8:00:68
+# offset=46
+# }
+# }
+#-------------------------------------------------------------------------------------
+# example: filter to check if the destination MAC address is unicast pkt
+# mef_entry_0={
+# mode=1 # HostSleep mode
+# action=3 # Allow and Wake host
+# filter_num=3 # Number of filter
+# RPN=Filter_0
+# #Filter_0 is Bit comparion filter, it always with type=0x43
+# #Byte filter always has type, byte, mask, offset 4 filed
+# #"byte" is the byte sequence constant with each byte in hex format, with ':' as delimiter between two byte
+# #"mask" is also with each byte in hex format, with ':' as delimiter between two byte
+# #"byte" should has the same length as "mask"
+# #Filter_0 will check if the destination MAC address is unicast pkt
+# Filter_0={
+# type=0x43 #Bit comparion filter
+# byte=00 #00 is the 1-byte sequence constant
+# offset=0 #0 is the byte offset of the rx pkt
+# mask=01 #1 is the 1-byte mask
+# }
+# }
+#--------------------------------------------------------------------------------------------------
+# example: Disable MEF filters
+# mefcfg={
+# #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast
+# Criteria=2 # Unicast frames are received during hostsleepmode
+# NumEntries=0 # Number of activated MEF entries
+# }
+#--------------------------------------------------------------------------------------------------
+# example: Test MEF filters
+# mefcfg={
+# Criteria=1
+# NumEntries=1
+# mef_entry_0={
+# mode=4 # Test Mode
+# action=16 # Invoke Test
+# filter_num=0
+# }
+# }
+#-----------------------------------------------------------------------------------------------------
+# example: Test MEF filters
+# mefcfg={
+# Criteria=1
+# NumEntries=1
+# mef_entry_0={
+# mode=4
+# action=0
+# filter_num=1
+# RPN=Filter_0
+# Filter_0={
+# type=0x44 # test filter
+# repeat=2 # 2 copies of 'BE:EF'
+# byte=BE:EF # 'BE:EF' is the byte sequence constant
+# offset=18 # 18 is the byte offset of the equal length field of rx'd pkt.
+# dest=00:50:43:20:5a:82 # '00:50:43:20:5a:82' is the byte sequence constant
+# }
+# }
+# }
+#----------------------------------------------------------------------------------------------------
diff --git a/wlan_src/mapp/mlanconfig/config/or_data.conf b/wlan_src/mapp/mlanconfig/config/or_data.conf
new file mode 100755
index 0000000..bf12214
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/or_data.conf
@@ -0,0 +1,7 @@
+ 07 01 03 3A 80 00 3A 00 ff ff 00 17 03 00 07 03
+ 09 00 0e 10 16 02 19 25 1a 04 1c ff 32 5e 33 15
+ 35 29 36 17 4b 74 4c 64 4d 3b 50 27 61 d6 62 98
+ 6b ae 6f 5b 77 f2 79 ff 7f 2d
+ 07 01 12 16 c0 00 ff ff ff ff 00 05 03 10 32 5c
+ 33 1a 6b a2 7f 20
+
diff --git a/wlan_src/mapp/mlanconfig/config/pmic_data.conf b/wlan_src/mapp/mlanconfig/config/pmic_data.conf
new file mode 100755
index 0000000..3a2b528
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/pmic_data.conf
@@ -0,0 +1,6 @@
+08 86 00 88
+ff 06 b1 05
+24 24 3c 42
+00 00 24 18
+a4 24 bc bc
+3d 00 a0 8f
diff --git a/wlan_src/mapp/mlanconfig/config/requesttpc.conf b/wlan_src/mapp/mlanconfig/config/requesttpc.conf
new file mode 100755
index 0000000..159829b
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/requesttpc.conf
@@ -0,0 +1,15 @@
+# File : requesttpc.conf
+
+######################### requesttpc command configuration ##################
+
+requesttpc={
+ CmdCode=0x0060 # do NOT change this line
+ #DestMac: Destination STA address
+ DestMac:6='0x02,0x04,0x0e,0x06,0x01,0x12'
+ #RateIndex: IEEE Rate index to send request
+ RateIndex:1=22
+ #Timeout: Response timeout in ms
+ Timeout:2=10
+}
+
+######################### End of requesttpc command configuration ##################
diff --git a/wlan_src/mapp/mlanconfig/config/robust_btc.conf b/wlan_src/mapp/mlanconfig/config/robust_btc.conf
new file mode 100755
index 0000000..823e530
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/robust_btc.conf
@@ -0,0 +1,63 @@
+# File : robust_btc.conf
+
+######################### Robust Coex command ###############
+robust_btc_get={
+ CmdCode=0x00e0 # do NOT change this line
+
+ Action:2=0 # GET
+ RSVD:2=0
+
+ # Robust Coex Mode TLV
+ RobustCoexTlvType:2=0x0160
+ RobustCoexTlvLength:2={
+ Enable:1=0x00 # Enable Robust Coex Mode
+ Reserved:3=0
+ }
+
+ # Robust Coex Period TLV
+ RobustCoexPeriodTlvType:2=0x0161
+ RobustCoexPeriodTlvLength:2={
+ Mode:2=0x0000 # Strict to time mode. So, 0
+ Reserved:2=0
+ BTTime:4=0 # Length of time to give to BT in uSeconds
+ Period:4=0 # Length of the period in uSeconds
+ }
+}
+
+robust_btc_enable={
+ CmdCode=0x00e0 # do NOT change this line
+
+ Action:2=1 # SET
+ RSVD:2=0
+
+ # Robust Coex Mode TLV
+ RobustCoexTlvType:2=0x0160
+ RobustCoexTlvLength:2={
+ Enable:1=0x01 # Enable Robust Coex Mode
+ Reserved:3=0
+ }
+
+ # Robust Coex Period TLV
+ RobustCoexPeriodTlvType:2=0x0161
+ RobustCoexPeriodTlvLength:2={
+ Mode:2=0x0000 # Strict to time mode. So, 0
+ Reserved:2=0
+ BTTime:4=14000 # Length of time to give to BT in uSeconds
+ Period:4=20000 # Length of the period in uSeconds
+ }
+}
+
+robust_btc_disable={
+ CmdCode=0x00e0 # do NOT change this line
+
+ Action:2=1 # SET
+ RSVD:2=0
+
+ # Robust Coex Mode TLV
+ RobustCoexTlvType:2=0x0160
+ RobustCoexTlvLength:2={
+ Enable:1=0x00 # Disable Robust Coex Mode
+ Reserved:3=0
+ }
+}
+######################### Robust Coex command ###############
diff --git a/wlan_src/mapp/mlanconfig/config/subevent.conf b/wlan_src/mapp/mlanconfig/config/subevent.conf
new file mode 100755
index 0000000..cd56149
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/subevent.conf
@@ -0,0 +1,97 @@
+# File : subevent.conf
+
+######################### Subscribe Events command ##################
+subevent_get={
+ CmdCode=0x0075 # do NOT change this line
+
+ Action:2=0 # GET
+ Events:2=0
+}
+
+subevent_set={
+ CmdCode=0x0075 # do NOT change this line
+
+ Action:2=1 # SET
+ Events:2=0xbc8 # bit0 - Beacon RSSI_LOW; bit1 - Beacon SNR_LOW
+ # bit2 - FAILED_COUNT; bit3 - Beacon Missed
+ # bit4 - Beacon RSSI_HIGH; bit5 - Beacon SNR_HIGH
+ # bit6 - Data RSSI_LOW; bit7 - Data SNR_LOW
+ # bit8 - Data RSSI_HIGH; bit9 - Data SNR_HIGH
+ # bit10 - LINK_QUALITY; bit11 - PRE_BCN_LOST
+ # bit12-15 reserved
+
+ LowRssiTlvType:2=0x0104
+ LowRssiTlvLength:2={
+ Threshold:1=70
+ ReportingFreq:1=0
+ }
+
+ LowSnrTlvType:2=0x0105
+ LowSnrTlvLength:2={
+ Threshold:1=56
+ ReportingFreq:1=0
+ }
+
+ FailedCountTlvType:2=0x0106
+ FailedCountTlvLength:2={
+ Threshold:1=5
+ ReportingFreq:1=0
+ }
+
+ BeaconMissTlvType:2=0x0107
+ BeaconMissTlvLength:2={
+ BeaconMissed:1=60
+ Reserved:1=0
+ }
+
+ HighRssiTlvType:2=0x0116
+ HighRssiTlvLength:2={
+ Threshold:1=40
+ ReportingFreq:1=0
+ }
+
+ HighSnrTlvType:2=0x0117
+ HighSnrTlvLength:2={
+ Threshold:1=86
+ ReportingFreq:1=0
+ }
+
+ DataLowRssiTlvType:2=0x0126
+ DataLowRssiTlvLength:2={
+ Threshold:1=10
+ ReportingFreq:1=0
+ }
+
+ DataLowSnrTlvType:2=0x0127
+ DataLowSnrTlvLength:2={
+ Threshold:1=66
+ ReportingFreq:1=0
+ }
+
+ DataHighRssiTlvType:2=0x0128
+ DataHighRssiTlvLength:2={
+ Threshold:1=50
+ ReportingFreq:1=0
+ }
+
+ DataHighSnrTlvType:2=0x0129
+ DataHighSnrTlvLength:2={
+ Threshold:1=96
+ ReportingFreq:1=1
+ }
+ LinkQualityTlvType:2=0x0124
+ LinkQualityTlvType:2={
+ LinkSNRThreshold:2=0x0056
+ LinkSNRFrequency:2=0x0003
+ MinRateVal:2=0x0014
+ MinRateFreq:2=0x0003
+ TxLatencyVal:4=0x00C8
+ TxLatencyThreshold:4=0x0003
+ }
+ PreBcnLostTlvType:2=0x0149
+ PreBcnLostTlvLength:2={
+ PreBeaconCnt:1=30
+ Reserved:1=0
+ }
+}
+######################### Subscribe Events command ##################
diff --git a/wlan_src/mapp/mlanconfig/config/tspecs.conf b/wlan_src/mapp/mlanconfig/config/tspecs.conf
new file mode 100755
index 0000000..92c1f9d
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/tspecs.conf
@@ -0,0 +1,99 @@
+# TSPEC contents for TID=0, UserPriority = 6
+[tspec0]
+# Element ID
+dd
+# Length
+3d
+# OUI
+00 50 f2
+# OUI Type
+02
+# OUI SubType
+02
+# Version
+01
+# TSInfo
+e0 34 00
+# Nominal MSDU Size
+d0 80
+# Maximum MSDU Size
+d0 00
+# Min Service Interval
+20 4e 00 00
+# Max Service Interval
+20 4e 00 00
+# Inactivity Interval
+80 96 98 00
+# Suspension Interval
+ff ff ff ff
+# Service Start Time
+00 00 00 00
+# Minimum Data Rate
+00 45 01 00
+# Mean Data Rate
+00 45 01 00
+# Peak Data Rate
+00 45 01 00
+# Max Burst Size
+00 00 00 00
+# Delay Bound
+00 00 00 00
+# Min PHY Rate
+00 1b b7 00
+# Surplus Bandwidth Allowance
+00 30
+# Medium Time
+00 00
+# Extra Data Bytes
+[/tspec0]
+
+
+# TSPEC contents for TID=1, UserPriority = 4
+[tspec1]
+# Element ID
+dd
+# Length
+3d
+# OUI
+00 50 f2
+# OUI Type
+02
+# OUI SubType
+02
+# Version
+01
+# TSInfo
+e3 20 00
+# Nominal MSDU Size
+96 00
+# Maximum MSDU Size
+dc 05
+# Min Service Interval
+00 00 00 00
+# Max Service Interval
+00 00 00 00
+# Inactivity Interval
+00 00 00 00
+# Suspension Interval
+ff ff ff ff
+# Service Start Time
+00 00 00 00
+# Minimum Data Rate
+a0 00 00 00
+# Mean Data Rate
+a0 00 00 00
+# Peak Data Rate
+a0 00 00 00
+# Max Burst Size
+00 00 00 00
+# Delay Bound
+00 00 00 00
+# Min PHY Rate
+80 8d 5b 00
+# Surplus Bandwidth Allowance
+00 30
+# Medium Time
+00 00
+# Extra Data Bytes
+[/tspec1]
+
diff --git a/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf b/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf
new file mode 100755
index 0000000..f72aa66
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf
@@ -0,0 +1,331 @@
+# File : txpwrlimit_cfg.conf
+
+## Get CFG data for Tx power limitation
+txpwrlimit_cfg_get={
+ CmdCode=0x008f # do NOT change this line
+ Action:2=0 # 0 - GET
+ Type:2=4 # do NOT change this line
+
+ CfgLen:2={
+ }
+}
+
+## Set CFG data for Tx power limitation
+txpwrlimit_cfg_set={
+ CmdCode=0x008f # do NOT change this line
+ Action:2=1 # 1 - SET
+ Type:2=4 # do NOT change this line
+
+ CfgLen:2={
+ # Channel 1 Tx Power Limit
+ ch1.channel:1=1 # Channel 1
+
+ ch1.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch1.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch1.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch1.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch1.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch1.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch1.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch1.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch1.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch1.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch1.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch1.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch1.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch1.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch1.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 2 Tx Power Limit
+ ch2.channel:1=2 # Channel 2
+
+ ch2.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch2.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch2.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch2.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch2.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch2.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch2.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch2.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch2.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch2.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch2.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch2.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch2.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch2.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch2.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 3 Tx Power Limit
+ ch3.channel:1=3 # Channel 3
+
+ ch3.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch3.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch3.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch3.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch3.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch3.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch3.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch3.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch3.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch3.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch3.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch3.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch3.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch3.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch3.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 4 Tx Power Limit
+ ch4.channel:1=4 # Channel 4
+
+ ch4.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch4.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch4.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch4.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch4.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch4.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch4.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch4.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch4.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch4.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch4.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch4.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch4.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch4.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch4.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 5 Tx Power Limit
+ ch5.channel:1=5 # Channel 5
+
+ ch5.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch5.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch5.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch5.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch5.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch5.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch5.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch5.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch5.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch5.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch5.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch5.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch5.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch5.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch5.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 6 Tx Power Limit
+ ch6.channel:1=6 # Channel 6
+
+ ch6.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch6.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch6.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch6.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch6.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch6.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch6.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch6.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch6.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch6.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch6.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch6.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch6.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch6.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch6.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 7 Tx Power Limit
+ ch7.channel:1=7 # Channel 7
+
+ ch7.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch7.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch7.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch7.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch7.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch7.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch7.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch7.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch7.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch7.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch7.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch7.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch7.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch7.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch7.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+
+ # Channel 8 Tx Power Limit
+ ch8.channel:1=8 # Channel 8
+
+ ch8.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch8.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch8.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch8.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch8.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch8.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch8.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch8.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch8.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch8.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch8.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch8.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch8.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch8.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch8.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 9 Tx Power Limit
+ ch9.channel:1=9 # Channel 9
+
+ ch9.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch9.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch9.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch9.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch9.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch9.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch9.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch9.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch9.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch9.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch9.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch9.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch9.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch9.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch9.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 10 Tx Power Limit
+ ch10.channel:1=10 # Channel 10
+
+ ch10.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch10.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch10.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch10.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch10.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch10.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch10.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch10.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch10.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch10.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch10.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch10.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch10.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch10.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch10.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 11 Tx Power Limit
+ ch11.channel:1=11 # Channel 11
+
+ ch11.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch11.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch11.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch11.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch11.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch11.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch11.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch11.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch11.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch11.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch11.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch11.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch11.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch11.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch11.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 12 Tx Power Limit
+ ch12.channel:1=12 # Channel 12
+
+ ch12.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch12.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch12.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch12.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch12.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch12.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch12.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch12.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch12.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch12.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch12.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch12.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch12.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch12.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch12.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 13 Tx Power Limit
+ ch13.channel:1=13 # Channel 13
+
+ ch13.pwr_limit_11b_cck:1=16 # DSSS 11, 5.5 Mbps
+ ch13.pwr_limit_11b_qpsk:1=16 # DSSS 2 Mbps
+ ch13.pwr_limit_11b_bpsk:1=16 # DSSS 1 Mbps
+
+ ch13.pwr_limit_11g_qam64:1=15 # OFDM 48, 54 Mbps
+ ch13.pwr_limit_11g_qam16:1=16 # OFDM 24, 36 Mbps
+ ch13.pwr_limit_11g_qpsk:1=16 # OFDM 12, 18 Mbps
+ ch13.pwr_limit_11g_bpsk:1=16 # OFDM 6, 9 Mbps
+
+ ch13.pwr_limit_ht_bw20_qam64:1=15 # HTBW20 MCS 5, 6, 7
+ ch13.pwr_limit_ht_bw20_qam16:1=16 # HTBW20 MCS 3, 4
+ ch13.pwr_limit_ht_bw20_qpsk:1=16 # HTBW20 MCS 1, 2
+ ch13.pwr_limit_ht_bw20_bpsk:1=16 # HTBW20 MCS 0
+
+ ch13.pwr_limit_ht_bw40_qam64:1=15 # HTBW40 MCS 5, 6, 7
+ ch13.pwr_limit_ht_bw40_qam16:1=16 # HTBW40 MCS 3, 4
+ ch13.pwr_limit_ht_bw40_qpsk:1=16 # HTBW40 MCS 1, 2
+ ch13.pwr_limit_ht_bw40_bpsk:1=16 # HTBW40 MCS 0, 32
+
+ # Channel 14 Tx Power Limit
+ ch14.channel:1=14 # Channel 14
+
+ ch14.pwr_limit_11b_cck:1=12 # DSSS 11, 5.5 Mbps
+ ch14.pwr_limit_11b_qpsk:1=12 # DSSS 2 Mbps
+ ch14.pwr_limit_11b_bpsk:1=12 # DSSS 1 Mbps
+
+ ch14.pwr_limit_11g_qam64:1=12 # OFDM 48, 54 Mbps
+ ch14.pwr_limit_11g_qam16:1=12 # OFDM 24, 36 Mbps
+ ch14.pwr_limit_11g_qpsk:1=12 # OFDM 12, 18 Mbps
+ ch14.pwr_limit_11g_bpsk:1=12 # OFDM 6, 9 Mbps
+
+ ch14.pwr_limit_ht_bw20_qam64:1=12 # HTBW20 MCS 5, 6, 7
+ ch14.pwr_limit_ht_bw20_qam16:1=12 # HTBW20 MCS 3, 4
+ ch14.pwr_limit_ht_bw20_qpsk:1=12 # HTBW20 MCS 1, 2
+ ch14.pwr_limit_ht_bw20_bpsk:1=12 # HTBW20 MCS 0
+
+ ch14.pwr_limit_ht_bw40_qam64:1=12 # HTBW40 MCS 5, 6, 7
+ ch14.pwr_limit_ht_bw40_qam16:1=12 # HTBW40 MCS 3, 4
+ ch14.pwr_limit_ht_bw40_qpsk:1=12 # HTBW40 MCS 1, 2
+ ch14.pwr_limit_ht_bw40_bpsk:1=12 # HTBW40 MCS 0, 32
+
+ }
+}
+
diff --git a/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf b/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf
new file mode 100755
index 0000000..17b0ae0
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf
@@ -0,0 +1,126 @@
+# File : txrate_cfg.conf
+
+## Tx Rate Configuration command
+txrate_cfg_get={
+ CmdCode=0x00d6 # do NOT change this line
+ Action:2=0 # 0 - GET
+ Index:2=0 # do NOT change this line
+
+ TxRateScope.TlvType:2=0x0153
+ TxRateScope.TlvLength:2={
+ }
+}
+
+txrate_cfg_set_bg={
+ CmdCode=0x00d6 # do NOT change this line
+
+ Action:2=1 # 1 - SET
+ Index:2=0 # do NOT change this line
+
+ TxRateScope.TlvType:2=0x0153
+ TxRateScope.TlvLength:2={
+ ################# TXRATE SCOPE ######################
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 1 Mbps
+ # 1 2 Mbps
+ # 2 5.5 Mbps
+ # 3 11 Mbps
+ # 4 Reserved
+ HRDSSS.RateScope:2=0x0000
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 6 Mbps
+ # 1 9 Mbps
+ # 2 12 Mbps
+ # 3 18 Mbps
+ # 4 24 Mbps
+ # 5 36 Mbps
+ # 6 48 Mbps
+ # 7 54 Mbps
+ OFDM.RateScope:2=0x0080
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 MCS0
+ # 1 MCS1
+ # 2 MCS2
+ # 3 MCS3
+ # 4 MCS4
+ # 5 MCS5
+ # 6 MCS6
+ # 7 MCS7
+ # 32 MCS32
+ HT.RateScopeDword0:4=0x00000000
+ HT.RateScopeDword1:4=0x00000000
+ HT.RateScopeDword2:4=0x00000000
+ HT.RateScopeDword3:4=0x00000000
+ }
+
+ TxRateDrop.TlvType:2=0x0151
+ TxRateDrop.TlvLength:2={
+ RateDrop.Mode:4=0x00000001
+ }
+}
+
+txrate_cfg_set_bgn={
+ CmdCode=0x00d6 # do NOT change this line
+
+ Action:2=1 # 1 - SET
+ Index:2=0 # do NOT change this line
+
+ TxRateScope.TlvType:2=0x0153
+ TxRateScope.TlvLength:2={
+ ################# TXRATE SCOPE ######################
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 1 Mbps
+ # 1 2 Mbps
+ # 2 5.5 Mbps
+ # 3 11 Mbps
+ # 4 Reserved
+ HRDSSS.RateScope:2=0x0000
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 6 Mbps
+ # 1 9 Mbps
+ # 2 12 Mbps
+ # 3 18 Mbps
+ # 4 24 Mbps
+ # 5 36 Mbps
+ # 6 48 Mbps
+ # 7 54 Mbps
+ OFDM.RateScope:2=0x0000
+
+ # The following table shows the bitmap of the rates:
+ # (bit 0 is the least significant bit)
+ # Bit Data rate
+ # 0 MCS0
+ # 1 MCS1
+ # 2 MCS2
+ # 3 MCS3
+ # 4 MCS4
+ # 5 MCS5
+ # 6 MCS6
+ # 7 MCS7
+ # 32 MCS32
+ HT.RateScopeDword0:4=0x00000080
+ HT.RateScopeDword1:4=0x00000000
+ HT.RateScopeDword2:4=0x00000000
+ HT.RateScopeDword3:4=0x00000000
+ }
+
+ TxRateDrop.TlvType:2=0x0151
+ TxRateDrop.TlvLength:2={
+ RateDrop.Mode:4=0x00000001
+ }
+}
diff --git a/wlan_src/mapp/mlanconfig/mlanconfig.c b/wlan_src/mapp/mlanconfig/mlanconfig.c
new file mode 100755
index 0000000..a4f8abf
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanconfig.c
@@ -0,0 +1,2268 @@
+/** @file mlanconfig.c
+ *
+ * @brief Program to configure addition parameters into the mlandriver
+ *
+ * Usage: mlanconfig mlanX cmd [...]
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 11/26/2008: initial version
+ 03/10/2009: add setuserscan, getscantable etc. commands
+ 08/11/2009: add addts, regclass, setra, scanagent etc. commands
+************************************************************************/
+
+#include "mlanconfig.h"
+#include "mlanhostcmd.h"
+#include "mlanmisc.h"
+
+/** mlanconfig version number */
+#define MLANCONFIG_VER "M1.3"
+
+/** Initial number of total private ioctl calls */
+#define IW_INIT_PRIV_NUM 128
+/** Maximum number of total private ioctl calls supported */
+#define IW_MAX_PRIV_NUM 1024
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Private ioctl commands */
+enum COMMANDS
+{
+ CMD_HOSTCMD,
+ CMD_MEFCFG,
+ CMD_ARPFILTER,
+ CMD_CFG_DATA,
+ CMD_CMD52RW,
+ CMD_CMD53RW,
+ CMD_GET_SCAN_RSP,
+ CMD_SET_USER_SCAN,
+ CMD_ADD_TS,
+ CMD_DEL_TS,
+ CMD_QCONFIG,
+ CMD_QSTATS,
+ CMD_TS_STATUS,
+ CMD_WMM_QSTATUS,
+ CMD_REGRW,
+};
+
+static t_s8 *commands[] = {
+ "hostcmd",
+ "mefcfg",
+ "arpfilter",
+ "cfgdata",
+ "sdcmd52rw",
+ "sdcmd53rw",
+ "getscantable",
+ "setuserscan",
+ "addts",
+ "delts",
+ "qconfig",
+ "qstats",
+ "ts_status",
+ "qstatus",
+ "regrdwr",
+};
+
+static t_s8 *usage[] = {
+ "Usage: ",
+ " mlanconfig -v (version)",
+ " mlanconfig <mlanX> <cmd> [...]",
+ " where",
+ " mlanX : wireless network interface",
+ " cmd : hostcmd",
+ " : mefcfg",
+ " : arpfilter",
+ " : cfgdata",
+ " : sdcmd52rw, sdcmd53rw",
+ " : getscantable, setuserscan",
+ " : addts, delts, qconfig, qstats, ts_status, qstatus",
+ " : regrdwr",
+ " : additional parameter for hostcmd",
+ " : <filename> <cmd>",
+ " : additional parameters for mefcfg are:",
+ " : <filename>",
+ " : additional parameter for arpfilter",
+ " : <filename>",
+ " : additional parameter for cfgdata",
+ " : <type> <filename>",
+ " : additional parameter for sdcmd52rw",
+ " : <function> <reg addr.> <data>",
+ " : additional parameter for sdcmd53rw",
+ " : <func> <addr> <mode> <blksiz> <blknum> <data1> ... ...<dataN> ",
+ " : additional parameter for addts",
+ " : <filename.conf> <section# of tspec> <timeout in ms>",
+ " : additional parameter for delts",
+ " : <filename.conf> <section# of tspec>",
+ " : additional parameter for qconfig",
+ " : <[set msdu <lifetime in TUs> [Queue Id: 0-3]]",
+ " : [get [Queue Id: 0-3]] [def [Queue Id: 0-3]]>",
+ " : additional parameter for qstats",
+ " : <[on [Queue Id: 0-3]] [off [Queue Id: 0-3]] [get [Queue Id: 0-3]]>",
+ " : additional parameter for regrdwr",
+ " : <type> <offset> [value]",
+};
+
+static FILE *fp; /**< socket */
+t_s32 sockfd; /**< socket */
+t_s8 dev_name[IFNAMSIZ + 1]; /**< device name */
+static struct iw_priv_args *priv_args = NULL; /**< private args */
+static int we_version_compiled = 0;
+ /**< version compiled */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Get private info.
+ *
+ * @param ifname A pointer to net name
+ * @return MLAN_STATUS_SUCCESS--success, otherwise --fail
+ */
+static int
+get_private_info(const t_s8 * ifname)
+{
+ /* This function sends the SIOCGIWPRIV command, which is handled by the
+ kernel and gets the total number of private ioctl's available in the
+ host driver. */
+ struct iwreq iwr;
+ int s, ret = MLAN_STATUS_SUCCESS;
+ struct iw_priv_args *ppriv = NULL;
+ struct iw_priv_args *new_priv;
+ int result = 0;
+ size_t size = IW_INIT_PRIV_NUM;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, ifname, IFNAMSIZ);
+
+ do {
+ /* (Re)allocate the buffer */
+ new_priv = realloc(ppriv, size * sizeof(ppriv[0]));
+ if (new_priv == NULL) {
+ printf("Error: Buffer allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ ppriv = new_priv;
+
+ iwr.u.data.pointer = (caddr_t) ppriv;
+ iwr.u.data.length = size;
+ iwr.u.data.flags = 0;
+
+ if (ioctl(s, SIOCGIWPRIV, &iwr) < 0) {
+ result = errno;
+ ret = MLAN_STATUS_FAILURE;
+ if (result == E2BIG) {
+ /* We need a bigger buffer. Check if kernel gave us any hints. */
+ if (iwr.u.data.length > size) {
+ /* Kernel provided required size */
+ size = iwr.u.data.length;
+ } else {
+ /* No hint from kernel, double the buffer size */
+ size *= 2;
+ }
+ } else {
+ /* ioctl error */
+ perror("ioctl[SIOCGIWPRIV]");
+ break;
+ }
+ } else {
+ /* Success. Return the number of private ioctls */
+ priv_args = ppriv;
+ ret = iwr.u.data.length;
+ break;
+ }
+ } while (size <= IW_MAX_PRIV_NUM);
+
+ if ((ret == MLAN_STATUS_FAILURE) && (ppriv))
+ free(ppriv);
+
+ close(s);
+
+ return ret;
+}
+
+/**
+ * @brief Get Sub command ioctl number
+ *
+ * @param i command index
+ * @param priv_cnt Total number of private ioctls availabe in driver
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+marvell_get_subioctl_no(t_s32 i,
+ t_s32 priv_cnt, int *ioctl_val, int *subioctl_val)
+{
+ t_s32 j;
+
+ if (priv_args[i].cmd >= SIOCDEVPRIVATE) {
+ *ioctl_val = priv_args[i].cmd;
+ *subioctl_val = 0;
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ j = -1;
+
+ /* Find the matching *real* ioctl */
+
+ while ((++j < priv_cnt)
+ && ((priv_args[j].name[0] != '\0') ||
+ (priv_args[j].set_args != priv_args[i].set_args) ||
+ (priv_args[j].get_args != priv_args[i].get_args))) {
+ }
+
+ /* If not found... */
+ if (j == priv_cnt) {
+ printf("%s: Invalid private ioctl definition for: 0x%x\n",
+ dev_name, priv_args[i].cmd);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Save ioctl numbers */
+ *ioctl_val = priv_args[j].cmd;
+ *subioctl_val = priv_args[i].cmd;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get ioctl number
+ *
+ * @param ifname A pointer to net name
+ * @param priv_cmd A pointer to priv command buffer
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+marvell_get_ioctl_no(const t_s8 * ifname,
+ const t_s8 * priv_cmd, int *ioctl_val, int *subioctl_val)
+{
+ t_s32 i;
+ t_s32 priv_cnt;
+ int ret = MLAN_STATUS_FAILURE;
+
+ priv_cnt = get_private_info(ifname);
+
+ /* Are there any private ioctls? */
+ if (priv_cnt <= 0 || priv_cnt > IW_MAX_PRIV_NUM) {
+ /* Could skip this message ? */
+ printf("%-8.8s no private ioctls.\n", ifname);
+ } else {
+ for (i = 0; i < priv_cnt; i++) {
+ if (priv_args[i].name[0] && !strcmp(priv_args[i].name, priv_cmd)) {
+ ret = marvell_get_subioctl_no(i, priv_cnt,
+ ioctl_val, subioctl_val);
+ break;
+ }
+ }
+ }
+
+ if (priv_args) {
+ free(priv_args);
+ priv_args = NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Retrieve the ioctl and sub-ioctl numbers for the given ioctl string
+ *
+ * @param ioctl_name Private IOCTL string name
+ * @param ioctl_val A pointer to return ioctl number
+ * @param subioctl_val A pointer to return sub-ioctl number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+get_priv_ioctl(char *ioctl_name, int *ioctl_val, int *subioctl_val)
+{
+ int retval;
+
+ retval = marvell_get_ioctl_no(dev_name,
+ ioctl_name, ioctl_val, subioctl_val);
+
+ return retval;
+}
+
+/**
+ * @brief Process host_cmd
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_host_cmd(int argc, char *argv[])
+{
+ t_s8 cmdname[256];
+ t_u8 *buf;
+ HostCmd_DS_GEN *hostcmd;
+ struct iwreq iwr;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("hostcmd",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc < 5) {
+ printf("Error: invalid no of arguments\n");
+ printf("Syntax: ./mlanconfig mlanX hostcmd <hostcmd.conf> <cmdname>\n");
+ exit(1);
+ }
+
+ if ((fp = fopen(argv[3], "r")) == NULL) {
+ fprintf(stderr, "Cannot open file %s\n", argv[3]);
+ exit(1);
+ }
+
+ buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (buf == NULL) {
+ printf("Error: allocate memory for hostcmd failed\n");
+ fclose(fp);
+ return -ENOMEM;
+ }
+ sprintf(cmdname, "%s", argv[4]);
+ ret = prepare_host_cmd_buffer(cmdname, buf);
+ fclose(fp);
+
+ if (ret == MLAN_STATUS_FAILURE)
+ goto _exit_;
+
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (t_u8 *) hostcmd;
+ iwr.u.data.length = le16_to_cpu(hostcmd->size);
+
+ iwr.u.data.flags = 0;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr, "mlanconfig: MLANHOSTCMD is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ goto _exit_;
+ }
+ ret = process_host_cmd_resp(buf);
+
+ _exit_:
+ if (buf)
+ free(buf);
+
+ return ret;
+}
+
+/**
+ * @brief get range
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise --fail
+ */
+static int
+get_range(t_void)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ size_t buf_len;
+
+ buf_len = sizeof(struct iw_range) + 500;
+ range = malloc(buf_len);
+ if (range == NULL) {
+ printf("Error: allocate memory for iw_range failed\n");
+ return -ENOMEM;
+ }
+ memset(range, 0, buf_len);
+ memset(&iwr, 0, sizeof(struct iwreq));
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buf_len;
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+
+ if ((ioctl(sockfd, SIOCGIWRANGE, &iwr)) < 0) {
+ printf("Get Range Results Failed\n");
+ free(range);
+ return MLAN_STATUS_FAILURE;
+ }
+ we_version_compiled = range->we_version_compiled;
+ printf("Driver build with Wireless Extension %d\n",
+ range->we_version_compiled);
+ free(range);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Display usage
+ *
+ * @return NA
+ */
+static t_void
+display_usage(t_void)
+{
+ t_s32 i;
+ for (i = 0; i < NELEMENTS(usage); i++)
+ fprintf(stderr, "%s\n", usage[i]);
+}
+
+/**
+ * @brief Find command
+ *
+ * @param maxcmds max command number
+ * @param cmds A pointer to commands buffer
+ * @param cmd A pointer to command buffer
+ * @return index of command or MLAN_STATUS_FAILURE
+ */
+static int
+findcommand(t_s32 maxcmds, t_s8 * cmds[], t_s8 * cmd)
+{
+ t_s32 i;
+
+ for (i = 0; i < maxcmds; i++) {
+ if (!strcasecmp(cmds[i], cmd)) {
+ return i;
+ }
+ }
+
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief Process arpfilter
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_arpfilter(int argc, char *argv[])
+{
+ t_u8 *buf;
+ struct iwreq iwr;
+ t_u16 length = 0;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("arpfilter",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc < 4) {
+ printf("Error: invalid no of arguments\n");
+ printf("Syntax: ./mlanconfig mlanX arpfilter <arpfilter.conf>\n");
+ exit(1);
+ }
+
+ if ((fp = fopen(argv[3], "r")) == NULL) {
+ fprintf(stderr, "Cannot open file %s\n", argv[3]);
+ return MLAN_STATUS_FAILURE;
+ }
+ buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (buf == NULL) {
+ printf("Error: allocate memory for arpfilter failed\n");
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ret = prepare_arp_filter_buffer(buf, &length);
+ fclose(fp);
+
+ if (ret == MLAN_STATUS_FAILURE)
+ goto _exit_;
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = length;
+ iwr.u.data.flags = 0;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr,
+ "mlanconfig: arpfilter command is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ goto _exit_;
+ }
+
+ _exit_:
+ if (buf)
+ free(buf);
+
+ return ret;
+}
+
+/**
+ * @brief Process cfgdata
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_cfg_data(int argc, char *argv[])
+{
+ t_u8 *buf;
+ HostCmd_DS_GEN *hostcmd;
+ struct iwreq iwr;
+ int ret = MLAN_STATUS_SUCCESS;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("hostcmd",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc < 4 || argc > 5) {
+ printf("Error: invalid no of arguments\n");
+ printf
+ ("Syntax: ./mlanconfig mlanX cfgdata <register type> <filename>\n");
+ exit(1);
+ }
+
+ if (argc == 5) {
+ if ((fp = fopen(argv[4], "r")) == NULL) {
+ fprintf(stderr, "Cannot open file %s\n", argv[3]);
+ exit(1);
+ }
+ }
+ buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (buf == NULL) {
+ printf("Error: allocate memory for hostcmd failed\n");
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ret = prepare_cfg_data_buffer(argc, argv, buf);
+ if (argc == 5)
+ fclose(fp);
+
+ if (ret == MLAN_STATUS_FAILURE)
+ goto _exit_;
+
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (t_u8 *) hostcmd;
+ iwr.u.data.length = le16_to_cpu(hostcmd->size);
+
+ iwr.u.data.flags = 0;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr, "mlanconfig: MLANHOSTCMD is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ goto _exit_;
+ }
+ ret = process_host_cmd_resp(buf);
+
+ _exit_:
+ if (buf)
+ free(buf);
+
+ return ret;
+}
+
+/**
+ * @brief read current command
+ * @param ptr A pointer to data
+ * @param curCmd A pointer to the buf which will hold current command
+ * @return NULL or the pointer to the left command buf
+ */
+static t_s8 *
+readCurCmd(t_s8 * ptr, t_s8 * curCmd)
+{
+ t_s32 i = 0;
+#define MAX_CMD_SIZE 64 /**< Max command size */
+
+ while (*ptr != ']' && i < (MAX_CMD_SIZE - 1))
+ curCmd[i++] = *(++ptr);
+
+ if (*ptr != ']')
+ return NULL;
+
+ curCmd[i - 1] = '\0';
+
+ return ++ptr;
+}
+
+/**
+ * @brief parse command and hex data
+ * @param fp A pointer to FILE stream
+ * @param dst A pointer to the dest buf
+ * @param cmd A pointer to command buf for search
+ * @return Length of hex data or MLAN_STATUS_FAILURE
+ */
+static int
+fparse_for_cmd_and_hex(FILE * fp, t_u8 * dst, t_u8 * cmd)
+{
+ t_s8 *ptr;
+ t_u8 *dptr;
+ t_s8 buf[256], curCmd[64];
+ t_s32 isCurCmd = 0;
+
+ dptr = dst;
+ while (fgets(buf, sizeof(buf), fp)) {
+ ptr = buf;
+
+ while (*ptr) {
+ /* skip leading spaces */
+ while (*ptr && isspace(*ptr))
+ ptr++;
+
+ /* skip blank lines and lines beginning with '#' */
+ if (*ptr == '\0' || *ptr == '#')
+ break;
+
+ if (*ptr == '[' && *(ptr + 1) != '/') {
+ if (!(ptr = readCurCmd(ptr, curCmd)))
+ return MLAN_STATUS_FAILURE;
+
+ if (strcasecmp(curCmd, (char *) cmd)) /* Not equal */
+ isCurCmd = 0;
+ else
+ isCurCmd = 1;
+ }
+
+ /* Ignore the rest if it is not correct cmd */
+ if (!isCurCmd)
+ break;
+
+ if (*ptr == '[' && *(ptr + 1) == '/')
+ return (dptr - dst);
+
+ if (isxdigit(*ptr)) {
+ ptr = convert2hex(ptr, dptr++);
+ } else {
+ /* Invalid character on data line */
+ ptr++;
+ }
+ }
+ }
+
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief Send an ADDTS command to the associated AP
+ *
+ * Process a given conf file for a specific TSPEC data block. Send the
+ * TSPEC along with any other IEs to the driver/firmware for transmission
+ * in an ADDTS request to the associated AP.
+ *
+ * Return the execution status of the command as well as the ADDTS response
+ * from the AP if any.
+ *
+ * mlanconfig mlanX addts <filename.conf> <section# of tspec> <timeout in ms>
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_addts(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ int ieBytes;
+ wlan_ioctl_wmm_addts_req_t addtsReq;
+
+ FILE *fp;
+ char filename[48];
+ char config_id[20];
+
+ memset(&addtsReq, 0x00, sizeof(addtsReq));
+ memset(filename, 0x00, sizeof(filename));
+
+ if (get_priv_ioctl("addts",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc != 6) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+
+ ieBytes = 0;
+
+ strncpy(filename, argv[3], MIN(sizeof(filename) - 1, strlen(argv[3])));
+ if ((fp = fopen(filename, "r")) == NULL) {
+ perror("fopen");
+ fprintf(stderr, "Cannot open file %s\n", argv[3]);
+ exit(1);
+ }
+
+ sprintf(config_id, "tspec%d", atoi(argv[4]));
+
+ ieBytes =
+ fparse_for_cmd_and_hex(fp, addtsReq.tspecData, (t_u8 *) config_id);
+
+ if (ieBytes > 0) {
+ printf("Found %d bytes in the %s section of conf file %s\n",
+ ieBytes, config_id, filename);
+ } else {
+ fprintf(stderr, "section %s not found in %s\n", config_id, filename);
+ exit(1);
+ }
+
+ addtsReq.timeout_ms = atoi(argv[5]);
+
+ printf("Cmd Input:\n");
+ hexdump(config_id, addtsReq.tspecData, ieBytes, ' ');
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) & addtsReq;
+ iwr.u.data.length = (sizeof(addtsReq.timeout_ms)
+ + sizeof(addtsReq.commandResult)
+ + sizeof(addtsReq.ieeeStatusCode)
+ + ieBytes);
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: addts ioctl");
+ return -EFAULT;
+ }
+
+ ieBytes = iwr.u.data.length - (sizeof(addtsReq.timeout_ms)
+ + sizeof(addtsReq.commandResult)
+ + sizeof(addtsReq.ieeeStatusCode));
+ printf("Cmd Output:\n");
+ printf("ADDTS Command Result = %d\n", addtsReq.commandResult);
+ printf("ADDTS IEEE Status = %d\n", addtsReq.ieeeStatusCode);
+ hexdump(config_id, addtsReq.tspecData, ieBytes, ' ');
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Send a DELTS command to the associated AP
+ *
+ * Process a given conf file for a specific TSPEC data block. Send the
+ * TSPEC along with any other IEs to the driver/firmware for transmission
+ * in a DELTS request to the associated AP.
+ *
+ * Return the execution status of the command. There is no response to a
+ * DELTS from the AP.
+ *
+ * mlanconfig mlanX delts <filename.conf> <section# of tspec>
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_delts(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ int ieBytes;
+ wlan_ioctl_wmm_delts_req_t deltsReq;
+
+ FILE *fp;
+ char filename[48];
+ char config_id[20];
+
+ memset(&deltsReq, 0x00, sizeof(deltsReq));
+ memset(filename, 0x00, sizeof(filename));
+
+ if (get_priv_ioctl("delts",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc != 5) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+
+ ieBytes = 0;
+
+ strncpy(filename, argv[3], MIN(sizeof(filename) - 1, strlen(argv[3])));
+ if ((fp = fopen(filename, "r")) == NULL) {
+ perror("fopen");
+ fprintf(stderr, "Cannot open file %s\n", argv[3]);
+ exit(1);
+ }
+
+ sprintf(config_id, "tspec%d", atoi(argv[4]));
+
+ ieBytes =
+ fparse_for_cmd_and_hex(fp, deltsReq.tspecData, (t_u8 *) config_id);
+
+ if (ieBytes > 0) {
+ printf("Found %d bytes in the %s section of conf file %s\n",
+ ieBytes, config_id, filename);
+ } else {
+ fprintf(stderr, "section %s not found in %s\n", config_id, filename);
+ exit(1);
+ }
+
+ deltsReq.ieeeReasonCode = 0x20; /* 32, unspecified QOS reason */
+
+ printf("Cmd Input:\n");
+ hexdump(config_id, deltsReq.tspecData, ieBytes, ' ');
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) & deltsReq;
+ iwr.u.data.length = (sizeof(deltsReq.commandResult)
+ + sizeof(deltsReq.ieeeReasonCode)
+ + ieBytes);
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: delts ioctl");
+ return -EFAULT;
+ }
+
+ printf("Cmd Output:\n");
+ printf("DELTS Command Result = %d\n", deltsReq.commandResult);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Send a WMM AC Queue configuration command to get/set/default params
+ *
+ * Configure or get the parameters of a WMM AC queue. The command takes
+ * an optional Queue Id as a last parameter. Without the queue id, all
+ * queues will be acted upon.
+ *
+ * mlanconfig mlanX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
+ * mlanconfig mlanX qconfig get [Queue Id: 0-3]
+ * mlanconfig mlanX qconfig def [Queue Id: 0-3]
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_qconfig(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ wlan_ioctl_wmm_queue_config_t queue_config_cmd;
+ mlan_wmm_ac_e ac_idx;
+ mlan_wmm_ac_e ac_idx_start;
+ mlan_wmm_ac_e ac_idx_stop;
+
+ const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" };
+
+ if (argc < 4) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+
+ if (get_priv_ioctl("qconfig",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ memset(&queue_config_cmd, 0x00, sizeof(queue_config_cmd));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) & queue_config_cmd;
+ iwr.u.data.length = sizeof(queue_config_cmd);
+ iwr.u.data.flags = subioctl_val;
+
+ if (strcmp(argv[3], "get") == 0) {
+ /* 3 4 5 */
+ /* qconfig get [qid] */
+ if (argc == 4) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 5) {
+ if (atoi(argv[4]) < WMM_AC_BK || atoi(argv[4]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[4]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_GET;
+
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_config_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qconfig ioctl");
+ } else {
+ printf("qconfig %s(%d): MSDU Lifetime GET = 0x%04x (%d)\n",
+ ac_str_tbl[ac_idx],
+ ac_idx,
+ queue_config_cmd.msduLifetimeExpiry,
+ queue_config_cmd.msduLifetimeExpiry);
+ }
+ }
+ } else if (strcmp(argv[3], "set") == 0) {
+ if ((argc >= 5) && strcmp(argv[4], "msdu") == 0) {
+ /* 3 4 5 6 7 */
+ /* qconfig set msdu <value> [qid] */
+ if (argc == 6) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 7) {
+ if (atoi(argv[6]) < WMM_AC_BK || atoi(argv[6]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[6]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_SET;
+ queue_config_cmd.msduLifetimeExpiry = atoi(argv[5]);
+
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_config_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qconfig ioctl");
+ } else {
+ printf("qconfig %s(%d): MSDU Lifetime SET = 0x%04x (%d)\n",
+ ac_str_tbl[ac_idx],
+ ac_idx,
+ queue_config_cmd.msduLifetimeExpiry,
+ queue_config_cmd.msduLifetimeExpiry);
+ }
+ }
+ } else {
+ /* Only MSDU Lifetime provisioning accepted for now */
+ fprintf(stderr, "Invalid set parameter: s/b [msdu]\n");
+ return -EINVAL;
+ }
+ } else if (strncmp(argv[3], "def", strlen("def")) == 0) {
+ /* 3 4 5 */
+ /* qconfig def [qid] */
+ if (argc == 4) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 5) {
+ if (atoi(argv[4]) < WMM_AC_BK || atoi(argv[4]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[4]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_DEFAULT;
+
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_config_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qconfig ioctl");
+ } else {
+ printf("qconfig %s(%d): MSDU Lifetime DEFAULT = 0x%04x (%d)\n",
+ ac_str_tbl[ac_idx],
+ ac_idx,
+ queue_config_cmd.msduLifetimeExpiry,
+ queue_config_cmd.msduLifetimeExpiry);
+ }
+ }
+ } else {
+ fprintf(stderr, "Invalid qconfig command; s/b [set, get, default]\n");
+ return -EINVAL;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Turn on/off or retrieve and clear the queue statistics for an AC
+ *
+ * Turn the queue statistics collection on/off for a given AC or retrieve the
+ * current accumulated stats and clear them from the firmware. The command
+ * takes an optional Queue Id as a last parameter. Without the queue id,
+ * all queues will be acted upon.
+ *
+ * mlanconfig mlanX qstats on [Queue Id: 0-3]
+ * mlanconfig mlanX qstats off [Queue Id: 0-3]
+ * mlanconfig mlanX qstats get [Queue Id: 0-3]
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_qstats(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ wlan_ioctl_wmm_queue_stats_t queue_stats_cmd;
+ mlan_wmm_ac_e ac_idx;
+ mlan_wmm_ac_e ac_idx_start;
+ mlan_wmm_ac_e ac_idx_stop;
+ t_u16 usedTime[MAX_AC_QUEUES];
+ t_u16 policedTime[MAX_AC_QUEUES];
+
+ const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" };
+
+ if (argc < 3) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+
+ if (get_priv_ioctl("qstats",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ printf("\n");
+
+ memset(usedTime, 0x00, sizeof(usedTime));
+ memset(policedTime, 0x00, sizeof(policedTime));
+ memset(&queue_stats_cmd, 0x00, sizeof(queue_stats_cmd));
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) & queue_stats_cmd;
+ iwr.u.data.length = sizeof(queue_stats_cmd);
+ iwr.u.data.flags = subioctl_val;
+
+ if ((argc > 3) && strcmp(argv[3], "on") == 0) {
+ if (argc == 4) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 5) {
+ if (atoi(argv[4]) < WMM_AC_BK || atoi(argv[4]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[4]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ queue_stats_cmd.action = WMM_STATS_ACTION_START;
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_stats_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qstats ioctl");
+ } else {
+ printf("qstats %s(%d) turned on\n", ac_str_tbl[ac_idx], ac_idx);
+ }
+ }
+ } else if ((argc > 3) && strcmp(argv[3], "off") == 0) {
+ if (argc == 4) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 5) {
+ if (atoi(argv[4]) < WMM_AC_BK || atoi(argv[4]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[4]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ queue_stats_cmd.action = WMM_STATS_ACTION_STOP;
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_stats_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qstats ioctl");
+ } else {
+ printf("qstats %s(%d) turned off\n",
+ ac_str_tbl[ac_idx], ac_idx);
+ }
+ }
+ } else if ((argc >= 3) && ((argc == 3) ? 1 : (strcmp(argv[3], "get") == 0))) {
+ /* If the user types: "mlanconfig mlanX qstats" without get argument.
+ The mlanconfig application invokes "get" option for all queues */
+ if ((argc == 4) || (argc == 3)) {
+ ac_idx_start = WMM_AC_BK;
+ ac_idx_stop = WMM_AC_VO;
+ } else if (argc == 5) {
+ if (atoi(argv[4]) < WMM_AC_BK || atoi(argv[4]) > WMM_AC_VO) {
+ fprintf(stderr, "ERROR: Invalid Queue ID!\n");
+ return -EINVAL;
+ }
+ ac_idx_start = atoi(argv[4]);
+ ac_idx_stop = ac_idx_start;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return -EINVAL;
+ }
+ printf("AC Count Loss TxDly QDly"
+ " <=5 <=10 <=20 <=30 <=40 <=50 >50\n");
+ printf("----------------------------------"
+ "---------------------------------------------\n");
+ queue_stats_cmd.action = WMM_STATS_ACTION_GET_CLR;
+
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ queue_stats_cmd.accessCategory = ac_idx;
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("qstats ioctl");
+ } else {
+ printf("%s %5u %5u %6u %6u"
+ " %5u %5u %5u %5u %5u %5u %5u\n",
+ ac_str_tbl[ac_idx],
+ queue_stats_cmd.pktCount,
+ queue_stats_cmd.pktLoss,
+ (unsigned int) queue_stats_cmd.avgTxDelay,
+ (unsigned int) queue_stats_cmd.avgQueueDelay,
+ queue_stats_cmd.delayHistogram[0],
+ queue_stats_cmd.delayHistogram[1],
+ queue_stats_cmd.delayHistogram[2],
+ queue_stats_cmd.delayHistogram[3],
+ queue_stats_cmd.delayHistogram[4],
+ queue_stats_cmd.delayHistogram[5],
+ queue_stats_cmd.delayHistogram[6]);
+
+ usedTime[ac_idx] = queue_stats_cmd.usedTime;
+ policedTime[ac_idx] = queue_stats_cmd.policedTime;
+ }
+ }
+
+ printf("----------------------------------"
+ "---------------------------------------------\n");
+ printf("\nAC UsedTime PolicedTime\n");
+ printf("---------------------------------\n");
+
+ for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) {
+ printf("%s %6u %6u\n",
+ ac_str_tbl[ac_idx],
+ (unsigned int) usedTime[ac_idx],
+ (unsigned int) policedTime[ac_idx]);
+ }
+ } else {
+ fprintf(stderr, "Invalid qstats command;\n");
+ return -EINVAL;
+ }
+ printf("\n");
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get the current status of the WMM Queues
+ *
+ * Command: mlanconfig mlanX qstatus
+ *
+ * Retrieve the following information for each AC if wmm is enabled:
+ * - WMM IE ACM Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_wmm_qstatus(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ wlan_ioctl_wmm_queue_status_t qstatus;
+ mlan_wmm_ac_e acVal;
+
+ if (get_priv_ioctl("qstatus",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ memset(&qstatus, 0x00, sizeof(qstatus));
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) & qstatus;
+ iwr.u.data.length = (sizeof(qstatus));
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: qstatus ioctl");
+ return -EFAULT;
+ }
+
+ for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+ switch (acVal) {
+ case WMM_AC_BK:
+ printf("BK: ");
+ break;
+ case WMM_AC_BE:
+ printf("BE: ");
+ break;
+ case WMM_AC_VI:
+ printf("VI: ");
+ break;
+ case WMM_AC_VO:
+ printf("VO: ");
+ break;
+ default:
+ printf("??: ");
+ }
+
+ printf("ACM[%c], FlowReq[%c], FlowCreated[%c], Enabled[%c],"
+ " DE[%c], TE[%c]\n",
+ (qstatus.acStatus[acVal].wmmAcm ? 'X' : ' '),
+ (qstatus.acStatus[acVal].flowRequired ? 'X' : ' '),
+ (qstatus.acStatus[acVal].flowCreated ? 'X' : ' '),
+ (qstatus.acStatus[acVal].disabled ? ' ' : 'X'),
+ (qstatus.acStatus[acVal].deliveryEnabled ? 'X' : ' '),
+ (qstatus.acStatus[acVal].triggerEnabled ? 'X' : ' '));
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get the current status of the WMM Traffic Streams
+ *
+ * Command: mlanconfig mlanX ts_status
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_wmm_ts_status(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ wlan_ioctl_wmm_ts_status_t ts_status;
+ int tid;
+
+ const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" };
+
+ if (get_priv_ioctl("ts_status",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ printf("\nTID Valid AC UP PSB FlowDir MediumTime\n");
+ printf("---------------------------------------------------\n");
+
+ for (tid = 0; tid <= 7; tid++) {
+ memset(&ts_status, 0x00, sizeof(ts_status));
+ ts_status.tid = tid;
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) & ts_status;
+ iwr.u.data.length = (sizeof(ts_status));
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: ts_status ioctl");
+ return -EFAULT;
+ }
+
+ printf(" %02d %3s %2s %u %c ",
+ ts_status.tid,
+ (ts_status.valid ? "Yes" : "No"),
+ (ts_status.valid ? ac_str_tbl[ts_status.accessCategory] : "--"),
+ ts_status.userPriority, (ts_status.psb ? 'U' : 'L'));
+
+ if ((ts_status.flowDir & 0x03) == 0) {
+ printf("%s", " ---- ");
+ } else {
+ printf("%2s%4s",
+ (ts_status.flowDir & 0x01 ? "Up" : ""),
+ (ts_status.flowDir & 0x02 ? "Down" : ""));
+ }
+
+ printf("%12u\n", ts_status.mediumTime);
+ }
+
+ printf("\n");
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Provides interface to perform read/write operations on regsiter
+ *
+ * Command: mlanconfig mlanX regrdwr <type> <offset> [value]
+ *
+ * @param argc Number of arguments
+ * @param argv Pointer to the arguments
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_regrdwr(int argc, char *argv[])
+{
+ struct iwreq iwr;
+ int ioctl_val, subioctl_val;
+ t_u32 type, offset, value;
+ t_u8 buf[100];
+ HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *) buf;
+ int ret = MLAN_STATUS_SUCCESS;
+
+ /* Check arguments */
+ if ((argc < 5) || (argc > 6)) {
+ printf("Parameters for regrdwr: <type> <offset> [value]\n");
+ return -EINVAL;
+ }
+
+ if (get_priv_ioctl("hostcmd",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ type = a2hex_or_atoi(argv[3]);
+ offset = a2hex_or_atoi(argv[4]);
+ if (argc > 5)
+ value = a2hex_or_atoi(argv[5]);
+ if ((ret = prepare_hostcmd_regrdwr(type, offset,
+ (argc > 5) ? &value : NULL, buf))) {
+ return ret;
+ }
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = le16_to_cpu(hostcmd->size);
+ iwr.u.data.flags = 0;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr, "mlanconfig: MLANHOSTCMD is not supported by %s\n",
+ dev_name);
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = process_host_cmd_resp(buf);
+
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Get one line from the File
+ *
+ * @param s Storage location for data.
+ * @param size Maximum number of characters to read.
+ * @param line A pointer to return current line number
+ * @return returns string or NULL
+ */
+t_s8 *
+mlan_config_get_line(t_s8 * s, t_s32 size, int *line)
+{
+ t_s8 *pos, *end, *sstart;
+
+ while (fgets(s, size, fp)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ pos = s;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
+ *pos == '\n' || *pos == '\0')
+ continue;
+
+ /* Remove # comments unless they are within a double quoted * string.
+ Remove trailing white space. */
+ sstart = strchr(pos, '"');
+ if (sstart)
+ sstart = strchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + strlen(pos) - 1;
+ while (end > pos && (*end == '\r' || *end == '\n' ||
+ *end == ' ' || *end == '\t')) {
+ *end-- = '\0';
+ }
+ if (*pos == '\0')
+ continue;
+ return pos;
+ }
+ return NULL;
+}
+
+/**
+ * @brief parse hex data
+ * @param dst A pointer to receive hex data
+ * @return length of hex data
+ */
+int
+fparse_for_hex(t_u8 * dst)
+{
+ t_s8 *ptr;
+ t_u8 *dptr;
+ t_s8 buf[256];
+
+ dptr = dst;
+ while (fgets(buf, sizeof(buf), fp)) {
+ ptr = buf;
+
+ while (*ptr) {
+ /* skip leading spaces */
+ while (*ptr && (isspace(*ptr) || *ptr == '\t'))
+ ptr++;
+
+ /* skip blank lines and lines beginning with '#' */
+ if (*ptr == '\0' || *ptr == '#')
+ break;
+
+ if (isxdigit(*ptr)) {
+ ptr = convert2hex(ptr, dptr++);
+ } else {
+ /* Invalid character on data line */
+ ptr++;
+ }
+ }
+ }
+
+ return (dptr - dst);
+}
+
+#define STACK_NBYTES 100 /**< Number of bytes in stack */
+#define MAX_BYTESEQ 6 /**< Maximum byte sequence */
+#define TYPE_DNUM 1 /**< decimal number */
+#define TYPE_BYTESEQ 2 /**< byte sequence */
+#define MAX_OPERAND 0x40 /**< Maximum operands */
+#define TYPE_EQ (MAX_OPERAND+1) /**< byte comparison: == operator */
+#define TYPE_EQ_DNUM (MAX_OPERAND+2) /**< decimal comparison: =d operator */
+#define TYPE_EQ_BIT (MAX_OPERAND+3) /**< bit comparison: =b operator */
+#define TYPE_AND (MAX_OPERAND+4) /**< && operator */
+#define TYPE_OR (MAX_OPERAND+5) /**< || operator */
+typedef struct
+{
+ t_u16 sp; /**< Stack pointer */
+ t_u8 byte[STACK_NBYTES]; /**< Stack */
+} stack_t;
+
+typedef struct
+{
+ t_u8 type; /**< Type */
+ t_u8 reserve[3]; /**< so 4-byte align val array */
+ /* byte sequence is the largest among all the operands and operators. */
+ /* byte sequence format: 1 byte of num of bytes, then variable num bytes */
+ t_u8 val[MAX_BYTESEQ + 1]; /**< Value */
+} op_t;
+
+/**
+ * @brief push data to stack
+ *
+ * @param s a pointer to stack_t structure
+ *
+ * @param nbytes number of byte to push to stack
+ *
+ * @param val a pointer to data buffer
+ *
+ * @return TRUE-- sucess , FALSE -- fail
+ *
+ */
+static int
+push_n(stack_t * s, t_u8 nbytes, t_u8 * val)
+{
+ if ((s->sp + nbytes) < STACK_NBYTES) {
+ memcpy((void *) (s->byte + s->sp), (const void *) val, (size_t) nbytes);
+ s->sp += nbytes;
+ /* printf("push: n %d sp %d\n", nbytes, s->sp); */
+ return TRUE;
+ } else /* stack full */
+ return FALSE;
+}
+
+/**
+ * @brief push data to stack
+ *
+ * @param s a pointer to stack_t structure
+ *
+ * @param op a pointer to op_t structure
+ *
+ * @return TRUE-- sucess , FALSE -- fail
+ *
+ */
+static int
+push(stack_t * s, op_t * op)
+{
+ t_u8 nbytes;
+ switch (op->type) {
+ case TYPE_DNUM:
+ if (push_n(s, 4, op->val))
+ return (push_n(s, 1, &op->type));
+ return FALSE;
+ case TYPE_BYTESEQ:
+ nbytes = op->val[0];
+ if (push_n(s, nbytes, op->val + 1) &&
+ push_n(s, 1, op->val) && push_n(s, 1, &op->type))
+ return TRUE;
+ return FALSE;
+ default:
+ return (push_n(s, 1, &op->type));
+ }
+}
+
+/**
+ * @brief parse RPN string
+ *
+ * @param s a pointer to Null-terminated string to scan.
+ *
+ * @param first_time a pointer to return first_time
+ *
+ * @return A pointer to the last token found in string.
+ * NULL is returned when there are no more tokens to be found.
+ *
+ */
+static char *
+getop(char *s, int *first_time)
+{
+ const char delim[] = " \t\n";
+ char *p;
+ if (*first_time) {
+ p = strtok(s, delim);
+ *first_time = FALSE;
+ } else {
+ p = strtok(NULL, delim);
+ }
+ return (p);
+}
+
+/**
+ * @brief Verify hex digit.
+ *
+ * @param c input ascii char
+ * @param h a pointer to return integer value of the digit char.
+ * @return TURE -- c is hex digit, FALSE -- c is not hex digit.
+ */
+static int
+ishexdigit(char c, t_u8 * h)
+{
+ if (c >= '0' && c <= '9') {
+ *h = c - '0';
+ return (TRUE);
+ } else if (c >= 'a' && c <= 'f') {
+ *h = c - 'a' + 10;
+ return (TRUE);
+ } else if (c >= 'A' && c <= 'F') {
+ *h = c - 'A' + 10;
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/**
+ * @brief convert hex string to integer.
+ *
+ * @param s A pointer to hex string, string length up to 2 digits.
+ * @return integer value.
+ */
+static t_u8
+hex_atoi(char *s)
+{
+ int i;
+ t_u8 digit; /* digital value */
+ t_u8 t = 0; /* total value */
+
+ for (i = 0, t = 0; ishexdigit(s[i], &digit) && i < 2; i++)
+ t = 16 * t + digit;
+ return (t);
+}
+
+/**
+ * @brief Parse byte sequence in hex format string to a byte sequence.
+ *
+ * @param opstr A pointer to byte sequence in hex format string, with ':' as delimiter between two byte.
+ * @param val A pointer to return byte sequence string
+ * @return NA
+ */
+static void
+parse_hex(char *opstr, t_u8 * val)
+{
+ char delim = ':';
+ char *p;
+ char *q;
+ t_u8 i;
+
+ /* +1 is for skipping over the preceding h character. */
+ p = opstr + 1;
+
+ /* First byte */
+ val[1] = hex_atoi(p++);
+
+ /* Parse subsequent bytes. */
+ /* Each byte is preceded by the : character. */
+ for (i = 1; *p; i++) {
+ q = strchr(p, delim);
+ if (!q)
+ break;
+ p = q + 1;
+ val[i + 1] = hex_atoi(p);
+ }
+ /* Set num of bytes */
+ val[0] = i;
+}
+
+/**
+ * @brief str2bin, convert RPN string to binary format
+ *
+ * @param str A pointer to rpn string
+ * @param stack A pointer to stack_t structure
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+str2bin(char *str, stack_t * stack)
+{
+ int first_time;
+ char *opstr;
+ op_t op; /* operator/operand */
+ int dnum;
+ int ret = MLAN_STATUS_SUCCESS;
+
+ memset(stack, 0, sizeof(stack_t));
+ first_time = TRUE;
+ while ((opstr = getop(str, &first_time)) != NULL) {
+ if (isdigit(*opstr)) {
+ op.type = TYPE_DNUM;
+ dnum = atoi(opstr);
+ memcpy((t_u8 *) op.val, &dnum, sizeof(dnum));
+ if (!push(stack, &op)) {
+ printf("push decimal number failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (*opstr == 'h') {
+ op.type = TYPE_BYTESEQ;
+ parse_hex(opstr, op.val);
+ if (!push(stack, &op)) {
+ printf("push byte sequence failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (!strcmp(opstr, "==")) {
+ op.type = TYPE_EQ;
+ if (!push(stack, &op)) {
+ printf("push byte cmp operator failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (!strcmp(opstr, "=d")) {
+ op.type = TYPE_EQ_DNUM;
+ if (!push(stack, &op)) {
+ printf("push decimal cmp operator failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (!strcmp(opstr, "=b")) {
+ op.type = TYPE_EQ_BIT;
+ if (!push(stack, &op)) {
+ printf("push bit cmp operator failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (!strcmp(opstr, "&&")) {
+ op.type = TYPE_AND;
+ if (!push(stack, &op)) {
+ printf("push AND operator failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else if (!strcmp(opstr, "||")) {
+ op.type = TYPE_OR;
+ if (!push(stack, &op)) {
+ printf("push OR operator failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ } else {
+ printf("Unknown operand\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+ return ret;
+}
+
+#define FILTER_BYTESEQ TYPE_EQ /**< byte sequence */
+#define FILTER_DNUM TYPE_EQ_DNUM /**< decimal number */
+#define FILTER_BITSEQ TYPE_EQ_BIT /**< bit sequence */
+#define FILTER_TEST FILTER_BITSEQ+1 /**< test */
+
+#define NAME_TYPE 1 /**< Field name 'type' */
+#define NAME_PATTERN 2 /**< Field name 'pattern' */
+#define NAME_OFFSET 3 /**< Field name 'offset' */
+#define NAME_NUMBYTE 4 /**< Field name 'numbyte' */
+#define NAME_REPEAT 5 /**< Field name 'repeat' */
+#define NAME_BYTE 6 /**< Field name 'byte' */
+#define NAME_MASK 7 /**< Field name 'mask' */
+#define NAME_DEST 8 /**< Field name 'dest' */
+
+static struct mef_fields
+{
+ t_s8 *name;
+ /**< Name */
+ t_s8 nameid;/**< Name Id. */
+} mef_fields[] = {
+ {
+ "type", NAME_TYPE}, {
+ "pattern", NAME_PATTERN}, {
+ "offset", NAME_OFFSET}, {
+ "numbyte", NAME_NUMBYTE}, {
+ "repeat", NAME_REPEAT}, {
+ "byte", NAME_BYTE}, {
+ "mask", NAME_MASK}, {
+ "dest", NAME_DEST}
+};
+
+/**
+ * @brief get filter data
+ *
+ * @param fp A pointer to file stream
+ * @param ln A pointer to line number
+ * @param buf A pointer to hostcmd data
+ * @param size A pointer to the return size of hostcmd buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+mlan_get_filter_data(FILE * fp, int *ln, t_u8 * buf, t_u16 * size)
+{
+ t_s32 errors = 0, i;
+ t_s8 line[256], *pos, *pos1;
+ t_u16 type = 0;
+ t_u32 pattern = 0;
+ t_u16 repeat = 0;
+ t_u16 offset = 0;
+ t_s8 byte_seq[50];
+ t_s8 mask_seq[50];
+ t_u16 numbyte = 0;
+ t_s8 type_find = 0;
+ t_s8 pattern_find = 0;
+ t_s8 offset_find = 0;
+ t_s8 numbyte_find = 0;
+ t_s8 repeat_find = 0;
+ t_s8 byte_find = 0;
+ t_s8 mask_find = 0;
+ t_s8 dest_find = 0;
+ t_s8 dest_seq[50];
+
+ *size = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), ln))) {
+ if (strcmp(pos, "}") == 0) {
+ break;
+ }
+ pos1 = strchr(pos, '=');
+ if (pos1 == NULL) {
+ printf("Line %d: Invalid mef_filter line '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos1++ = '\0';
+ for (i = 0; i < NELEMENTS(mef_fields); i++) {
+ if (strncmp(pos, mef_fields[i].name, strlen(mef_fields[i].name)) ==
+ 0) {
+ switch (mef_fields[i].nameid) {
+ case NAME_TYPE:
+ type = a2hex_or_atoi(pos1);
+ if ((type != FILTER_DNUM) && (type != FILTER_BYTESEQ)
+ && (type != FILTER_BITSEQ) && (type != FILTER_TEST)) {
+ printf("Invalid filter type:%d\n", type);
+ return MLAN_STATUS_FAILURE;
+ }
+ type_find = 1;
+ break;
+ case NAME_PATTERN:
+ pattern = a2hex_or_atoi(pos1);
+ pattern_find = 1;
+ break;
+ case NAME_OFFSET:
+ offset = a2hex_or_atoi(pos1);
+ offset_find = 1;
+ break;
+ case NAME_NUMBYTE:
+ numbyte = a2hex_or_atoi(pos1);
+ numbyte_find = 1;
+ break;
+ case NAME_REPEAT:
+ repeat = a2hex_or_atoi(pos1);
+ repeat_find = 1;
+ break;
+ case NAME_BYTE:
+ memset(byte_seq, 0, sizeof(byte_seq));
+ strcpy(byte_seq, pos1);
+ byte_find = 1;
+ break;
+ case NAME_MASK:
+ memset(mask_seq, 0, sizeof(mask_seq));
+ strcpy(mask_seq, pos1);
+ mask_find = 1;
+ break;
+ case NAME_DEST:
+ memset(dest_seq, 0, sizeof(dest_seq));
+ strcpy(dest_seq, pos1);
+ dest_find = 1;
+ break;
+ }
+ break;
+ }
+ }
+ if (i == NELEMENTS(mef_fields)) {
+ printf("Line %d: unknown mef field '%s'.\n", *line, pos);
+ errors++;
+ }
+ }
+ if (type_find == 0) {
+ printf("Can not find filter type\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ switch (type) {
+ case FILTER_DNUM:
+ if (!pattern_find || !offset_find || !numbyte_find) {
+ printf
+ ("Missing field for FILTER_DNUM: pattern=%d,offset=%d,numbyte=%d\n",
+ pattern_find, offset_find, numbyte_find);
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(line, 0, sizeof(line));
+ sprintf(line, "%ld %d %d =d ", pattern, offset, numbyte);
+ break;
+ case FILTER_BYTESEQ:
+ if (!byte_find || !offset_find || !repeat_find) {
+ printf
+ ("Missing field for FILTER_BYTESEQ: byte=%d,offset=%d,repeat=%d\n",
+ byte_find, offset_find, repeat_find);
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(line, 0, sizeof(line));
+ sprintf(line, "%d h%s %d == ", repeat, byte_seq, offset);
+ break;
+ case FILTER_BITSEQ:
+ if (!byte_find || !offset_find || !mask_find) {
+ printf
+ ("Missing field for FILTER_BYTESEQ: byte=%d,offset=%d,repeat=%d\n",
+ byte_find, offset_find, mask_find);
+ return MLAN_STATUS_FAILURE;
+ }
+ if (strlen(byte_seq) != strlen(mask_seq)) {
+ printf("byte string's length is different with mask's length!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(line, 0, sizeof(line));
+ sprintf(line, "h%s %d h%s =b ", byte_seq, offset, mask_seq);
+ break;
+ case FILTER_TEST:
+ if (!byte_find || !offset_find || !repeat_find || !dest_find) {
+ printf
+ ("Missing field for FILTER_TEST: byte=%d,offset=%d,repeat=%d,dest=%d\n",
+ byte_find, offset_find, repeat_find, dest_find);
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(line, 0, sizeof(line));
+ sprintf(line, "h%s %d h%s %d ", dest_seq, repeat, byte_seq, offset);
+ break;
+ }
+ memcpy(buf, line, strlen(line));
+ *size = strlen(line);
+ return MLAN_STATUS_SUCCESS;
+}
+
+#define NAME_MODE 1 /**< Field name 'mode' */
+#define NAME_ACTION 2 /**< Field name 'action' */
+#define NAME_FILTER_NUM 3 /**< Field name 'filter_num' */
+#define NAME_RPN 4 /**< Field name 'RPN' */
+static struct mef_entry_fields
+{
+ t_s8 *name;
+ /**< Name */
+ t_s8 nameid;/**< Name id */
+} mef_entry_fields[] = {
+ {
+ "mode", NAME_MODE}, {
+ "action", NAME_ACTION}, {
+ "filter_num", NAME_FILTER_NUM}, {
+"RPN", NAME_RPN},};
+
+typedef struct _MEF_ENTRY
+{
+ /** Mode */
+ t_u8 Mode;
+ /** Size */
+ t_u8 Action;
+ /** Size of expression */
+ t_u16 ExprSize;
+} MEF_ENTRY;
+
+/**
+ * @brief get mef_entry data
+ *
+ * @param fp A pointer to file stream
+ * @param ln A pointer to line number
+ * @param buf A pointer to hostcmd data
+ * @param size A pointer to the return size of hostcmd buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+mlan_get_mef_entry_data(FILE * fp, int *ln, t_u8 * buf, t_u16 * size)
+{
+ t_s8 line[256], *pos, *pos1;
+ t_u8 mode, action, filter_num = 0;
+ t_s8 rpn[256];
+ t_s8 mode_find = 0;
+ t_s8 action_find = 0;
+ t_s8 filter_num_find = 0;
+ t_s8 rpn_find = 0;
+ t_s8 rpn_str[256];
+ int rpn_len = 0;
+ t_s8 filter_name[50];
+ t_s8 name_found = 0;
+ t_u16 len = 0;
+ int i;
+ int first_time = TRUE;
+ char *opstr;
+ t_s8 filter_action[10];
+ t_s32 errors = 0;
+ MEF_ENTRY *pMefEntry = (MEF_ENTRY *) buf;
+ stack_t stack;
+ while ((pos = mlan_config_get_line(line, sizeof(line), ln))) {
+ if (strcmp(pos, "}") == 0) {
+ break;
+ }
+ pos1 = strchr(pos, '=');
+ if (pos1 == NULL) {
+ printf("Line %d: Invalid mef_entry line '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos1++ = '\0';
+ if (!mode_find || !action_find || !filter_num_find || !rpn_find) {
+ for (i = 0; i < NELEMENTS(mef_entry_fields); i++) {
+ if (strncmp
+ (pos, mef_entry_fields[i].name,
+ strlen(mef_entry_fields[i].name)) == 0) {
+ switch (mef_entry_fields[i].nameid) {
+ case NAME_MODE:
+ mode = a2hex_or_atoi(pos1);
+ if (mode & ~0x7) {
+ printf("invalid mode=%d\n", mode);
+ return MLAN_STATUS_FAILURE;
+ }
+ pMefEntry->Mode = mode;
+ mode_find = 1;
+ break;
+ case NAME_ACTION:
+ action = a2hex_or_atoi(pos1);
+ if (action & ~0xff) {
+ printf("invalid action=%d\n", action);
+ return MLAN_STATUS_FAILURE;
+ }
+ pMefEntry->Action = action;
+ action_find = 1;
+ break;
+ case NAME_FILTER_NUM:
+ filter_num = a2hex_or_atoi(pos1);
+ filter_num_find = 1;
+ break;
+ case NAME_RPN:
+ memset(rpn, 0, sizeof(rpn));
+ strcpy(rpn, pos1);
+ rpn_find = 1;
+ break;
+ }
+ break;
+ }
+ }
+ if (i == NELEMENTS(mef_fields)) {
+ printf("Line %d: unknown mef_entry field '%s'.\n", *line, pos);
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ if (mode_find && action_find && filter_num_find && rpn_find) {
+ for (i = 0; i < filter_num; i++) {
+ opstr = getop(rpn, &first_time);
+ if (opstr == NULL)
+ break;
+ sprintf(filter_name, "%s={", opstr);
+ name_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), ln))) {
+ if (strncmp(pos, filter_name, strlen(filter_name)) == 0) {
+ name_found = 1;
+ break;
+ }
+ }
+ if (!name_found) {
+ fprintf(stderr, "mlanconfig: %s not found in file\n",
+ filter_name);
+ return MLAN_STATUS_FAILURE;
+ }
+ if (MLAN_STATUS_FAILURE ==
+ mlan_get_filter_data(fp, ln, (t_u8 *) (rpn_str + rpn_len),
+ &len))
+ break;
+ rpn_len += len;
+ if (i > 0) {
+ memcpy(rpn_str + rpn_len, filter_action,
+ strlen(filter_action));
+ rpn_len += strlen(filter_action);
+ }
+ opstr = getop(rpn, &first_time);
+ if (opstr == NULL)
+ break;
+ memset(filter_action, 0, sizeof(filter_action));
+ sprintf(filter_action, "%s ", opstr);
+ }
+ /* Remove the last space */
+ if (rpn_len > 0) {
+ rpn_len--;
+ rpn_str[rpn_len] = 0;
+ }
+ if (MLAN_STATUS_FAILURE == str2bin(rpn_str, &stack)) {
+ printf("Fail on str2bin!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ *size = sizeof(MEF_ENTRY);
+ pMefEntry->ExprSize = stack.sp;
+ memmove(buf + sizeof(MEF_ENTRY), stack.byte, stack.sp);
+ *size += stack.sp;
+ break;
+ } else if (mode_find && action_find && filter_num_find &&
+ (filter_num == 0)) {
+ pMefEntry->ExprSize = 0;
+ *size = sizeof(MEF_ENTRY);
+ break;
+ }
+ }
+ return MLAN_STATUS_SUCCESS;
+}
+
+#define MEFCFG_CMDCODE 0x009a
+/**
+ * @brief Process mef cfg
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_mef_cfg(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ t_s8 line[256], cmdname[256], *pos;
+ int cmdname_found = 0, name_found = 0;
+ int ln = 0;
+ int ret = MLAN_STATUS_SUCCESS;
+ int i;
+ t_u8 *buf;
+ t_u16 buf_len = 0;
+ t_u16 len;
+ struct iwreq iwr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ HostCmd_DS_GEN *hostcmd;
+
+ if (argc < 4) {
+ printf("Error: invalid no of arguments\n");
+ printf("Syntax: ./mlanconfig eth1 mefcfg <mef.conf>\n");
+ exit(1);
+ }
+ if (get_priv_ioctl("hostcmd",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+ sprintf(cmdname, "%s={", argv[2]);
+ cmdname_found = 0;
+ if ((fp = fopen(argv[3], "r")) == NULL) {
+ fprintf(stderr, "Cannot open file %s\n", argv[4]);
+ exit(1);
+ }
+
+ buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (buf == NULL) {
+ fclose(fp);
+ fprintf(stderr, "Cannot alloc memory\n");
+ exit(1);
+ }
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ hostcmd = (HostCmd_DS_GEN *) (buf);
+ hostcmd->command = MEFCFG_CMDCODE;
+ mefcmd = (HostCmd_DS_MEF_CFG *) (buf + S_DS_GEN);
+ buf_len = sizeof(HostCmd_DS_MEF_CFG) + S_DS_GEN;
+
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strcmp(pos, cmdname) == 0) {
+ cmdname_found = 1;
+ sprintf(cmdname, "Criteria=");
+ name_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strncmp(pos, cmdname, strlen(cmdname)) == 0) {
+ name_found = 1;
+ mefcmd->Criteria = a2hex_or_atoi(pos + strlen(cmdname));
+ break;
+ }
+ }
+ if (!name_found) {
+ fprintf(stderr, "mlanconfig: criteria not found in file '%s'\n",
+ argv[3]);
+ break;
+ }
+ sprintf(cmdname, "NumEntries=");
+ name_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strncmp(pos, cmdname, strlen(cmdname)) == 0) {
+ name_found = 1;
+ mefcmd->NumEntries = a2hex_or_atoi(pos + strlen(cmdname));
+ break;
+ }
+ }
+ if (!name_found) {
+ fprintf(stderr,
+ "mlanconfig: NumEntries not found in file '%s'\n",
+ argv[3]);
+ break;
+ }
+ for (i = 0; i < mefcmd->NumEntries; i++) {
+ sprintf(cmdname, "mef_entry_%d={", i);
+ name_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strncmp(pos, cmdname, strlen(cmdname)) == 0) {
+ name_found = 1;
+ break;
+ }
+ }
+ if (!name_found) {
+ fprintf(stderr, "mlanconfig: %s not found in file '%s'\n",
+ cmdname, argv[3]);
+ break;
+ }
+ if (MLAN_STATUS_FAILURE ==
+ mlan_get_mef_entry_data(fp, &ln, buf + buf_len, &len)) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ buf_len += len;
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ /* hexdump("mef_cfg",buf,buf_len, ' '); */
+ if (!cmdname_found)
+ fprintf(stderr, "mlanconfig: cmdname '%s' not found in file '%s'\n",
+ argv[4], argv[3]);
+
+ if (!cmdname_found || !name_found) {
+ ret = MLAN_STATUS_FAILURE;
+ goto mef_exit;
+ }
+ hostcmd->size = buf_len;
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = buf_len;
+ iwr.u.data.flags = 0;
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ fprintf(stderr, "mlanconfig: MEFCFG is not supported by %s\n",
+ dev_name);
+ ret = MLAN_STATUS_FAILURE;
+ goto mef_exit;
+ }
+ ret = process_host_cmd_resp(buf);
+
+ mef_exit:
+ if (buf)
+ free(buf);
+ return ret;
+
+}
+
+/**
+ * @brief Entry function for mlanconfig
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+main(int argc, char *argv[])
+{
+ t_s32 cmd;
+
+ if ((argc == 2) && (strcmp(argv[1], "-v") == 0)) {
+ fprintf(stdout, "Marvell mlanconfig version %s\n", MLANCONFIG_VER);
+ exit(0);
+ }
+ if (argc < 3) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ display_usage();
+ exit(1);
+ }
+
+ strncpy(dev_name, argv[1], IFNAMSIZ);
+
+ /*
+ * create a socket
+ */
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "mlanconfig: Cannot open socket.\n");
+ exit(1);
+ }
+ if (get_range() < 0) {
+ fprintf(stderr, "mlanconfig: Cannot get range.\n");
+ exit(1);
+ }
+ switch ((cmd = findcommand(NELEMENTS(commands), commands, argv[2]))) {
+ case CMD_HOSTCMD:
+ process_host_cmd(argc, argv);
+ break;
+ case CMD_MEFCFG:
+ process_mef_cfg(argc, argv);
+ break;
+ case CMD_ARPFILTER:
+ process_arpfilter(argc, argv);
+ break;
+ case CMD_CFG_DATA:
+ process_cfg_data(argc, argv);
+ break;
+ case CMD_CMD52RW:
+ process_sdcmd52rw(argc, argv);
+ break;
+ case CMD_CMD53RW:
+ process_sdcmd53rw(argc, argv);
+ break;
+ case CMD_GET_SCAN_RSP:
+ process_getscantable(argc, argv);
+ break;
+ case CMD_SET_USER_SCAN:
+ process_setuserscan(argc, argv);
+ break;
+ case CMD_ADD_TS:
+ process_addts(argc, argv);
+ break;
+ case CMD_DEL_TS:
+ process_delts(argc, argv);
+ break;
+ case CMD_QCONFIG:
+ process_qconfig(argc, argv);
+ break;
+ case CMD_QSTATS:
+ process_qstats(argc, argv);
+ break;
+ case CMD_TS_STATUS:
+ process_wmm_ts_status(argc, argv);
+ break;
+ case CMD_WMM_QSTATUS:
+ process_wmm_qstatus(argc, argv);
+ break;
+ case CMD_REGRW:
+ process_regrdwr(argc, argv);
+ break;
+ default:
+ fprintf(stderr, "Invalid command specified!\n");
+ display_usage();
+ exit(1);
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mapp/mlanconfig/mlanconfig.h b/wlan_src/mapp/mlanconfig/mlanconfig.h
new file mode 100755
index 0000000..9f31311
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanconfig.h
@@ -0,0 +1,111 @@
+/** @file mlanconfig.h
+ *
+ * @brief This file contains definitions for application
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 11/26/2008: initial version
+************************************************************************/
+#ifndef _MLANCONFIG_H_
+#define _MLANCONFIG_H_
+
+/** Include header files */
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+#include <sys/types.h>
+#include <linux/if_ether.h>
+#include <linux/byteorder/swab.h>
+#include <time.h>
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#undef BIG_ENDIAN
+#endif
+
+/** Type definition: boolean */
+typedef enum
+{ FALSE, TRUE } boolean;
+
+/**
+ * This macro specifies the attribute pack used for structure packing
+ */
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__((packed))
+#endif
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+((t_u16)((((t_u16)(x) & 0x00ffU) << 8) | \
+ (((t_u16)(x) & 0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+((t_u32)((((t_u32)(x) & 0x000000ffUL) << 24) | \
+ (((t_u32)(x) & 0x0000ff00UL) << 8) | \
+ (((t_u32)(x) & 0x00ff0000UL) >> 8) | \
+ (((t_u32)(x) & 0xff000000UL) >> 24)))
+
+/** Convert to correct endian format */
+#ifdef BIG_ENDIAN
+/** CPU to little-endian convert for 16-bit */
+#define cpu_to_le16(x) swap_byte_16(x)
+/** CPU to little-endian convert for 32-bit */
+#define cpu_to_le32(x) swap_byte_32(x)
+/** Little-endian to CPU convert for 16-bit */
+#define le16_to_cpu(x) swap_byte_16(x)
+/** Little-endian to CPU convert for 32-bit */
+#define le32_to_cpu(x) swap_byte_32(x)
+#else
+/** Do nothing */
+#define cpu_to_le16(x) (x)
+/** Do nothing */
+#define cpu_to_le32(x) (x)
+/** Do nothing */
+#define le16_to_cpu(x) (x)
+/** Do nothing */
+#define le32_to_cpu(x) (x)
+#endif
+
+/** Character, 1 byte */
+typedef char t_s8;
+/** Unsigned character, 1 byte */
+typedef unsigned char t_u8;
+
+/** Short integer */
+typedef signed short t_s16;
+/** Unsigned short integer */
+typedef unsigned short t_u16;
+
+/** Long integer */
+typedef signed long t_s32;
+/** Unsigned long integer */
+typedef unsigned long t_u32;
+
+/** Long long integer */
+typedef signed long long t_s64;
+/** Unsigned long long integer */
+typedef unsigned long long t_u64;
+
+/** Void pointer (4-bytes) */
+typedef void t_void;
+
+/** Success */
+#define MLAN_STATUS_SUCCESS (0)
+/** Failure */
+#define MLAN_STATUS_FAILURE (-1)
+
+t_s8 *mlan_config_get_line(t_s8 * s, t_s32 size, int *line);
+int get_priv_ioctl(char *ioctl_name, int *ioctl_val, int *subioctl_val);
+int fparse_for_hex(t_u8 * dst);
+
+#endif /* _MLANCONFIG_H_ */
diff --git a/wlan_src/mapp/mlanconfig/mlanhostcmd.c b/wlan_src/mapp/mlanconfig/mlanhostcmd.c
new file mode 100755
index 0000000..feb5a5d
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanhostcmd.c
@@ -0,0 +1,822 @@
+/** @file mlanhostcmd.c
+ *
+ * @brief This file contains mlanconfig helper functions
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 11/26/2008: initial version
+************************************************************************/
+
+#include "mlanconfig.h"
+#include "mlanhostcmd.h"
+
+#ifndef MIN
+/** Find minimum value */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif /* MIN */
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief get hostcmd data
+ *
+ * @param ln A pointer to line number
+ * @param buf A pointer to hostcmd data
+ * @param size A pointer to the return size of hostcmd buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+mlan_get_hostcmd_data(int *ln, t_u8 * buf, t_u16 * size)
+{
+ t_s32 errors = 0, i;
+ t_s8 line[256], *pos, *pos1, *pos2, *pos3;
+ t_u16 len;
+
+ while ((pos = mlan_config_get_line(line, sizeof(line), ln))) {
+ (*ln)++;
+ if (strcmp(pos, "}") == 0) {
+ break;
+ }
+
+ pos1 = strchr(pos, ':');
+ if (pos1 == NULL) {
+ printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos1++ = '\0';
+
+ pos2 = strchr(pos1, '=');
+ if (pos2 == NULL) {
+ printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos2++ = '\0';
+
+ len = a2hex_or_atoi(pos1);
+ if (len < 1 || len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+
+ *size += len;
+
+ if (*pos2 == '"') {
+ pos2++;
+ if ((pos3 = strchr(pos2, '"')) == NULL) {
+ printf("Line %d: invalid quotation '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos3 = '\0';
+ memset(buf, 0, len);
+ memmove(buf, pos2, MIN(strlen(pos2), len));
+ buf += len;
+ } else if (*pos2 == '\'') {
+ pos2++;
+ if ((pos3 = strchr(pos2, '\'')) == NULL) {
+ printf("Line %d: invalid quotation '%s'\n", *ln, pos);
+ errors++;
+ continue;
+ }
+ *pos3 = ',';
+ for (i = 0; i < len; i++) {
+ if ((pos3 = strchr(pos2, ',')) != NULL) {
+ *pos3 = '\0';
+ *buf++ = (t_u8) a2hex_or_atoi(pos2);
+ pos2 = pos3 + 1;
+ } else
+ *buf++ = 0;
+ }
+ } else if (*pos2 == '{') {
+ t_u16 tlvlen = 0, tmp_tlvlen;
+ mlan_get_hostcmd_data(ln, buf + len, &tlvlen);
+ tmp_tlvlen = tlvlen;
+ while (len--) {
+ *buf++ = (t_u8) (tmp_tlvlen & 0xff);
+ tmp_tlvlen >>= 8;
+ }
+ *size += tlvlen;
+ buf += tlvlen;
+ } else {
+ t_u32 value = a2hex_or_atoi(pos2);
+ while (len--) {
+ *buf++ = (t_u8) (value & 0xff);
+ value >>= 8;
+ }
+ }
+ }
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief convert char to hex integer
+ *
+ * @param chr char to convert
+ * @return hex integer or 0
+ */
+int
+hexval(t_s32 chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+/**
+ * @brief Hump hex data
+ *
+ * @param prompt A pointer prompt buffer
+ * @param p A pointer to data buffer
+ * @param len the len of data buffer
+ * @param delim delim char
+ * @return hex integer
+ */
+t_void
+hexdump(t_s8 * prompt, t_void * p, t_s32 len, t_s8 delim)
+{
+ t_s32 i;
+ t_u8 *s = p;
+
+ if (prompt) {
+ printf("%s: len=%d\n", prompt, (int) len);
+ }
+ for (i = 0; i < len; i++) {
+ if (i != len - 1)
+ printf("%02x%c", *s++, delim);
+ else
+ printf("%02x\n", *s);
+ if ((i + 1) % 16 == 0)
+ printf("\n");
+ }
+}
+
+/**
+ * @brief convert char to hex integer
+ *
+ * @param chr char
+ * @return hex integer
+ */
+t_u8
+hexc2bin(t_s8 chr)
+{
+ if (chr >= '0' && chr <= '9')
+ chr -= '0';
+ else if (chr >= 'A' && chr <= 'F')
+ chr -= ('A' - 10);
+ else if (chr >= 'a' && chr <= 'f')
+ chr -= ('a' - 10);
+
+ return chr;
+}
+
+/**
+ * @brief convert string to hex integer
+ *
+ * @param s A pointer string buffer
+ * @return hex integer
+ */
+t_u32
+a2hex(t_s8 * s)
+{
+ t_u32 val = 0;
+
+ if (!strncasecmp("0x", s, 2)) {
+ s += 2;
+ }
+
+ while (*s && isxdigit(*s)) {
+ val = (val << 4) + hexc2bin(*s++);
+ }
+
+ return val;
+}
+
+/*
+ * @brief convert String to integer
+ *
+ * @param value A pointer to string
+ * @return integer
+ */
+t_u32
+a2hex_or_atoi(t_s8 * value)
+{
+ if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) {
+ return a2hex(value + 2);
+ } else if (isdigit(*value)) {
+ return atoi(value);
+ } else {
+ return *value;
+ }
+}
+
+/**
+ * @brief convert string to hex
+ *
+ * @param ptr A pointer to data buffer
+ * @param chr A pointer to return integer
+ * @return A pointer to next data field
+ */
+t_s8 *
+convert2hex(t_s8 * ptr, t_u8 * chr)
+{
+ t_u8 val;
+
+ for (val = 0; *ptr && isxdigit(*ptr); ptr++) {
+ val = (val * 16) + hexval(*ptr);
+ }
+
+ *chr = val;
+
+ return ptr;
+}
+
+/**
+ * @brief Check the Hex String
+ * @param s A pointer to the string
+ * @return MLAN_STATUS_SUCCESS --HexString, MLAN_STATUS_FAILURE --not HexString
+ */
+int
+ishexstring(t_s8 * s)
+{
+ int ret = MLAN_STATUS_FAILURE;
+ t_s32 tmp;
+
+ if (!strncasecmp("0x", s, 2)) {
+ s += 2;
+ }
+ while (*s) {
+ tmp = toupper(*s);
+ if (tmp >= 'A' && tmp <= 'F' || (tmp >= '0' && tmp <= '9')) {
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ s++;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Convert String to Integer
+ * @param buf A pointer to the string
+ * @return Integer
+ */
+int
+atoval(t_s8 * buf)
+{
+ if (!strncasecmp(buf, "0x", 2))
+ return a2hex(buf + 2);
+ else if (!ishexstring(buf))
+ return a2hex(buf);
+ else
+ return atoi(buf);
+}
+
+/**
+ * @brief Prepare host-command buffer
+ * @param cmd_name Command name
+ * @param buf A pointer to comand buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+prepare_host_cmd_buffer(char *cmd_name, t_u8 * buf)
+{
+ t_s8 line[256], cmdname[256], *pos, cmdcode[10];
+ HostCmd_DS_GEN *hostcmd;
+ int ln = 0;
+ int cmdname_found = 0, cmdcode_found = 0;
+
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ hostcmd->command = 0xffff;
+
+ sprintf(cmdname, "%s={", cmd_name);
+ cmdname_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strcmp(pos, cmdname) == 0) {
+ cmdname_found = 1;
+ sprintf(cmdcode, "CmdCode=");
+ cmdcode_found = 0;
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strncmp(pos, cmdcode, strlen(cmdcode)) == 0) {
+ cmdcode_found = 1;
+ hostcmd->command = a2hex_or_atoi(pos + strlen(cmdcode));
+ hostcmd->size = S_DS_GEN;
+ mlan_get_hostcmd_data(&ln, buf + hostcmd->size,
+ &hostcmd->size);
+ break;
+ }
+ }
+ if (!cmdcode_found) {
+ fprintf(stderr, "mlanconfig: CmdCode not found in conf file\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ break;
+ }
+ }
+
+ if (!cmdname_found) {
+ fprintf(stderr, "mlanconfig: cmdname '%s' is not found in conf file\n",
+ cmd_name);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ hostcmd->seq_num = 0;
+ hostcmd->result = 0;
+ hostcmd->command = cpu_to_le16(hostcmd->command);
+ hostcmd->size = cpu_to_le16(hostcmd->size);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Config data header length */
+#define CFG_DATA_HEADER_LEN 6
+
+/**
+ * @brief Prepare cfg-data buffer
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @param buf A pointer to comand buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+prepare_cfg_data_buffer(int argc, char *argv[], t_u8 * buf)
+{
+ int ln = 0, type;
+ HostCmd_DS_GEN *hostcmd;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_data;
+
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
+ pcfg_data = (HostCmd_DS_802_11_CFG_DATA *) (buf + S_DS_GEN);
+ pcfg_data->action = (argc == 4) ? HostCmd_ACT_GEN_GET : HostCmd_ACT_GEN_SET;
+ type = atoi(argv[3]);
+ if ((type < 1) || (type > 3)) {
+ fprintf(stderr, "mlanconfig: Invalid register type\n");
+ return MLAN_STATUS_FAILURE;
+ } else {
+ pcfg_data->type = type;
+ }
+ if (argc == 5) {
+ ln = fparse_for_hex(pcfg_data->data);
+ }
+ pcfg_data->data_len = ln;
+ hostcmd->size =
+ cpu_to_le16(pcfg_data->data_len + S_DS_GEN + CFG_DATA_HEADER_LEN);
+ pcfg_data->data_len = cpu_to_le16(pcfg_data->data_len);
+ pcfg_data->type = cpu_to_le16(pcfg_data->type);
+ pcfg_data->action = cpu_to_le16(pcfg_data->action);
+
+ hostcmd->seq_num = 0;
+ hostcmd->result = 0;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Process host_cmd response
+ * @param buf A pointer to the response buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_host_cmd_resp(t_u8 * buf)
+{
+ HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *) buf;
+ int ret = MLAN_STATUS_SUCCESS;
+
+ hostcmd->command = le16_to_cpu(hostcmd->command);
+ hostcmd->size = le16_to_cpu(hostcmd->size);
+
+ hostcmd->command &= ~HostCmd_RET_BIT;
+ if (!le16_to_cpu(hostcmd->result)) {
+ switch (hostcmd->command) {
+ case HostCmd_CMD_CFG_DATA:
+ {
+ HostCmd_DS_802_11_CFG_DATA *pstcfgData =
+ (HostCmd_DS_802_11_CFG_DATA *) (buf + S_DS_GEN);
+ pstcfgData->data_len = le16_to_cpu(pstcfgData->data_len);
+ pstcfgData->action = le16_to_cpu(pstcfgData->action);
+
+ if (pstcfgData->action == HostCmd_ACT_GEN_GET) {
+ hexdump("cfgdata", pstcfgData->data, pstcfgData->data_len,
+ ' ');
+ }
+ break;
+ }
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ {
+ mlan_ioctl_11h_tpc_resp *tpcIoctlResp =
+ (mlan_ioctl_11h_tpc_resp *) (buf + S_DS_GEN);
+ if (tpcIoctlResp->status_code == 0) {
+ printf
+ ("tpcrequest: txPower(%d), linkMargin(%d), rssi(%d)\n",
+ tpcIoctlResp->tx_power, tpcIoctlResp->link_margin,
+ tpcIoctlResp->rssi);
+ } else {
+ printf("tpcrequest: failure, status = %d\n",
+ tpcIoctlResp->status_code);
+ }
+ break;
+ }
+ case HostCmd_CMD_802_11_CRYPTO:
+ {
+ t_u16 alg =
+ le16_to_cpu((t_u16) * (buf + S_DS_GEN + sizeof(t_u16)));
+ if (alg != CIPHER_TEST_AES_CCM) {
+ HostCmd_DS_802_11_CRYPTO *cmd =
+ (HostCmd_DS_802_11_CRYPTO *) (buf + S_DS_GEN);
+ cmd->encdec = le16_to_cpu(cmd->encdec);
+ cmd->algorithm = le16_to_cpu(cmd->algorithm);
+ cmd->key_IV_length = le16_to_cpu(cmd->key_IV_length);
+ cmd->key_length = le16_to_cpu(cmd->key_length);
+ cmd->data.header.type = le16_to_cpu(cmd->data.header.type);
+ cmd->data.header.len = le16_to_cpu(cmd->data.header.len);
+
+ printf
+ ("crypto_result: encdec=%d algorithm=%d,KeyIVLen=%d, KeyLen=%d,dataLen=%d\n",
+ cmd->encdec, cmd->algorithm, cmd->key_IV_length,
+ cmd->key_length, cmd->data.header.len);
+ hexdump("KeyIV", cmd->keyIV, cmd->key_IV_length, ' ');
+ hexdump("Key", cmd->key, cmd->key_length, ' ');
+ hexdump("Data", cmd->data.data, cmd->data.header.len, ' ');
+ } else {
+ HostCmd_DS_802_11_CRYPTO_AES_CCM *cmd_aes_ccm =
+ (HostCmd_DS_802_11_CRYPTO_AES_CCM *) (buf + S_DS_GEN);
+
+ cmd_aes_ccm->encdec = le16_to_cpu(cmd_aes_ccm->encdec);
+ cmd_aes_ccm->algorithm =
+ le16_to_cpu(cmd_aes_ccm->algorithm);
+ cmd_aes_ccm->key_length =
+ le16_to_cpu(cmd_aes_ccm->key_length);
+ cmd_aes_ccm->nonce_length =
+ le16_to_cpu(cmd_aes_ccm->nonce_length);
+ cmd_aes_ccm->AAD_length =
+ le16_to_cpu(cmd_aes_ccm->AAD_length);
+ cmd_aes_ccm->data.header.type =
+ le16_to_cpu(cmd_aes_ccm->data.header.type);
+ cmd_aes_ccm->data.header.len =
+ le16_to_cpu(cmd_aes_ccm->data.header.len);
+
+ printf
+ ("crypto_result: encdec=%d algorithm=%d,KeyLen=%d, NonceLen=%d,AADLen=%d,dataLen=%d\n",
+ cmd_aes_ccm->encdec, cmd_aes_ccm->algorithm,
+ cmd_aes_ccm->key_length, cmd_aes_ccm->nonce_length,
+ cmd_aes_ccm->AAD_length, cmd_aes_ccm->data.header.len);
+ hexdump("Key", cmd_aes_ccm->key, cmd_aes_ccm->key_length,
+ ' ');
+ hexdump("Nonce", cmd_aes_ccm->nonce,
+ cmd_aes_ccm->nonce_length, ' ');
+ hexdump("AAD", cmd_aes_ccm->AAD, cmd_aes_ccm->AAD_length,
+ ' ');
+ hexdump("Data", cmd_aes_ccm->data.data,
+ cmd_aes_ccm->data.header.len, ' ');
+ }
+ break;
+ }
+ case HostCmd_CMD_802_11_AUTO_TX:
+ {
+ HostCmd_DS_802_11_AUTO_TX *at =
+ (HostCmd_DS_802_11_AUTO_TX *) (buf + S_DS_GEN);
+
+ if (le16_to_cpu(at->action) == HostCmd_ACT_GEN_GET) {
+ if (S_DS_GEN + sizeof(at->action) == hostcmd->size) {
+ printf("auto_tx not configured\n");
+ } else {
+ MrvlIEtypesHeader_t *header = &at->auto_tx.header;
+ header->type = le16_to_cpu(header->type);
+ header->len = le16_to_cpu(header->len);
+ if ((S_DS_GEN + sizeof(at->action) +
+ sizeof(MrvlIEtypesHeader_t) + header->len ==
+ hostcmd->size) &&
+ (header->type == TLV_TYPE_AUTO_TX)) {
+ AutoTx_MacFrame_t *atmf =
+ &at->auto_tx.auto_tx_mac_frame;
+ printf("Interval: %d second(s)\n",
+ le16_to_cpu(atmf->interval));
+ printf("Priority: %#x\n", atmf->priority);
+ printf("Frame Length: %d\n",
+ le16_to_cpu(atmf->frame_len));
+ printf
+ ("Dest Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ atmf->dest_mac_addr[0], atmf->dest_mac_addr[1],
+ atmf->dest_mac_addr[2], atmf->dest_mac_addr[3],
+ atmf->dest_mac_addr[4],
+ atmf->dest_mac_addr[5]);
+ printf
+ ("Src Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ atmf->src_mac_addr[0], atmf->src_mac_addr[1],
+ atmf->src_mac_addr[2], atmf->src_mac_addr[3],
+ atmf->src_mac_addr[4], atmf->src_mac_addr[5]);
+
+ hexdump("Frame Payload", atmf->payload,
+ le16_to_cpu(atmf->frame_len) -
+ MLAN_MAC_ADDR_LENGTH * 2, ' ');
+ } else {
+ printf("incorrect auto_tx command response\n");
+ }
+ }
+ }
+ break;
+ }
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ {
+ HostCmd_DS_802_11_SUBSCRIBE_EVENT *se =
+ (HostCmd_DS_802_11_SUBSCRIBE_EVENT *) (buf + S_DS_GEN);
+ if (le16_to_cpu(se->action) == HostCmd_ACT_GEN_GET) {
+ int len =
+ S_DS_GEN + sizeof(HostCmd_DS_802_11_SUBSCRIBE_EVENT);
+ printf("\nEvent\t\tValue\tFreq\tsubscribed\n\n");
+ while (len < hostcmd->size) {
+ MrvlIEtypesHeader_t *header =
+ (MrvlIEtypesHeader_t *) (buf + len);
+ switch (le16_to_cpu(header->type)) {
+ case TLV_TYPE_RSSI_LOW:
+ {
+ MrvlIEtypes_RssiThreshold_t *low_rssi =
+ (MrvlIEtypes_RssiThreshold_t *) (buf + len);
+ printf("Beacon Low RSSI\t%d\t%d\t%s\n",
+ low_rssi->RSSI_value,
+ low_rssi->RSSI_freq,
+ (le16_to_cpu(se->events) & 0x0001) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_SNR_LOW:
+ {
+ MrvlIEtypes_SnrThreshold_t *low_snr =
+ (MrvlIEtypes_SnrThreshold_t *) (buf + len);
+ printf("Beacon Low SNR\t%d\t%d\t%s\n",
+ low_snr->SNR_value,
+ low_snr->SNR_freq,
+ (le16_to_cpu(se->events) & 0x0002) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_FAILCOUNT:
+ {
+ MrvlIEtypes_FailureCount_t *failure_count =
+ (MrvlIEtypes_FailureCount_t *) (buf + len);
+ printf("Failure Count\t%d\t%d\t%s\n",
+ failure_count->fail_value,
+ failure_count->fail_freq,
+ (le16_to_cpu(se->events) & 0x0004) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_BCNMISS:
+ {
+ MrvlIEtypes_BeaconsMissed_t *bcn_missed =
+ (MrvlIEtypes_BeaconsMissed_t *) (buf + len);
+ printf("Beacon Missed\t%d\tN/A\t%s\n",
+ bcn_missed->beacon_missed,
+ (le16_to_cpu(se->events) & 0x0008) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_RSSI_HIGH:
+ {
+ MrvlIEtypes_RssiThreshold_t *high_rssi =
+ (MrvlIEtypes_RssiThreshold_t *) (buf + len);
+ printf("Bcn High RSSI\t%d\t%d\t%s\n",
+ high_rssi->RSSI_value,
+ high_rssi->RSSI_freq,
+ (le16_to_cpu(se->events) & 0x0010) ?
+ "yes" : "no");
+ break;
+ }
+
+ case TLV_TYPE_SNR_HIGH:
+ {
+ MrvlIEtypes_SnrThreshold_t *high_snr =
+ (MrvlIEtypes_SnrThreshold_t *) (buf + len);
+ printf("Beacon High SNR\t%d\t%d\t%s\n",
+ high_snr->SNR_value,
+ high_snr->SNR_freq,
+ (le16_to_cpu(se->events) & 0x0020) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_RSSI_LOW_DATA:
+ {
+ MrvlIEtypes_RssiThreshold_t *low_rssi =
+ (MrvlIEtypes_RssiThreshold_t *) (buf + len);
+ printf("Data Low RSSI\t%d\t%d\t%s\n",
+ low_rssi->RSSI_value,
+ low_rssi->RSSI_freq,
+ (le16_to_cpu(se->events) & 0x0040) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_SNR_LOW_DATA:
+ {
+ MrvlIEtypes_SnrThreshold_t *low_snr =
+ (MrvlIEtypes_SnrThreshold_t *) (buf + len);
+ printf("Data Low SNR\t%d\t%d\t%s\n",
+ low_snr->SNR_value,
+ low_snr->SNR_freq,
+ (le16_to_cpu(se->events) & 0x0080) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_RSSI_HIGH_DATA:
+ {
+ MrvlIEtypes_RssiThreshold_t *high_rssi =
+ (MrvlIEtypes_RssiThreshold_t *) (buf + len);
+ printf("Data High RSSI\t%d\t%d\t%s\n",
+ high_rssi->RSSI_value,
+ high_rssi->RSSI_freq,
+ (le16_to_cpu(se->events) & 0x0100) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_SNR_HIGH_DATA:
+ {
+ MrvlIEtypes_SnrThreshold_t *high_snr =
+ (MrvlIEtypes_SnrThreshold_t *) (buf + len);
+ printf("Data High SNR\t%d\t%d\t%s\n",
+ high_snr->SNR_value,
+ high_snr->SNR_freq,
+ (le16_to_cpu(se->events) & 0x0200) ?
+ "yes" : "no");
+ break;
+ }
+ case TLV_TYPE_LINK_QUALITY:
+ {
+ MrvlIEtypes_LinkQuality_t *link_qual =
+ (MrvlIEtypes_LinkQuality_t *) (buf + len);
+ printf("Link Quality Parameters:\n");
+ printf("------------------------\n");
+ printf("Link Quality Event Subscribed\t%s\n",
+ (le16_to_cpu(se->events) & 0x0400) ?
+ "yes" : "no");
+ printf("Link SNR Threshold = %d\n",
+ le16_to_cpu(link_qual->link_SNR_thrs));
+ printf("Link SNR Frequency = %d\n",
+ le16_to_cpu(link_qual->link_SNR_freq));
+ printf("Min Rate Value = %d\n",
+ le16_to_cpu(link_qual->min_rate_val));
+ printf("Min Rate Frequency = %d\n",
+ le16_to_cpu(link_qual->min_rate_freq));
+ printf("Tx Latency Value = %ld\n",
+ le32_to_cpu(link_qual->tx_latency_val));
+ printf("Tx Latency Threshold = %ld\n",
+ le32_to_cpu(link_qual->tx_latency_thrs));
+
+ break;
+ }
+ case TLV_TYPE_PRE_BEACON_LOST:
+ {
+ MrvlIEtypes_PreBeaconLost_t *pre_bcn_lost =
+ (MrvlIEtypes_PreBeaconLost_t *) (buf + len);
+ printf("------------------------\n");
+ printf("Pre-Beacon Lost Event Subscribed\t%s\n",
+ (le16_to_cpu(se->events) & 0x0800) ?
+ "yes" : "no");
+ printf("Pre-Beacon Lost: %d\n",
+ pre_bcn_lost->pre_beacon_lost);
+
+ break;
+ }
+ default:
+ printf
+ ("unknown subscribed event TLV Type=%#x, Len=%d\n",
+ le16_to_cpu(header->type),
+ le16_to_cpu(header->len));
+ break;
+ }
+ len +=
+ sizeof(MrvlIEtypesHeader_t) +
+ le16_to_cpu(header->len);
+ }
+ }
+ break;
+ }
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_REG *preg = (HostCmd_DS_REG *) (buf + S_DS_GEN);
+ preg->action = le16_to_cpu(preg->action);
+ if (preg->action == HostCmd_ACT_GEN_GET) {
+ preg->value = le32_to_cpu(preg->value);
+ printf("value = 0x%08lx\n", preg->value);
+ }
+ break;
+ }
+
+ default:
+ printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n",
+ le16_to_cpu(hostcmd->command), le16_to_cpu(hostcmd->result));
+ break;
+ }
+ } else {
+ printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",
+ le16_to_cpu(hostcmd->command), le16_to_cpu(hostcmd->result));
+ }
+ return ret;
+}
+
+/**
+ * @brief Prepare ARP filter buffer
+ * @param buf A pointer to the buffer
+ * @param length A pointer to the length of buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+prepare_arp_filter_buffer(t_u8 * buf, t_u16 * length)
+{
+ t_s8 line[256], *pos;
+ int ln = 0;
+ int ret = MLAN_STATUS_SUCCESS;
+ int arpfilter_found = 0;
+
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ while ((pos = mlan_config_get_line(line, sizeof(line), &ln))) {
+ if (strcmp(pos, "arpfilter={") == 0) {
+ arpfilter_found = 1;
+ mlan_get_hostcmd_data(&ln, buf, length);
+ break;
+ }
+ }
+ if (!arpfilter_found) {
+ fprintf(stderr, "mlanconfig: 'arpfilter' not found in conf file");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ return ret;
+}
+
+/**
+ * @brief Prepare the hostcmd for register access
+ * @param type Register type
+ * @param offset Register offset
+ * @param value Pointer to value (NULL for read)
+ * @param buf Pointer to hostcmd buffer
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 * value, t_u8 * buf)
+{
+ HostCmd_DS_GEN *hostcmd;
+ HostCmd_DS_REG *preg;
+
+ hostcmd = (HostCmd_DS_GEN *) buf;
+ switch (type) {
+ case 1:
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_MAC_REG_ACCESS);
+ break;
+ case 2:
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_BBP_REG_ACCESS);
+ break;
+ case 3:
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_RF_REG_ACCESS);
+ break;
+ case 4:
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_PMIC_REG_ACCESS);
+ break;
+ case 5:
+ hostcmd->command = cpu_to_le16(HostCmd_CMD_CAU_REG_ACCESS);
+ break;
+ default:
+ printf("Invalid register set specified\n");
+ return -EINVAL;
+ }
+ preg = (HostCmd_DS_REG *) (buf + S_DS_GEN);
+ preg->action = (value) ? HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET;
+ preg->action = cpu_to_le16(preg->action);
+ preg->offset = cpu_to_le16((t_u16) offset);
+ if (value)
+ preg->value = cpu_to_le32(*value);
+ else
+ preg->value = 0;
+ hostcmd->size = cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_REG));
+ hostcmd->seq_num = 0;
+ hostcmd->result = 0;
+
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mapp/mlanconfig/mlanhostcmd.h b/wlan_src/mapp/mlanconfig/mlanhostcmd.h
new file mode 100755
index 0000000..30412d9
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanhostcmd.h
@@ -0,0 +1,333 @@
+/** @file mlanhostcmd.h
+ *
+ * @brief This file contains command structures for mlanconfig application
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 11/26/2008: initial version
+************************************************************************/
+#ifndef _MLANHOSTCMD_H_
+#define _MLANHOSTCMD_H_
+
+/** Find number of elements */
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE 0x0004
+
+/** Read/Write Mac register */
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+/** Read/Write BBP register */
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+/** Read/Write RF register */
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+/** Host Command ID : PMIC register access */
+#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad
+/** Host Command ID : CAU register access */
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+
+/** Host Command ID : 802.11 BG scan configuration */
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
+/** Host Command ID : Configuration data */
+#define HostCmd_CMD_CFG_DATA 0x008f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060
+/** Host Command ID : 802.11 crypto */
+#define HostCmd_CMD_802_11_CRYPTO 0x0078
+/** Host Command ID : 802.11 auto Tx */
+#define HostCmd_CMD_802_11_AUTO_TX 0x0082
+
+/** Host Command ID : 802.11 subscribe event */
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
+/** TLV type : Auto Tx */
+#define TLV_TYPE_AUTO_TX (PROPRIETARY_TLV_BASE_ID + 24)
+/** TLV type :Link Quality */
+#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 36)
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 38)
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 39)
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 40)
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 41)
+/** TLV type: Pre-Beacon Lost */
+#define TLV_TYPE_PRE_BEACON_LOST (PROPRIETARY_TLV_BASE_ID + 73)
+
+/* Define general hostcmd data structure */
+/** HostCmd_DS_GEN */
+typedef struct MAPP_HostCmd_DS_GEN
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} __ATTRIB_PACK__ HostCmd_DS_GEN;
+
+typedef struct _HostCmd_DS_MEF_CFG
+{
+ /** Criteria */
+ t_u32 Criteria;
+ /** Number of entries */
+ t_u16 NumEntries;
+} __ATTRIB_PACK__ HostCmd_DS_MEF_CFG;
+
+typedef struct _MEF_CFG_DATA
+{
+ /** Size */
+ t_u16 size;
+ /** Data */
+ HostCmd_DS_MEF_CFG data;
+} __ATTRIB_PACK__ MEF_CFG_DATA;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/** HostCmd_DS_REG */
+typedef struct MAPP_HostCmd_DS_REG
+{
+ /** Read or write */
+ t_u16 action;
+ /** Register offset */
+ t_u16 offset;
+ /** Value */
+ t_u32 value;
+} __ATTRIB_PACK__ HostCmd_DS_REG;
+
+/** HostCmd_DS_802_11_CFG_DATA */
+typedef struct MAPP_HostCmd_DS_802_11_CFG_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+ t_u8 data[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA;
+
+/** mlan_ioctl_11h_tpc_resp */
+typedef struct
+{
+ int status_code; /**< Firmware command result status code */
+ int tx_power; /**< Reported TX Power from the TPC Report */
+ int link_margin; /**< Reported Link margin from the TPC Report */
+ int rssi; /**< RSSI of the received TPC Report frame */
+} __ATTRIB_PACK__ mlan_ioctl_11h_tpc_resp;
+
+/** MrvlIEtypesHeader_t */
+typedef struct MrvlIEtypesHeader
+{
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef struct MrvlIEtypes_Data_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[1];
+} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
+
+/** HostCmd_DS_802_11_CRYPTO */
+typedef struct MAPP_HostCmd_DS_802_11_CRYPTO
+{
+ t_u16 encdec; /**< Decrypt=0, Encrypt=1 */
+ t_u16 algorithm; /**< RC4=1 AES=2 , AES_KEY_WRAP=3 */
+ t_u16 key_IV_length; /**< Length of Key IV (bytes) */
+ t_u8 keyIV[32]; /**< Key IV */
+ t_u16 key_length; /**< Length of Key (bytes) */
+ t_u8 key[32]; /**< Key */
+ MrvlIEtypes_Data_t data; /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO;
+
+/** HostCmd_DS_802_11_CRYPTO_AES_CCM */
+typedef struct MAPP_HostCmd_DS_802_11_CRYPTO_AES_CCM
+{
+ t_u16 encdec; /**< Decrypt=0, Encrypt=1 */
+ t_u16 algorithm; /**< AES_CCM=4 */
+ t_u16 key_length; /**< Length of Key (bytes) */
+ t_u8 key[32]; /**< Key */
+ t_u16 nonce_length; /**< Length of Nonce (bytes) */
+ t_u8 nonce[14]; /**< Nonce */
+ t_u16 AAD_length; /**< Length of AAD (bytes) */
+ t_u8 AAD[32]; /**< AAD */
+ MrvlIEtypes_Data_t data; /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO_AES_CCM;
+
+/** AES CCM cipher test */
+#define CIPHER_TEST_AES_CCM (4)
+/** AutoTx_MacFrame_t */
+typedef struct AutoTx_MacFrame
+{
+ t_u16 interval; /**< in seconds */
+ t_u8 priority; /**< User Priority: 0~7, ignored if non-WMM */
+ t_u8 reserved; /**< set to 0 */
+ t_u16 frame_len; /**< Length of MAC frame payload */
+ t_u8 dest_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Destination MAC address */
+ t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Source MAC address */
+ t_u8 payload[]; /**< Payload */
+} __ATTRIB_PACK__ AutoTx_MacFrame_t;
+
+/** MrvlIEtypes_AutoTx_t */
+typedef struct MrvlIEtypes_AutoTx
+{
+ MrvlIEtypesHeader_t header; /**< Header */
+ AutoTx_MacFrame_t auto_tx_mac_frame; /**< Auto Tx MAC frame */
+} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t;
+
+/** HostCmd_DS_802_11_AUTO_TX */
+typedef struct MAPP_HostCmd_DS_802_11_AUTO_TX
+{
+ /** Action */
+ t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */
+ MrvlIEtypes_AutoTx_t auto_tx; /**< Auto Tx */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX;
+
+/** HostCmd_DS_802_11_SUBSCRIBE_EVENT */
+typedef struct MAPP_HostCmd_DS_802_11_SUBSCRIBE_EVENT
+{
+ /** Action */
+ t_u16 action;
+ /** Events */
+ t_u16 events;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT;
+
+/** MrvlIEtypes_RssiParamSet_t */
+typedef struct MrvlIEtypes_RssiThreshold
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSSI value */
+ t_u8 RSSI_value;
+ /** RSSI frequency */
+ t_u8 RSSI_freq;
+} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t;
+
+/** MrvlIEtypes_SnrThreshold_t */
+typedef struct MrvlIEtypes_SnrThreshold
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SNR value */
+ t_u8 SNR_value;
+ /** SNR frequency */
+ t_u8 SNR_freq;
+} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t;
+
+/** MrvlIEtypes_FailureCount_t */
+typedef struct MrvlIEtypes_FailureCount
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Failure value */
+ t_u8 fail_value;
+ /** Failure frequency */
+ t_u8 fail_freq;
+} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t;
+
+/** MrvlIEtypes_BeaconsMissed_t */
+typedef struct MrvlIEtypes_BeaconsMissed
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of beacons missed */
+ t_u8 beacon_missed;
+ /** Reserved */
+ t_u8 reserved;
+} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t;
+
+/** MrvlIEtypes_LinkQuality_t */
+typedef struct MrvlIEtypes_LinkQuality
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Link SNR threshold */
+ t_u16 link_SNR_thrs;
+ /** Link SNR frequency */
+ t_u16 link_SNR_freq;
+ /** Minimum rate value */
+ t_u16 min_rate_val;
+ /** Minimum rate frequency */
+ t_u16 min_rate_freq;
+ /** Tx latency value */
+ t_u32 tx_latency_val;
+ /** Tx latency threshold */
+ t_u32 tx_latency_thrs;
+} __ATTRIB_PACK__ MrvlIEtypes_LinkQuality_t;
+
+/** MrvlIEtypes_PreBeaconLost_t */
+typedef struct MrvlIEtypes_PreBeaconLost
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Pre-Beacon Lost */
+ t_u8 pre_beacon_lost;
+ /** Reserved */
+ t_u8 reserved;
+} __ATTRIB_PACK__ MrvlIEtypes_PreBeaconLost_t;
+
+/* String helper functions */
+/** Convert char to hex integer */
+int hexval(t_s32 chr);
+/** Convert char to hex integer */
+t_u8 hexc2bin(t_s8 chr);
+/** Convert string to hex integer */
+t_u32 a2hex(t_s8 * s);
+/** Check the Hex String */
+int ishexstring(t_s8 * s);
+/** Convert String to integer */
+t_u32 a2hex_or_atoi(t_s8 * value);
+/** Convert String to Integer */
+int atoval(t_s8 * buf);
+/** Hump hex data */
+void hexdump(t_s8 * prompt, void *p, t_s32 len, t_s8 delim);
+/** Convert String to Hex */
+t_s8 *convert2hex(t_s8 * ptr, t_u8 * chr);
+
+int process_host_cmd_resp(t_u8 * buf);
+int prepare_host_cmd_buffer(char *cmd_name, t_u8 * buf);
+int prepare_arp_filter_buffer(t_u8 * buf, t_u16 * length);
+int prepare_cfg_data_buffer(int argc, char *argv[], t_u8 * buf);
+int prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 * value,
+ t_u8 * buf);
+
+#endif /* _MLANHOSTCMD_H_ */
diff --git a/wlan_src/mapp/mlanconfig/mlanmisc.c b/wlan_src/mapp/mlanconfig/mlanmisc.c
new file mode 100755
index 0000000..4e1a135
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanmisc.c
@@ -0,0 +1,960 @@
+/** @file mlanmisc.c
+ *
+ * @brief Program to prepare command buffer
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/************************************************************************
+Change log:
+ 03/10/2009: initial version
+************************************************************************/
+
+#include "mlanconfig.h"
+#include "mlanhostcmd.h"
+#include "mlanmisc.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern t_s32 sockfd; /**< socket */
+extern t_s8 dev_name[IFNAMSIZ + 1]; /**< device name */
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Helper function for process_getscantable_idx
+ *
+ * @param pbuf A pointer to the buffer
+ * @param buf_len buffer length
+ *
+ * @return NA
+ *
+ */
+static void
+dump_scan_elems(const t_u8 * pbuf, uint buf_len)
+{
+ uint idx;
+ uint marker = 2 + pbuf[1];
+
+ for (idx = 0; idx < buf_len; idx++) {
+ if (idx % 0x10 == 0) {
+ printf("\n%04x: ", idx);
+ }
+
+ if (idx == marker) {
+ printf("|");
+ marker = idx + pbuf[idx + 1] + 2;
+ } else {
+ printf(" ");
+ }
+
+ printf("%02x ", pbuf[idx]);
+ }
+
+ printf("\n");
+}
+
+/**
+ * @brief Helper function for process_getscantable_idx
+ * Find next element
+ *
+ * @param pp_ie_out pointer of a IEEEtypes_Generic_t structure pointer
+ * @param p_buf_left integer pointer, which contains the number of left p_buf
+ *
+ * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
+ */
+static int
+scantable_elem_next(IEEEtypes_Generic_t ** pp_ie_out, int *p_buf_left)
+{
+ IEEEtypes_Generic_t *pie_gen;
+ t_u8 *p_next;
+
+ if (*p_buf_left < 2) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pie_gen = *pp_ie_out;
+
+ p_next = (t_u8 *) pie_gen + (pie_gen->ieee_hdr.len
+ + sizeof(pie_gen->ieee_hdr));
+ *p_buf_left -= (p_next - (t_u8 *) pie_gen);
+
+ *pp_ie_out = (IEEEtypes_Generic_t *) p_next;
+
+ if (*p_buf_left <= 0) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+ /**
+ * @brief Helper function for process_getscantable_idx
+ * scantable find element
+ *
+ * @param ie_buf pointer of the IE buffer
+ * @param ie_buf_len IE buffer length
+ * @param ie_type IE type
+ * @param ppie_out pointer to the IEEEtypes_Generic_t structure pointer
+ * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
+ */
+static int
+scantable_find_elem(t_u8 * ie_buf,
+ unsigned int ie_buf_len,
+ IEEEtypes_ElementId_e ie_type,
+ IEEEtypes_Generic_t ** ppie_out)
+{
+ int found;
+ unsigned int ie_buf_left;
+
+ ie_buf_left = ie_buf_len;
+
+ found = FALSE;
+
+ *ppie_out = (IEEEtypes_Generic_t *) ie_buf;
+
+ do {
+ found = ((*ppie_out)->ieee_hdr.element_id == ie_type);
+
+ } while (!found &&
+ (scantable_elem_next(ppie_out, (int *) &ie_buf_left) == 0));
+
+ if (!found) {
+ *ppie_out = NULL;
+ }
+
+ return (found ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE);
+}
+
+ /**
+ * @brief Helper function for process_getscantable_idx
+ * It gets SSID from IE
+ *
+ * @param ie_buf IE buffer
+ * @param ie_buf_len IE buffer length
+ * @param pssid SSID
+ * @param ssid_buf_max size of SSID
+ * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE
+ */
+static int
+scantable_get_ssid_from_ie(t_u8 * ie_buf,
+ unsigned int ie_buf_len,
+ t_u8 * pssid, unsigned int ssid_buf_max)
+{
+ int retval;
+ IEEEtypes_Generic_t *pie_gen;
+
+ retval = scantable_find_elem(ie_buf, ie_buf_len, SSID, &pie_gen);
+
+ memcpy(pssid, pie_gen->data, MIN(pie_gen->ieee_hdr.len, ssid_buf_max));
+
+ return retval;
+}
+
+/**
+ * @brief Provision the driver with a IEEE IE for use in the next join cmd
+ *
+ * @param table_idx table index
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+process_getscantable_idx(int table_idx)
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ t_u8 *pcurrent;
+ int bss_info_len, ret = 0;
+ char ssid[33];
+ t_u16 tmp_cap;
+ t_u8 tsf[8];
+ t_u16 beacon_interval;
+ t_u8 *scan_rsp_buf = NULL;
+ t_u16 cap_info;
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+
+ scan_rsp_buf = (t_u8 *) malloc(SCAN_RESP_BUF_SIZE);
+ if (scan_rsp_buf == NULL) {
+ printf("Error: allocate memory for scan_rsp_buf failed\n");
+ return -ENOMEM;
+ }
+ memset(ssid, 0x00, sizeof(ssid));
+
+ prsp_info = (wlan_ioctl_get_scan_table_info *) scan_rsp_buf;
+
+ prsp_info->scan_number = table_idx;
+
+ if (get_priv_ioctl("getscantable",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ /*
+ * Set up and execute the ioctl call
+ */
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) prsp_info;
+ iwr.u.data.length = SCAN_RESP_BUF_SIZE;
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: getscantable ioctl");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ prsp_entry
+ = (wlan_ioctl_get_scan_table_entry *) prsp_info->scan_table_entry_buf;
+
+ if (prsp_info->scan_number == 0) {
+ printf("mlanconfig: getscantable ioctl - index out of range\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pcurrent = prsp_info->scan_table_entry_buf;
+ pcurrent += (sizeof(prsp_entry->fixed_field_length) +
+ prsp_entry->fixed_field_length);
+
+ bss_info_len = prsp_entry->bss_info_length;
+ pcurrent += sizeof(prsp_entry->bss_info_length);
+
+ /* time stamp is 8 byte long */
+ memcpy(tsf, pcurrent, sizeof(tsf));
+ pcurrent += sizeof(tsf);
+ bss_info_len -= sizeof(tsf);
+
+ /* beacon interval is 2 byte long */
+ memcpy(&beacon_interval, pcurrent, sizeof(beacon_interval));
+ /* endian convert needed here */
+ beacon_interval = le16_to_cpu(beacon_interval);
+ pcurrent += sizeof(beacon_interval);
+ bss_info_len -= sizeof(beacon_interval);
+
+ /* capability information is 2 byte long */
+ memcpy(&cap_info, pcurrent, sizeof(cap_info));
+ /* endian convert needed here */
+ cap_info = le16_to_cpu(cap_info);
+ pcurrent += sizeof(cap_info);
+ bss_info_len -= sizeof(cap_info);
+
+ scantable_get_ssid_from_ie(pcurrent,
+ bss_info_len, (t_u8 *) ssid, sizeof(ssid));
+
+ printf("\n*** [%s], %02x:%02x:%02x:%02x:%02x:%2x\n",
+ ssid,
+ prsp_entry->fixed_fields.bssid[0], prsp_entry->fixed_fields.bssid[1],
+ prsp_entry->fixed_fields.bssid[2], prsp_entry->fixed_fields.bssid[3],
+ prsp_entry->fixed_fields.bssid[4],
+ prsp_entry->fixed_fields.bssid[5]);
+ memcpy(&tmp_cap, &cap_info, sizeof(tmp_cap));
+ printf("Channel = %d, SS = %d, CapInfo = 0x%04x, BcnIntvl = %d\n",
+ prsp_entry->fixed_fields.channel,
+ 255 - prsp_entry->fixed_fields.rssi, tmp_cap, beacon_interval);
+
+ printf("TSF Values: AP(0x%02x%02x%02x%02x%02x%02x%02x%02x), ",
+ tsf[7], tsf[6], tsf[5], tsf[4], tsf[3], tsf[2], tsf[1], tsf[0]);
+
+ printf("Network(0x%016llx)\n", prsp_entry->fixed_fields.network_tsf);
+ printf("\n");
+ printf("Element Data (%d bytes)\n", bss_info_len);
+ printf("------------");
+ dump_scan_elems(pcurrent, bss_info_len);
+ printf("\n");
+
+ done:
+ if (scan_rsp_buf)
+ free(scan_rsp_buf);
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/** Maximum SDIO command-52 buffer length */
+#define CMD52_BUF_LEN 7
+
+/**
+ * @brief SD comand52 read/write
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_sdcmd52rw(int argc, char *argv[])
+{
+ struct iwreq iwr;
+ t_u8 buf[CMD52_BUF_LEN];
+ t_u32 tmp;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("sdcmd52rw",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc == 5) {
+ buf[0] = 0; /* CMD52 read */
+ iwr.u.data.length = CMD52_BUF_LEN - 1;
+ } else if (argc == 6) {
+ buf[0] = 1; /* CMD52 write */
+ buf[6] = atoval(argv[5]); /* dat */
+ iwr.u.data.length = CMD52_BUF_LEN;
+ } else {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ buf[1] = atoval(argv[3]); /* func */
+ tmp = atoval(argv[4]); /* reg */
+ buf[2] = tmp & 0xff;
+ buf[3] = (tmp >> 8) & 0xff;
+ buf[4] = (tmp >> 16) & 0xff;
+ buf[5] = (tmp >> 24) & 0xff;
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) buf;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ perror("mlanconfig");
+ fprintf(stderr,
+ "mlanconfig: CMD52 R/W not supported by "
+ "interface %s\n", dev_name);
+ return MLAN_STATUS_FAILURE;
+ }
+ printf("sdcmd52rw returns 0x%02X\n", buf[0]);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Maximum SDIO command-53 buffer length */
+#define CMD53_BUF_LEN 2000
+
+/**
+ * @brief SD comand53 read/write
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_sdcmd53rw(int argc, char *argv[])
+{
+ struct iwreq iwr;
+ t_s8 *buf = NULL;
+ int addr, mode, blklen, blknum, i, rw;
+ int ioctl_val, subioctl_val;
+
+ if (get_priv_ioctl("sdcmd53rw",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ if (argc < 8) {
+ fprintf(stderr, "Invalid number of parameters!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (!(buf = malloc(CMD53_BUF_LEN)))
+ return -ENOMEM;
+ memset(buf, 0, CMD53_BUF_LEN);
+
+ if (argc == 8) {
+ rw = buf[0] = 0; /* CMD53 read */
+ } else {
+ rw = buf[0] = 1; /* CMD53 write */
+ }
+ buf[1] = atoval(argv[3]); /* func */
+ addr = atoval(argv[4]); /* address */
+ buf[2] = addr & 0xff;
+ buf[3] = (addr >> 8) & 0xff;
+ buf[4] = (addr >> 16) & 0xff;
+ buf[5] = (addr >> 24) & 0xff;
+ mode = atoval(argv[5]); /* mode */
+ buf[6] = (t_u8) mode;
+ blklen = atoval(argv[6]); /* block size */
+ buf[7] = blklen & 0xff;
+ buf[8] = (blklen >> 8) & 0xff;
+ blknum = atoval(argv[7]); /* block number or byte number */
+ buf[9] = blknum & 0xff;
+ buf[10] = (blknum >> 8) & 0xff;
+ iwr.u.data.length = 11;
+ if (buf[0]) {
+ for (i = 0; i < (argc - 8); i++)
+ buf[11 + i] = atoval(argv[8 + i]);
+ iwr.u.data.length += (argc - 8);
+ }
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.flags = subioctl_val;
+ iwr.u.data.pointer = (caddr_t) buf;
+
+ if (ioctl(sockfd, ioctl_val, &iwr)) {
+ perror("mlanconfig");
+ fprintf(stderr,
+ "mlanconfig: CMD53 R/W not supported by "
+ "interface %s\n", dev_name);
+ free(buf);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (mode) {
+ fprintf(stderr, "CMD53rw blklen = %d, blknum = %d\n", blklen, blknum);
+ } else {
+ blklen = 1;
+ fprintf(stderr, "CMD53rw bytelen = %d\n", blknum);
+ }
+ if (!rw)
+ hexdump("data", buf, blklen * blknum, ' ');
+
+ free(buf);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve and display the contents of the driver scan table.
+ *
+ * The ioctl to retrieve the scan table contents will be invoked, and portions
+ * of the scan data will be displayed on stdout. The entire beacon or
+ * probe response is also retrieved (if available in the driver). This
+ * data would be needed in case the application was explicitly controlling
+ * the association (inserting IEs, TLVs, etc).
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_getscantable(int argc, char *argv[])
+{
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ t_u8 *scan_rsp_buf = NULL;
+
+ unsigned int scan_start;
+ int idx, ret = 0;
+
+ t_u8 *pcurrent;
+ t_u8 *pnext;
+ IEEEtypes_ElementId_e *pelement_id;
+ t_u8 *pelement_len;
+ int bss_info_len;
+ int ssid_idx;
+ t_u8 *pbyte;
+ char ssid[33];
+ int ssid_len = 0;
+
+ IEEEtypes_CapInfo_t cap_info = { 0 };
+ t_u16 tmp_cap;
+ t_u8 tsf[8];
+ t_u16 beacon_interval;
+
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+ IEEEtypes_WmmParameter_t *pwmm_ie;
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+ IEEEtypes_VendorSpecific_t *pwps_ie;
+ const t_u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
+ char wmm_cap;
+ char wps_cap;
+ char dot11k_cap;
+ char dot11r_cap;
+ char priv_cap;
+ char ht_cap;
+
+ int displayed_info;
+
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+
+ scan_rsp_buf = (t_u8 *) malloc(SCAN_RESP_BUF_SIZE);
+ if (scan_rsp_buf == NULL) {
+ printf("Error: allocate memory for scan_rsp_buf failed\n");
+ return -ENOMEM;
+ }
+ prsp_info = (wlan_ioctl_get_scan_table_info *) scan_rsp_buf;
+
+ if (get_priv_ioctl("getscantable",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ if (argc > 3 && (strcmp(argv[3], "tsf") != 0)
+ && (strcmp(argv[3], "help") != 0)) {
+
+ idx = strtol(argv[3], NULL, 10);
+
+ if (idx >= 0) {
+ if (scan_rsp_buf)
+ free(scan_rsp_buf);
+ return process_getscantable_idx(idx);
+ }
+ }
+
+ displayed_info = FALSE;
+ scan_start = 1;
+
+ printf("---------------------------------------");
+ printf("---------------------------------------\n");
+ printf("# | ch | ss | bssid | cap | SSID \n");
+ printf("---------------------------------------");
+ printf("---------------------------------------\n");
+
+ do {
+ prsp_info->scan_number = scan_start;
+
+ /*
+ * Set up and execute the ioctl call
+ */
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) prsp_info;
+ iwr.u.data.length = SCAN_RESP_BUF_SIZE;
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: getscantable ioctl");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pcurrent = 0;
+ pnext = prsp_info->scan_table_entry_buf;
+
+ for (idx = 0; idx < prsp_info->scan_number; idx++) {
+
+ /*
+ * Set pcurrent to pnext in case pad bytes are at the end
+ * of the last IE we processed.
+ */
+ pcurrent = pnext;
+
+ prsp_entry = (wlan_ioctl_get_scan_table_entry *) pcurrent;
+
+ printf("%02u| %03d | %03d | %02x:%02x:%02x:%02x:%02x:%02x |",
+ scan_start + idx,
+ prsp_entry->fixed_fields.channel,
+ 255 - prsp_entry->fixed_fields.rssi,
+ prsp_entry->fixed_fields.bssid[0],
+ prsp_entry->fixed_fields.bssid[1],
+ prsp_entry->fixed_fields.bssid[2],
+ prsp_entry->fixed_fields.bssid[3],
+ prsp_entry->fixed_fields.bssid[4],
+ prsp_entry->fixed_fields.bssid[5]);
+
+ displayed_info = TRUE;
+
+ pcurrent += (sizeof(prsp_entry->fixed_field_length) +
+ prsp_entry->fixed_field_length);
+
+ bss_info_len = prsp_entry->bss_info_length;
+ pcurrent += sizeof(prsp_entry->bss_info_length);
+ pnext = pcurrent + prsp_entry->bss_info_length;
+
+ if (bss_info_len >= (sizeof(tsf)
+ + sizeof(beacon_interval) + sizeof(cap_info))) {
+ /* time stamp is 8 byte long */
+ memcpy(tsf, pcurrent, sizeof(tsf));
+ pcurrent += sizeof(tsf);
+ bss_info_len -= sizeof(tsf);
+
+ /* beacon interval is 2 byte long */
+ memcpy(&beacon_interval, pcurrent, sizeof(beacon_interval));
+ /* endian convert needed here */
+ beacon_interval = le16_to_cpu(beacon_interval);
+ pcurrent += sizeof(beacon_interval);
+ bss_info_len -= sizeof(beacon_interval);
+
+ /* capability information is 2 byte long */
+ memcpy(&tmp_cap, pcurrent, sizeof(tmp_cap));
+ /* endian convert needed here */
+ tmp_cap = le16_to_cpu(tmp_cap);
+ memcpy(&cap_info, &tmp_cap, sizeof(cap_info));
+ pcurrent += sizeof(cap_info);
+ bss_info_len -= sizeof(cap_info);
+ }
+
+ wmm_cap = ' '; /* M (WMM), C (WMM-Call Admission Control) */
+ wps_cap = ' '; /* "S" */
+ dot11k_cap = ' '; /* "K" */
+ dot11r_cap = ' '; /* "R" */
+ ht_cap = ' '; /* "N" */
+
+ /* "P" for Privacy (WEP) since "W" is WPA, and "2" is RSN/WPA2 */
+ priv_cap = cap_info.privacy ? 'P' : ' ';
+
+ while (bss_info_len >= 2) {
+ pelement_id = (IEEEtypes_ElementId_e *) pcurrent;
+ pelement_len = pcurrent + 1;
+ pcurrent += 2;
+
+ switch (*pelement_id) {
+
+ case SSID:
+ if (*pelement_len &&
+ *pelement_len <= MRVDRV_MAX_SSID_LENGTH) {
+ memcpy(ssid, pcurrent, *pelement_len);
+ ssid_len = *pelement_len;
+ }
+ break;
+
+ case WPA_IE:
+ pwpa_ie = (IEEEtypes_VendorSpecific_t *) pelement_id;
+ if ((memcmp
+ (pwpa_ie->vend_hdr.oui, wpa_oui,
+ sizeof(pwpa_ie->vend_hdr.oui)) == 0)
+ && (pwpa_ie->vend_hdr.oui_type == wpa_oui[3])) {
+ /* WPA IE found, 'W' for WPA */
+ priv_cap = 'W';
+ } else {
+ pwmm_ie = (IEEEtypes_WmmParameter_t *) pelement_id;
+ if ((memcmp(pwmm_ie->vend_hdr.oui,
+ wmm_oui,
+ sizeof(pwmm_ie->vend_hdr.oui)) == 0)
+ && (pwmm_ie->vend_hdr.oui_type == wmm_oui[3])) {
+ /* Check the subtype: 1 == parameter, 0 == info */
+ if ((pwmm_ie->vend_hdr.oui_subtype == 1)
+ && pwmm_ie->ac_params[WMM_AC_VO].aci_aifsn.acm) {
+ /* Call admission on VO; 'C' for CAC */
+ wmm_cap = 'C';
+ } else {
+ /* No CAC; 'M' for uh, WMM */
+ wmm_cap = 'M';
+ }
+ } else {
+ pwps_ie =
+ (IEEEtypes_VendorSpecific_t *) pelement_id;
+ if ((memcmp
+ (pwps_ie->vend_hdr.oui, wps_oui,
+ sizeof(pwps_ie->vend_hdr.oui)) == 0)
+ && (pwps_ie->vend_hdr.oui_type == wps_oui[3])) {
+ wps_cap = 'S';
+ }
+ }
+ }
+ break;
+
+ case RSN_IE:
+ /* RSN IE found; '2' for WPA2 (RSN) */
+ priv_cap = '2';
+ break;
+ case HT_CAPABILITY:
+ ht_cap = 'N';
+ break;
+
+ default:
+ break;
+ }
+
+ pcurrent += *pelement_len;
+ bss_info_len -= (2 + *pelement_len);
+ }
+
+ /* "A" for Adhoc "I" for Infrastructure, "D" for DFS (Spectrum
+ Mgmt) */
+ printf(" %c%c%c%c%c%c%c%c | ", cap_info.ibss ? 'A' : 'I', priv_cap, /* P
+ (WEP),
+ W
+ (WPA),
+ 2
+ (WPA2)
+ */
+ cap_info.spectrum_mgmt ? 'D' : ' ', wmm_cap, /* M (WMM), C
+ (WMM-Call
+ Admission
+ Control) */
+ dot11k_cap, /* K */
+ dot11r_cap, /* R */
+ wps_cap, /* S */
+ ht_cap); /* N */
+
+ /* Print out the ssid or the hex values if non-printable */
+ for (ssid_idx = 0; ssid_idx < ssid_len; ssid_idx++) {
+ if (isprint(ssid[ssid_idx])) {
+ printf("%c", ssid[ssid_idx]);
+ } else {
+ printf("\\%02x", ssid[ssid_idx]);
+ }
+ }
+
+ printf("\n");
+
+ if (argc > 3 && strcmp(argv[3], "tsf") == 0) {
+ /* TSF is a u64, some formatted printing libs have trouble
+ printing long longs, so cast and dump as bytes */
+ pbyte = (t_u8 *) & prsp_entry->fixed_fields.network_tsf;
+ printf(" TSF=%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ pbyte[7], pbyte[6], pbyte[5], pbyte[4],
+ pbyte[3], pbyte[2], pbyte[1], pbyte[0]);
+ }
+ }
+
+ scan_start += prsp_info->scan_number;
+
+ } while (prsp_info->scan_number);
+
+ if (displayed_info == TRUE) {
+ if (argc > 3 && strcmp(argv[3], "help") == 0) {
+ printf("\n\n"
+ "Capability Legend (Not all may be supported)\n"
+ "-----------------\n"
+ " I [ Infrastructure ]\n"
+ " A [ Ad-hoc ]\n"
+ " W [ WPA IE ]\n"
+ " 2 [ WPA2/RSN IE ]\n"
+ " M [ WMM IE ]\n"
+ " C [ Call Admission Control - WMM IE, VO ACM set ]\n"
+ " D [ Spectrum Management - DFS (11h) ]\n"
+ " K [ 11k ]\n"
+ " R [ 11r ]\n" " S [ WPS ]\n" " N [ HT (11n) ]\n" "\n\n");
+ }
+ } else {
+ printf("< No Scan Results >\n");
+ }
+
+ done:
+ if (scan_rsp_buf)
+ free(scan_rsp_buf);
+ return ret;
+}
+
+/** Maximum channel scratch */
+#define MAX_CHAN_SCRATCH 100
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 10
+/**
+ * @brief Request a scan from the driver and display the scan table afterwards
+ *
+ * Command line interface for performing a specific immediate scan based
+ * on the following keyword parsing:
+ *
+ * chan=[chan#][band][mode] where band is [a,b,g,n] and mode is
+ * blank for active or 'p' for passive
+ * bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
+ * ssid="[SSID]" specify a SSID filter for the scan
+ * keep=[0 or 1] keep the previous scan results (1), discard (0)
+ * dur=[scan time] time to scan for each channel in milliseconds
+ * probes=[#] number of probe requests to send on each chan
+ * type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+ *
+ * Any combination of the above arguments can be supplied on the command line.
+ * If the chan token is absent, a full channel scan will be completed by
+ * the driver. If the dur or probes tokens are absent, the drivers default
+ * setting will be used. The bssid and ssid fields, if blank,
+ * will produce an unfiltered scan. The type field will default to 3 (Any)
+ * and the keep field will default to 0 (Discard).
+ *
+ * @param argc number of arguments
+ * @param argv A pointer to arguments array
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+process_setuserscan(int argc, char *argv[])
+{
+ wlan_ioctl_user_scan_cfg scan_req;
+ int ioctl_val, subioctl_val;
+ struct iwreq iwr;
+ char *parg_tok;
+ char *pchan_tok;
+ char *parg_cookie;
+ char *pchan_cookie;
+ int arg_idx;
+ int chan_parse_idx;
+ int chan_cmd_idx;
+ char chan_scratch[MAX_CHAN_SCRATCH];
+ char *pscratch;
+ int tmp_idx;
+ int scan_time;
+ int num_ssid;
+ unsigned int mac[ETH_ALEN];
+
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ chan_cmd_idx = 0;
+ scan_time = 0;
+ num_ssid = 0;
+
+ if (get_priv_ioctl("setuserscan",
+ &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) {
+ return -EOPNOTSUPP;
+ }
+
+ for (arg_idx = 0; arg_idx < argc; arg_idx++) {
+ if (strncmp(argv[arg_idx], "chan=", strlen("chan=")) == 0) {
+ /*
+ * "chan" token string handler
+ */
+ parg_tok = argv[arg_idx] + strlen("chan=");
+
+ if (strlen(parg_tok) > MAX_CHAN_SCRATCH) {
+
+ printf("Error: Specified channels exceeds max limit\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ while ((parg_tok = strtok_r(parg_tok, ",", &parg_cookie)) != NULL) {
+
+ memset(chan_scratch, 0x00, sizeof(chan_scratch));
+ pscratch = chan_scratch;
+
+ for (chan_parse_idx = 0;
+ chan_parse_idx < strlen(parg_tok); chan_parse_idx++) {
+ if (isalpha(*(parg_tok + chan_parse_idx))) {
+ *pscratch++ = ' ';
+ }
+
+ *pscratch++ = *(parg_tok + chan_parse_idx);
+ }
+ *pscratch = 0;
+ parg_tok = NULL;
+
+ pchan_tok = chan_scratch;
+
+ while ((pchan_tok = strtok_r(pchan_tok, " ",
+ &pchan_cookie)) != NULL) {
+ if (isdigit(*pchan_tok)) {
+ scan_req.chan_list[chan_cmd_idx].chan_number
+ = atoi(pchan_tok);
+ } else {
+ switch (toupper(*pchan_tok)) {
+ case 'A':
+ scan_req.chan_list[chan_cmd_idx].radio_type = 1;
+ break;
+ case 'B':
+ case 'G':
+ case 'N':
+ scan_req.chan_list[chan_cmd_idx].radio_type = 0;
+ break;
+ case 'P':
+ scan_req.chan_list[chan_cmd_idx].scan_type = 1;
+ break;
+ default:
+ printf("Error: Band type not supported!\n");
+ return -EOPNOTSUPP;
+ }
+ }
+ pchan_tok = NULL;
+ }
+ chan_cmd_idx++;
+ }
+ } else if (strncmp(argv[arg_idx], "bssid=", strlen("bssid=")) == 0) {
+ /*
+ * "bssid" token string handler
+ */
+ sscanf(argv[arg_idx] + strlen("bssid="), "%2x:%2x:%2x:%2x:%2x:%2x",
+ mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5);
+
+ for (tmp_idx = 0; tmp_idx < NELEMENTS(mac); tmp_idx++) {
+ scan_req.specific_bssid[tmp_idx] = (t_u8) mac[tmp_idx];
+ }
+ } else if (strncmp(argv[arg_idx], "keep=", strlen("keep=")) == 0) {
+ /*
+ * "keep" token string handler
+ */
+ scan_req.keep_previous_scan = atoi(argv[arg_idx] + strlen("keep="));
+ } else if (strncmp(argv[arg_idx], "dur=", strlen("dur=")) == 0) {
+ /*
+ * "dur" token string handler
+ */
+ scan_time = atoi(argv[arg_idx] + strlen("dur="));
+ scan_req.chan_list[0].scan_time = scan_time;
+ } else if (strncmp(argv[arg_idx], "ssid=", strlen("ssid=")) == 0) {
+ /*
+ * "ssid" token string handler
+ */
+ if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) {
+ strncpy(scan_req.ssid_list[num_ssid].ssid,
+ argv[arg_idx] + strlen("ssid="),
+ sizeof(scan_req.ssid_list[num_ssid].ssid));
+
+ scan_req.ssid_list[num_ssid].max_len = 0;
+
+ num_ssid++;
+ }
+ } else if (strncmp(argv[arg_idx], "wc=", strlen("wc=")) == 0) {
+
+ if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) {
+ /*
+ * "wc" token string handler
+ */
+ pscratch = strrchr(argv[arg_idx], ',');
+
+ if (pscratch) {
+ *pscratch = 0;
+ pscratch++;
+
+ if (isdigit(*pscratch)) {
+ scan_req.ssid_list[num_ssid].max_len = atoi(pscratch);
+ } else {
+ scan_req.ssid_list[num_ssid].max_len = *pscratch;
+ }
+ } else {
+ /* Standard wildcard matching */
+ scan_req.ssid_list[num_ssid].max_len = 0xFF;
+ }
+
+ strncpy(scan_req.ssid_list[num_ssid].ssid,
+ argv[arg_idx] + strlen("wc="),
+ sizeof(scan_req.ssid_list[num_ssid].ssid));
+
+ num_ssid++;
+ }
+ } else if (strncmp(argv[arg_idx], "probes=", strlen("probes=")) == 0) {
+ /*
+ * "probes" token string handler
+ */
+ scan_req.num_probes = atoi(argv[arg_idx] + strlen("probes="));
+ if (scan_req.num_probes > MAX_PROBES) {
+ fprintf(stderr, "Invalid probes (> %d)\n", MAX_PROBES);
+ return -EOPNOTSUPP;
+ }
+ } else if (strncmp(argv[arg_idx], "type=", strlen("type=")) == 0) {
+ /*
+ * "type" token string handler
+ */
+ scan_req.bss_mode = atoi(argv[arg_idx] + strlen("type="));
+ switch (scan_req.bss_mode) {
+ case MLAN_SCAN_MODE_BSS:
+ case MLAN_SCAN_MODE_IBSS:
+ break;
+ case MLAN_SCAN_MODE_ANY:
+ default:
+ /* Set any unknown types to ANY */
+ scan_req.bss_mode = MLAN_SCAN_MODE_ANY;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Update all the channels to have the same scan time
+ */
+ for (tmp_idx = 1; tmp_idx < chan_cmd_idx; tmp_idx++) {
+ scan_req.chan_list[tmp_idx].scan_time = scan_time;
+ }
+
+ strncpy(iwr.ifr_name, dev_name, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) & scan_req;
+ iwr.u.data.length = sizeof(scan_req);
+ iwr.u.data.flags = subioctl_val;
+
+ if (ioctl(sockfd, ioctl_val, &iwr) < 0) {
+ perror("mlanconfig: setuserscan ioctl");
+ return -EFAULT;
+ }
+
+ process_getscantable(0, 0);
+
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mapp/mlanconfig/mlanmisc.h b/wlan_src/mapp/mlanconfig/mlanmisc.h
new file mode 100755
index 0000000..a9450fa
--- /dev/null
+++ b/wlan_src/mapp/mlanconfig/mlanmisc.h
@@ -0,0 +1,618 @@
+/** @file mlanmisc.h
+ *
+ * @brief This file contains command definitions for application
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/************************************************************************
+Change log:
+ 03/10/2009: initial version
+************************************************************************/
+
+#ifndef _MLANMISC_H_
+#define _MLANMISC_H_
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+/** Maximum scan response buffer size */
+#define SCAN_RESP_BUF_SIZE 2000
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifndef MIN
+/** Find minimum value */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif /* MIN */
+
+#ifndef MAX
+/** Find maximum value */
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif /* MAX */
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} __ATTRIB_PACK__ mlan_wmm_ac_e;
+
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+/** Enumeration for scan mode */
+enum
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Length of ethernet address */
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Maximum number of channels that can be sent in a setuserscan ioctl */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
+
+/** IEEE Type definitions */
+typedef enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+ COUNTRY_INFO = 7,
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+} __ATTRIB_PACK__ IEEEtypes_ElementId_e;
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN
+typedef struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN */
+
+/** IEEE IE header */
+typedef struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} __ATTRIB_PACK__ IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+__ATTRIB_PACK__ IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+__ATTRIB_PACK__ IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE 63
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES 256
+
+/**
+ * @brief Enumeration for the command result from an ADDTS or DELTS command
+ */
+typedef enum
+{
+ TSPEC_RESULT_SUCCESS = 0,
+ TSPEC_RESULT_EXEC_FAILURE = 1,
+ TSPEC_RESULT_TIMEOUT = 2,
+ TSPEC_RESULT_DATA_INVALID = 3,
+} __ATTRIB_PACK__ mlan_wmm_tspec_result_e;
+
+/**
+ * @brief Enumeration for the action field in the Queue configure command
+ */
+typedef enum
+{
+ WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+
+ WMM_QUEUE_CONFIG_ACTION_MAX
+} __ATTRIB_PACK__ mlan_wmm_queue_config_action_e;
+
+/**
+ * @brief Enumeration for the action field in the queue stats command
+ */
+typedef enum
+{
+ WMM_STATS_ACTION_START = 0,
+ WMM_STATS_ACTION_STOP = 1,
+ WMM_STATS_ACTION_GET_CLR = 2,
+ WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+
+ WMM_STATS_ACTION_MAX
+} __ATTRIB_PACK__ mlan_wmm_stats_action_e;
+
+/** Data structure of WMM QoS information */
+typedef struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+
+} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa wlan_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_tspec_result_e commandResult; /**< Firmware execution result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieeeStatusCode; /**< IEEE status code */
+ t_u8 tspecData[WMM_TSPEC_SIZE]; /**< TSPEC to send in the ADDTS */
+ t_u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES]; /**< ADDTS extra IE buffer */
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa wlan_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_tspec_result_e commandResult; /**< Firmware execution result */
+ t_u8 ieeeReasonCode; /**< IEEE reason code sent, unused for WMM */
+ t_u8 tspecData[WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msduLifetimeExpiry is ignored if set to 0 on a set command
+ *
+ * @sa wlan_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e accessCategory; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msduLifetimeExpiry; /**< lifetime expiry in TUs */
+ t_u8 supportedRates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS 7
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa wlan_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_stats_action_e action; /**< Start, Stop, or Get */
+ mlan_wmm_ac_e accessCategory; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 pktCount; /**< Number of successful packets transmitted */
+ t_u16 pktLoss; /**< Packets lost; not included in pktCount */
+ t_u32 avgQueueDelay; /**< Average Queue delay in microseconds */
+ t_u32 avgTxDelay; /**< Average Transmission delay in microseconds */
+ t_u16 usedTime; /**< Calculated used time - units of 32 microseconds */
+ t_u16 policedTime; /**< Calculated policed time - units of 32 microseconds */
+
+ /** @brief Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t;
+
+/**
+ * @brief IOCTL and command sub structure for a Traffic stream status.
+ */
+typedef struct
+{
+ t_u8 tid; /**< TSID: Range: 0->7 */
+ t_u8 valid; /**< TSID specified is valid */
+ t_u8 accessCategory; /**< AC TSID is active on */
+ t_u8 userPriority; /**< UP specified for the TSID */
+
+ t_u8 psb; /**< Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 flowDir; /**< Upstream (0), Downlink(1), Bidirectional(3) */
+ t_u16 mediumTime; /**< Medium time granted for the TSID */
+} HostCmd_DS_WMM_TS_STATUS,
+ wlan_ioctl_wmm_ts_status_t, wlan_cmd_wmm_ts_status_t;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmmAcm;
+ /** Flow required flag */
+ t_u8 flowRequired;
+ /** Flow created flag */
+ t_u8 flowCreated;
+ /** Disabled flag */
+ t_u8 disabled;
+ /** delivery enabled */
+ t_u8 deliveryEnabled;
+ /** trigger enabled */
+ t_u8 triggerEnabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa wlan_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t;
+
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows starting at bssInfoBuffer
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ t_u8 bss_info_buffer[1];
+} wlan_ioctl_get_scan_table_entry;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+typedef struct
+{
+ t_u8 chan_number; /**< Channel Number to scan */
+ t_u8 radio_type; /**< Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 scan_type; /**< Scan type: Active = 0, Passive = 1 */
+ t_u8 reserved; /**< Reserved */
+ t_u32 scan_time; /**< Scan duration in milliseconds; if 0 default used */
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan;
+
+typedef struct
+{
+ char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; /**< SSID */
+ t_u8 max_len; /**< Maximum length of SSID */
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid;
+
+typedef struct
+{
+
+ /** Flag set to keep the previous scan table intact */
+ t_u8 keep_previous_scan; /* Do not erase the existing scan results */
+
+ /** BSS mode to be sent in the firmware command */
+ t_u8 bss_mode;
+
+ /** Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+
+ /** Reserved */
+ t_u8 reserved;
+
+ /** BSSID filter sent in the firmware command to limit the results */
+ t_u8 specific_bssid[ETH_ALEN];
+ /** SSID filter list used in the to limit the scan results */
+ wlan_ioctl_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_ioctl_user_scan_chan chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg;
+
+int process_sdcmd52rw(int argc, char *argv[]);
+int process_sdcmd53rw(int argc, char *argv[]);
+int process_setuserscan(int argc, char *argv[]);
+int process_getscantable(int argc, char *argv[]);
+
+#endif /* _MLANMISC_H_ */
diff --git a/wlan_src/mlan/mlan.h b/wlan_src/mlan/mlan.h
new file mode 100755
index 0000000..14dcfd6
--- /dev/null
+++ b/wlan_src/mlan/mlan.h
@@ -0,0 +1,23 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/wlan_src/mlan/mlan_11d.c b/wlan_src/mlan/mlan_11d.c
new file mode 100755
index 0000000..f808608
--- /dev/null
+++ b/wlan_src/mlan/mlan_11d.c
@@ -0,0 +1,1298 @@
+/** @file mlan_11d.c
+ *
+ * @brief This file contains functions for 802.11D.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Default Tx power */
+#define TX_PWR_DEFAULT 10
+
+/** Universal region code */
+#define UNIVERSAL_REGION_CODE 0xff
+
+/** Region code mapping */
+typedef struct _region_code_mapping
+{
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ {"JP ", 0x41}, /* Japan */
+ {"JP ", 0xFF}, /* Japan special */
+};
+
+/* Following two structures define the supported channels */
+/** Channels for 802.11b/g */
+static chan_freq_power_t channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT},
+ {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT},
+ {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT},
+ {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT},
+ {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT},
+ {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT},
+ {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT},
+ {14, 2484, TX_PWR_DEFAULT}
+};
+
+/** Channels for 802.11a/j */
+static chan_freq_power_t channel_freq_power_UN_AJ[] = {
+ {8, 5040, TX_PWR_DEFAULT},
+ {12, 5060, TX_PWR_DEFAULT},
+ {16, 5080, TX_PWR_DEFAULT},
+ {34, 5170, TX_PWR_DEFAULT},
+ {38, 5190, TX_PWR_DEFAULT},
+ {42, 5210, TX_PWR_DEFAULT},
+ {46, 5230, TX_PWR_DEFAULT},
+ {36, 5180, TX_PWR_DEFAULT},
+ {40, 5200, TX_PWR_DEFAULT},
+ {44, 5220, TX_PWR_DEFAULT},
+ {48, 5240, TX_PWR_DEFAULT},
+ {52, 5260, TX_PWR_DEFAULT},
+ {56, 5280, TX_PWR_DEFAULT},
+ {60, 5300, TX_PWR_DEFAULT},
+ {64, 5320, TX_PWR_DEFAULT},
+ {100, 5500, TX_PWR_DEFAULT},
+ {104, 5520, TX_PWR_DEFAULT},
+ {108, 5540, TX_PWR_DEFAULT},
+ {112, 5560, TX_PWR_DEFAULT},
+ {116, 5580, TX_PWR_DEFAULT},
+ {120, 5600, TX_PWR_DEFAULT},
+ {124, 5620, TX_PWR_DEFAULT},
+ {128, 5640, TX_PWR_DEFAULT},
+ {132, 5660, TX_PWR_DEFAULT},
+ {136, 5680, TX_PWR_DEFAULT},
+ {140, 5700, TX_PWR_DEFAULT},
+ {149, 5745, TX_PWR_DEFAULT},
+ {153, 5765, TX_PWR_DEFAULT},
+ {157, 5785, TX_PWR_DEFAULT},
+ {161, 5805, TX_PWR_DEFAULT},
+ {165, 5825, TX_PWR_DEFAULT},
+/* {240, 4920, TX_PWR_DEFAULT},
+ {244, 4940, TX_PWR_DEFAULT},
+ {248, 4960, TX_PWR_DEFAULT},
+ {252, 4980, TX_PWR_DEFAULT},
+channels for 11J JP 10M channel gap */
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function converts a lowercase character to uppercase
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param c Input character
+ *
+ * @return Corresponding uppercase character
+ */
+static t_u8
+wlan_11d_lower_to_upper(pmlan_adapter pmadapter, t_u8 c)
+{
+ t_u8 upper;
+
+ ENTER();
+
+ if (c >= 'a' && c <= 'z')
+ upper = c - 0x20;
+ else
+ upper = c;
+
+ LEAVE();
+ return upper;
+}
+
+/**
+ * @brief This function convert region string to code integer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region Region string
+ *
+ * @return Region id
+ */
+static t_u8
+wlan_11d_region_2_code(pmlan_adapter pmadapter, t_u8 * region)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
+ region[i] = wlan_11d_lower_to_upper(pmadapter, region[i]);
+
+ /* Look for region in mapping table */
+ for (i = 0; i < size; i++) {
+ if (!memcmp(region, region_code_mapping[i].region, COUNTRY_CODE_LEN)) {
+ LEAVE();
+ return (region_code_mapping[i].code);
+ }
+ }
+
+ LEAVE();
+ /* Default is US */
+ return (region_code_mapping[0].code);
+}
+
+/**
+ * @brief This function converts interger code to region string
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param code Region code
+ *
+ * @return Region string
+ */
+static t_u8 *
+wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++) {
+ if (region_code_mapping[i].code == code) {
+ LEAVE();
+ return (region_code_mapping[i].region);
+ }
+ }
+
+ LEAVE();
+ /* Default is US */
+ return (region_code_mapping[0].region);
+}
+
+/**
+ * @brief This function Checks if chan txpwr is learned from AP/IBSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Channel number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_channel_known(pmlan_adapter pmadapter,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ chan_power_11d_t *pchan_pwr = parsed_region_chan->chan_pwr;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 i = 0;
+
+ ENTER();
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) pchan_pwr,
+ sizeof(chan_power_11d_t) * no_of_chan);
+
+ /* Search channel */
+ for (i = 0; i < no_of_chan; i++) {
+ if (chan == pchan_pwr[i].chan) {
+ PRINTM(MINFO, "11D: Found chan:%d\n", chan);
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ PRINTM(MERROR, "11D: Could not find chan:%d\n", chan);
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function sets domain info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_set_domain_info(mlan_private * pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send cmd to FW to set domain info */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to download domain Info\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info
+ * learned from AP/IBSS
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param region_chan Pointer to region_chan_t
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_generate_parsed_region_chan(pmlan_adapter pmadapter,
+ region_chan_t * region_chan,
+ parsed_region_chan_11d_t *
+ parsed_region_chan)
+{
+ chan_freq_power_t *cfp;
+ t_u8 i;
+
+ ENTER();
+
+ /* Region channel must be provided */
+ if (!region_chan) {
+ PRINTM(MINFO, "11D: region_chan is MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Get channel-frequecy-power trio */
+ cfp = region_chan->pcfp;
+ if (!cfp) {
+ PRINTM(MINFO, "11D: cfp equal MNULL \n");
+ LEAVE();
+ return;
+ }
+
+ /* Set band, region and country code */
+ parsed_region_chan->band = region_chan->band;
+ parsed_region_chan->region = region_chan->region;
+ memcpy(parsed_region_chan->country_code,
+ wlan_11d_code_2_region(pmadapter, region_chan->region),
+ COUNTRY_CODE_LEN);
+
+ PRINTM(MINFO, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+ parsed_region_chan->band);
+
+ /* Set channel and power */
+ for (i = 0; i < region_chan->num_cfp; i++, cfp++) {
+ parsed_region_chan->chan_pwr[i].chan = (t_u8) cfp->channel;
+ parsed_region_chan->chan_pwr[i].pwr = (t_u8) cfp->max_tx_power;
+ PRINTM(MINFO, "11D: Chan[%d] Pwr[%d]\n",
+ parsed_region_chan->chan_pwr[i].chan,
+ parsed_region_chan->chan_pwr[i].pwr);
+ }
+ parsed_region_chan->no_of_chan = region_chan->num_cfp;
+
+ PRINTM(MINFO, "11D: no_of_chan[%d]\n", parsed_region_chan->no_of_chan);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function generates domain_info from parsed_region_chan
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ * @param domain_info Pointer to wlan_802_11d_domain_reg_t
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_generate_domain_info(pmlan_adapter pmadapter,
+ parsed_region_chan_11d_t * parsed_region_chan,
+ wlan_802_11d_domain_reg_t * domain_info)
+{
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = 0;
+
+ ENTER();
+
+ /* Set country code */
+ memcpy(domain_info->country_code,
+ parsed_region_chan->country_code, COUNTRY_CODE_LEN);
+
+ PRINTM(MINFO, "11D: no_of_chan=%d\n", no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ /* Set channel and power */
+ for (i = 0; i < no_of_chan; i++) {
+ if (!flag) {
+ flag = 1;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1 &&
+ parsed_region_chan->chan_pwr[i].pwr == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ no_of_parsed_chan = 1;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ domain_info->no_of_sub_band = no_of_sub_band;
+
+ PRINTM(MINFO, "11D: no_of_sub_band=0x%x\n", domain_info->no_of_sub_band);
+ HEXDUMP("11D: domain_info", (t_u8 *) domain_info,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates the channel power table with the channel
+ * present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_update_chan_pwr_table(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i;
+ t_u8 tx_power = 0;
+ t_u8 chan;
+
+ ENTER();
+
+ chan = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ tx_power = wlan_get_txpwr_of_chan_from_cfp(pmpriv, chan);
+
+ if (!tx_power) {
+ PRINTM(MMSG, "11D: Invalid channel\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Check whether the channel already exists in channel power table of
+ parsed region */
+ for (i = 0; ((i < parsed_region_chan->no_of_chan) &&
+ (i < MAX_NO_OF_CHAN)); i++) {
+ if (parsed_region_chan->chan_pwr[i].chan == chan) {
+ /* Channel already exists update the tx_power */
+ parsed_region_chan->chan_pwr[i].pwr =
+ MIN(parsed_region_chan->chan_pwr[i].pwr, tx_power);
+ break;
+ }
+ }
+
+ if (i == parsed_region_chan->no_of_chan && i < MAX_NO_OF_CHAN) {
+ /* Channel not found. Update the channel in the channel-power table */
+ parsed_region_chan->chan_pwr[i].chan = chan;
+ parsed_region_chan->chan_pwr[i].pwr = tx_power;
+ parsed_region_chan->no_of_chan++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds the no_of_chan-th chan after the first_chan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band
+ * @param first_chan First channel number
+ * @param no_of_chan Number of channels
+ * @param chan Pointer to the returned no_of_chan-th chan number
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_get_chan(pmlan_adapter pmadapter, t_u8 band, t_u8 first_chan,
+ t_u8 no_of_chan, t_u8 * chan)
+{
+ chan_freq_power_t *cfp = MNULL;
+ t_u8 i;
+ t_u8 cfp_no = 0;
+
+ ENTER();
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ } else if (band & (BAND_A | BAND_AN)) {
+ cfp = channel_freq_power_UN_AJ;
+ cfp_no = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ PRINTM(MERROR, "11D: Wrong Band[%d]\n", band);
+ LEAVE();
+ return MFALSE;
+ }
+ /* Locate the first_chan */
+ for (i = 0; i < cfp_no; i++) {
+ if (cfp && ((cfp + i)->channel == first_chan)) {
+ PRINTM(MINFO, "11D: first_chan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /* Check if beyond the boundary */
+ if (i + no_of_chan < cfp_no) {
+ /* Get first_chan + no_of_chan */
+ *chan = (t_u8) (cfp + i + no_of_chan)->channel;
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function parses country information for region channel
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param country_info Country information
+ * @param band Chan band
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
+ IEEEtypes_CountryInfoFullSet_t * country_info,
+ t_u8 band,
+ parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 no_of_sub_band, no_of_chan;
+ t_u8 last_chan, first_chan, cur_chan = 0;
+ t_u8 idx = 0;
+ t_u8 j, i;
+
+ ENTER();
+
+ /*
+ * Validation Rules:
+ * 1. Valid Region Code
+ * 2. First Chan increment
+ * 3. Channel range no overlap
+ * 4. Channel is valid?
+ * 5. Channel is supported by Region?
+ * 6. Others
+ */
+
+ HEXDUMP("country_info", (t_u8 *) country_info, 30);
+
+ if (!(*(country_info->country_code)) ||
+ (country_info->len <= COUNTRY_CODE_LEN)) {
+ /* No region info or wrong region info: treat as no 11D info */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Step 1: Check region_code */
+ parsed_region_chan->region =
+ wlan_11d_region_2_code(pmadapter, country_info->country_code);
+
+ PRINTM(MINFO, "11D: region code=0x%x\n", (t_u8) parsed_region_chan->region);
+ HEXDUMP("11D: Country Code", (t_u8 *) country_info->country_code,
+ COUNTRY_CODE_LEN);
+
+ parsed_region_chan->band = band;
+
+ memcpy(parsed_region_chan->country_code,
+ country_info->country_code, COUNTRY_CODE_LEN);
+
+ no_of_sub_band = (country_info->len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t);
+
+ for (j = 0, last_chan = 0; j < no_of_sub_band; j++) {
+
+ if (country_info->sub_band[j].first_chan <= last_chan) {
+ /* Step2&3: Check First Chan Num increment and no overlap */
+ PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n",
+ country_info->sub_band[j].first_chan, last_chan);
+ continue;
+ }
+
+ first_chan = country_info->sub_band[j].first_chan;
+ no_of_chan = country_info->sub_band[j].no_of_chan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < no_of_chan; i++) {
+ /* Step 4 : Channel is supported? */
+ if (wlan_11d_get_chan(pmadapter, band, first_chan, i, &cur_chan) ==
+ MFALSE) {
+ /* Chan is not found in UN table */
+ PRINTM(MWARN, "11D: chan is not supported: %d\n", i);
+ break;
+ }
+
+ last_chan = cur_chan;
+
+ /* Step 5: We don't need to check if cur_chan is supported by mrvl
+ in region */
+ parsed_region_chan->chan_pwr[idx].chan = cur_chan;
+ parsed_region_chan->chan_pwr[idx].pwr =
+ country_info->sub_band[j].max_tx_pwr;
+ idx++;
+ }
+
+ /* Step 6: Add other checking if any */
+ }
+
+ parsed_region_chan->no_of_chan = idx;
+
+ PRINTM(MINFO, "11D: no_of_chan=0x%x\n", parsed_region_chan->no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ 2 + COUNTRY_CODE_LEN + sizeof(parsed_region_chan_11d_t) * idx);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function processes the country info present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_process_country_info(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i, j, num_chan_added = 0;
+
+ ENTER();
+
+ memset(®ion_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* Parse 11D country info */
+ wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band, ®ion_chan);
+
+ if (parsed_region_chan->no_of_chan != 0) {
+ /*
+ * Check if the channel number already exists in the
+ * chan-power table of parsed_region_chan
+ */
+ for (i = 0; (i < region_chan.no_of_chan && i < MAX_NO_OF_CHAN); i++) {
+ for (j = 0; (j < parsed_region_chan->no_of_chan &&
+ j < MAX_NO_OF_CHAN); j++) {
+ /*
+ * Channel already exists, update the tx power with minimum
+ * value among existing tx_power and new tx power
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ parsed_region_chan->chan_pwr[j].chan) {
+ parsed_region_chan->chan_pwr[j].pwr =
+ MIN(parsed_region_chan->chan_pwr[j].pwr,
+ region_chan.chan_pwr[i].pwr);
+ break;
+ }
+ }
+
+ if (j == parsed_region_chan->no_of_chan && j < MAX_NO_OF_CHAN) {
+ /*
+ * Channel does not exist in the channel power table,
+ * update this new chan and tx_power to the channel power table
+ */
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].chan =
+ region_chan.chan_pwr[i].chan;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].pwr =
+ region_chan.chan_pwr[i].pwr;
+ num_chan_added++;
+ }
+ }
+ parsed_region_chan->no_of_chan += num_chan_added;
+ } else {
+ /* Parsed region is empty, copy the first one */
+ memcpy(parsed_region_chan,
+ ®ion_chan, sizeof(parsed_region_chan_11d_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function converts channel to frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Channel number
+ * @param band Band
+ *
+ * @return Channel frequency
+ */
+t_u32
+wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band)
+{
+ chan_freq_power_t *cf;
+ t_u16 cnt;
+ t_u16 i;
+ t_u32 freq = 0;
+
+ ENTER();
+
+ /* Get channel-frequency-power trios */
+ if (band & (BAND_A | BAND_AN)) {
+ cf = channel_freq_power_UN_AJ;
+ cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ cf = channel_freq_power_UN_BG;
+ cnt = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ }
+
+ /* Locate channel and return corresponding frequency */
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ LEAVE();
+ return freq;
+}
+
+/**
+ * @brief This function setups scan channels
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ * @param band Band
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 size = sizeof(chan_freq_power_t);
+ t_u16 i = 0;
+
+ ENTER();
+
+ memset(pmadapter->universal_channel, 0,
+ sizeof(pmadapter->universal_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN))
+ /* If band B, G or N */
+ {
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ (t_u8) (sizeof(channel_freq_power_UN_BG) / size);
+ PRINTM(MINFO, "11D: BG-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_BG;
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ if (band & BAND_GN)
+ pmadapter->universal_channel[i].band = BAND_G;
+ else
+ pmadapter->universal_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+
+ if (band & (BAND_A | BAND_AN)) {
+ /* If band A */
+
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ sizeof(channel_freq_power_UN_AJ) / size;
+ PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
+
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ pmadapter->universal_channel[i].band = BAND_A;
+ i++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets if 11D is enabled
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return ENABLE_11D or DISABLE_11D
+ */
+state_11d_t
+wlan_11d_get_state(mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ wlan_802_11d_state_t *state = &pmadapter->state_11d;
+ ENTER();
+ LEAVE();
+ return (state->enable_11d);
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Chan number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+ */
+t_u8
+wlan_11d_get_scan_type(pmlan_adapter pmadapter,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 scan_type = HostCmd_SCAN_TYPE_PASSIVE;
+
+ ENTER();
+
+ if (wlan_11d_channel_known(pmadapter, chan, parsed_region_chan)) {
+ /* Channel found */
+ PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
+ scan_type = HostCmd_SCAN_TYPE_ACTIVE;
+ } else
+ PRINTM(MINFO, "11D: Channel not found and doing Passive Scan\n");
+
+ LEAVE();
+ return scan_type;
+}
+
+/**
+ * @brief Initialize internal variable for 11D
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11d_init(mlan_adapter * pmadapter)
+{
+ wlan_802_11d_state_t *state = &pmadapter->state_11d;
+
+ ENTER();
+
+ /* Start in disabled mode */
+ state->enable_11d = DISABLE_11D;
+ state->user_enable_11d = DISABLE_11D;
+
+ memset(&(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ memset(&(pmadapter->universal_channel), 0, sizeof(region_chan_t));
+ memset(&(pmadapter->domain_reg), 0, sizeof(wlan_802_11d_domain_reg_t));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function enable/disable 11D
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param flag 11D status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf, state_11d_t flag)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ wlan_802_11d_state_t *state = &pmadapter->state_11d;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable = flag;
+
+ ENTER();
+
+ memset(&pmadapter->parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11D_i, (t_void *) pioctl_buf, &enable);
+
+ if (ret) {
+ if (flag)
+ PRINTM(MERROR, "11D: Failed to enable 11D\n");
+ else
+ PRINTM(MERROR, "11D: Failed to disable 11D\n");
+ } else {
+ state->enable_11d = flag;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ state->user_enable_11d = flag;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function setups scan channels
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band band
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_set_universal_table(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 size = sizeof(chan_freq_power_t);
+ t_u16 i = 0;
+
+ ENTER();
+
+ memset(pmadapter->universal_channel, 0,
+ sizeof(pmadapter->universal_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ pmadapter->universal_channel[i].num_cfp =
+ (t_u8) (sizeof(channel_freq_power_UN_BG) / size);
+ PRINTM(MINFO, "11D: BG-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_BG;
+ pmadapter->universal_channel[i].valid = MTRUE;
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+ if (band & BAND_GN)
+ pmadapter->universal_channel[i].band = BAND_G;
+ else
+ pmadapter->universal_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+
+ if (band & (BAND_A | BAND_AN)) {
+ pmadapter->universal_channel[i].num_cfp =
+ sizeof(channel_freq_power_UN_AJ) / size;
+ PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
+
+ pmadapter->universal_channel[i].valid = MTRUE;
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+ pmadapter->universal_channel[i].band = BAND_A;
+ i++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure of
+ * command buffer
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd, t_u16 cmd_action)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info = &pcmd->params.domain_info;
+ MrvlIEtypes_DomainParamSet_t *domain = &pdomain_info->domain;
+ t_u8 no_of_sub_band = pmadapter->domain_reg.no_of_sub_band;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: no_of_sub_band=0x%x\n", no_of_sub_band);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+ pdomain_info->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ /* Dump domain info */
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* Set domain info fields */
+ domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(domain->country_code,
+ pmadapter->domain_reg.country_code, sizeof(domain->country_code));
+
+ domain->header.len = ((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) +
+ sizeof(domain->country_code));
+
+ if (no_of_sub_band) {
+ memcpy(domain->sub_band,
+ pmadapter->domain_reg.sub_band,
+ no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t));
+
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) +
+ domain->header.len +
+ sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+ } else {
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ }
+ domain->header.len = wlan_cpu_to_le16(domain->header.len);
+
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11d_domain_info(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP *domain_info =
+ &resp->params.domain_info_resp;
+ MrvlIEtypes_DomainParamSet_t *domain = &domain_info->domain;
+ t_u16 action = wlan_le16_to_cpu(domain_info->action);
+ t_u8 no_of_sub_band = 0;
+
+ ENTER();
+
+ /* Dump domain info response data */
+ HEXDUMP("11D: DOMAIN Info Rsp Data", (t_u8 *) resp, resp->size);
+
+ no_of_sub_band =
+ (t_u8) ((wlan_le16_to_cpu(domain->header.len) -
+ 3) / sizeof(IEEEtypes_SubbandSet_t));
+ /* Country code is 3 bytes */
+
+ PRINTM(MINFO, "11D Domain Info Resp: no_of_sub_band=%d\n", no_of_sub_band);
+
+ if (no_of_sub_band > MRVDRV_MAX_SUBBAND_802_11D) {
+ PRINTM(MWARN, "11D: Invalid number of subbands %d returned!!\n",
+ no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET: /* Proc Set Action */
+ break;
+ case HostCmd_ACT_GEN_GET:
+ break;
+ default:
+ PRINTM(MERROR, "11D: Invalid Action:%d\n", domain_info->action);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode
+ * and download to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band to create
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *region_chan;
+ parsed_region_chan_11d_t parsed_region_chan;
+ t_u8 j;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: Band[%d]\n", band);
+
+ /* Update parsed_region_chan; download domain info to FW */
+
+ /* Find region channel */
+ for (j = 0;
+ j <
+ sizeof(pmadapter->region_channel) /
+ sizeof(pmadapter->region_channel[0]); j++) {
+ region_chan = &pmadapter->region_channel[j];
+
+ PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid || !region_chan->pcfp)
+ continue;
+ switch (region_chan->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_B:
+ case BAND_G:
+ case BAND_G | BAND_B:
+ case BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ /* Check if region channel found */
+ if (j >= sizeof(pmadapter->region_channel) /
+ sizeof(pmadapter->region_channel[0])) {
+ PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Generate parsed region channel info from region channel */
+ memset(&parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
+ wlan_11d_generate_parsed_region_chan(pmadapter, region_chan,
+ &parsed_region_chan);
+
+ /* Generate domain info from parsed region channel info */
+ memset(&pmadapter->domain_reg, 0, sizeof(wlan_802_11d_domain_reg_t));
+ wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan,
+ &pmadapter->domain_reg);
+
+ /* Set domain info */
+ ret = wlan_11d_set_domain_info(pmpriv);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses country info from AP and
+ * download country info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSS descriptor
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t bssdesc_region_chan;
+ t_u32 i, j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_get_state(pmpriv) == ENABLE_11D) {
+
+ memset(&pmadapter->domain_reg, 0, sizeof(wlan_802_11d_domain_reg_t));
+ memset(®ion_chan, 0, sizeof(parsed_region_chan_11d_t));
+ memset(&bssdesc_region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ memcpy(®ion_chan,
+ &pmadapter->parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ if (pbss_desc) {
+ /* Parse domain info if available */
+ ret =
+ wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ pbss_desc->bss_band,
+ &bssdesc_region_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ /* Update the channel-power table */
+ for (i = 0; ((i < bssdesc_region_chan.no_of_chan)
+ && (i < MAX_NO_OF_CHAN)); i++) {
+
+ for (j = 0; ((j < region_chan.no_of_chan)
+ && (j < MAX_NO_OF_CHAN)); j++) {
+ /*
+ * Channel already exists, so overwrite existing
+ * tx power with the tx_power received from
+ * country info of the current AP
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ bssdesc_region_chan.chan_pwr[j].chan) {
+ region_chan.chan_pwr[j].pwr =
+ bssdesc_region_chan.chan_pwr[i].pwr;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Generate domain info */
+ wlan_11d_generate_domain_info(pmadapter, ®ion_chan,
+ &pmadapter->domain_reg);
+
+ /* Set domain info */
+ ret = wlan_11d_set_domain_info(pmpriv);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares domain info from scan table and
+ * downloads the domain info command to the FW.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
+ t_u32 idx;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_get_state(pmpriv) == ENABLE_11D &&
+ pmadapter->num_in_scan_table != 0) {
+ for (idx = 0; idx < pmadapter->num_in_scan_table; idx++) {
+ pcountry_full = &pmadapter->pscan_table[idx].country_info;
+
+ if (*(pcountry_full->country_code) == 0 ||
+ (pcountry_full->len <= COUNTRY_CODE_LEN)) {
+ /* Country info not found in the BSS descriptor */
+ ret =
+ wlan_11d_update_chan_pwr_table(pmpriv,
+ &pmadapter->
+ pscan_table[idx]);
+ } else {
+ /* Country info found in the BSS Descriptor */
+ ret =
+ wlan_11d_process_country_info(pmpriv,
+ &pmadapter->pscan_table[idx]);
+ }
+ }
+
+ /* Check if connected */
+ if (pmpriv->media_connected == MTRUE) {
+ ret =
+ wlan_11d_parse_dnld_countryinfo(pmpriv,
+ &pmpriv->curr_bss_params.
+ bss_descriptor);
+ } else {
+ ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_11h.c b/wlan_src/mlan/mlan_11h.c
new file mode 100755
index 0000000..8c38b18
--- /dev/null
+++ b/wlan_src/mlan/mlan_11h.c
@@ -0,0 +1,1263 @@
+/** @file mlan_11h.c
+ *
+ * @brief This file contains functions for 802.11H.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_meas.h"
+#include "mlan_11h.h"
+
+/*
+ * Constants
+ */
+
+/** Default IBSS DFS recovery interval (in TBTTs); used for adhoc start */
+#define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL 100
+
+/** Default 11h power constraint used to offset the maximum transmit power */
+#define WLAN_11H_TPC_POWERCONSTRAINT 0
+
+/** 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MIN 5
+
+/** 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MAX 20
+
+/** Regulatory requirement for the duration of a channel availability check */
+#define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION 60000 /* in ms */
+
+/** U-NII sub-band config : Start Channel = 36, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = { 36, 4 };
+
+/** U-NII sub-band config : Start Channel = 52, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = { 52, 4 };
+
+/** U-NII sub-band config : Start Channel = 100, NumChans = 11 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band = { 100, 11 };
+
+/** U-NII sub-band config : Start Channel = 149, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = { 149, 4 };
+
+/*
+ * Local types
+ */
+
+/** Internally passed structure used to send a CMD_802_11_TPC_INFO command */
+typedef struct
+{
+ t_u8 chan; /**< Channel to which the power constraint applies */
+ t_u8 power_constraint; /**< Local power constraint to send to firmware */
+} wlan_11h_tpc_info_param_t;
+
+/**
+ * @brief Utility function to get a random number based on the underlying OS
+ *
+ * @return random integer
+ */
+static int
+wlan_11h_get_random_num(t_void)
+{
+ return 112233;
+
+}
+
+/**
+ * @brief Convert an IEEE formatted IE to 16-bit ID/Len Marvell
+ * proprietary format
+ *
+ * @param pout_buf Output parameter: Buffer to output Marvell formatted IE
+ * @param pin_ie Pointer to IEEE IE to be converted to Marvell format
+ *
+ * @return Number of bytes output to pout_buf parameter return
+ */
+static int
+wlan_11h_convert_ieee_to_mrvl_ie(char *pout_buf, const char *pin_ie)
+{
+ MrvlIEtypesHeader_t mrvl_ie_hdr;
+ char *ptmp_buf = pout_buf;
+
+ ENTER();
+ /* Assign the Element Id and Len to the Marvell struct attributes */
+ mrvl_ie_hdr.type = wlan_cpu_to_le16(pin_ie[0]);
+ mrvl_ie_hdr.len = wlan_cpu_to_le16(pin_ie[1]);
+
+ /* If the element ID is zero, return without doing any copying */
+ if (!mrvl_ie_hdr.type)
+ return 0;
+
+ /* Copy the header to the buffer pointer */
+ memcpy(ptmp_buf, &mrvl_ie_hdr, sizeof(mrvl_ie_hdr));
+
+ /* Increment the temp buffer pointer by the size appended */
+ ptmp_buf += sizeof(mrvl_ie_hdr);
+
+ /* Append the data section of the IE; length given by the IEEE IE length */
+ memcpy(ptmp_buf, pin_ie + 2, pin_ie[1]);
+
+ LEAVE();
+ /* Return the number of bytes appended to pout_buf */
+ return (sizeof(mrvl_ie_hdr) + pin_ie[1]);
+}
+
+/**
+ * @brief Setup the IBSS DFS element passed to the firmware in adhoc start
+ * and join commands
+ *
+ * The DFS Owner and recovery fields are set to be our MAC address and
+ * a predetermined constant recovery value. If we are joining an adhoc
+ * network, these values are replaced with the existing IBSS values.
+ * They are valid only when starting a new IBSS.
+ *
+ * The IBSS DFS Element is variable in size based on the number of
+ * channels supported in our current region.
+ *
+ * @param priv Private driver information structure
+ * @param pdfs Output parameter: Pointer to the IBSS DFS element setup by
+ * this function.
+ *
+ * @return
+ * - Length of the returned element in pdfs output parameter
+ * - 0 if returned element is not setup
+ */
+static int
+wlan_11h_set_ibss_dfs_ie(mlan_private * priv, IEEEtypes_IBSS_DFS_t * pdfs)
+{
+ int num_chans = 0;
+ MeasRptBasicMap_t initial_map;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+ PRINTM(MINFO, "11h: IBSS DFS Element, 11D parsed region: %c%c (0x%x)\n",
+ adapter->parsed_region_chan.country_code[0],
+ adapter->parsed_region_chan.country_code[1],
+ adapter->parsed_region_chan.region);
+
+ memset(pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ /*
+ * A basic measurement report is included with each channel in the
+ * map field. Initial value for the map for each supported channel
+ * is with only the unmeasured bit set.
+ */
+ memset(&initial_map, 0x00, sizeof(initial_map));
+ initial_map.unmeasured = 1;
+
+ /* Set the DFS Owner and recovery interval fields */
+ memcpy(pdfs->dfs_owner, priv->curr_addr, sizeof(pdfs->dfs_owner));
+ pdfs->dfs_recovery_interval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
+
+ for (; (num_chans < adapter->parsed_region_chan.no_of_chan)
+ && (num_chans < WLAN_11H_MAX_IBSS_DFS_CHANNELS); num_chans++) {
+ pdfs->channel_map[num_chans].channel_number =
+ adapter->parsed_region_chan.chan_pwr[num_chans].chan;
+
+ /*
+ * Set the inital map field with a basic measurement
+ */
+ pdfs->channel_map[num_chans].rpt_map = initial_map;
+ }
+
+ /*
+ * If we have an established channel map, include it and return
+ * a valid DFS element
+ */
+ if (num_chans) {
+ PRINTM(MINFO, "11h: Added %d channels to IBSS DFS Map\n", num_chans);
+
+ pdfs->element_id = IBSS_DFS;
+ pdfs->len =
+ (sizeof(pdfs->dfs_owner) + sizeof(pdfs->dfs_recovery_interval)
+ + num_chans * sizeof(IEEEtypes_ChannelMap_t));
+
+ return (pdfs->len + sizeof(pdfs->len) + sizeof(pdfs->element_id));
+ }
+
+ /* Ensure the element is zeroed out for an invalid return */
+ memset(pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Setup the Supported Channel IE sent in association requests
+ *
+ * The Supported Channels IE is required to be sent when the spectrum
+ * management capability (11h) is enabled. The element contains a
+ * starting channel and number of channels tuple for each sub-band
+ * the STA supports. This information is based on the operating region.
+ *
+ * @param priv Private driver information structure
+ * @param psup_chan Output parameter: Pointer to the Supported Chan element
+ * setup by this function.
+ *
+ * @return
+ * - Length of the returned element in psup_chan output parameter
+ * - 0 if returned element is not setup
+ */
+static int
+wlan_11h_set_supp_channels_ie(mlan_private * priv,
+ IEEEtypes_SupportedChannels_t * psup_chan)
+{
+ int num_subbands = 0;
+ int ret_len = 0;
+
+ ENTER();
+ memset(psup_chan, 0x00, sizeof(IEEEtypes_SupportedChannels_t));
+
+ /*
+ * Set the supported channel elements based on the region code,
+ * incrementing num_subbands for each sub-band we append to the
+ * element.
+ */
+ switch (priv->adapter->region_code) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x30: /* Europe ETSI */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * If we have setup any supported subbands in the element, return a
+ * valid IE along with its size, else return 0.
+ */
+ if (num_subbands) {
+ psup_chan->element_id = SUPPORTED_CHANNELS;
+ psup_chan->len = num_subbands * sizeof(IEEEtypes_SupportChan_Subband_t);
+
+ ret_len = (psup_chan->len
+ + sizeof(psup_chan->len) + sizeof(psup_chan->element_id));
+
+ HEXDUMP("11h: SupChan", (t_u8 *) psup_chan, ret_len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_tpc_request(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ ENTER();
+
+ memcpy(&pcmd_ptr->params.tpc_req, pinfo_buf,
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+
+ pcmd_ptr->params.tpc_req.req.timeout =
+ wlan_cpu_to_le16(pcmd_ptr->params.tpc_req.req.timeout);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
+
+ HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (t_u8 *) pcmd_ptr, (int) pcmd_ptr->size);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_INFO firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf wlan_11h_tpc_info_param_t passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_tpc_info(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ HostCmd_DS_802_11_TPC_INFO *ptpc_info = &pcmd_ptr->params.tpc_info;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint =
+ &ptpc_info->local_constraint;
+ MrvlIEtypes_PowerCapability_t *pcap = &ptpc_info->power_cap;
+
+ wlan_11h_state_t *pstate = &priv->adapter->state_11h;
+ const wlan_11h_tpc_info_param_t *ptpc_info_param =
+ (wlan_11h_tpc_info_param_t *) pinfo_buf;
+
+ ENTER();
+
+ pcap->min_power = pstate->min_tx_power_capability;
+ pcap->max_power = pstate->max_tx_power_capability;
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+
+ pconstraint->chan = ptpc_info_param->chan;
+ pconstraint->constraint = ptpc_info_param->power_constraint;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
+
+ HEXDUMP("11h: TPC INFO", (t_u8 *) pcmd_ptr, (int) pcmd_ptr->size);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_CHAN_SW_ANN firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_chan_sw_ann(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ const HostCmd_DS_802_11_CHAN_SW_ANN *pch_sw_ann =
+ (HostCmd_DS_802_11_CHAN_SW_ANN *) pinfo_buf;
+
+ ENTER();
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
+
+ memcpy(&pcmd_ptr->params.chan_sw_ann, pch_sw_ann,
+ sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
+
+ PRINTM(MINFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+ PRINTM(MINFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
+ pch_sw_ann->new_chan, pch_sw_ann->switch_count,
+ pch_sw_ann->switch_mode);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set the local power constraint in the firmware
+ *
+ * Construct and send a CMD_802_11_TPC_INFO command with the local power
+ * constraint.
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel to which the power constraint applies
+ * @param power_constraint Power constraint to be applied on the channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_set_local_power_constraint(mlan_private * priv,
+ t_u8 channel, t_u8 power_constraint)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ wlan_11h_tpc_info_param_t tpc_info_param;
+
+ ENTER();
+ tpc_info_param.chan = channel;
+ tpc_info_param.power_constraint = power_constraint;
+
+ PRINTM(MINFO, "11h: Set Local Constraint = %d\n",
+ tpc_info_param.power_constraint);
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_TPC_INFO,
+ HostCmd_ACT_GEN_SET, 0, 0, &tpc_info_param);
+
+ if (ret) {
+ PRINTM(MINFO, "11h: Err: Send TPC_INFO CMD: %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Utility function to process a join to an infrastructure BSS
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static int
+wlan_11h_process_infra_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ MrvlIEtypesHeader_t ie_header;
+ IEEEtypes_SupportedChannels_t sup_chan_ie;
+ int ret_len = 0;
+ int sup_chan_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if (!ppbuffer)
+ return 0;
+ if (!(*ppbuffer))
+ return 0;
+
+ /* Set the local constraint configured in the firmware */
+ wlan_11h_set_local_power_constraint(priv, channel,
+ (p11h_bss_info->
+ power_constraint.local_constraint));
+
+ /* Setup the Supported Channels IE */
+ sup_chan_len = wlan_11h_set_supp_channels_ie(priv, &sup_chan_ie);
+
+ /*
+ * If we returned a valid Supported Channels IE, wrap and append it
+ */
+ if (sup_chan_len) {
+ /* Wrap the supported channels IE with a passthrough TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = sup_chan_len;
+ memcpy(*ppbuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the supported channels IE to the output buf, advance pointer */
+ memcpy(*ppbuffer, &sup_chan_ie, sup_chan_len);
+ *ppbuffer += sup_chan_len;
+ ret_len += sup_chan_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Utility function to process a start or join to an adhoc network
+ *
+ * Add the elements to the TLV buffer needed in the start/join adhoc commands:
+ * - IBSS DFS IE
+ * - Quiet IE
+ *
+ * Also send the local constraint to the firmware in a TPC_INFO command.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param channel Channel on which we are starting/joining the IBSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response. NULL
+ * indicates we are starting the adhoc network
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static int
+wlan_11h_process_adhoc(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ IEEEtypes_IBSS_DFS_t dfs_elem;
+ int size_appended;
+ int ret_len = 0;
+ t_s8 local_constraint = 0;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* Format our own IBSS DFS Element. Include our channel map fields */
+ wlan_11h_set_ibss_dfs_ie(priv, &dfs_elem);
+
+ if (p11h_bss_info) {
+ /*
+ * Copy the DFS Owner/Recovery Interval from the BSS we are joining
+ */
+ memcpy(dfs_elem.dfs_owner,
+ p11h_bss_info->ibss_dfs.dfs_owner, sizeof(dfs_elem.dfs_owner));
+ dfs_elem.dfs_recovery_interval =
+ p11h_bss_info->ibss_dfs.dfs_recovery_interval;
+ }
+
+ /* Append the dfs element to the TLV buffer */
+ size_appended = wlan_11h_convert_ieee_to_mrvl_ie((char *) *ppbuffer,
+ (char *) &dfs_elem);
+
+ HEXDUMP("11h: IBSS-DFS", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+
+ /*
+ * Check to see if we are joining a network. Join is indicated by the
+ * BSS Info pointer being valid (not NULL)
+ */
+ if (p11h_bss_info) {
+ /*
+ * If there was a quiet element, include it in adhoc join command
+ */
+ if (p11h_bss_info->quiet.element_id == QUIET) {
+ size_appended
+ = wlan_11h_convert_ieee_to_mrvl_ie((char *) *ppbuffer,
+ (char *) &p11h_bss_info->
+ quiet);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+
+ /* Copy the local constraint from the network */
+ local_constraint = p11h_bss_info->power_constraint.local_constraint;
+ } else {
+ /*
+ * If we are the adhoc starter, we can add a quiet element
+ */
+ if (adapter->state_11h.quiet_ie.quiet_period) {
+ size_appended = wlan_11h_convert_ieee_to_mrvl_ie((char *) *ppbuffer,
+ (char *) &adapter->
+ state_11h.
+ quiet_ie);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+
+ /* Use the local_constraint configured in the driver state */
+ local_constraint = adapter->state_11h.usr_def_power_constraint;
+ }
+ }
+
+ /* Set the local constraint configured in the firmware */
+ wlan_11h_set_local_power_constraint(priv, channel, local_constraint);
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Return whether the driver is currently setup to use 11h for
+ * adhoc start.
+ *
+ * Association/Join commands are dynamic in that they enable 11h in the
+ * driver/firmware when they are detected in the existing BSS.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h is enabled
+ * - MFALSE otherwise
+ */
+static int
+wlan_11h_is_enabled(mlan_private * priv)
+{
+ wlan_11h_state_t *pstate_11h = &priv->adapter->state_11h;
+
+ return (pstate_11h->is_11h_enabled ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief Query 11h firmware enabled state.
+ *
+ * Return whether the firmware currently has 11h extensions enabled
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h has been activated in the firmware
+ * - MFALSE otherwise
+ *
+ * @sa wlan_11h_activate
+ */
+int
+wlan_11h_is_active(mlan_private * priv)
+{
+ wlan_11h_state_t *pstate_11h = &priv->adapter->state_11h;
+
+ return (pstate_11h->is_11h_active ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief Disable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return t_void
+ */
+t_void
+wlan_11h_tx_disable(mlan_private * priv)
+{
+ wlan_11h_state_t *pstate_11h = &priv->adapter->state_11h;
+
+ ENTER();
+ pstate_11h->tx_disabled = MTRUE;
+ LEAVE();
+}
+
+/**
+ * @brief Enable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return t_void
+ */
+t_void
+wlan_11h_tx_enable(mlan_private * priv)
+{
+ wlan_11h_state_t *pstate_11h = &priv->adapter->state_11h;
+
+ ENTER();
+ pstate_11h->tx_disabled = MFALSE;
+ LEAVE();
+}
+
+/**
+ * @brief Enable or Disable the 11h extensions in the firmware
+ *
+ * @param priv Private driver information structure
+ * @param flag Enable 11h if MTRUE, disable otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_activate(mlan_private * priv, t_u32 flag)
+{
+ wlan_11h_state_t *pstate_11h = &priv->adapter->state_11h;
+ int enable = flag ? 1 : 0;
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /*
+ * Send cmd to FW to enable/disable 11h function in firmware
+ */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11H_i, MNULL, &enable);
+
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ /* Set boolean flag in driver 11h state */
+ pstate_11h->is_11h_active = flag;
+
+ PRINTM(MINFO, "11h: %s\n", enable ? "Activate" : "Deactivate");
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ *
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return t_void
+ */
+t_void
+wlan_11h_init(mlan_adapter * adapter)
+{
+ wlan_11h_state_t *pstate_11h = &adapter->state_11h;
+ IEEEtypes_Quiet_t *pquiet = &adapter->state_11h.quiet_ie;
+
+ ENTER();
+
+ pstate_11h->usr_def_power_constraint = WLAN_11H_TPC_POWERCONSTRAINT;
+ pstate_11h->min_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
+ pstate_11h->max_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
+
+ /*
+ * By default, the driver should have its preference set as 11h being
+ * activated when starting an ad hoc network. For infrastructure
+ * and ad hoc join, 11h will be sensed and activated accordingly.
+ */
+ pstate_11h->is_11h_enabled = MTRUE;
+
+ /*
+ * On power up, the firmware should have 11h support inactive.
+ */
+ pstate_11h->is_11h_active = MFALSE;
+
+ /* Initialize quiet_ie */
+ memset(pquiet, 0, sizeof(IEEEtypes_Quiet_t));
+
+ pquiet->element_id = QUIET;
+ pquiet->len = (sizeof(pquiet->quiet_count) + sizeof(pquiet->quiet_period)
+ + sizeof(pquiet->quiet_duration)
+ + sizeof(pquiet->quiet_offset));
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and an A-Band channel start band preference
+ * configured in the driver, the start channel must be random in order
+ * to meet with
+ *
+ * @param priv Private driver information structure
+ *
+ * @return Integer starting channel
+ */
+int
+wlan_11h_get_adhoc_start_channel(mlan_private * priv)
+{
+ unsigned int start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ int region;
+ int rand_entry;
+ region_chan_t *chn_tbl;
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ ) {
+ /*
+ * Set default to the A Band default. Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band */
+ if (chn_tbl->valid
+ && chn_tbl->region == adapter->region_code
+ && chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random number and
+ * use it to pick an entry in the table between 0
+ * and the number of channels in the table (NumCFP).
+ */
+ rand_entry = wlan_11h_get_random_num() % chn_tbl->num_cfp;
+ start_chn = chn_tbl->pcfp[rand_entry].channel;
+ }
+ }
+ }
+ }
+
+ PRINTM(MINFO, "11h: %s: AdHoc Channel set to %u\n",
+ wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", start_chn);
+
+ LEAVE();
+
+ return start_chn;
+}
+
+/**
+ * @brief Check if the current region's regulations require the input channel
+ * to be scanned for radar.
+ *
+ * Based on statically defined requirements for sub-bands per regulatory
+ * agency requirements.
+ *
+ * Used in adhoc start to determine if channel availability check is required
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ *
+ * @sa wlan_11h_radar_detected
+ */
+int
+wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel)
+{
+ int required;
+
+ ENTER();
+
+ /*
+ * Assume that radar detection is required unless exempted below.
+ * No checks for 11h or measurement code being enabled is placed here
+ * since regulatory requirements exist whether we support them or not.
+ */
+ required = MTRUE;
+
+ switch (priv->adapter->region_code) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ /*
+ * FCC does not yet require radar detection in the
+ * 5.25-5.35 (U-NII middle) band
+ */
+ if (channel < wlan_11h_unii_middle_band.start_chan ||
+ channel >= wlan_11h_unii_mid_upper_band.start_chan) {
+ required = MFALSE;
+ }
+ break;
+ case 0x30: /* Europe ETSI */
+ /*
+ * Radar detection is not required in the
+ * 5.15-5.25 (U-NII lower) and 5.725-5.825 (U-NII upper) bands
+ */
+ if (channel < wlan_11h_unii_middle_band.start_chan ||
+ channel >= wlan_11h_unii_upper_band.start_chan) {
+ /* Radar detection not required */
+ required = MFALSE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ PRINTM(MINFO, "11h: Radar detection in region %#02x "
+ "is %srequired for channel %d\n",
+ priv->adapter->region_code, (required ? "" : "NOT "), channel);
+
+ if (required == MTRUE && priv->media_connected == MTRUE
+ && priv->curr_bss_params.bss_descriptor.channel == channel) {
+ required = MFALSE;
+
+ PRINTM(MINFO, "11h: Radar detection not required. "
+ "Already operating on the channel");
+ }
+
+ LEAVE();
+ return required;
+}
+
+/**
+ * @brief Perform a radar measurement and report the result if required on
+ * given channel
+ *
+ * Check to see if the provided channel requires a channel availability
+ * check (60 second radar detection measurement). If required, perform
+ * measurement, stalling calling thread until the measurement completes
+ * and then report result.
+ *
+ * Used when starting an adhoc network.
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel on which to perform radar measurement
+ *
+ * @return
+ * - MTRUE if radar has been detected
+ * - MFALSE if radar detection is not required or radar has not been detected
+ *
+ * @sa wlan_11h_radar_detect_required
+ */
+int
+wlan_11h_radar_detected(mlan_private * priv, t_u8 channel)
+{
+ int ret;
+ HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+
+ ENTER();
+
+ /*
+ * If the channel requires radar, default the return value to it being
+ * detected.
+ */
+ ret = wlan_11h_radar_detect_required(priv, channel);
+
+ memset(&meas_req, 0x00, sizeof(meas_req));
+ memset(&meas_rpt, 0x00, sizeof(meas_rpt));
+
+ /*
+ * Send a basic measurement request on the indicated channel for the
+ * required channel availability check time.
+ */
+ meas_req.meas_type = WLAN_MEAS_BASIC;
+ meas_req.req.basic.channel = channel;
+ meas_req.req.basic.duration = WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
+
+ /*
+ * Set the STA that we are requesting the measurement from to our own
+ * mac address, causing our firmware to perform the measurement itself
+ */
+ memcpy(meas_req.mac_addr, priv->curr_addr, sizeof(meas_req.mac_addr));
+
+ /*
+ * Send the measurement request and timeout duration to wait for
+ * the command to spend until the measurement report is received
+ * from the firmware. If the command fails, the default ret value set
+ * above will be returned.
+ */
+ if (!wlan_meas_util_send_req(priv, &meas_req,
+ meas_req.req.basic.duration, &meas_rpt)) {
+ /*
+ * If the report indicates no measurement was done, leave the default
+ * return value alone.
+ */
+ if (!meas_rpt.rpt.basic.map.unmeasured)
+ /*
+ * Set the return value based on the radar indication bit
+ */
+ ret = meas_rpt.rpt.basic.map.radar ? MTRUE : MFALSE;
+
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Adhoc start command.
+ *
+ * Activate 11h functionality in the firmware if driver has is enabled
+ * for 11h (configured by the application via IOCTL).
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param channel Channel on which we are starting the IBSS
+ * @param p11h_bss_info Input/Output parameter: Pointer to the 11h BSS
+ * information for this network that we are establishing.
+ * 11h sensed flag set on output if warranted.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ *
+ */
+int
+wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ mlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+ if (wlan_11h_is_enabled(priv)
+ && ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ )
+ ) {
+ if (wlan_11d_get_state(priv) == DISABLE_11D) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+ wlan_11d_create_dnld_countryinfo(priv, adapter->adhoc_start_band);
+ }
+
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MTRUE);
+ pcap_info->spectrum_mgmt = 1;
+
+ /* Set flag indicating this BSS we are starting is using 11h */
+ p11h_bss_info->sensed_11h = MTRUE;
+
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel, MNULL);
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MFALSE);
+ pcap_info->spectrum_mgmt = 0;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Join command for
+ * both adhoc and infra networks
+ *
+ * The TLV command processing for a BSS join for either adhoc or
+ * infrastructure network is performed with this function. The
+ * capability bits are inspected for the IBSS flag and the appropriate
+ * local routines are called to setup the necessary TLVs.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network information for the BSS we are
+ * joining.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this
+ * network that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer), MLAN_STATUS_FAILURE (-1),
+ * or MLAN_STATUS_SUCCESS (0)
+ */
+int
+wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->media_connected == MTRUE) {
+ if (wlan_11h_is_active(priv) == p11h_bss_info->sensed_11h) {
+ /* Assume DFS parameters are the same for roaming as long as the
+ current & next APs have the same spectrum mgmt capability bit
+ setting */
+ ret = MLAN_STATUS_SUCCESS;
+
+ } else {
+ /* No support for roaming between DFS/non-DFS yet */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+ }
+
+ if (p11h_bss_info->sensed_11h) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+ wlan_11d_parse_dnld_countryinfo(priv, priv->pattempted_bss_desc);
+
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MTRUE);
+ pcap_info->spectrum_mgmt = 1;
+
+ if (pcap_info->ibss) {
+ PRINTM(MINFO, "11h: Adhoc join: Sensed\n");
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
+ p11h_bss_info);
+ } else {
+ PRINTM(MINFO, "11h: Infra join: Sensed\n");
+ ret = wlan_11h_process_infra_join(priv, ppbuffer,
+ channel, p11h_bss_info);
+ }
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MFALSE);
+ pcap_info->spectrum_mgmt = 0;
+ }
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ *
+ * @brief Prepare the HostCmd_DS_Command structure for an 11h command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer pass through with data necessary for a
+ * specific command type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_cmd_tpc_request
+ * @sa wlan_11h_cmd_tpc_info
+ * @sa wlan_11h_cmd_chan_sw_ann
+ */
+int
+wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ ret = wlan_11h_cmd_tpc_request(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_TPC_INFO:
+ ret = wlan_11h_cmd_tpc_info(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmd_chan_sw_ann(priv, pcmd_ptr, pinfo_buf);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware if from an 11h command
+ *
+ * Use the Command field to determine if the command response being
+ * is for 11h. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ *
+ * @param priv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware
+ * command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_cmdresp_process(mlan_private * priv, const HostCmd_DS_COMMAND * resp)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ HEXDUMP("11h: TPC REQUEST Rsp:", (t_u8 *) resp, (int) resp->size);
+ memcpy(priv->adapter->curr_cmd->pdata_buf,
+ &resp->params.tpc_req, sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+ break;
+
+ case HostCmd_CMD_802_11_TPC_INFO:
+ HEXDUMP("11h: TPC INFO Rsp Data:", (t_u8 *) resp, (int) resp->size);
+ break;
+
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ PRINTM(MINFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an element from a scan response, copy relevant info for 11h
+ *
+ * @param p11h_bss_info Output parameter: Pointer to the 11h BSS information
+ * for the network that is being processed
+ * @param pelement Pointer to the current IE we are inspecting for 11h
+ * relevance
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_process_bss_elem(wlan_11h_bss_info_t * p11h_bss_info,
+ const t_u8 * pelement)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (*pelement) {
+ case POWER_CONSTRAINT:
+ PRINTM(MINFO, "11h: Power Constraint IE Found\n");
+ p11h_bss_info->sensed_11h = 1;
+ memcpy(&p11h_bss_info->power_constraint, pelement,
+ sizeof(IEEEtypes_PowerConstraint_t));
+ break;
+
+ case POWER_CAPABILITY:
+ PRINTM(MINFO, "11h: Power Capability IE Found\n");
+ p11h_bss_info->sensed_11h = 1;
+ memcpy(&p11h_bss_info->power_capability, pelement,
+ sizeof(IEEEtypes_PowerCapability_t));
+ break;
+
+ case TPC_REPORT:
+ PRINTM(MINFO, "11h: Tpc Report IE Found\n");
+ p11h_bss_info->sensed_11h = 1;
+ memcpy(&p11h_bss_info->tpc_report, pelement,
+ sizeof(IEEEtypes_TPCReport_t));
+ break;
+
+ case CHANNEL_SWITCH_ANN:
+ p11h_bss_info->sensed_11h = 1;
+ PRINTM(MINFO, "11h: Channel Switch Ann IE Found\n");
+ break;
+
+ case QUIET:
+ PRINTM(MINFO, "11h: Quiet IE Found\n");
+ p11h_bss_info->sensed_11h = 1;
+ memcpy(&p11h_bss_info->quiet, pelement, sizeof(IEEEtypes_Quiet_t));
+ break;
+
+ case IBSS_DFS:
+ PRINTM(MINFO, "11h: Ibss Dfs IE Found\n");
+ p11h_bss_info->sensed_11h = 1;
+ memcpy(&p11h_bss_info->ibss_dfs, pelement,
+ sizeof(IEEEtypes_IBSS_DFS_t));
+ break;
+
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ /*
+ * These elements are not in beacons/probe responses. Included here
+ * to cover set of enumerated 11h elements.
+ */
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_11h.h b/wlan_src/mlan/mlan_11h.h
new file mode 100755
index 0000000..71550a9
--- /dev/null
+++ b/wlan_src/mlan/mlan_11h.h
@@ -0,0 +1,73 @@
+/** @file mlan_11h.h
+ *
+ * @brief This header file contains data structures and
+ * function declarations of 802.11h
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial creation
+*************************************************************/
+
+#ifndef _MLAN_11H_
+#define _MLAN_11H_
+
+/**
+ * 11H APIs
+ */
+
+/** Initialize the 11h software module */
+extern void wlan_11h_init(mlan_adapter * pmadapter);
+
+/** Return 1 if 11h is active in the firmware, 0 if it is inactive */
+extern int wlan_11h_is_active(mlan_private * priv);
+
+/** Activate 11h extensions in the firmware */
+extern int wlan_11h_activate(mlan_private * priv, t_u32 flag);
+
+/** Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_enable(mlan_private * priv);
+
+/** Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_disable(mlan_private * priv);
+
+/** Check if radar detection is required on the specified channel */
+extern int wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel);
+
+/** Perform a standard availibility check on the specified channel */
+extern int wlan_11h_radar_detected(mlan_private * priv, t_u8 channel);
+
+/** Get an initial random channel to start an adhoc network on */
+extern int wlan_11h_get_adhoc_start_channel(mlan_private * priv);
+
+/** Add any 11h TLVs necessary to complete a join command (adhoc or infra) */
+extern int wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Add any 11h TLVs necessary to complete an adhoc start command */
+extern int wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Receive IEs from scan processing and record any needed info for 11h */
+int wlan_11h_process_bss_elem(wlan_11h_bss_info_t * p11h_bss_info,
+ const t_u8 * pelement);
+
+/** Complete the firmware command preparation for an 11h command function */
+extern int wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/** Process the response of an 11h firmware command */
+extern int wlan_11h_cmdresp_process(mlan_private * priv,
+ const HostCmd_DS_COMMAND * resp);
+
+#endif /*_MLAN_11H_ */
diff --git a/wlan_src/mlan/mlan_11n.c b/wlan_src/mlan/mlan_11n.c
new file mode 100755
index 0000000..3aafcd5
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n.c
@@ -0,0 +1,1454 @@
+/** @file mlan_11n.c
+ *
+ * @brief This file contains functions for 11n handling.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ *
+ * @brief set/get max tx buf size
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_max_tx_buf_size(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if ((cfg->param.tx_buf_size == MLAN_TX_DATA_BUF_SIZE_2K) ||
+ (cfg->param.tx_buf_size == MLAN_TX_DATA_BUF_SIZE_4K) ||
+ (cfg->param.tx_buf_size == MLAN_TX_DATA_BUF_SIZE_8K)) {
+ pmadapter->max_tx_buf_size = (t_u16) cfg->param.tx_buf_size;
+ } else
+ ret = MLAN_STATUS_FAILURE;
+ } else
+ cfg->param.tx_buf_size = (t_u32) pmadapter->max_tx_buf_size;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get htcapinfo configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (((cfg->param.htcap_cfg & ~IGN_HW_DEV_CAP) &
+ pmpriv->adapter->hw_dot_11n_dev_cap)
+ != (cfg->param.htcap_cfg & ~IGN_HW_DEV_CAP))
+ ret = MLAN_STATUS_FAILURE;
+ else
+ pmadapter->usr_dot_11n_dev_cap = cfg->param.htcap_cfg;
+ PRINTM(MINFO, "UsrDot11nCap 0x%x\n", pmadapter->usr_dot_11n_dev_cap);
+ } else {
+ cfg->param.htcap_cfg = pmadapter->usr_dot_11n_dev_cap;
+ PRINTM(MINFO, "UsrDot11nCap 0x%x\n", cfg->param.htcap_cfg);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable AMSDU AGGR CTRL
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_amsdu_aggr_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ PRINTM(MERROR, "Prepare the command\n");
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_AMSDU_AGGR_CTRL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.amsdu_aggr_ctrl);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get 11n configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_11N_CFG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.tx_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get addba parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_addba_param(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u32 timeout;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.addba_param.timeout = pmpriv->add_ba_param.timeout;
+ cfg->param.addba_param.txwinsize = pmpriv->add_ba_param.tx_win_size;
+ cfg->param.addba_param.rxwinsize = pmpriv->add_ba_param.rx_win_size;
+ } else {
+ timeout = pmpriv->add_ba_param.timeout;
+ pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout;
+ pmpriv->add_ba_param.tx_win_size = cfg->param.addba_param.txwinsize;
+ pmpriv->add_ba_param.rx_win_size = cfg->param.addba_param.rxwinsize;
+ if (timeout != pmpriv->add_ba_param.timeout) {
+ wlan_11n_update_addba_request(pmpriv);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get addba reject set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_addba_reject(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MERROR, "Addba reject MLAN\n");
+ memcpy(cfg->param.addba_reject, pmpriv->addba_reject, MAX_NUM_TID);
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if (cfg->param.addba_reject[i] > ADDBA_RSP_STATUS_REJECT) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->addba_reject[i] = cfg->param.addba_reject[i];
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get aggr_prio_tbl
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_aggr_prio_tbl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg->param.aggr_prio_tbl.ampdu[i] =
+ pmpriv->aggr_prio_tbl[i].ampdu_user;
+ cfg->param.aggr_prio_tbl.amsdu[i] = pmpriv->aggr_prio_tbl[i].amsdu;
+ }
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if ((cfg->param.aggr_prio_tbl.ampdu[i] > HIGH_PRIO_TID) &&
+ (cfg->param.aggr_prio_tbl.ampdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->aggr_prio_tbl[i].ampdu_ap =
+ pmpriv->aggr_prio_tbl[i].ampdu_user =
+ cfg->param.aggr_prio_tbl.ampdu[i];
+
+ /* For AMSDU */
+ if ((cfg->param.aggr_prio_tbl.amsdu[i] > HIGH_PRIO_TID &&
+ cfg->param.aggr_prio_tbl.amsdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ } else {
+ pmpriv->aggr_prio_tbl[i].amsdu =
+ cfg->param.aggr_prio_tbl.amsdu[i];
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function fills the cap info
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ *
+ * @return N/A
+ */
+void
+wlan_fill_cap_info(mlan_adapter * pmadapter, MrvlIETypes_HTCap_t * pht_cap)
+{
+ int rx_mcs_supp;
+
+ ENTER();
+
+ if (ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) &&
+ ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_GREENFIELD(pmadapter->hw_dot_11n_dev_cap) &&
+ ISSUPP_GREENFIELD(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI20(pmadapter->hw_dot_11n_dev_cap) &&
+ ISSUPP_SHORTGI20(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI40(pmadapter->hw_dot_11n_dev_cap) &&
+ ISSUPP_SHORTGI40(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for RX STBC yet */
+ if (ISSUPP_RXSTBC(pmadapter->hw_dot_11n_dev_cap)
+ && ISSUPP_RXSTBC(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info, 1);
+ else
+ RESETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for TX STBC yet */
+ if (ISSUPP_TXSTBC(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for Delayed BACK yet */
+ if (GET_DELAYEDBACK(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISENABLED_40MHZ_INTOLARENT(pmadapter->usr_dot_11n_dev_cap))
+ SETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+
+ SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
+ SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
+
+ /* Need change to support 8k AMSDU receive */
+ RESETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);
+
+ rx_mcs_supp = GET_RXMCSSUPP(pmadapter->hw_dev_mcs_support);
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+ /* Set MCS for 1x1 */
+ memset((t_u8 *) pht_cap->ht_cap.supported_mcs_set, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset((t_u8 *) & pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32, this is mandatory for any 11n device */
+ SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prints the 802.11n device capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void
+wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
+ (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
+ PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
+ (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
+ (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
+ (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
+ (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
+ (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
+ (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
+ (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
+ (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
+ (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
+ GET_DELAYEDBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
+ GET_IMMEDIATEBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
+
+ if (ISSUPP_RXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Rx antennea A\n");
+ }
+ if (ISSUPP_RXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Rx antennea B\n");
+ }
+ if (ISSUPP_RXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Rx antennea C\n");
+ }
+ if (ISSUPP_RXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Rx antennea D\n");
+ }
+ if (ISSUPP_TXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Tx antennea A\n");
+ }
+ if (ISSUPP_TXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Tx antennea B\n");
+ }
+ if (ISSUPP_TXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Tx antennea C\n");
+ }
+ if (ISSUPP_TXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Prescence of Tx antennea D\n");
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prints the 802.11n device MCS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void
+wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n", GET_RXMCSSUPP(support),
+ GET_TXMCSSUPP(support));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ int tid;
+ TxBAStreamTbl *ptx_ba_tbl;
+ HostCmd_DS_11N_DELBA *pdel_ba =
+ (HostCmd_DS_11N_DELBA *) & resp->params.del_ba;
+
+ ENTER();
+
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+ if (pdel_ba->del_result == BA_RESULT_SUCCESS) {
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_SENT,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ wlan_send_addba(priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra);
+ }
+ } else { /*
+ * In case of failure, recreate the deleted stream in
+ * case we initiated the ADDBA
+ */
+ if (INITIATOR_BIT(pdel_ba->del_ba_param_set)) {
+ wlan_11n_create_txbastream_tbl(priv, pdel_ba->peer_mac_addr, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ mlan_11n_delete_bastream_tbl(priv, ptx_ba_tbl->tid,
+ ptx_ba_tbl->ra, TYPE_DELBA_SENT,
+ MTRUE);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * add a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_addba_req(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ int tid;
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *) & resp->params.add_ba_rsp;
+ TxBAStreamTbl *ptx_ba_tbl;
+
+ ENTER();
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo = wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = (wlan_le16_to_cpu(padd_ba_rsp->ssn)) & SSN_MASK;
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_tbl(priv, tid,
+ padd_ba_rsp->
+ peer_mac_addr))) {
+ PRINTM(MINFO, "BA stream complete\n");
+ ptx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+ } else {
+ PRINTM(MERROR, "Stream not created!!!\n");
+ }
+ } else {
+ mlan_11n_delete_bastream_tbl(priv, tid, padd_ba_rsp->peer_mac_addr,
+ TYPE_DELBA_SENT, MTRUE);
+ if (padd_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) {
+ priv->aggr_prio_tbl[tid].ampdu_ap = BA_STREAM_NOT_ALLOWED;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11ncfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
+
+ ENTER();
+ if (pioctl_buf) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
+ cfg->param.tx_cfg.httxinfo = wlan_le16_to_cpu(htcfg->ht_tx_info);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reconfigure tx buf
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
+ t_u16 action = (t_u16) cmd_action;
+ t_u16 buf_size = *((t_u16 *) pdata_buf);
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG)
+ + S_DS_GEN);
+ ptx_buf->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ PRINTM(MCMND, "set tx_buf=%d\n", buf_size);
+ ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ ptx_buf->buff_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of amsdu aggr control
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
+ t_u16 action = (t_u16) cmd_action;
+ mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl = (mlan_ds_11n_amsdu_aggr_ctrl *)
+ pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL)
+ + S_DS_GEN);
+ pamsdu_ctrl->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of amsdu aggr ctrl
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.amsdu_aggr_ctrl.enable =
+ wlan_le16_to_cpu(amsdu_ctrl->enable);
+ cfg->param.amsdu_aggr_ctrl.curr_buf_size =
+ wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares 11n cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
+ mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *) pdata_buf;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
+ htcfg->action = wlan_cpu_to_le16(cmd_action);
+ htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
+ htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function append the 802_11N tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int
+wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc, OUT t_u8 ** ppbuffer)
+{
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list;
+ MrvlIETypes_2040BSSCo_t *p2040_bss_co;
+ MrvlIETypes_ExtCap_t *pext_cap;
+ int ret_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == 0) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == 0) {
+ LEAVE();
+ return 0;
+ }
+
+ if (pbss_desc->pht_cap) {
+ pht_cap = (MrvlIETypes_HTCap_t *) * ppbuffer;
+ memset(pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ memcpy((t_u8 *) pht_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t),
+ pht_cap->header.len);
+
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
+ wlan_fill_cap_info(pmpriv->adapter, pht_cap);
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
+
+ HEXDUMP("HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
+ ret_len += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ if (pbss_desc->pht_info) {
+ pht_info = (MrvlIETypes_HTInfo_t *) * ppbuffer;
+ memset(pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+
+ memcpy((t_u8 *) pht_info + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_info + sizeof(IEEEtypes_Header_t),
+ pht_info->header.len);
+
+ if (!ISSUPP_CHANWIDTH40(pmpriv->adapter->hw_dot_11n_dev_cap) ||
+ !ISSUPP_CHANWIDTH40(pmpriv->adapter->usr_dot_11n_dev_cap)) {
+ RESET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+
+ *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
+ ret_len += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+
+ pchan_list = (MrvlIEtypes_ChanListParamSet_t *) * ppbuffer;
+ memset(pchan_list, 0, sizeof(MrvlIEtypes_ChanListParamSet_t));
+ pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_list->header.len = sizeof(MrvlIEtypes_ChanListParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t);
+ pchan_list->chan_scan_param[0].chan_number = pbss_desc->pht_info->
+ ht_info.pri_chan;
+ pchan_list->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ if ((ISSUPP_CHANWIDTH40(pmpriv->adapter->hw_dot_11n_dev_cap) &&
+ ISSUPP_CHANWIDTH40(pmpriv->adapter->usr_dot_11n_dev_cap)) &&
+ ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2))
+ SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
+ GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
+ field2));
+
+ HEXDUMP("ChanList", (t_u8 *) pchan_list,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ HEXDUMP("pht_info", (t_u8 *) pbss_desc->pht_info,
+ sizeof(MrvlIETypes_HTInfo_t) - 2);
+ *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ pchan_list->header.len = wlan_cpu_to_le16(pchan_list->header.len);
+ }
+
+ if (pbss_desc->pbss_co_2040) {
+ p2040_bss_co = (MrvlIETypes_2040BSSCo_t *) * ppbuffer;
+ memset(p2040_bss_co, 0, sizeof(MrvlIETypes_2040BSSCo_t));
+ p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
+ p2040_bss_co->header.len = sizeof(BSSCo2040_t);
+
+ memcpy((t_u8 *) p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pbss_co_2040 + sizeof(IEEEtypes_Header_t),
+ p2040_bss_co->header.len);
+
+ HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *) p2040_bss_co,
+ sizeof(MrvlIETypes_2040BSSCo_t));
+ *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
+ ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
+ p2040_bss_co->header.len = wlan_cpu_to_le16(p2040_bss_co->header.len);
+ }
+
+ if (pbss_desc->pext_cap) {
+ pext_cap = (MrvlIETypes_ExtCap_t *) * ppbuffer;
+ memset(pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
+ pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
+ pext_cap->header.len = sizeof(ExtCap_t);
+
+ memcpy((t_u8 *) pext_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t),
+ pext_cap->header.len);
+
+ HEXDUMP("Extended Capabilities IE", (t_u8 *) pext_cap,
+ sizeof(MrvlIETypes_ExtCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
+ ret_len += sizeof(MrvlIETypes_ExtCap_t);
+ pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief This function reconfigure the tx buf size in firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc BSSDescriptor_t from the scan table to assoc
+ *
+ * @return N/A
+ */
+void
+wlan_cfg_tx_buf(mlan_private * pmpriv, BSSDescriptor_t * pbss_desc)
+{
+ t_u16 max_amsdu = MLAN_TX_DATA_BUF_SIZE_2K;
+ t_u16 tx_buf = 0;
+
+ ENTER();
+
+ if (pbss_desc->pht_cap) {
+ if (GETHT_MAXAMSDU(pbss_desc->pht_cap->ht_cap.ht_cap_info))
+ max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ }
+
+ tx_buf = MIN(pmpriv->adapter->max_tx_buf_size, max_amsdu);
+
+ PRINTM(MINFO, "max_amsdu=%d, maxTxBuf=%d\n", max_amsdu,
+ pmpriv->adapter->max_tx_buf_size);
+
+ if (pmpriv->adapter->tx_buf_size != tx_buf) {
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &tx_buf);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief 11n configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11N_CFG_TX:
+ status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_HTCAP_CFG:
+ status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AGGR_PRIO_TBL:
+ status = wlan_11n_ioctl_aggr_prio_tbl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_REJECT:
+ status = wlan_11n_ioctl_addba_reject(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_PARAM:
+ status = wlan_11n_ioctl_addba_param(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE:
+ status = wlan_11n_ioctl_max_tx_buf_size(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL:
+ status = wlan_11n_ioctl_amsdu_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function checks if the given pointer is valid entry of
+ * Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptxtblptr Pointer to tx ba stream entry
+ *
+ * @return MTRUE or MFALSE
+ */
+int
+wlan_is_txbastreamptr_valid(mlan_private * priv, TxBAStreamTbl * ptxtblptr)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr, MNULL,
+ MNULL))) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl == ptxtblptr) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will delete the given entry in Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptx_tbl Pointer to tx ba stream entry to delete
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(priv->tx_ba_stream_tbl_ptr.plock);
+
+ if (!ptx_tbl && wlan_is_txbastreamptr_valid(priv, ptx_tbl)) {
+ goto exit;
+ }
+
+ PRINTM(MINFO, "tx_ba_stream_tbl_ptr %p\n", ptx_tbl);
+
+ util_unlink_list(&priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) ptx_tbl, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree((t_u8 *) ptx_tbl);
+
+ exit:
+ pmadapter->callbacks.moal_spin_unlock(priv->tx_ba_stream_tbl_ptr.plock);
+ LEAVE();
+}
+
+/**
+ * @brief This function will delete all the entires in Tx BA Stream table
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_deleteall_txbastream_tbl(mlan_private * priv)
+{
+ int i;
+ TxBAStreamTbl *del_tbl_ptr;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (TxBAStreamTbl *)
+ util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->tx_ba_stream_tbl_ptr);
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].ampdu_ap = priv->aggr_prio_tbl[i].ampdu_user;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will return the pointer to a entry in BA Stream
+ * table which matches the ba_status requested
+ *
+ * @param priv A pointer to mlan_private
+ * @param ba_status Current status of the BA stream
+ *
+ * @return A pointer to first entry matching status in BA stream
+ */
+TxBAStreamTbl *
+wlan_11n_get_txbastream_status(mlan_private * priv, baStatus_e ba_status)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl->ba_status == ba_status) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will return the pointer to a entry in BA Stream
+ * table which matches the give RA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to find in reordering table
+ * @param ra RA to find in reordering table
+ *
+ * @return A pointer to first entry matching RA/TID in BA stream
+ */
+TxBAStreamTbl *
+wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid, t_u8 * ra)
+{
+ TxBAStreamTbl *ptx_tbl;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", ptx_tbl->tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+
+ if ((!memcmp(ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH))
+ && (ptx_tbl->tid == tid)) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will create a entry in tx ba stream table for the
+ * given RA/TID.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in reordering table
+ * @param tid TID to find in reordering table
+ * @param ba_status BA stream status to create the stream with
+ *
+ * @return N/A
+ */
+void
+wlan_11n_create_txbastream_tbl(mlan_private * priv,
+ t_u8 * ra, int tid, baStatus_e ba_status)
+{
+ TxBAStreamTbl *newNode;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!wlan_11n_get_txbastream_tbl(priv, tid, ra)) {
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d", tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->callbacks.moal_malloc(sizeof(TxBAStreamTbl),
+ (t_u8 **) & newNode);
+ util_init_list((pmlan_linked_list) newNode);
+
+ newNode->tid = tid;
+ newNode->ba_status = ba_status;
+ memcpy(newNode->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ util_enqueue_list_tail(&priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) newNode,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will send a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac)
+{
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ static t_u8 dialog_tok;
+ mlan_status ret;
+
+ ENTER();
+
+ PRINTM(MCMND, "Send addba: TID %d\n", tid);
+ DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ add_ba_req.block_ack_param_set = (t_u16) ((tid << BLOCKACKPARAM_TID_POS) |
+ (priv->add_ba_param.tx_win_size
+ << BLOCKACKPARAM_WINSIZE_POS) |
+ IMMEDIATE_BLOCK_ACK);
+ add_ba_req.block_ack_tmo = (t_u16) priv->add_ba_param.timeout;
+
+ ++dialog_tok;
+
+ if (dialog_tok == 0)
+ dialog_tok = 1;
+
+ add_ba_req.dialog_token = dialog_tok;
+ memcpy(&add_ba_req.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+ 0, 0, MNULL, &add_ba_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac, int initiator)
+{
+ HostCmd_DS_11N_DELBA delba;
+ mlan_status ret;
+
+ ENTER();
+
+ memset(&delba, 0, sizeof(delba));
+ delba.del_ba_param_set = (tid << DELBA_TID_POS);
+
+ if (initiator)
+ DELBA_INITIATOR(delba.del_ba_param_set);
+ else
+ DELBA_RECIPIENT(delba.del_ba_param_set);
+
+ memcpy(&delba.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &delba);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param del_ba A pointer to command response buffer
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *) del_ba;
+ int tid;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *) pdel_ba, 20);
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_RECEIVE,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will resend addba request to all
+ * the peer in the TxBAStreamTbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_update_addba_request(mlan_private * priv)
+{
+
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ wlan_send_addba(priv, ptx_tbl->tid, ptx_tbl->ra);
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ mlan_main_process(priv->adapter);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get Rx reordering table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to rx_reorder_tbl structure
+ * @return num of rx reorder table entry
+ */
+int
+wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf)
+{
+ int i;
+ rx_reorder_tbl *ptbl = buf;
+ RxReorderTbl *rxReorderTblPtr;
+ int count = 0;
+ ENTER();
+ if (!
+ (rxReorderTblPtr =
+ (RxReorderTbl *) util_peek_list(&priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return count;
+ }
+ while (rxReorderTblPtr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ ptbl->tid = (t_u16) rxReorderTblPtr->tid;
+ memcpy(ptbl->ta, rxReorderTblPtr->ta, MLAN_MAC_ADDR_LENGTH);
+ ptbl->start_win = rxReorderTblPtr->start_win;
+ ptbl->win_size = rxReorderTblPtr->win_size;
+ for (i = 0; i < rxReorderTblPtr->win_size; ++i) {
+ if (rxReorderTblPtr->rx_reorder_ptr[i])
+ ptbl->buffer[i] = MTRUE;
+ else
+ ptbl->buffer[i] = MFALSE;
+ }
+ rxReorderTblPtr = rxReorderTblPtr->pnext;
+ ptbl++;
+ count++;
+ }
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief Get transmit BA stream table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to tx_ba_stream_tbl structure
+ * @return number of ba stream table entry
+ */
+int
+wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf)
+{
+ TxBAStreamTbl *ptxtbl;
+ tx_ba_stream_tbl *ptbl = buf;
+ int count = 0;
+
+ ENTER();
+
+ if (!(ptxtbl = (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return count;
+ }
+
+ while (ptxtbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ ptbl->tid = (t_u16) ptxtbl->tid;
+ PRINTM(MMSG, "tid=%d\n", ptbl->tid);
+ memcpy(ptbl->ra, ptxtbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ptxtbl = ptxtbl->pnext;
+ ptbl++;
+ count++;
+ }
+
+ LEAVE();
+ return count;
+}
diff --git a/wlan_src/mlan/mlan_11n.h b/wlan_src/mlan/mlan_11n.h
new file mode 100755
index 0000000..91d7536
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n.h
@@ -0,0 +1,273 @@
+/** @file mlan_11n.h
+ *
+ * @brief Interface for the 802.11n mlan_11n module implemented in mlan_11n.c
+ *
+ * Driver interface functions and type declarations for the 11n module
+ * implemented in mlan_11n.c.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 12/01/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_H_
+#define _MLAN_11N_H_
+
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#include "mlan_wmm.h"
+
+/** Print the 802.11n device capability */
+void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap);
+/** Print the 802.11n device MCS */
+void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support);
+/** Handle the command response of a delete block ack request */
+mlan_status wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp);
+/** Handle the command response of an add block ack request */
+mlan_status wlan_ret_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+/** Handle the command response of 11ncfg command */
+mlan_status wlan_ret_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Prepare 11ncfg command */
+mlan_status wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+/** Append the 802_11N tlv */
+int wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 ** ppbuffer);
+/** Reconfigure the tx buf size in firmware */
+void wlan_cfg_tx_buf(mlan_private * pmpriv, BSSDescriptor_t * pbss_desc);
+/** wlan fill cap info */
+void wlan_fill_cap_info(mlan_adapter * pmadapter,
+ MrvlIETypes_HTCap_t * pht_cap);
+/** Miscellaneous configuration handler */
+mlan_status wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** Delete Tx BA stream table entry */
+void wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl);
+/** Delete all Tx BA stream table entries */
+void wlan_11n_deleteall_txbastream_tbl(mlan_private * priv);
+/** Get Tx BA stream status */
+TxBAStreamTbl *wlan_11n_get_txbastream_status(mlan_private * priv,
+ baStatus_e ba_status);
+/** Get Tx BA stream table */
+TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid,
+ t_u8 * ra);
+/** Create Tx BA stream table */
+void wlan_11n_create_txbastream_tbl(mlan_private * priv, t_u8 * ra, int tid,
+ baStatus_e ba_status);
+/** Send ADD BA request */
+int wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac);
+/** Send DEL BA request */
+int wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac,
+ int initiator);
+/** This function handles the command response of delete a block ack request*/
+void wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba);
+/** This function will resend addba request to all the peer in the TxBAStreamTbl */
+void wlan_11n_update_addba_request(mlan_private * priv);
+/** get rx reorder table */
+int wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf);
+/** get tx ba stream table */
+int wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf);
+/** AMSDU Aggr control cmd resp */
+mlan_status wlan_ret_amsdu_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+/** reconfigure tx buf size */
+mlan_status wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+/** AMSDU aggr control cmd */
+mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+
+/**
+ * @brief This function checks whether current BA stream is high priority or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_cur_bastream_high_prio(mlan_private * priv, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock)))
+ return MNULL;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (priv->aggr_prio_tbl[tid].ampdu_user >
+ priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether AMPDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_ampdu_allowed(mlan_private * priv, raListTbl * ptr)
+{
+ return ((priv->aggr_prio_tbl[wlan_get_tid(priv->adapter, ptr)].ampdu_ap
+ != BA_STREAM_NOT_ALLOWED) ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_amsdu_allowed(mlan_private * priv, raListTbl * ptr)
+{
+ return ((priv->aggr_prio_tbl[wlan_get_tid(priv->adapter, ptr)].amsdu
+ != BA_STREAM_NOT_ALLOWED)
+ ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether a BA stream is available or not
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_bastream_avail(mlan_private * priv)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i = 0;
+ t_u32 bastream_num = 0;
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmpriv = priv->adapter->priv[i];
+ bastream_num +=
+ wlan_wmm_list_len(priv->adapter,
+ (pmlan_list_head) & pmpriv->tx_ba_stream_tbl_ptr);
+ }
+ return ((bastream_num < MLAN_MAX_BASTREAM_SUPPORTED) ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function finds the stream to delete
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptid A pointer to TID
+ * @param ra RA
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_find_stream_to_delete(mlan_private * priv,
+ raListTbl * ptr, int *ptid, t_u8 * ra)
+{
+ int tid;
+ t_u8 ret = MFALSE;
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return ret;
+ }
+
+ tid = priv->aggr_prio_tbl[wlan_get_tid(priv->adapter, ptr)].ampdu_user;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (tid > priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ tid = priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user;
+ *ptid = ptx_tbl->tid;
+ memcpy(ra, ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ret = MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks whether BA stream is setup
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_bastream_setup(mlan_private * priv, raListTbl * ptr)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv,
+ wlan_get_tid(priv->adapter, ptr),
+ ptr->ra))) {
+ LEAVE();
+ return IS_BASTREAM_SETUP(ptx_tbl) ? MTRUE : MFALSE;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether 11n is supported
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_11n_enabled(mlan_private * priv, t_u8 * ra)
+{
+ int ret = MFALSE;
+ ENTER();
+ LEAVE();
+ return ret;
+}
+#endif /* !_MLAN_11N_H_ */
diff --git a/wlan_src/mlan/mlan_11n_aggr.c b/wlan_src/mlan/mlan_11n_aggr.c
new file mode 100755
index 0000000..794e622
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n_aggr.c
@@ -0,0 +1,447 @@
+/** @file mlan_11n_aggr.c
+ *
+ * @brief This file contains functions for 11n Aggregation.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Aggregate individual packets into one AMSDU packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param amsdu_buf A pointer to packet buffer
+ * @param data A pointer to aggregated data packet being formed
+ * @param pkt_len Length of current packet to aggregate
+ * @param pad Pad
+ *
+ * @return Final packet size
+ */
+static int
+wlan_11n_form_amsdu_pkt(pmlan_adapter pmadapter, t_u8 * amsdu_buf, t_u8 * data,
+ int pkt_len, int *pad)
+{
+ int dt_offset, amsdu_buf_offset;
+ Rfc1042Hdr_t snap = {
+ 0xaa, /* LLC DSAP */
+ 0xaa, /* LLC SSAP */
+ 0x03, /* LLC CTRL */
+ {0x00, 0x00, 0x00}, /* SNAP OUI */
+ 0x0000 /* SNAP type */
+ /*
+ * This field will be overwritten
+ * later with ethertype
+ */
+ };
+
+ ENTER();
+
+ memcpy(amsdu_buf, data, (MLAN_MAC_ADDR_LENGTH) * 2);
+ dt_offset = amsdu_buf_offset = (MLAN_MAC_ADDR_LENGTH) * 2;
+
+ snap.snap_type = *(t_u16 *) (data + dt_offset);
+ dt_offset += sizeof(t_u16);
+ *(t_u16 *) (amsdu_buf + amsdu_buf_offset) = mlan_htons(pkt_len +
+ LLC_SNAP_LEN -
+ ((2 *
+ MLAN_MAC_ADDR_LENGTH)
+ + sizeof(t_u16)));
+ amsdu_buf_offset += sizeof(t_u16);
+ memcpy(amsdu_buf + amsdu_buf_offset, &snap, LLC_SNAP_LEN);
+ amsdu_buf_offset += LLC_SNAP_LEN;
+
+ memcpy(amsdu_buf + amsdu_buf_offset, data + dt_offset, pkt_len - dt_offset);
+ *pad = (((pkt_len + LLC_SNAP_LEN) & 3)) ?
+ (4 - (((pkt_len + LLC_SNAP_LEN)) & 3)) : 0;
+
+ LEAVE();
+ return (pkt_len + LLC_SNAP_LEN + *pad);
+}
+
+/**
+ * @brief Add TxPD to AMSDU header
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf Pointer to buffer where the TxPD will be formed
+ *
+ * @return N/A
+ */
+static void
+wlan_11n_form_amsdu_txpd(mlan_private * priv, mlan_buffer * mbuf)
+{
+ TxPD *ptx_pd;
+ mlan_adapter *pmadapter = priv->adapter;
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ memset(ptx_pd, 0, sizeof(TxPD));
+
+ /*
+ * Original priority has been overwritten
+ */
+ ptx_pd->priority = (t_u8) mbuf->priority;
+ ptx_pd->pkt_delay_2ms = wlan_wmm_compute_driver_packet_delay(priv, mbuf);
+ ptx_pd->bss_num = (t_u8) mbuf->bss_num;
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ if (MTRUE == wlan_check_last_packet_indication(priv)) {
+ pmadapter->tx_lock_flag = MTRUE;
+ ptx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+ /* Always zero as the data is followed by TxPD */
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ ptx_pd->tx_pkt_type = PKT_TYPE_AMSDU;
+
+ if (ptx_pd->tx_control == 0)
+ /* TxCtrl set by user or default */
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+
+ endian_convert_TxPD(ptx_pd);
+
+ LEAVE();
+}
+
+/**
+ * @brief Update the TxPktLength field in TxPD after the complete AMSDU
+ * packet is formed
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mbuf TxPD buffer
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_11n_update_pktlen_amsdu_txpd(pmlan_adapter pmadapter, pmlan_buffer mbuf)
+{
+ TxPD *ptx_pd;
+
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ ptx_pd->tx_pkt_length =
+ (t_u16) wlan_cpu_to_le16(mbuf->data_len - sizeof(TxPD));
+
+ LEAVE();
+}
+
+/**
+ * @brief Get number of aggregated packets
+ *
+ * @param data A pointer to packet data
+ * @param total_pkt_len Total packet length
+ *
+ * @return Number of packets
+ */
+static int
+wlan_11n_get_num_aggrpkts(t_u8 * data, int total_pkt_len)
+{
+ int pkt_count = 0, pkt_len, pad;
+
+ while (total_pkt_len > 0) {
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+ data += pkt_len + pad + sizeof(Eth803Hdr_t);
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+ ++pkt_count;
+ }
+
+ return pkt_count;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Deaggregate the received AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to aggregated data packet
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf)
+{
+ t_u16 pkt_len;
+ int total_pkt_len;
+ t_u8 *data;
+ int pad;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ RxPacketHdr_t *prx_pkt;
+ mlan_buffer *daggr_mbuf;
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0x00
+ };
+
+ ENTER();
+
+ data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ total_pkt_len = pmbuf->data_len;
+
+ /* Sanity test */
+ if (total_pkt_len > MLAN_RX_DATA_BUF_SIZE) {
+ PRINTM(MERROR, "Total packet length greater than tx buffer"
+ " size %d\n", total_pkt_len);
+ goto done;
+ }
+
+ pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len);
+
+ while (total_pkt_len > 0) {
+ prx_pkt = (RxPacketHdr_t *) data;
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ if (pkt_len > total_pkt_len) {
+ PRINTM(MERROR, "Error in pkt_len %d %d\n", total_pkt_len, pkt_len);
+ break;
+ }
+
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+
+ if (memcmp(&prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+ memmove(data + LLC_SNAP_LEN, data, (2 * MLAN_MAC_ADDR_LENGTH));
+ data += LLC_SNAP_LEN;
+ pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN;
+ } else {
+ *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))
+ = (t_u16) 0;
+ pkt_len += sizeof(Eth803Hdr_t);
+ }
+
+ if ((pmadapter->callbacks.moal_malloc(sizeof(mlan_buffer),
+ (t_u8 **) & daggr_mbuf))) {
+ PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(daggr_mbuf, pmbuf, sizeof(mlan_buffer));
+
+ daggr_mbuf->data_offset = 0;
+ daggr_mbuf->data_len = pkt_len;
+ daggr_mbuf->pbuf = data;
+ daggr_mbuf->pdesc = MNULL;
+ daggr_mbuf->pparent = pmbuf;
+ daggr_mbuf->priority = pmbuf->priority;
+ ret =
+ pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ daggr_mbuf);
+
+ switch (ret) {
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_FAILURE:
+ PRINTM(MERROR, "Deaggr, send to moal failed\n");
+ case MLAN_STATUS_SUCCESS:
+ wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ data += pkt_len + pad;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Aggregate multiple packets into one single AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pra_list Pointer to the RA List table containing the pointers
+ * to packets.
+ * @param headroom Any interface specific headroom that may be need. TxPD
+ * will be formed leaving this headroom.
+ * @param ptrindex Pointer index
+ *
+ * @return Final packet size
+ */
+int
+wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
+ int headroom, int ptrindex)
+{
+ int pkt_size = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_buffer *pmbuf_aggr, *pmbuf_src;
+ t_u8 *data;
+ int pad = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sec, usec;
+ mlan_tx_param tx_param;
+ ENTER();
+
+ PRINTM(MDAT_D, "Handling Aggr packet\n");
+
+ if ((pmbuf_src = (pmlan_buffer) util_peek_list(&pra_list->buf_head,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+
+ if (!
+ (pmbuf_aggr =
+ wlan_alloc_mlan_buffer(&pmadapter->callbacks,
+ pmadapter->tx_buf_size))) {
+ PRINTM(MERROR, "Error allocating mlan_buffer\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ data = pmbuf_aggr->pbuf + headroom;
+ memcpy(pmbuf_aggr, pmbuf_src, sizeof(mlan_buffer));
+
+ pmbuf_aggr->pbuf = data;
+ pmbuf_aggr->pdesc = MNULL;
+ pmbuf_aggr->data_offset = 0;
+
+ /* Form AMSDU */
+ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr);
+ pkt_size = sizeof(TxPD);
+ } else {
+ goto exit;
+ }
+
+ while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN)
+ + headroom)
+ <= pmadapter->tx_buf_size)) {
+
+ pmbuf_src = (pmlan_buffer)
+ util_dequeue_list(&pra_list->buf_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pra_list->total_pkts_size -= pmbuf_src->data_len;
+
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ pkt_size += wlan_11n_form_amsdu_pkt(pmadapter,
+ (data + pkt_size),
+ pmbuf_src->pbuf +
+ pmbuf_src->data_offset,
+ pmbuf_src->data_len, &pad);
+
+ DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer));
+ pmadapter->callbacks.moal_send_packet_complete(pmadapter->pmoal_handle,
+ pmbuf_src,
+ MLAN_STATUS_SUCCESS);
+
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf_src = (pmlan_buffer) util_peek_list(&pra_list->buf_head,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+
+ /* Last AMSDU packet does not need padding */
+ pkt_size -= pad;
+ pmbuf_aggr->data_len = pkt_size;
+ wlan_11n_update_pktlen_amsdu_txpd(pmadapter, pmbuf_aggr);
+ pmbuf_aggr->data_len += headroom;
+ pmbuf_aggr->pbuf = data - headroom;
+ tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
+ (((pra_list->total_pkts_size) >
+ pmadapter->tx_buf_size) ? pmadapter->
+ tx_buf_size : pra_list->total_pkts_size +
+ LLC_SNAP_LEN + sizeof(TxPD)) : 0);
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf_aggr,
+ &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf_aggr,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ util_enqueue_list_head(&pra_list->buf_head,
+ (pmlan_linked_list) pmbuf_aggr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pra_list->total_pkts_size += pmbuf_aggr->data_len;
+
+ pmbuf_aggr->flags = MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ PRINTM(MDATA, "MLAN_STATUS_RESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: moal_write_data_async failed: 0x%X\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ goto exit;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ }
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MDATA, "%lu.%lu : Data => FW\n", sec, usec);
+
+ exit:
+ LEAVE();
+ return (pkt_size + headroom);
+}
diff --git a/wlan_src/mlan/mlan_11n_aggr.h b/wlan_src/mlan/mlan_11n_aggr.h
new file mode 100755
index 0000000..197ce08
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n_aggr.h
@@ -0,0 +1,27 @@
+/** @file mlan_11n_aggr.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n aggregation functionalities
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_AGGR_H_
+#define _MLAN_11N_AGGR_H_
+
+/** AMSDU packet type */
+#define PKT_TYPE_AMSDU 0xE6
+
+/** Aggregate 11N packets */
+mlan_status wlan_11n_deaggregate_pkt(pmlan_private priv, pmlan_buffer pmbuf);
+/** Deaggregate 11N packets */
+int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * ptr,
+ int headroom, int ptrindex);
+
+#endif /* !_MLAN_11N_AGGR_H_ */
diff --git a/wlan_src/mlan/mlan_11n_rxreorder.c b/wlan_src/mlan/mlan_11n_rxreorder.c
new file mode 100755
index 0000000..72c15b5
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n_rxreorder.c
@@ -0,0 +1,788 @@
+/** @file mlan_11n_rxreorder.c
+ *
+ * @brief This file contains the handling of RxReordering in wlan
+ * driver.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function will process the rx packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to rx packet payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_pkt(t_void * priv, t_void * payload)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = ((pmlan_private) priv)->adapter;
+ ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer) payload);
+ return ret;
+}
+
+/**
+ * @brief This function dispatchs all the packets in the buffer.
+ * There could be holes in the buffer.
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ * @param start_win Start window
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_pkt_until_start_win(t_void * priv,
+ RxReorderTbl * rx_reor_tbl_ptr,
+ int start_win)
+{
+ int no_pkt_to_send, i, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+ MIN((start_win - rx_reor_tbl_ptr->start_win),
+ rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
+
+ for (i = 0; i < no_pkt_to_send; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->rx_pkt_lock);
+ rx_tmp_ptr = MNULL;
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ }
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->rx_pkt_lock);
+ if (rx_tmp_ptr)
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
+ for (i = 0; i < xchg; ++i) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
+ }
+
+ rx_reor_tbl_ptr->start_win = start_win;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->rx_pkt_lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will display the rxReorder table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ ENTER();
+
+ DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
+ rx_reor_tbl_ptr->win_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will dispatch all packets sequentially
+ * from start_win until a hole is found and adjust the
+ * start_win appropriately
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_scan_and_dispatch(t_void * priv, RxReorderTbl * rx_reor_tbl_ptr)
+{
+ int i, j, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->rx_pkt_lock);
+ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->rx_pkt_lock);
+ break;
+ }
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->rx_pkt_lock);
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ if (i > 0) {
+ xchg = rx_reor_tbl_ptr->win_size - i;
+ for (j = 0; j < xchg; ++j) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
+ }
+ }
+ rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
+ & (MAX_TID_VALUE - 1);
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->rx_pkt_lock);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function delete rxreorder table's entry
+ * and free the memory
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_delete_rxreorder_tbl_entry(mlan_private * priv,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size)
+ & (MAX_TID_VALUE - 1));
+
+ if (rx_reor_tbl_ptr->timer_context.timer) {
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ priv->adapter->callbacks.moal_stop_timer(rx_reor_tbl_ptr->
+ timer_context.timer);
+ priv->adapter->callbacks.moal_free_timer(rx_reor_tbl_ptr->
+ timer_context.timer);
+ }
+
+ PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
+ util_unlink_list(&priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) rx_reor_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pmadapter->callbacks.moal_mfree((t_u8 *) rx_reor_tbl_ptr->rx_reorder_ptr);
+ pmadapter->callbacks.moal_mfree((t_u8 *) rx_reor_tbl_ptr);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will return the pointer to a entry in rx reordering
+ * table which matches the give TA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ *
+ * @return A pointer to structure RxReorderTbl
+ */
+RxReorderTbl *
+wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid, t_u8 * ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ (RxReorderTbl *) util_peek_list(&priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ if ((!memcmp(rx_reor_tbl_ptr->ta, ta, MLAN_MAC_ADDR_LENGTH)) &&
+ (rx_reor_tbl_ptr->tid == tid)) {
+ LEAVE();
+ return rx_reor_tbl_ptr;
+ }
+
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+static int
+wlan_11n_find_last_seqnum(RxReorderTbl * rxReorderTblPtr)
+{
+ int i;
+
+ for (i = (rxReorderTblPtr->win_size - 1); i >= 0; --i) {
+ if (rxReorderTblPtr->rx_reorder_ptr[i]) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static t_void
+wlan_flush_data(t_void * context)
+{
+ reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *) context;
+ int startWin;
+
+ reorder_cnxt->timer_is_set = MFALSE;
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+
+ if ((startWin = wlan_11n_find_last_seqnum(reorder_cnxt->ptr)) >= 0) {
+ PRINTM(MINFO, "Flush data %d\n", startWin);
+ wlan_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
+ reorder_cnxt->ptr,
+ ((reorder_cnxt->ptr->start_win +
+ startWin + 1) & (MAX_TID_VALUE -
+ 1)));
+ }
+
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+}
+
+/**
+ * @brief This function will create a entry in rx reordering table for the
+ * given ta/tid and will initialize it with seq_num, win_size
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ * @param win_size win_size for the give ta/tid pair.
+ * @param seq_num Starting sequence number for current entry.
+ *
+ * @return N/A
+ */
+t_void
+wlan_11n_create_rxreorder_tbl(mlan_private * priv, t_u8 * ta, int tid,
+ int win_size, int seq_num)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ RxReorderTbl *rx_reor_tbl_ptr, *new_node;
+
+ ENTER();
+
+ /*
+ * If we get a TID, ta pair which is already present dispatch all the
+ * the packets and move the window size until the ssn
+ */
+ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta))) {
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, seq_num);
+ } else {
+ PRINTM(MDAT_D, "%s: seq_num %d, tid %d, ta %02x:%02x:%02x:%02x:"
+ "%02x:%02x, win_size %d\n", __FUNCTION__,
+ seq_num, tid, ta[0], ta[1], ta[2], ta[3],
+ ta[4], ta[5], win_size);
+ if (pmadapter->callbacks.moal_malloc(sizeof(RxReorderTbl),
+ (t_u8 **) & new_node)) {
+ PRINTM(MERROR, "Rx reorder memory allocation failed\n");
+ return;
+ }
+
+ util_init_list((pmlan_linked_list) new_node);
+ new_node->tid = tid;
+ memcpy(new_node->ta, ta, MLAN_MAC_ADDR_LENGTH);
+ new_node->start_win = seq_num;
+ new_node->win_size = win_size;
+
+ if (pmadapter->callbacks.moal_malloc(sizeof(t_void *) * win_size,
+ (t_u8 **) & new_node->
+ rx_reorder_ptr)) {
+ PRINTM(MERROR, "Rx reorder table memory allocation" "failed\n");
+ pmadapter->callbacks.moal_mfree((t_u8 *) new_node);
+ return;
+ }
+
+ PRINTM(MDAT_D, "Create ReorderPtr: %p\n", new_node);
+ new_node->timer_context.ptr = new_node;
+ new_node->timer_context.priv = priv;
+ new_node->timer_context.timer_is_set = MFALSE;
+
+ pmadapter->callbacks.moal_init_timer(&new_node->timer_context.
+ timer, wlan_flush_data,
+ &new_node->timer_context);
+
+ for (i = 0; i < win_size; ++i)
+ new_node->rx_reorder_ptr[i] = MNULL;
+
+ util_enqueue_list_tail(&priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) new_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, t_void * pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_REQ *padd_ba_req = (HostCmd_DS_11N_ADDBA_REQ *)
+ & cmd->params.add_ba_req;
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) + S_DS_GEN);
+
+ memcpy(padd_ba_req, pdata_buf, sizeof(HostCmd_DS_11N_ADDBA_REQ));
+ padd_ba_req->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
+ padd_ba_req->block_ack_tmo = wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
+ padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * response.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & cmd->params.add_ba_rsp;
+ HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
+ (HostCmd_DS_11N_ADDBA_REQ *) pdata_buf;
+ t_u8 tid;
+
+ ENTER();
+
+ pevt_addba_req->block_ack_param_set =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
+ pevt_addba_req->block_ack_tmo =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
+ pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
+
+ memcpy(padd_ba_rsp->peer_mac_addr, pevt_addba_req->peer_mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
+ padd_ba_rsp->block_ack_tmo =
+ wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
+
+ padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(priv->addba_reject[tid]);
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
+ /* We donot support AMSDU inside AMPDU, hence reset the bit */
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ padd_ba_rsp->block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
+ BLOCKACKPARAM_WINSIZE_POS);
+ padd_ba_rsp->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo =
+ (t_u16) wlan_cpu_to_le16(priv->add_ba_param.timeout);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for deleting a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_delba(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)
+ & cmd->params.del_ba;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
+
+ memcpy(pdel_ba, pdata_buf, sizeof(HostCmd_DS_11N_DELBA));
+ pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will identify if RxReodering is needed for the packet
+ * and will do the reordering if required before sending it to kernel
+ *
+ * @param priv A pointer to mlan_private
+ * @param seq_num Seqence number of the current packet
+ * @param tid Tid of the current packet
+ * @param ta Transmiter address of the current packet
+ * @param pkt_type Packetype for the current packet (to identify if its a BAR)
+ * @param payload Pointer to the payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
+ t_u8 * ta, t_u8 pkt_type, void *payload)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ int start_win, end_win, win_size;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = ((mlan_private *) priv)->adapter;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl((mlan_private *) priv, tid, ta))) {
+ LEAVE();
+ if (pkt_type == PKT_TYPE_BAR)
+ return ret;
+ else {
+ wlan_11n_dispatch_pkt(priv, payload);
+ return ret;
+ }
+ } else {
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D, "BAR ");
+
+ start_win = rx_reor_tbl_ptr->start_win;
+ win_size = rx_reor_tbl_ptr->win_size;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ pmadapter->callbacks.moal_stop_timer(rx_reor_tbl_ptr->timer_context.
+ timer);
+ pmadapter->callbacks.moal_start_timer(rx_reor_tbl_ptr->timer_context.
+ timer, MFALSE,
+ MIN_FLUSH_TIMER_MS * win_size);
+ rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
+
+ PRINTM(MDAT_D, "TID %d, TA %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tid, ta[0], ta[1], ta[2], ta[3], ta[4], ta[5]);
+ PRINTM(MDAT_D, "1:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+ /*
+ * If seq_num is less then starting win then ignore and drop the
+ * packet
+ */
+ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { /* Wrap */
+ if (seq_num >= ((start_win + (TWOPOW11)) &
+ (MAX_TID_VALUE - 1)) && (seq_num < start_win)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ } else if ((seq_num < start_win) ||
+ (seq_num > (start_win + (TWOPOW11)))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /*
+ * If this packet is a BAR we adjust seq_num as
+ * WinStart = seq_num
+ */
+ if (pkt_type == PKT_TYPE_BAR)
+ seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D, "2:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+
+ if (((end_win < start_win) && (seq_num < (TWOPOW11 -
+ (MAX_TID_VALUE - start_win)))
+ && (seq_num > end_win))
+ || ((end_win > start_win) &&
+ ((seq_num > end_win) || (seq_num < start_win)))) {
+ end_win = seq_num;
+ if (((seq_num - win_size) + 1) >= 0)
+ start_win = (end_win - win_size) + 1;
+ else
+ start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
+ if ((ret = wlan_11n_dispatch_pkt_until_start_win(priv,
+ rx_reor_tbl_ptr,
+ start_win))) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ PRINTM(MDAT_D, "3:seq_num %d start_win %d win_size %d"
+ " end_win %d\n", seq_num, start_win, win_size, end_win);
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (seq_num >= start_win)
+ rx_reor_tbl_ptr->rx_reorder_ptr[seq_num - start_win] = payload;
+ else /* Wrap condition */
+ rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+ + (MAX_TID_VALUE)) -
+ start_win] = payload;
+ }
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+
+ /*
+ * Dispatch all packets sequentially from start_win until a
+ * hole is found and adjust the start_win appropriately
+ */
+ ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete an entry for a given tid/ta pair. tid/ta
+ * are taken from delba_event body
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid to send delba
+ * @param peer_mac MAC address to send delba
+ * @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
+ * @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
+ *
+ * @return N/A
+ */
+void
+mlan_11n_delete_bastream_tbl(mlan_private * priv, int tid,
+ t_u8 * peer_mac, t_u8 type, int initiator)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ TxBAStreamTbl *ptxtbl;
+ t_u8 cleanup_rx_reorder_tbl;
+
+ ENTER();
+
+ if (type == TYPE_DELBA_RECEIVE)
+ cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
+ else
+ cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
+
+ PRINTM(MEVENT, "DELBA: %02x:%02x:%02x:%02x:%02x:%02x tid=%d,"
+ "initiator=%d\n", peer_mac[0],
+ peer_mac[1], peer_mac[2],
+ peer_mac[3], peer_mac[4], peer_mac[5], tid, initiator);
+
+ if (cleanup_rx_reorder_tbl) {
+ if (!(rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid,
+ peer_mac))) {
+ PRINTM(MWARN, "TID, TA not found in table!\n");
+ LEAVE();
+ return;
+ }
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ } else {
+ if (!(ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac))) {
+ PRINTM(MWARN, "TID, RA not found in table!\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of
+ * a block ack response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_addba_resp(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & resp->params.add_ba_rsp;
+ int tid, win_size;
+
+ ENTER();
+
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ /* Check if we had rejected the ADDBA, if yes then do not create the stream */
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_le16_to_cpu(padd_ba_rsp->ssn);
+
+ win_size =
+ (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+
+ wlan_11n_create_rxreorder_tbl(priv, padd_ba_rsp->peer_mac_addr, tid,
+ win_size, padd_ba_rsp->ssn);
+
+ PRINTM(MCMND, "ADDBA RSP: %02x:%02x:%02x:%02x:%02x:%02x tid=%d\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid);
+ } else {
+ PRINTM(MERROR,
+ "ADDBA RSP: Failed(%02x:%02x:%02x:%02x:%02x:%02x tid=%d)\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid);
+
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles ba_stream_timeout event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
+ *
+ * @return N/A
+ */
+void
+wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event)
+{
+ HostCmd_DS_11N_DELBA delba;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *) event, 20);
+
+ memset(&delba, 0, sizeof(HostCmd_DS_11N_DELBA));
+ memcpy(delba.peer_mac_addr, event->peer_mac_addr, MLAN_MAC_ADDR_LENGTH);
+
+ delba.del_ba_param_set |= (t_u16) event->tid << DELBA_TID_POS;
+ delba.del_ba_param_set |= (t_u16) event->origninator << DELBA_INITIATOR_POS;
+ delba.reason_code = REASON_CODE_STA_TIMEOUT;
+ wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function cleans up reorder tbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_cleanup_reorder_tbl(mlan_private * priv)
+{
+ RxReorderTbl *del_tbl_ptr;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (RxReorderTbl *)
+ util_peek_list(&priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->rx_reorder_tbl_ptr);
+
+ LEAVE();
+}
diff --git a/wlan_src/mlan/mlan_11n_rxreorder.h b/wlan_src/mlan/mlan_11n_rxreorder.h
new file mode 100755
index 0000000..47ea16a
--- /dev/null
+++ b/wlan_src/mlan/mlan_11n_rxreorder.h
@@ -0,0 +1,78 @@
+/** @file mlan_11n_rxreorder.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n RxReordering functionalities
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_RXREORDER_H_
+#define _MLAN_11N_RXREORDER_H_
+
+/** Rx packet type for BAR */
+#define PKT_TYPE_BAR 0xE7
+/** Max value a TID can take = 2^12 = 4096 */
+#define MAX_TID_VALUE (2 << 11)
+/** 2^11 = 2048 */
+#define TWOPOW11 (2 << 10)
+
+/** Tid Mask used for extracting TID from BlockAckParamSet */
+#define BLOCKACKPARAM_TID_MASK 0x3C
+/** Tid position in BlockAckParamSet */
+#define BLOCKACKPARAM_TID_POS 2
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_MASK 0xffc0
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
+/** WinSize position in BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_POS 6
+/** Position of TID in DelBA Param set */
+#define DELBA_TID_POS 12
+/** Position of INITIATOR in DelBA Param set */
+#define DELBA_INITIATOR_POS 11
+/** Reason code: Requested from peer STA as it does not want to use the mechanism */
+#define REASON_CODE_STA_DONT_WANT 37
+/** Reason code: Requested from peer STA due to timeout*/
+#define REASON_CODE_STA_TIMEOUT 39
+/** Type: send delba command */
+#define TYPE_DELBA_SENT 1
+/** Type: recieve delba command */
+#define TYPE_DELBA_RECEIVE 2
+/** Set Initiator Bit */
+#define DELBA_INITIATOR(paramset) (paramset = (paramset | (1 << 11)))
+/** Reset Initiator Bit for recipient */
+#define DELBA_RECIPIENT(paramset) (paramset = (paramset & ~(1 << 11)))
+/** Immediate block ack */
+#define IMMEDIATE_BLOCK_ACK 0x2
+
+/** ADDBA response status : Reject */
+#define ADDBA_RSP_STATUS_REJECT 1
+/** ADDBA response status : Accept */
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seqNum, t_u16 tid,
+ t_u8 * ta, t_u8 pkttype, void *payload);
+void mlan_11n_delete_bastream_tbl(mlan_private * priv, int Tid,
+ t_u8 * PeerMACAddr, t_u8 type, int initiator);
+void wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event);
+mlan_status wlan_ret_11n_addba_resp(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+mlan_status wlan_cmd_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf);
+void wlan_11n_cleanup_reorder_tbl(mlan_private * priv);
+RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid,
+ t_u8 * ta);
+
+#endif /* _MLAN_11N_RXREORDER_H_ */
diff --git a/wlan_src/mlan/mlan_cfp.c b/wlan_src/mlan/mlan_cfp.c
new file mode 100755
index 0000000..a41d932
--- /dev/null
+++ b/wlan_src/mlan/mlan_cfp.c
@@ -0,0 +1,960 @@
+/**
+ * @file mlan_cfp.c
+ *
+ * @brief This file contains WLAN client mode channel, frequence and power
+ * related code
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 04/16/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_join.h"
+#include "mlan_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** 100mW */
+#define WLAN_TX_PWR_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20
+/** 50mW */
+#define WLAN_TX_PWR_JP_DEFAULT 16
+/** 100mW */
+#define WLAN_TX_PWR_FR_100MW 20
+/** 10mW */
+#define WLAN_TX_PWR_FR_10MW 10
+/** 100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/** Band: 'B/G', Region: USA FCC/Canada IC */
+static chan_freq_power_t channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/** Band: 'B/G', Region: Europe ETSI */
+static chan_freq_power_t channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/** Band: 'B/G', Region: France */
+static chan_freq_power_t channel_freq_power_FR_BG[] = {
+ {1, 2412, WLAN_TX_PWR_FR_100MW},
+ {2, 2417, WLAN_TX_PWR_FR_100MW},
+ {3, 2422, WLAN_TX_PWR_FR_100MW},
+ {4, 2427, WLAN_TX_PWR_FR_100MW},
+ {5, 2432, WLAN_TX_PWR_FR_100MW},
+ {6, 2437, WLAN_TX_PWR_FR_100MW},
+ {7, 2442, WLAN_TX_PWR_FR_100MW},
+ {8, 2447, WLAN_TX_PWR_FR_100MW},
+ {9, 2452, WLAN_TX_PWR_FR_100MW},
+ {10, 2457, WLAN_TX_PWR_FR_10MW},
+ {11, 2462, WLAN_TX_PWR_FR_10MW},
+ {12, 2467, WLAN_TX_PWR_FR_10MW},
+ {13, 2472, WLAN_TX_PWR_FR_10MW}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN41_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN40_BG[] = {
+ {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/** Band : 'B/G', Region: Special */
+static chan_freq_power_t channel_freq_power_SPECIAL_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+ {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/** Band: 'A', Region: USA FCC, Canada IC, Spain, France */
+static chan_freq_power_t channel_freq_power_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT},
+ {120, 5600, WLAN_TX_PWR_US_DEFAULT},
+ {124, 5620, WLAN_TX_PWR_US_DEFAULT},
+ {128, 5640, WLAN_TX_PWR_US_DEFAULT},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/** Band: 'A', Region: Europe ETSI */
+static chan_freq_power_t channel_freq_power_EU_A[] = {
+ {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT},
+ {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT},
+ {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT},
+ {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT},
+ {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT},
+ {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT},
+ {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT},
+ {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT},
+ {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT},
+ {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT},
+ {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT},
+ {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT},
+ {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT},
+ {120, 5600, WLAN_TX_PWR_EMEA_DEFAULT},
+ {124, 5620, WLAN_TX_PWR_EMEA_DEFAULT},
+ {128, 5640, WLAN_TX_PWR_EMEA_DEFAULT},
+ {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT},
+ {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT},
+ {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/** Band: 'A', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN_A[] = {
+ {8, 5040, WLAN_TX_PWR_JP_DEFAULT},
+ {12, 5060, WLAN_TX_PWR_JP_DEFAULT},
+ {16, 5080, WLAN_TX_PWR_JP_DEFAULT},
+ {34, 5170, WLAN_TX_PWR_JP_DEFAULT},
+ {38, 5190, WLAN_TX_PWR_JP_DEFAULT},
+ {42, 5210, WLAN_TX_PWR_JP_DEFAULT},
+ {46, 5230, WLAN_TX_PWR_JP_DEFAULT},
+};
+
+/**
+ * The structure for channel, frequency and power
+ */
+typedef struct _region_cfp_table
+{
+ /** Region */
+ t_u8 region;
+ /** Frequency/Power */
+ chan_freq_power_t *cfp_BG;
+ /** No BG flag */
+ int cfp_no_BG;
+ /** Frequency/Power for band A */
+ chan_freq_power_t *cfp_A;
+ /** No A flag */
+ int cfp_no_A;
+} region_cfp_table_t;
+
+/**
+ * The structure for the mapping between region and CFP
+ */
+static region_cfp_table_t region_cfp_table[] = {
+ {0x10, /* US FCC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x20, /* CANADA IC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x30, /* EU */
+ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_EU_A,
+ sizeof(channel_freq_power_EU_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x32, /* FRANCE */
+ channel_freq_power_FR_BG,
+ sizeof(channel_freq_power_FR_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x40, /* JAPAN */
+ channel_freq_power_JPN40_BG,
+ sizeof(channel_freq_power_JPN40_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x41, /* JAPAN */
+ channel_freq_power_JPN41_BG,
+ sizeof(channel_freq_power_JPN41_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xff, /* Special */
+ channel_freq_power_SPECIAL_BG,
+ sizeof(channel_freq_power_SPECIAL_BG) / sizeof(chan_freq_power_t),
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+/* Add new region here */
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+/**
+ * The rates supported for ad-hoc B mode
+ */
+t_u8 AdhocRates_B[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
+
+/**
+ * The rates supported for ad-hoc G mode
+ */
+t_u8 AdhocRates_G[G_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported for ad-hoc BG mode
+ */
+t_u8 AdhocRates_BG[BG_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The rates supported in A mode for ad-hoc
+ */
+t_u8 AdhocRates_A[A_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+/**
+ * The rates supported in A mode (used for BAND_A)
+ */
+t_u8 SupportedRates_A[A_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+/**
+ * The rates supported by the card
+ */
+t_u16 WlanDataRates[WLAN_SUPPORTED_RATES_EXT] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
+ 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75,
+ 0x82, 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2,
+ 0xD8, 0xF3, 0x10E, 0x00
+};
+
+/**
+ * The rates supported in B mode
+ */
+t_u8 SupportedRates_B[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+
+/**
+ * The rates supported in G mode (BAND_G, BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_G[G_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported in BG mode (BAND_B|BAND_G, BAND_B|BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_BG[BG_SUPPORTED_RATES] =
+ { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The table to keep region code
+ */
+t_u16 region_code_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0xff };
+
+/**
+ * The rates supported in N mode
+ */
+t_u8 SupportedRates_N[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Find a character in a string.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to string
+ * @param c Character to be located
+ * @param n The length of string
+ *
+ * @return A pointer to the first occurrence of c in string, or MNULL if c is not found.
+ */
+static void *
+wlan_memchr(pmlan_adapter pmadapter, void *s, int c, int n)
+{
+ const t_u8 *p = (t_u8 *) s;
+
+ ENTER();
+
+ while (n--) {
+ if ((t_u8) c == *p++) {
+ LEAVE();
+ return (void *) (p - 1);
+ }
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Use index to get the data rate
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param index The index of data rate
+ * @param ht_info ht info
+ *
+ * @return Data rate or 0
+ */
+t_u32
+wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index, t_u8 ht_info)
+{
+ t_u16 mcs_rate[4][8] = { {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
+ , /* LG 40M */
+ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
+ , /* SG 40M */
+ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
+ , /* LG 20M */
+ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
+ }; /* SG 20M */
+
+ t_u32 rate;
+ ENTER();
+
+ if (ht_info & MBIT(0)) {
+ if (index == MLAN_RATE_BITMAP_MCS0) {
+ if (ht_info & MBIT(2))
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < 8) {
+ if (ht_info & MBIT(1)) {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[1][index]; /* SGI, 40M */
+ else
+ rate = mcs_rate[0][index]; /* LGI, 40M */
+ } else {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[3][index]; /* SGI, 20M */
+ else
+ rate = mcs_rate[2][index]; /* LGI, 20M */
+ }
+ } else
+ rate = WlanDataRates[0];
+ } else {
+ if (index >= WLAN_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = WlanDataRates[index];
+ }
+ LEAVE();
+ return rate;
+}
+
+/**
+ * @brief Use rate to get the index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate Data rate
+ *
+ * @return Index or 0
+ */
+t_u8
+wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate)
+{
+ t_u16 *ptr;
+
+ ENTER();
+ if (rate)
+ if ((ptr = wlan_memchr(pmadapter, WlanDataRates, (t_u8) rate,
+ sizeof(WlanDataRates)))) {
+ LEAVE();
+ return (t_u8) (ptr - WlanDataRates);
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rates The buf to return the active rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_active_data_rates(mlan_private * pmpriv, WLAN_802_11_RATES rates)
+{
+ t_u32 k;
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ k = wlan_get_supported_rates(pmpriv, rates);
+ } else {
+ k = wlan_copy_rates(rates, 0, pmpriv->curr_bss_params.data_rates,
+ pmpriv->curr_bss_params.num_of_rates);
+ }
+
+ LEAVE();
+ return k;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ *
+ * @return A pointer to CFP
+ */
+chan_freq_power_t *
+wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
+ int *cfp_no)
+{
+ t_u32 i;
+
+ ENTER();
+
+ for (i = 0; i < sizeof(region_cfp_table) / sizeof(region_cfp_table_t); i++) {
+ PRINTM(MINFO, "region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ /* Check if region matches */
+ if (region_cfp_table[i].region == region) {
+ /* Select by band */
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ LEAVE();
+ return region_cfp_table[i].cfp_BG;
+ } else if (band & (BAND_A | BAND_AN)) {
+ *cfp_no = region_cfp_table[i].cfp_no_A;
+ LEAVE();
+ return region_cfp_table[i].cfp_A;
+ } else {
+ PRINTM(MERROR, "Error Band[0x%x]\n", band);
+ LEAVE();
+ return MNULL;
+
+ }
+ }
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function search through all the regions cfp table to find the channel,
+ * if the channel is found then gets the MIN txpower of the channel
+ * present in all the regions.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number.
+ *
+ * @return The Tx power
+ */
+t_u8
+wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel)
+{
+ t_u8 i = 0;
+ t_u8 j = 0;
+ t_u8 tx_power = 0;
+ t_u32 cfp_no;
+ chan_freq_power_t *cfp = MNULL;
+ chan_freq_power_t *cfp_a = MNULL;
+ t_u32 cfp_no_a;
+
+ ENTER();
+
+ for (i = 0; i < NELEMENTS(region_cfp_table); i++) {
+ /* Get CFP */
+ cfp = region_cfp_table[i].cfp_BG;
+ cfp_no = region_cfp_table[i].cfp_no_BG;
+
+ cfp_a = region_cfp_table[i].cfp_A;
+ cfp_no_a = region_cfp_table[i].cfp_no_A;
+ /* Find matching channel and get Tx power */
+ for (j = 0; j < cfp_no; j++) {
+ if ((cfp + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp + j)->max_tx_power);
+ else
+ tx_power = (t_u8) (cfp + j)->max_tx_power;
+ break;
+ }
+ }
+
+ for (j = 0; j < cfp_no_a; j++) {
+ if ((cfp_a + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp_a + j)->max_tx_power);
+ else
+ tx_power = (cfp_a + j)->max_tx_power;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return tx_power;
+}
+
+/**
+ * @brief Get the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ * @param region_channel A pointer to region_chan_t structure
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+
+chan_freq_power_t *
+wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u16 channel, region_chan_t * region_channel)
+{
+ region_chan_t *rc;
+ chan_freq_power_t *cfp = MNULL;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = ®ion_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B: /* Matching BAND_B/G */
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ if (channel == FIRST_VALID_CHANNEL)
+ cfp = &rc->pcfp[0];
+ else {
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].channel == channel) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ PRINTM(MERROR, "wlan_get_cfp_by_band_and_channel(): cannot find "
+ "cfp by band %d & channel %d\n", band, channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel)
+{
+ chan_freq_power_t *cfp = MNULL;
+
+ ENTER();
+
+ if (pmadapter->state_11d.enable_11d == ENABLE_11D)
+ cfp =
+ wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->universal_channel);
+ else
+ cfp =
+ wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->region_channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param freq The frequency to search for
+ *
+ * @return Pointer to chan_freq_power_t structure; MNULL if not found
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter, t_u8 band, t_u32 freq)
+{
+ chan_freq_power_t *cfp = MNULL;
+ region_chan_t *rc;
+ int count = sizeof(pmadapter->region_channel) /
+ sizeof(pmadapter->region_channel[0]);
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < count); j++) {
+ rc = &pmadapter->region_channel[j];
+
+ if (pmadapter->state_11d.enable_11d == ENABLE_11D)
+ rc = &pmadapter->universal_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B:
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].freq == freq) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ PRINTM(MERROR, "find_cfp_by_band_and_freql(): cannot find cfp by "
+ "band %d & freq %d\n", band, freq);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Check if Rate Auto
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_is_rate_auto(mlan_private * pmpriv)
+{
+ t_u32 i;
+ int rate_num = 0;
+
+ ENTER();
+
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates); i++)
+ if (pmpriv->bitmap_rates[i])
+ rate_num++;
+
+ LEAVE();
+ if (rate_num > 1)
+ return MTRUE;
+ else
+ return MFALSE;
+}
+
+/**
+ * @brief Covert Rate Bitmap to Rate index
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param rate_bitmap Pointer to rate bitmap
+ * @param size Size of the bitmap array
+ *
+ * @return Rate index
+ */
+int
+wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rate_bitmap, int size)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < size * 8; i++) {
+ if (rate_bitmap[i / 16] & (1 << (i % 16))) {
+ LEAVE();
+ return i;
+ }
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get supported data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rates The buf to return the supported rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_supported_rates(mlan_private * pmpriv, WLAN_802_11_RATES rates)
+{
+ t_u32 k = 0;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Infra. mode */
+ switch (pmadapter->config_bands) {
+ case BAND_B:
+ PRINTM(MINFO, "Infra Band=%d SupportedRates_B\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_B,
+ sizeof(SupportedRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_G\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_BG\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_N\n",
+ pmadapter->config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_N,
+ sizeof(SupportedRates_N));
+ break;
+ }
+ } else {
+ /* Ad-hoc mode */
+ switch (pmadapter->adhoc_start_band) {
+ case BAND_B:
+ PRINTM(MINFO, "Adhoc B\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_B, sizeof(AdhocRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Adhoc G only\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_G, sizeof(AdhocRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Adhoc BG\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_BG, sizeof(AdhocRates_BG));
+ break;
+ case BAND_A:
+ case BAND_A | BAND_AN:
+ PRINTM(MINFO, "Adhoc A\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_A, sizeof(AdhocRates_A));
+ break;
+ }
+ }
+
+ LEAVE();
+ return k;
+}
+
+/**
+ * @brief This function sets region table.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param region The region code
+ * @param band The band
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int i = 0;
+ chan_freq_power_t *cfp;
+ int cfp_no;
+
+ ENTER();
+
+ memset(pmadapter->region_channel, 0, sizeof(pmadapter->region_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp =
+ wlan_get_region_cfp_table(pmadapter, region,
+ BAND_G | BAND_B | BAND_GN, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band B-G\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ if (band & BAND_GN)
+ pmadapter->region_channel[i].band = BAND_G;
+ else
+ pmadapter->region_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+ if (band & (BAND_A | BAND_AN)) {
+ cfp = wlan_get_region_cfp_table(pmadapter, region, BAND_A, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band A\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ pmadapter->region_channel[i].band = BAND_A;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mlan/mlan_cmdevt.c b/wlan_src/mlan/mlan_cmdevt.c
new file mode 100755
index 0000000..b3584b6
--- /dev/null
+++ b/wlan_src/mlan/mlan_cmdevt.c
@@ -0,0 +1,1475 @@
+/**
+ * @file mlan_cmdevt.c
+ *
+ * @brief This file contains the handling of CMD/EVENT in MLAN
+ *
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/12/2009: initial version
+************************************************************/
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+/********************************************************
+ Local Variables
+********************************************************/
+
+/*******************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return N/A
+ */
+void
+wlan_init_cmd_node(IN pmlan_private pmpriv,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ t_u8 *head_ptr = MNULL;
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->priv = pmpriv;
+ pcmd_node->cmd_oid = cmd_oid;
+ pcmd_node->pioctl_buf = pioctl_buf;
+ pcmd_node->pdata_buf = pdata_buf;
+
+ pcmd_node->cmdbuf = pcmd_node->pmbuf;
+
+ /* Make sure head_ptr for cmd buf is Align */
+ head_ptr = (t_u8 *) ALIGN_ADDR(pcmd_node->cmdbuf->pbuf, HEADER_ALIGNMENT);
+ pcmd_node->cmdbuf->data_offset =
+ (t_u32) (head_ptr - pcmd_node->cmdbuf->pbuf);
+ memset(head_ptr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ /* Prepare mlan_buffer for command sending */
+ pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD;
+ pcmd_node->cmdbuf->data_offset += INTF_HEADER_LEN;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL
+ */
+cmd_ctrl_node *
+wlan_get_cmd_node(mlan_adapter * pmadapter)
+{
+ cmd_ctrl_node *pcmd_node;
+
+ ENTER();
+
+ if (pmadapter == MNULL) {
+ LEAVE();
+ return MNULL;
+ }
+
+ if (util_peek_list(&pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ pcmd_node = (cmd_ctrl_node *) util_dequeue_list(&pmadapter->cmd_free_q,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ } else {
+ PRINTM(MERROR, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ pcmd_node = MNULL;
+ }
+
+ LEAVE();
+ return pcmd_node;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_clean_cmd_node(pmlan_adapter pmadapter, cmd_ctrl_node * pcmd_node)
+{
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->cmd_oid = 0;
+ pcmd_node->cmd_flag = 0;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->pdata_buf = MNULL;
+
+ if (pcmd_node->respbuf) {
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ pcmd_node->respbuf, 0,
+ MLAN_STATUS_SUCCESS);
+ pcmd_node->respbuf = MNULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which matches the given pioctl_req
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+cmd_ctrl_node *
+wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ if (!
+ (pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *) & pmadapter->cmd_pending_q) {
+ if (pcmd_node->pioctl_buf == pioctl_req) {
+ LEAVE();
+ return pcmd_node;
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function handles the command response of host_cmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc;
+ t_u16 size = wlan_le16_to_cpu(resp->size);
+
+ ENTER();
+
+ PRINTM(MINFO, "host command response size = %d\n", size);
+ size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.hostcmd.len = size;
+ memcpy(misc->param.hostcmd.cmd, (void *) resp, size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends host command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *) pdata_buf;
+
+ ENTER();
+
+ /* Copy the HOST command to command buffer */
+ memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
+ PRINTM(MCMND, "Host command size = %d\n", pcmd_ptr->len);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function downloads a command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u16 cmd_code;
+ t_u16 cmd_size;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ if (!pmadapter || !pcmd_node) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ if (pcmd_node->pioctl_buf != MNULL)
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+
+ /* Sanity test */
+ if (pcmd == MNULL || pcmd->size == 0) {
+ PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, "
+ "Not sending\n");
+ if (pioctl_buf != MNULL)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Set command sequence number */
+ pmadapter->seq_num++;
+ pcmd->seq_num = wlan_cpu_to_le16(pmadapter->seq_num);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = pcmd_node;
+ wlan_release_cmd_lock(pmadapter);
+
+ cmd_code = wlan_le16_to_cpu(pcmd->command);
+ cmd_size = wlan_le16_to_cpu(pcmd->size);
+
+ /* Set BSS_NO_BITS to HostCmd */
+ cmd_code = HostCmd_SET_BSS_NO(cmd_code, pcmd_node->priv->bss_num);
+ pcmd->command = wlan_cpu_to_le16(cmd_code);
+
+ pcmd_node->cmdbuf->data_len = cmd_size;
+
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MCMND, "DNLD_CMD (%lu.%lu): 0x%x, act 0x%x, len %d, seqno %d\n",
+ sec, usec, cmd_code,
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size,
+ wlan_le16_to_cpu(pcmd->seq_num));
+ DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size);
+
+ /* Send the command to lower layer */
+
+ pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN;
+ pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN;
+ /* Extra header for SDIO is added here */
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf,
+ MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
+ if (pioctl_buf != MNULL)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ pmadapter->dbg.num_cmd_host_to_card_failure++;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the last command id and action to debug log */
+ pmadapter->dbg.last_cmd_index =
+ (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN));
+
+ /* Clear BSS_NO_BITS from HostCmd */
+ cmd_code &= HostCmd_CMD_ID_MASK;
+
+ /* Setup the timer after transmit command */
+ pcb->moal_start_timer(pmadapter->pmlan_cmd_timer, MFALSE, MRVDRV_TIMER_10S);
+
+ pmadapter->cmd_timer_is_set = MTRUE;
+
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends sleep confirm command to firmware.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ static t_u32 i = 0;
+ t_u16 cmd_len = 0;
+ HostCmd_DS_802_11_PS_MODE_ENH *pps_mode = MNULL;
+ opt_sleep_confirm_buffer *sleep_cfm_buf =
+ (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset);
+
+ ENTER();
+
+ cmd_len = sizeof(HostCmd_DS_COMMAND);
+ pps_mode = &sleep_cfm_buf->ps_cfm_sleep.params.psmode_enh;
+ sleep_cfm_buf->ps_cfm_sleep.seq_num =
+ wlan_cpu_to_le16(++pmadapter->seq_num);
+ pps_mode->params.sleep_cfm.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep, cmd_len);
+
+ /* Send sleep confirm command to firmware */
+
+ pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN;
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD,
+ pmadapter->psleep_cfm, MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "SLEEP_CFM: failed\n");
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+ goto done;
+ } else {
+ if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type ==
+ MLAN_BSS_TYPE_STA) {
+ if (!pps_mode->params.sleep_cfm.resp_ctrl) {
+ /* Response is not needed for sleep confirm command */
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ } else {
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+ }
+
+ if (pps_mode->params.sleep_cfm.resp_ctrl != RESP_NEEDED
+ && (pmadapter->is_hs_configured &&
+ !pmadapter->sleep_period.period)) {
+ pmadapter->pm_wakeup_card_req = MTRUE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_TYPE_STA),
+ MTRUE);
+ }
+ }
+#define NUM_SC_PER_LINE 16
+ if (++i % NUM_SC_PER_LINE == 0)
+ PRINTM(MEVENT, "+\n");
+ else
+ PRINTM(MEVENT, "+");
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Event handler
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param event_id Event ID
+ * @param pmevent Event buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_event(pmlan_private priv, mlan_event_id event_id, t_void * pmevent)
+{
+ pmlan_callbacks pcb = &priv->adapter->callbacks;
+
+ ENTER();
+
+ if (pmevent)
+ /* The caller has provided the event. */
+ pcb->moal_recv_event(priv->adapter->pmoal_handle,
+ (pmlan_event) pmevent);
+ else {
+ mlan_event mevent;
+
+ memset(&mevent, 0, sizeof(mlan_event));
+ mevent.bss_num = priv->bss_num;
+ mevent.event_id = event_id;
+ mevent.event_len = 0;
+
+ pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates the command buffer and links
+ * it to command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array;
+ t_u32 buf_size;
+ t_u32 i;
+
+ ENTER();
+
+ /* Allocate and initialize cmd_ctrl_node */
+ buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+ ret = pcb->moal_malloc(buf_size, (t_u8 **) & pcmd_array);
+ if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->cmd_pool = pcmd_array;
+ memset(pmadapter->cmd_pool, 0, buf_size);
+
+ /* Allocate and initialize command buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (!
+ (pcmd_array[i].pmbuf =
+ wlan_alloc_mlan_buffer(pcb,
+ (MRVDRV_SIZE_OF_CMD_BUFFER +
+ HEADER_ALIGNMENT)))) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_free_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array;
+ t_u32 i;
+
+ ENTER();
+
+ /* Need to check if cmd pool is allocated or not */
+ if (pmadapter->cmd_pool == MNULL) {
+ PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n");
+ goto done;
+ }
+
+ pcmd_array = pmadapter->cmd_pool;
+
+ /* Release shared memory buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (pcmd_array[i].pmbuf) {
+ PRINTM(MCMND, "Free all the command buffer.\n");
+ wlan_free_mlan_buffer(pcb, pcmd_array[i].pmbuf);
+ pcmd_array[i].pmbuf = MNULL;
+ }
+ if (pcmd_array[i].respbuf) {
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ pcmd_array[i].respbuf, 0,
+ MLAN_STATUS_SUCCESS);
+ pcmd_array[i].respbuf = MNULL;
+ }
+ }
+ /* Release cmd_ctrl_node */
+ if (pmadapter->cmd_pool) {
+ PRINTM(MCMND, "Free command pool.\n");
+ pcb->moal_mfree((t_u8 *) pmadapter->cmd_pool);
+ pmadapter->cmd_pool = MNULL;
+ }
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_event(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u32 bss_num = 0;
+ t_u32 in_ts_sec;
+ t_u32 in_ts_usec;
+ ENTER();
+
+ /* Save the last event to debug log */
+ pmadapter->dbg.last_event_index =
+ (pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] =
+ (t_u16) eventcause;
+
+ /* Get BSS number and corresponding priv */
+ bss_num = EVENT_GET_BSS_NUM((t_u16) eventcause);
+ priv = pmadapter->priv[bss_num];
+ if (!priv) {
+ bss_num = 0;
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ }
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ if (pmbuf)
+ pmbuf->bss_num = bss_num;
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
+ pmadapter->callbacks.moal_get_system_time(&in_ts_sec, &in_ts_usec);
+ PRINTM(MEVENT, "%lu.%lu : Event: 0x%x\n", in_ts_sec, in_ts_usec,
+ eventcause);
+ }
+
+ ret = priv->ops.process_event(priv);
+
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+
+ if (pmbuf) {
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ 0, MLAN_STATUS_SUCCESS);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function requests a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_request_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin lock callback function */
+ pcb->moal_spin_lock(pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function releases a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_release_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin unlock callback function */
+ pcb->moal_spin_unlock(pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_prepare_cmd(IN mlan_private * pmpriv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_COMMAND *cmd_ptr = MNULL;
+
+ ENTER();
+
+ /* Sanity test */
+ if (pmadapter == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: pmadapter is MNULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->surprise_removed) {
+ PRINTM(MERROR, "PREP_CMD: Card is Removed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->hw_status == WlanHardwareStatusReset) {
+ if (cmd_no != HostCmd_CMD_FUNC_INIT) {
+ PRINTM(MERROR, "PREP_CMD: FW is in reset state\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Get a new command node */
+ pcmd_node = wlan_get_cmd_node(pmadapter);
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd node\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Initialize the command node */
+ wlan_init_cmd_node(pmpriv, pcmd_node, cmd_oid, pioctl_buf, pdata_buf);
+
+ if (pcmd_node->cmdbuf == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd buf\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd_ptr =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ cmd_ptr->command = cmd_no;
+ cmd_ptr->result = 0;
+
+ /* Prepare command */
+ if (cmd_no)
+ ret =
+ pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action, cmd_oid,
+ pioctl_buf, pdata_buf, cmd_ptr);
+ else {
+ ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf);
+ pcmd_node->cmd_flag |= CMD_F_HOSTCMD;
+ }
+
+ /* Return error, since the command preparation failed */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send command */
+ if (cmd_no == HostCmd_CMD_802_11_SCAN)
+ wlan_queue_scan_cmd(pmpriv, pcmd_node);
+ else
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function inserts command node to cmd_free_q
+ * after cleaning it.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ if (pcmd_node->pioctl_buf) {
+ pioctl_req = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR)
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_FAILURE);
+ else
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_SUCCESS);
+ }
+ /* Clean the node */
+ wlan_clean_cmd_node(pmadapter, pcmd_node);
+
+ /* Insert node into cmd_free_q */
+ util_enqueue_list_tail(&pmadapter->cmd_free_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function queues the command to cmd list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param add_tail Specify if the cmd needs to be queued in the header or tail
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node, IN t_u32 add_tail)
+{
+ HostCmd_DS_COMMAND *pcmd = MNULL;
+ t_u16 command;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n");
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ if (pcmd == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd is MNULL\n");
+ goto done;
+ }
+
+ command = wlan_le16_to_cpu(pcmd->command);
+
+/* Exit_PS command needs to be queued in the header always. */
+ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh;
+ if (wlan_le16_to_cpu(pm->action) == DIS_PS) {
+ if (pmadapter->ps_state != PS_STATE_AWAKE)
+ add_tail = MFALSE;
+ }
+ }
+
+ if (add_tail) {
+ util_enqueue_list_tail(&pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ } else {
+ util_enqueue_list_head(&pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ PRINTM(MCMND, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put firmware back to PS mode
+ * if applicable.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_exec_next_cmd(mlan_adapter * pmadapter)
+{
+ mlan_private *priv = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+
+ ENTER();
+
+ /* Sanity test */
+ if (pmadapter == MNULL) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Check if already in processing */
+ if (pmadapter->curr_cmd) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: there is command in processing!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ /* Check if any command is pending */
+ pcmd_node = (cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+
+ if (pcmd_node) {
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ priv = pcmd_node->priv;
+
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ PRINTM(MERROR,
+ "Cannot send command in sleep state, this should not happen\n");
+ wlan_release_cmd_lock(pmadapter);
+ goto done;
+ }
+
+ util_unlink_list(&pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ wlan_release_cmd_lock(pmadapter);
+ ret = wlan_dnld_cmd_to_fw(priv, pcmd_node);
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ /* Any command sent to the firmware when host is in sleep mode, should
+ de-configure host sleep */
+ /* We should skip the host sleep configuration command itself though */
+ if (priv &&
+ (pcmd->command !=
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(priv, MFALSE);
+ }
+ }
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_cmdresp(mlan_adapter * pmadapter)
+{
+ HostCmd_DS_COMMAND *resp = MNULL;
+ mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 orig_cmdresp_no;
+ t_u16 cmdresp_no;
+ t_u16 cmdresp_result;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ /* Now we got response from FW, cancel the command timer */
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmlan_cmd_timer);
+ /* Cancel command timeout timer */
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+
+ if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
+ resp = (HostCmd_DS_COMMAND *) pmadapter->upld_buf;
+ resp->command = wlan_le16_to_cpu(resp->command);
+ PRINTM(MERROR, "CMD_RESP: MNULL curr_cmd, 0x%x\n", resp->command);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ }
+
+ pmadapter->num_cmd_timeout = 0;
+
+ DBG_HEXDUMP(MCMD_D, "CMD_RESP",
+ pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset, pmadapter->upld_len);
+
+ resp =
+ (HostCmd_DS_COMMAND *) (pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset);
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ /* Copy original response back to response buffer */
+ wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
+ }
+ resp->command = wlan_le16_to_cpu(resp->command);
+ resp->size = wlan_le16_to_cpu(resp->size);
+ resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
+ resp->result = wlan_le16_to_cpu(resp->result);
+
+ orig_cmdresp_no = resp->command;
+ cmdresp_result = resp->result;
+
+ /* Save the last command response to debug log */
+ pmadapter->dbg.last_cmd_resp_index =
+ (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
+ orig_cmdresp_no;
+
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MCMND, "CMD_RESP (%lu.%lu): 0x%x, result %d, len %d, seqno %d\n",
+ sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
+ resp->seq_num);
+
+ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+ PRINTM(MERROR, "CMD_RESP: Invalid response to command!");
+ if (pioctl_buf) {
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get BSS number and corresponding priv */
+ pmpriv = pmadapter->priv[HostCmd_GET_BSS_NO(resp->command)];
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ /* Clear RET_BIT & BSS_NO_BITS from HostCmd */
+ resp->command &= HostCmd_CMD_ID_MASK;
+ cmdresp_no = resp->command;
+
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+ if ((cmdresp_result == HostCmd_RESULT_OK)
+ && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ } else {
+ /* handle response */
+ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf);
+ }
+
+ if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
+ (pmadapter->last_init_cmd == cmdresp_no)) {
+ if (cmdresp_result == HostCmd_RESULT_OK)
+ pmadapter->hw_status = WlanHardwareStatusInitdone;
+ else
+ wlan_init_fw_complete(pmadapter);
+ }
+
+ if (pmadapter->curr_cmd) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @param function_context A pointer to function_context
+ * @return n/a
+ */
+t_void
+wlan_cmd_timeout_func(t_void * function_context)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) function_context;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u32 sec, usec;
+ t_u8 i;
+ ENTER();
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+ pmadapter->num_cmd_timeout++;
+ pmadapter->dbg.num_cmd_timeout++;
+ if (!pmadapter->curr_cmd) {
+ PRINTM(MWARN, "CurCmd Empty\n");
+ goto exit;
+ }
+ pcmd_node = pmadapter->curr_cmd;
+ if (pcmd_node->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT;
+ }
+
+ if (pcmd_node) {
+ pmadapter->dbg.timeout_cmd_id =
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
+ pmadapter->dbg.timeout_cmd_act =
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MERROR, "Timeout cmd id (%lu.%lu) = 0x%x, act = 0x%x \n", sec,
+ usec, pmadapter->dbg.timeout_cmd_id,
+ pmadapter->dbg.timeout_cmd_act);
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ pmadapter->dbg.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ pmadapter->dbg.num_cmd_host_to_card_failure);
+
+ PRINTM(MERROR, "num_cmd_timeout = %d\n",
+ pmadapter->dbg.num_cmd_timeout);
+ PRINTM(MERROR, "num_tx_timeout = %d\n", pmadapter->dbg.num_tx_timeout);
+
+ PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]);
+ }
+ PRINTM(MMSG, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]);
+ }
+ PRINTM(MMSG, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n",
+ pmadapter->dbg.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]);
+ }
+ PRINTM(MMSG, "\n");
+
+ PRINTM(MERROR, "last_event_index = %d\n",
+ pmadapter->dbg.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]);
+ }
+ PRINTM(MMSG, "\n");
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent,
+ pmadapter->cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode,
+ pmadapter->ps_state);
+ }
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_init_fw_complete(pmadapter);
+ exit:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Cancel all pending cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+void
+wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+
+ /* Cancel current cmd */
+ if ((pmadapter->curr_cmd) && (pmadapter->curr_cmd->pioctl_buf)) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+ /* Cancel all pending command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(&pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ pcmd_node->pioctl_buf = MNULL;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ /* Cancel all pending scan command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(&pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(&pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+}
+
+/**
+ * @brief Cancel pending ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return N/A
+ */
+void
+wlan_cancel_pending_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ PRINTM(MCMND, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n",
+ pioctl_req->req_id, *((t_u32 *) pioctl_req->pbuf),
+ (int) pioctl_req->action);
+
+ if ((pmadapter->curr_cmd) &&
+ (pmadapter->curr_cmd->pioctl_buf == pioctl_req)) {
+ wlan_request_cmd_lock(pmadapter);
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ while ((pcmd_node =
+ wlan_get_pending_ioctl_cmd(pmadapter, pioctl_req)) != MNULL) {
+ util_unlink_list(&pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ if (pioctl_req->req_id == MLAN_IOCTL_SCAN) {
+ /* Cancel all pending scan command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(&pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(&pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ }
+ pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
+ MLAN_STATUS_FAILURE);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function checks conditions and prepares to
+ * send sleep confirm command to firmware if OK.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_check_ps_cond(mlan_adapter * pmadapter)
+{
+ ENTER();
+
+ if (!pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_CARD_RX_RCVD(pmadapter)) {
+ wlan_dnld_sleep_confirm_cmd(pmadapter);
+ } else {
+ PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s)\n",
+ (pmadapter->cmd_sent) ? "D" : "",
+ (pmadapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(pmadapter)) ? "R" : "");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_ACTIVATED event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param activated MTRUE if activated, MFALSE if de-activated
+ *
+ * @return None
+ */
+t_void
+wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated)
+{
+ ENTER();
+
+ if (activated) {
+ if (priv->adapter->is_hs_configured) {
+ priv->adapter->hs_activated = MTRUE;
+ PRINTM(MEVENT, "hs_actived\n");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED, MNULL);
+ } else
+ PRINTM(MWARN, "hs_activated: HS not configured !!!\n");
+ } else {
+ PRINTM(MEVENT, "hs_deactived\n");
+ priv->adapter->hs_activated = MFALSE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_WAKEUP event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return None
+ */
+t_void
+wlan_host_sleep_wakeup_event(pmlan_private priv)
+{
+ ENTER();
+
+ if (priv->adapter->is_hs_configured) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL);
+ } else {
+ PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of hs_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg;
+ ENTER();
+
+ if (phs_cfg->action == HS_ACTIVATE) {
+ wlan_host_sleep_activated_event(pmpriv, MTRUE);
+ goto done;
+ } else {
+ phs_cfg->params.hs_config.conditions =
+ wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions);
+ PRINTM(MCMND,
+ "CMD_RESP: HS_CFG cmd reply result=%#x,"
+ " conditions=0x%x gpio=0x%x gap=0x%x\n", resp->result,
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+ if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) {
+ pmadapter->is_hs_configured = MTRUE;
+ } else {
+ pmadapter->is_hs_configured = MFALSE;
+ if (pmadapter->hs_activated)
+ wlan_host_sleep_activated_event(pmpriv, MFALSE);
+ }
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Perform hs related activities on receving the power up interrupt
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @return N/A
+ */
+t_void
+wlan_process_hs_config(pmlan_adapter pmadapter)
+{
+ PRINTM(MINFO,
+ "Auto Cancelling host sleep since there is some interrupt from the firmware\n");
+ wlan_pm_wakeup_card(pmadapter);
+ pmadapter->hs_activated = MFALSE;
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY),
+ MFALSE);
+ return;
+}
+
+/**
+ * @brief Check sleep confirm command response and set the state to ASLEEP
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @param pbuf A pointer to the command response buffer
+ * @param upld_len Command response buffer length
+ * @return N/A
+ */
+void
+wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 upld_len)
+{
+ HostCmd_DS_COMMAND *cmd;
+ pmlan_private pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+
+ ENTER();
+
+ if (!upld_len) {
+ PRINTM(MERROR, "Command size is 0\n");
+ LEAVE();
+ return;
+ }
+ cmd = (HostCmd_DS_COMMAND *) pbuf;
+ cmd->result = wlan_le16_to_cpu(cmd->result);
+ cmd->command = wlan_le16_to_cpu(cmd->command);
+
+ /* Get BSS number and corresponding priv */
+ pmpriv = pmadapter->priv[HostCmd_GET_BSS_NO(cmd->command)];
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ /* Clear RET_BIT & BSS_NO_BITS from HostCmd */
+ cmd->command &= HostCmd_CMD_ID_MASK;
+
+ if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+ PRINTM(MERROR,
+ "Received unexpected response for command %x, result = %x\n",
+ cmd->command, cmd->result);
+ return;
+ }
+ PRINTM(MEVENT, "#\n");
+ if ((pmpriv->media_connected != MTRUE) || !pmadapter->sleep_period.period)
+ pmadapter->pm_wakeup_card_req = MTRUE;
+
+ if (cmd->result != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Sleep confirm command failed\n");
+ LEAVE();
+ return;
+ }
+ if (pmadapter->is_hs_configured && !pmadapter->sleep_period.period) {
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_TYPE_ANY), MTRUE);
+ }
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ LEAVE();
+}
diff --git a/wlan_src/mlan/mlan_decl.h b/wlan_src/mlan/mlan_decl.h
new file mode 100755
index 0000000..0ce78a7
--- /dev/null
+++ b/wlan_src/mlan/mlan_decl.h
@@ -0,0 +1,600 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "074"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef char t_s8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8;
+/** Signed short (2-bytes) */
+typedef short t_s16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16;
+/** Signed long (4-bytes) */
+typedef long t_s32;
+/** Unsigned long (4-bytes) */
+typedef unsigned long t_u32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64;
+/** Void pointer (4-bytes) */
+typedef void t_void;
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__ ((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packeing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifdef __GNUC__
+#define INLINE inline
+#else
+#define INLINE __inline
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_u32)(p)) + (((t_u32)(a)) - 1)) & ~(((t_u32)(a)) - 1))
+
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (1)
+
+/* NET IP alignment */
+#define MLAN_NET_IP_ALIGN 0
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN 32 // (sizeof(mlan_txpd))
+
+/** This is current limit on Maximum AMPDU allowed */
+#define MLAN_MAX_BASTREAM_SUPPORTED 2
+
+/** Default Win size attached during ADDBA request */
+#define MLAN_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_AMPDU_DEF_RXWINSIZE 16
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 12
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 19
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 44
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 139
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+
+/** Size of rx data buffer */
+#define MLAN_RX_DATA_BUF_SIZE (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE (2 * 1024)
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD 256
+
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE (4 * 1024)
+
+/** Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MFW_D MBIT(18)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** mlan_status */
+typedef enum _mlan_status
+{
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code
+{
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY,
+ MLAN_ERROR_FW_CMDRESP,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT,
+ MLAN_ERROR_CMD_INVALID,
+ MLAN_ERROR_CMD_TIMEOUT,
+ MLAN_ERROR_CMD_DNLD_FAIL,
+ MLAN_ERROR_CMD_CANCEL,
+ MLAN_ERROR_ASSOC_FAIL,
+ MLAN_ERROR_EVENT_UNKNOWN,
+ MLAN_ERROR_INVALID_PARAMETER,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type
+{
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+} mlan_buf_type;
+
+/** mlan_bss_type */
+typedef enum _mlan_bss_type
+{
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP,
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type
+{
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id
+{
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MLAN_EVENT_ID_FW_DISCONNECTED,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH,
+ MLAN_EVENT_ID_FW_MAX_FAIL,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH,
+ MLAN_EVENT_ID_FW_LINK_QUALITY,
+ MLAN_EVENT_ID_FW_PORT_RELEASE = 17,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MLAN_EVENT_ID_FW_HS_WAKEUP,
+ MLAN_EVENT_ID_FW_DS_AWAKE,
+ MLAN_EVENT_ID_FW_BG_SCAN,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR,
+ MLAN_EVENT_ID_FW_STOP_TX,
+ MLAN_EVENT_ID_FW_START_TX,
+ MLAN_EVENT_ID_FW_BW_CHANGED,
+
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ MLAN_EVENT_ID_DRV_PASSTHU,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image
+{
+ /** Helper image buffer pointer */
+ t_u8 *phelper_buf;
+ /** Helper image length */
+ t_u32 helper_len;
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** mlan_event data structure */
+typedef struct _mlan_event
+{
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_num;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[1];
+} mlan_event, *pmlan_event;
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req
+{
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_num;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_u32 reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer
+{
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS number */
+ t_u32 bss_num;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+} mlan_buffer, *pmlan_buffer;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr
+{
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e
+{
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e
+{
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e
+{
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie
+{
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks
+{
+ /** moal_init_fw_complete */
+ mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+ /** moal_recv_complete */
+ mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+ /** moal_recv_packet */
+ mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status(*moal_recv_event) (IN t_void * pmoal_handle,
+ IN pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+ /** moal_alloc_mlan_buffer */
+ mlan_status(*moal_alloc_mlan_buffer) (IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status(*moal_free_mlan_buffer) (IN pmlan_buffer pmbuf);
+ /** moal_write_reg */
+ mlan_status(*moal_write_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+ /** moal_read_reg */
+ mlan_status(*moal_read_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+ /** moal_write_data_sync */
+ mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_malloc */
+ mlan_status(*moal_malloc) (IN t_u32 size, OUT t_u8 ** ppbuf);
+ /** moal_mfree */
+ mlan_status(*moal_mfree) (IN t_u8 * pbuf);
+ /** moal_memset */
+ t_void *(*moal_memset) (IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy) (IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memmove */
+ t_void *(*moal_memmove) (IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memcmp */
+ t_s32(*moal_memcmp) (IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+ /** moal_get_system_time */
+ mlan_status(*moal_get_system_time) (OUT t_u32 * psec, OUT t_u32 * pusec);
+ /** moal_init_timer*/
+ mlan_status(*moal_init_timer) (OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+ /** moal_free_timer */
+ mlan_status(*moal_free_timer) (IN t_void * ptimer);
+ /** moal_start_timer*/
+ mlan_status(*moal_start_timer) (IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status(*moal_stop_timer) (IN t_void * ptimer);
+ /** moal_init_lock */
+ mlan_status(*moal_init_lock) (OUT t_void ** pplock);
+ /** moal_free_lock */
+ mlan_status(*moal_free_lock) (IN t_void * plock);
+ /** moal_spin_lock */
+ mlan_status(*moal_spin_lock) (IN t_void * plock);
+ /** moal_spin_unlock */
+ mlan_status(*moal_spin_unlock) (IN t_void * plock);
+ /** moal_print */
+ t_void(*moal_print) (IN t_u32 level, IN t_s8 * pformat, IN ...);
+} mlan_callbacks, *pmlan_callbacks;
+
+/** mlan_device data structure */
+typedef struct _mlan_device
+{
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice,
+ OUT t_void ** ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter,
+ IN pmlan_fw_image pmfw);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf);
+
+/** interrupt handler */
+MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter);
+
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+#endif /* !_MLAN_DECL_H_ */
diff --git a/wlan_src/mlan/mlan_fw.h b/wlan_src/mlan/mlan_fw.h
new file mode 100755
index 0000000..79aa037
--- /dev/null
+++ b/wlan_src/mlan/mlan_fw.h
@@ -0,0 +1,3118 @@
+/** @file mlan_fw.h
+ *
+ * @brief This file contains firmware specific defines.
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/27/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_FW_H_
+#define _MLAN_FW_H_
+
+/** Interface header length */
+#define INTF_HEADER_LEN 4
+
+/** Ethernet header */
+typedef struct
+{
+ /** Ethernet header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header length */
+ t_u16 h803_len;
+
+} Eth803Hdr_t;
+
+/** RFC 1042 header */
+typedef struct
+{
+ /** LLC DSAP */
+ t_u8 llc_dsap;
+ /** LLC SSAP */
+ t_u8 llc_ssap;
+ /** LLC CTRL */
+ t_u8 llc_ctrl;
+ /** SNAP OUI */
+ t_u8 snap_oui[3];
+ /** SNAP type */
+ t_u16 snap_type;
+
+} Rfc1042Hdr_t;
+
+/** Rx packet header */
+typedef struct
+{
+ /** Etherner header */
+ Eth803Hdr_t eth803_hdr;
+ /** RFC 1042 header */
+ Rfc1042Hdr_t rfc1042_hdr;
+
+} RxPacketHdr_t;
+
+/** Rates supported in band B */
+#define B_SUPPORTED_RATES 5
+/** Rates supported in band G */
+#define G_SUPPORTED_RATES 9
+/** Rates supported in band BG */
+#define BG_SUPPORTED_RATES 13
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define A_SUPPORTED_RATES 9
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define HOSTCMD_SUPPORTED_RATES 14
+
+/** Rates supported in band N */
+#define N_SUPPORTED_RATES 3
+/** All bands (B, G, N) */
+#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
+
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10) | MBIT(11))
+/** Check if multiple bands support is enabled in firmware */
+#define IS_SUPPORT_MULTI_BANDS(_adapter) \
+ (_adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+/** Get default bands of the firmware */
+#define GET_FW_DEFAULT_BANDS(_adapter) \
+ ((_adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+
+extern t_u8 SupportedRates_B[B_SUPPORTED_RATES];
+extern t_u8 SupportedRates_G[G_SUPPORTED_RATES];
+extern t_u8 SupportedRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 SupportedRates_A[A_SUPPORTED_RATES];
+extern t_u8 SupportedRates_N[N_SUPPORTED_RATES];
+extern t_u8 AdhocRates_G[G_SUPPORTED_RATES];
+extern t_u8 AdhocRates_B[B_SUPPORTED_RATES];
+extern t_u8 AdhocRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 AdhocRates_A[A_SUPPORTED_RATES];
+
+/** WEP Key index mask */
+#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
+
+/** Key information enabled */
+#define KEY_INFO_ENABLED 0x01
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID
+{
+ /** Key type : WEP */
+ KEY_TYPE_ID_WEP = 0,
+ /** Key type : TKIP */
+ KEY_TYPE_ID_TKIP,
+ /** Key type : AES */
+ KEY_TYPE_ID_AES,
+ KEY_TYPE_ID_WAPI,
+} KEY_TYPE_ID;
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP
+{
+ KEY_INFO_WEP_MCAST = 0x01,
+ KEY_INFO_WEP_UNICAST = 0x02,
+ KEY_INFO_WEP_ENABLED = 0x04
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP
+{
+ KEY_INFO_TKIP_MCAST = 0x01,
+ KEY_INFO_TKIP_UNICAST = 0x02,
+ KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES
+{
+ KEY_INFO_AES_MCAST = 0x01,
+ KEY_INFO_AES_UNICAST = 0x02,
+ KEY_INFO_AES_ENABLED = 0x04
+} KEY_INFO_AES;
+
+/** WPA AES key length */
+#define WPA_AES_KEY_LEN 16
+/** WPA TKIP key length */
+#define WPA_TKIP_KEY_LEN 32
+
+/** WAPI key length */
+#define WAPI_KEY_LEN 50
+/** KEY_INFO_WAPI*/
+typedef enum _KEY_INFO_WAPI
+{
+ KEY_INFO_WAPI_MCAST = 0x01,
+ KEY_INFO_WAPI_UNICAST = 0x02,
+ KEY_INFO_WAPI_ENABLED = 0x04
+} KEY_INFO_WAPI;
+
+/** Length of SNAP header */
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES 100
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active when multiple interface is present */
+#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active. (polling the scratch register). */
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+/** This is for firmware specific length */
+#define EXTRA_LEN 36
+
+/** Maximum ethernet frame length sans FCS */
+#define MV_ETH_FRAME_LEN 1514
+
+/** Buffer size for ethernet Tx packets */
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
+
+/** Buffer size for ethernet Rx packets */
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(RxPD) \
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+/* Macros in interface module */
+/** Firmware ready */
+#define FIRMWARE_READY 0xfedc
+
+/** Number of firmware blocks to transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/** Enumeration definition*/
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER
+{
+ Wlan802_11PrivFilterAcceptAll,
+ Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS
+{
+ Wlan802_11WEPEnabled,
+ Wlan802_11WEPDisabled,
+ Wlan802_11WEPKeyAbsent,
+ Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNR calculation */
+#define CAL_SNR(RSSI, NF) ((t_s16)((t_s16)(RSSI)-(t_s16)(NF)))
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+
+/** Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+/** TLV type : SSID */
+#define TLV_TYPE_SSID 0x0000
+/** TLV type : Rates */
+#define TLV_TYPE_RATES 0x0001
+/** TLV type : PHY FH */
+#define TLV_TYPE_PHY_FH 0x0002
+/** TLV type : PHY DS */
+#define TLV_TYPE_PHY_DS 0x0003
+/** TLV type : CF */
+#define TLV_TYPE_CF 0x0004
+/** TLV type : IBSS */
+#define TLV_TYPE_IBSS 0x0006
+
+/** TLV type : Domain */
+#define TLV_TYPE_DOMAIN 0x0007
+
+/** TLV type : Power constraint */
+#define TLV_TYPE_POWER_CONSTRAINT 0x0020
+/** TLV type : Power capability */
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+/** TLV type : Key material */
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
+/** TLV type : Channel list */
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
+/** TLV type : Number of probes */
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
+/** TLV type : LED behavior */
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
+/** TLV type : Passthrough */
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
+/** TLV type : Power TBL 2.4 Ghz */
+#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
+/** TLV type : Power TBL 5 GHz */
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
+/** TLV type : WMM queue status */
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
+/** TLV type : Wildcard SSID */
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
+/** TLV type : TSF timestamp */
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
+
+/** TLV type : Start BG scan later */
+#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 30)
+/** TLV type : Authentication type */
+#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
+/** TLV type : Link Quality */
+#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 36)
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 38)
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 39)
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 40)
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 41)
+
+/** TLV type : Channel band list */
+#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
+/** TLV type: WAPI IE */
+#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
+
+/** TLV type : Encryption Protocol TLV */
+#define TLV_TYPE_ENCRYPTION_PROTO (PROPRIETARY_TLV_BASE_ID + 64)
+/** TLV type : Cipher TLV */
+#define TLV_TYPE_CIPHER (PROPRIETARY_TLV_BASE_ID + 66)
+/** TLV type : PMK */
+#define TLV_TYPE_PMK (PROPRIETARY_TLV_BASE_ID + 68)
+/** TLV type : Passphrase */
+#define TLV_TYPE_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
+/** TLV type : BSSID */
+#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
+
+/** 2K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_2K 2048
+
+/** TLV type : HT Capabilities */
+#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 74)
+/** TLV type : HT Information */
+#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 75)
+/** TLV type : Secondary Channel Offset */
+#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 76)
+/** TLV type : 20/40 BSS Coexistence */
+#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 77)
+/** TLV type : Overlapping BSS Scan Parameters */
+#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 78)
+/** TLV type : Extended capabilities */
+#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 79)
+/** TLV type : Set of MCS values that STA desires to use within the BSS */
+#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 80)
+
+/** ADDBA TID mask */
+#define ADDBA_TID_MASK (MBIT(2) | MBIT(3) | MBIT(4) | MBIT(5))
+/** DELBA TID mask */
+#define DELBA_TID_MASK (MBIT(12) | MBIT(13) | MBIT(14) | MBIT(15))
+/** ADDBA Starting Sequence Number Mask */
+#define SSN_MASK 0xfff0
+
+/** Block Ack result status */
+/** Block Ack Result : Success */
+#define BA_RESULT_SUCCESS 0x0
+/** Block Ack Result : Execution failure */
+#define BA_RESULT_FAILURE 0x1
+/** Block Ack Result : Timeout */
+#define BA_RESULT_TIMEOUT 0x2
+/** Block Ack Result : Data invalid */
+#define BA_RESULT_DATA_INVALID 0x3
+
+/** Get the baStatus (NOT_SETUP, COMPLETE, IN_PROGRESS)
+ * in Tx BA stream table */
+#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
+
+/** An AMPDU/AMSDU could be disallowed for certain TID. 0xff means
+ * no aggregation is enabled for the assigned TID */
+#define BA_STREAM_NOT_ALLOWED 0xff
+
+/** Test if 11n is enabled by checking the HTCap IE */
+#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN ||priv->adapter->config_bands & BAND_AN) \
+ && priv->curr_bss_params.bss_descriptor.pht_cap)
+/** Find out if we are the initiator or not */
+#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) & \
+ MBIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+/** 4K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_4K 4096
+/** 8K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_8K 8192
+/** Max Rx AMPDU Size */
+#define MAX_RX_AMPDU_SIZE_64K 0x03
+/** Non green field station */
+#define NON_GREENFIELD_STAS 0x04
+
+/** Greenfield support */
+#define HWSPEC_GREENFIELD_SUPP MBIT(29)
+/** Channel width 40Mhz support */
+#define HWSPEC_RXSTBC_SUPP MBIT(26)
+/** ShortGI @ 40Mhz support */
+#define HWSPEC_SHORTGI40_SUPP MBIT(24)
+/** ShortGI @ 20Mhz support */
+#define HWSPEC_SHORTGI20_SUPP MBIT(23)
+/** Channel width 40Mhz support */
+#define HWSPEC_CHANBW40_SUPP MBIT(17)
+/** 40Mhz intolarent enable */
+#define CAPINFO_40MHZ_INTOLARENT MBIT(8)
+
+/** Default 11n capability mask */
+#define DEFAULT_11N_CAP_MASK (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP)
+/** Bits to ignore in hw_dev_cap as these bits are set in get_hw_spec */
+#define IGN_HW_DEV_CAP (CAPINFO_40MHZ_INTOLARENT)
+
+/** HW_SPEC FwCapInfo */
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & MBIT(11))
+
+/** HW_SPEC Dot11nDevCap : MAX AMSDU supported */
+#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & MBIT(31))
+/** HW_SPEC Dot11nDevCap : Beamforming support */
+#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & MBIT(30))
+/** HW_SPEC Dot11nDevCap : Green field support */
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & MBIT(29))
+/** HW_SPEC Dot11nDevCap : AMPDU support */
+#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & MBIT(28))
+/** HW_SPEC Dot11nDevCap : MIMO PS support */
+#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & MBIT(27))
+/** HW_SPEC Dot11nDevCap : Rx STBC support */
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(26))
+/** HW_SPEC Dot11nDevCap : Tx STBC support */
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(25))
+/** HW_SPEC Dot11nDevCap : Short GI @ 40Mhz support */
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24))
+/** HW_SPEC Dot11nDevCap : Short GI @ 20Mhz support */
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & MBIT(23))
+/** HW_SPEC Dot11nDevCap : Rx LDPC support */
+#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & MBIT(22))
+/** HW_SPEC Dot11nDevCap : Delayed ACK */
+#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03))
+/** HW_SPEC Dot11nDevCap : Immediate ACK */
+#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 40Mhz support */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 20Mhz support */
+#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & MBIT(16))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 10Mhz support */
+#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & MBIT(15))
+/** Dot11nUsrCap : 40Mhz intolarance enabled */
+#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & MBIT(8))
+/** HW_SPEC Dot11nDevCap : Rx AntennaD support */
+#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(7))
+/** HW_SPEC Dot11nDevCap : Rx AntennaC support */
+#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(6))
+/** HW_SPEC Dot11nDevCap : Rx AntennaB support */
+#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(5))
+/** HW_SPEC Dot11nDevCap : Rx AntennaA support */
+#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(4))
+/** HW_SPEC Dot11nDevCap : Tx AntennaD support */
+#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(3))
+/** HW_SPEC Dot11nDevCap : Tx AntennaC support */
+#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(2))
+/** HW_SPEC Dot11nDevCap : Tx AntennaB support */
+#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(1))
+/** HW_SPEC Dot11nDevCap : Tx AntennaA support */
+#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(0))
+
+/** HW_SPEC Dot11nDevCap : Set support of channel bw @ 40Mhz */
+#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= MBIT(17))
+/** HW_SPEC Dot11nDevCap : Reset support of channel bw @ 40Mhz */
+#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(17))
+
+/** DevMCSSupported : Tx MCS supported */
+#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4)
+/** DevMCSSupported : Rx MCS supported */
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+
+/** GET HTCapInfo : Supported Channel BW */
+#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & MBIT(1))
+/** GET HTCapInfo : Support for Greenfield */
+#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & MBIT(4))
+/** GET HTCapInfo : Support for Short GI @ 20Mhz */
+#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & MBIT(5))
+/** GET HTCapInfo : Support for Short GI @ 40Mhz */
+#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & MBIT(6))
+/** GET HTCapInfo : Support for Tx STBC */
+#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & MBIT(7))
+/** GET HTCapInfo : Support for Rx STBC */
+#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03)
+/** GET HTCapInfo : Support for Delayed ACK */
+#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & MBIT(10))
+/** GET HTCapInfo : Support for Max AMSDU */
+#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & MBIT(11))
+
+/** SET HTCapInfo : Set support for Channel BW */
+#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= MBIT(1))
+/** SET HTCapInfo : Set support for Greenfield */
+#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= MBIT(4))
+/** SET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= MBIT(5))
+/** SET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= MBIT(6))
+/** SET HTCapInfo : Set support for Tx STBC */
+#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= MBIT(7))
+/** SET HTCapInfo : Set support for Rx STBC */
+#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8))
+/** SET HTCapInfo : Set support for delayed block ack */
+#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= MBIT(10))
+/** SET HTCapInfo : Set support for Max size AMSDU */
+#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= MBIT(11))
+/** SET HTCapInfo : Set support for DSSS/CCK Rates @ 40Mhz */
+#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= MBIT(12))
+/** SET HTCapInfo : Enable 40Mhz Intolarence */
+#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= MBIT(14))
+
+/** RESET HTCapInfo : Set support for Channel BW */
+#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~MBIT(1))
+/** RESET HTCapInfo : Set support for Greenfield */
+#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~MBIT(4))
+/** RESET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~MBIT(5))
+/** RESET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~MBIT(6))
+/** RESET HTCapInfo : Set support for Tx STBC */
+#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~MBIT(7))
+/** RESET HTCapInfo : Set support for Rx STBC */
+#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8))
+/** RESET HTCapInfo : Set support for delayed block ack */
+#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~MBIT(10))
+/** RESET HTCapInfo : Set support for Max size AMSDU */
+#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~MBIT(11))
+/** RESET HTCapInfo : Disable 40Mhz Intolarence */
+#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~MBIT(14))
+/** SET MCS32 */
+#define SETHT_MCS32(x) (x[4] |= 1)
+/** Set mcs set defined bit */
+#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1)
+/* Set the highest Rx data rate */
+#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(t_u16 *) (x + 10)) = y)
+/** AMPDU factor size */
+#define AMPDU_FACTOR_64K 0x03
+/** Set AMPDU size in A-MPDU paramter field */
+#define SETAMPDU_SIZE(x, y) do { \
+ x = x & ~0x03; \
+ x |= y & 0x03; \
+} while (0) \
+/** Set AMPDU spacing in A-MPDU paramter field */
+#define SETAMPDU_SPACING(x, y) do { \
+ x = x & ~0x1c; \
+ x |= (y & 0x07) << 2; \
+} while (0) \
+
+/** RadioType : Support for Band A */
+#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & MBIT(10))
+/** RadioType : Support for 40Mhz channel BW */
+#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & MBIT(2))
+/** RadioType : Set support 40Mhz channel */
+#define SET_CHANWIDTH40(Field2) (Field2 |= MBIT(2))
+/** RadioType : Reset support 40Mhz channel */
+#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(MBIT(0) | MBIT(1) | MBIT(2)))
+/** RadioType : Get secondary channel */
+#define GET_SECONDARYCHAN(Field2) (Field2 & (MBIT(0) | MBIT(1)))
+/** RadioType : Set secondary channel */
+#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
+
+/** LLC/SNAP header len */
+#define LLC_SNAP_LEN 8
+
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 81)
+/** TLV type : Rate drop pattern */
+#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
+
+/** TLV type : Power group */
+#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
+
+/** Modulation class for DSSS Rates */
+#define MOD_CLASS_HR_DSSS 0x03
+/** Modulation class for OFDM Rates */
+#define MOD_CLASS_OFDM 0x07
+/** Modulation class for HT Rates */
+#define MOD_CLASS_HT 0x08
+/** HT bandwidth 20 MHz */
+#define HT_BW_20 0
+/** HT bandwidth 40 MHz */
+#define HT_BW_40 1
+
+/** Firmware Host Command ID Constants */
+/** Host Command ID : Get hardware specifications */
+#define HostCmd_CMD_GET_HW_SPEC 0x0003
+/** Host Command ID : 802.11 scan */
+#define HostCmd_CMD_802_11_SCAN 0x0006
+/** Host Command ID : 802.11 get log */
+#define HostCmd_CMD_802_11_GET_LOG 0x000b
+/** Host Command ID : MAC multicast address */
+#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
+/** Host Command ID : 802.11 associate */
+#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
+/** Host Command ID : 802.11 SNMP MIB */
+#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
+/** Host Command ID : MAC register access */
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+/** Host Command ID : BBP register access */
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+/** Host Command ID : RF register access */
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+/** Host Command ID : PMIC register access */
+#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad
+/** Host Command ID : 802.11 radio control */
+#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c
+/** Host Command ID : 802.11 RF channel */
+#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
+/** Host Command ID : 802.11 RF antenna */
+#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020
+
+/** Host Command ID : 802.11 deauthenticate */
+#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
+/** Host Command ID : MAC control */
+#define HostCmd_CMD_MAC_CONTROL 0x0028
+/** Host Command ID : 802.11 Ad-Hoc start */
+#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
+/** Host Command ID : 802.11 Ad-Hoc join */
+#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
+
+/** Host Command ID : 802.11 key material */
+#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
+
+/** Host Command ID : 802.11 Ad-Hoc stop */
+#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
+
+/** Host Command ID : 802.22 MAC address */
+#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
+
+/** Host Command ID : WMM Traffic Stream Status */
+#define HostCmd_CMD_WMM_TS_STATUS 0x005d
+
+/** Host Command ID : 802.11 D domain information */
+#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
+
+/** Host Command ID : 802.11 TPC information */
+#define HostCmd_CMD_802_11_TPC_INFO 0x005f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060
+/** Host Command ID : 802.11 channel SW ann */
+#define HostCmd_CMD_802_11_CHAN_SW_ANN 0x0061
+/** Host Command ID : Measurement request */
+#define HostCmd_CMD_MEASUREMENT_REQUEST 0x0062
+/** Host Command ID : Measurement report */
+#define HostCmd_CMD_MEASUREMENT_REPORT 0x0063
+
+/** Host Command ID : 802.11 sleep parameters */
+#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066
+
+/** Host Command ID : 802.11 sleep period */
+#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068
+/** Host Command ID : 802.11 BCA configuration timeshare */
+#define HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE 0x0069
+
+/** Host Command ID : 802.11 BG scan query */
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
+
+/** Host Command ID : WMM ADDTS req */
+#define HostCmd_CMD_WMM_ADDTS_REQ 0x006E
+/** Host Command ID : WMM DELTS req */
+#define HostCmd_CMD_WMM_DELTS_REQ 0x006F
+/** Host Command ID : WMM queue configuration */
+#define HostCmd_CMD_WMM_QUEUE_CONFIG 0x0070
+/** Host Command ID : 802.11 get status */
+#define HostCmd_CMD_WMM_GET_STATUS 0x0071
+
+/** Host Command ID : 802.11 Tx rate query */
+#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
+
+/** Host Command ID : WMM queue stats */
+#define HostCmd_CMD_WMM_QUEUE_STATS 0x0081
+
+/** Host Command ID : 802.11 IBSS coalescing status */
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+/** Host Command ID : Memory access */
+#define HostCmd_CMD_MEM_ACCESS 0x0086
+
+#ifdef MFG_CMD_SUPPORT
+/** Host Command ID : Mfg command */
+#define HostCmd_CMD_MFG_COMMAND 0x0089
+#endif
+/** Host Command ID : Inactivity timeout ext */
+#define HostCmd_CMD_INACTIVITY_TIMEOUT_EXT 0x008a
+
+/** Host Command ID : DBGS configuration */
+#define HostCmd_CMD_DBGS_CFG 0x008b
+/** Host Command ID : Get memory */
+#define HostCmd_CMD_GET_MEM 0x008c
+
+/** Host Command ID : SDIO pull control */
+#define HostCmd_CMD_SDIO_PULL_CTRL 0x0093
+
+/** Host Command ID : ECL system clock configuration */
+#define HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG 0x0094
+
+/** Host Command ID : 802.11 LDO configuration */
+#define HostCmd_CMD_802_11_LDO_CONFIG 0x0096
+
+/** Host Command ID : Extended version */
+#define HostCmd_CMD_VERSION_EXT 0x0097
+
+/** Host Command ID : 802.11 RSSI INFO*/
+#define HostCmd_CMD_RSSI_INFO 0x00a4
+
+/** Host Command ID : Function initialization */
+#define HostCmd_CMD_FUNC_INIT 0x00a9
+/** Host Command ID : Function shutdown */
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+
+/** Host Command ID: SUPPLICANT_PMK */
+#define HostCmd_CMD_SUPPLICANT_PMK 0x00c4
+/** Host Command ID: SUPPLICANT_PROFILE */
+#define HostCmd_CMD_SUPPLICANT_PROFILE 0x00c5
+
+/** Host Command ID : Add Block Ack Request */
+#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_CFG 0x00cd
+/** Host Command ID : Add Block Ack Response */
+#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_DELBA 0x00d0
+/** Host Command ID: Configure Tx Buf size */
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+/** Host Command ID: AMSDU Aggr Ctrl */
+#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
+
+/** Host Command ID : 802.11 TX power configuration */
+#define HostCmd_CMD_TXPWR_CFG 0x00d1
+
+/** Host Command ID : 802.11 b/g/n rate configration */
+#define HostCmd_CMD_TX_RATE_CFG 0x00d6
+
+/** Host Command ID : Enhanced PS mode */
+#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
+/** Host command action : Host sleep configuration */
+#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
+
+/** Host Command ID : CAU register access */
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+
+/** Enhanced PS modes */
+typedef enum _ENH_PS_MODES
+{
+ EN_PS = 1,
+ DIS_PS,
+ EN_AUTO_DS,
+ DIS_AUTO_DS,
+ SLEEP_CONFIRM,
+} ENH_PS_MODES;
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** General purpose action : Get_Current */
+#define HostCmd_ACT_GEN_GET_CURRENT 0x0003
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE 0x0004
+
+/** Host command action : Set both Rx and Tx */
+#define HostCmd_ACT_SET_BOTH 0x0003
+/** Host command action : Get Rx */
+#define HostCmd_ACT_GET_RX 0x0004
+/** Host command action : Get Tx */
+#define HostCmd_ACT_GET_TX 0x0008
+/** Host command action : Get both Rx and Tx */
+#define HostCmd_ACT_GET_BOTH 0x000c
+
+/** General Result Code*/
+/** General result code OK */
+#define HostCmd_RESULT_OK 0x0000
+/** Genenral error */
+#define HostCmd_RESULT_ERROR 0x0001
+/** Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT 0x0002
+/** Command is pending */
+#define HostCmd_RESULT_PENDING 0x0003
+/** System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY 0x0004
+/** Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA 0x0005
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+/** MAC action : Rx on */
+#define HostCmd_ACT_MAC_RX_ON 0x0001
+/** MAC action : Tx on */
+#define HostCmd_ACT_MAC_TX_ON 0x0002
+/** MAC action : Loopback on */
+#define HostCmd_ACT_MAC_LOOPBACK_ON 0x0004
+/** MAC action : WEP enable */
+#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
+/** MAC action : EthernetII enable */
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
+/** MAC action : Promiscous mode enable */
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+/** MAC action : All multicast enable */
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+/** MAC action : RTS/CTS enable */
+#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
+/** MAC action : Strict protection enable */
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+/** MAC action : Ad-Hoc G protection on */
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : BSS */
+#define HostCmd_BSS_MODE_BSS 0x0001
+/** Scan type : IBSS */
+#define HostCmd_BSS_MODE_IBSS 0x0002
+/** Scan type : Any */
+#define HostCmd_BSS_MODE_ANY 0x0003
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : Active */
+#define HostCmd_SCAN_TYPE_ACTIVE 0x0000
+/** Scan type : Passive */
+#define HostCmd_SCAN_TYPE_PASSIVE 0x0001
+
+/* Radio type definitions for the channel TLV */
+/** Radio type BG */
+#define HostCmd_SCAN_RADIO_TYPE_BG 0
+/** Radio type A */
+#define HostCmd_SCAN_RADIO_TYPE_A 1
+
+/** Define bitmap conditions for HOST_SLEEP_CFG : GPIO FF */
+#define HOST_SLEEP_CFG_GPIO_FF 0xff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GAP FF */
+#define HOST_SLEEP_CFG_GAP_FF 0xff
+
+/** Buffer Constants */
+/** Number of command buffers */
+#define MRVDRV_NUM_OF_CMD_BUFFER 20
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Maximum number of BSS Descriptors */
+#define MRVDRV_MAX_BSSID_LIST 64
+
+/** Host command flag in command */
+#define CMD_F_HOSTCMD (1 << 0)
+
+/** Host Command ID bit mask (bit 11:0) */
+#define HostCmd_CMD_ID_MASK 0x0fff
+
+/** Set BSS number to Host Command (bit 14:12) */
+#define HostCmd_SET_BSS_NO(cmd, bss) \
+ (((cmd) & HostCmd_CMD_ID_MASK) | \
+ (((bss) & (MLAN_MAX_BSS_NUM - 1)) << 12))
+
+/** Get BSS number from Host Command (bit 14:12) */
+#define HostCmd_GET_BSS_NO(cmd) \
+ (((cmd) >> 12) & (MLAN_MAX_BSS_NUM - 1))
+
+/** Card Event definition : Dummy host wakeup signal */
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
+/** Card Event definition : Link lost with scan */
+#define EVENT_LINK_LOST_WITH_SCAN 0x00000002
+/** Card Event definition : Link lost */
+#define EVENT_LINK_LOST 0x00000003
+/** Card Event definition : Link sensed */
+#define EVENT_LINK_SENSED 0x00000004
+/** Card Event definition : MIB changed */
+#define EVENT_MIB_CHANGED 0x00000006
+/** Card Event definition : Init done */
+#define EVENT_INIT_DONE 0x00000007
+/** Card Event definition : Deauthenticated */
+#define EVENT_DEAUTHENTICATED 0x00000008
+/** Card Event definition : Disassociated */
+#define EVENT_DISASSOCIATED 0x00000009
+/** Card Event definition : Power save awake */
+#define EVENT_PS_AWAKE 0x0000000a
+/** Card Event definition : Power save sleep */
+#define EVENT_PS_SLEEP 0x0000000b
+/** Card Event definition : MIC error multicast */
+#define EVENT_MIC_ERR_MULTICAST 0x0000000d
+/** Card Event definition : MIC error unicast */
+#define EVENT_MIC_ERR_UNICAST 0x0000000e
+/** Card Event definition : WM awake */
+#define EVENT_WM_AWAKE 0x0000000f
+/** Card Event definition : Deep Sleep awake */
+#define EVENT_DEEP_SLEEP_AWAKE 0x00000010
+/** Card Event definition : Ad-Hoc BCN lost */
+#define EVENT_ADHOC_BCN_LOST 0x00000011
+/** Card Event definition : Stop Tx */
+#define EVENT_STOP_TX 0x00000013
+/** Card Event definition : Start Tx */
+#define EVENT_START_TX 0x00000014
+/** Card Event definition : Channel switch */
+#define EVENT_CHANNEL_SWITCH 0x00000015
+/** Card Event definition : MEAS report ready */
+#define EVENT_MEAS_REPORT_RDY 0x00000016
+/** Card Event definition : WMM status change */
+#define EVENT_WMM_STATUS_CHANGE 0x00000017
+
+/** Card Event definition : BG scan report */
+#define EVENT_BG_SCAN_REPORT 0x00000018
+
+/** Card Event definition : Beacon RSSI low */
+#define EVENT_RSSI_LOW 0x00000019
+/** Card Event definition : Beacon SNR low */
+#define EVENT_SNR_LOW 0x0000001a
+/** Card Event definition : Maximum fail */
+#define EVENT_MAX_FAIL 0x0000001b
+/** Card Event definition : Beacon RSSI high */
+#define EVENT_RSSI_HIGH 0x0000001c
+/** Card Event definition : Beacon SNR high */
+#define EVENT_SNR_HIGH 0x0000001d
+/** Card Event definition : IBSS coalsced */
+#define EVENT_IBSS_COALESCED 0x0000001e
+
+/** Card Event definition : Data RSSI low */
+#define EVENT_DATA_RSSI_LOW 0x00000024
+/** Card Event definition : Data SNR low */
+#define EVENT_DATA_SNR_LOW 0x00000025
+/** Card Event definition : Data RSSI high */
+#define EVENT_DATA_RSSI_HIGH 0x00000026
+/** Card Event definition : Data SNR high */
+#define EVENT_DATA_SNR_HIGH 0x00000027
+/** Card Event definition : Link Quality */
+#define EVENT_LINK_QUALITY 0x00000028
+
+/** Card Event definition : Port release event */
+#define EVENT_PORT_RELEASE 0x0000002b
+
+/** Card Event definition : Pre-Beacon Lost */
+#define EVENT_PRE_BEACON_LOST 0x00000031
+/** Card Event definition : Add BA event */
+#define EVENT_ADDBA 0x00000033
+/** Card Event definition : Del BA event */
+#define EVENT_DELBA 0x00000034
+/** Card Event definition: BA stream timeout*/
+#define EVENT_BA_STREAM_TIEMOUT 0x00000037
+/** Card Event definition : AMSDU aggr control */
+#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+/** Card Event definition: WEP ICV error */
+#define EVENT_WEP_ICV_ERR 0x00000046
+/** Card Event definition : Host sleep enable */
+#define EVENT_HS_ACT_REQ 0x00000047
+/** Card Event definition : BW changed */
+#define EVENT_BW_CHANGE 0x00000048
+
+/** event ID mask */
+#define EVENT_ID_MASK 0x0fff
+
+/** Get BSS number from event cause (bit 14:12) */
+#define EVENT_GET_BSS_NUM(event_cause) \
+ (((event_cause) >> 12) & (MLAN_MAX_BSS_NUM - 1))
+
+/** Event_WEP_ICV_ERR structure */
+typedef struct _Event_WEP_ICV_ERR
+{
+ /** Reason code */
+ t_u16 reason_code;
+ /** Source MAC address */
+ t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** WEP decryption used key */
+ t_u8 wep_key_index;
+ /** WEP key length */
+ t_u8 wep_key_length;
+ /** WEP key */
+ t_u8 key[MAX_WEP_KEY_SIZE];
+} Event_WEP_ICV_ERR;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef struct _WLAN_802_11_FIXED_IEs
+{
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** Capabilities*/
+ t_u16 capabilities;
+} WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef struct _WLAN_802_11_VARIABLE_IEs
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 length;
+ /** IE data */
+ t_u8 data[1];
+} WLAN_802_11_VARIABLE_IEs;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlIEtypesHeader
+{
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} MLAN_PACK_END MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Data_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[1];
+} MLAN_PACK_END MrvlIEtypes_Data_t;
+
+/** Bit mask for TxPD status field for null packet */
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+/** Bit mask for TxPD status field for last packet */
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _TxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** Reserved */
+ t_u8 reserved1;
+} MLAN_PACK_END TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _RxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Rx Packet Length */
+ t_u16 rx_pkt_length;
+ /** Rx Pkt offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** Rx Packet Rate */
+ t_u8 rx_rate;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END RxPD, *PRxPD;
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) */
+#define MAX_NO_OF_CHAN 40
+
+/** Channel-power table entries */
+typedef MLAN_PACK_START struct _chan_power_11d
+{
+ /** 11D channel */
+ t_u8 chan;
+ /** 11D channel power */
+ t_u8 pwr;
+} MLAN_PACK_END chan_power_11d_t;
+
+/** Region channel info */
+typedef MLAN_PACK_START struct _parsed_region_chan_11d
+{
+ /** 11D band */
+ t_u8 band;
+ /** 11D region */
+ t_u8 region;
+ /** 11D country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** 11D channel power per channel */
+ chan_power_11d_t chan_pwr[MAX_NO_OF_CHAN];
+ /** 11D number of channels */
+ t_u8 no_of_chan;
+} MLAN_PACK_END parsed_region_chan_11d_t;
+
+/** ChanScanMode_t */
+typedef MLAN_PACK_START struct _ChanScanMode_t
+{
+#ifdef BIG_ENDIAN
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+#else
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+#endif
+} MLAN_PACK_END ChanScanMode_t;
+
+/** ChanScanParamSet_t */
+typedef MLAN_PACK_START struct _ChanScanParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel scan parameter : Channel number */
+ t_u8 chan_number;
+ /** Channel scan parameter : Channel scan mode */
+ ChanScanMode_t chan_scan_mode;
+ /** Channel scan parameter : Minimum scan time */
+ t_u16 min_scan_time;
+ /** Channel scan parameter : Maximum scan time */
+ t_u16 max_scan_time;
+} MLAN_PACK_END ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel scan parameters */
+ ChanScanParamSet_t chan_scan_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanListParamSet_t;
+
+/** ChanScanParamSet_t */
+typedef struct _ChanBandParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel number */
+ t_u8 chan_number;
+} ChanBandParamSet_t;
+
+/** MrvlIEtypes_ChanBandListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanBandListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel Band parameters */
+ ChanBandParamSet_t chan_band_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanBandListParamSet_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RatesParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Rates */
+ t_u8 rates[1];
+} MLAN_PACK_END MrvlIEtypes_RatesParamSet_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_SsIdParamSet_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_NumProbes_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of probes */
+ t_u16 num_probes;
+} MLAN_PACK_END MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WildCardSsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Maximum SSID length */
+ t_u8 max_ssid_length;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/**TSF data size */
+#define TSF_DATA_SIZE 8
+/** Table of TSF values returned in the scan result */
+typedef MLAN_PACK_START struct _MrvlIEtypes_TsfTimestamp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** the length of each TSF data is 8 bytes, could be multiple TSF here */
+ t_u8 tsf_data[1];
+} MLAN_PACK_END MrvlIEtypes_TsfTimestamp_t;
+
+/** CfParamSet_t */
+typedef MLAN_PACK_START struct _CfParamSet_t
+{
+ /** CF parameter : Count */
+ t_u8 cfp_cnt;
+ /** CF parameter : Period */
+ t_u8 cfp_period;
+ /** CF parameter : Duration */
+ t_u16 cfp_max_duration;
+ /** CF parameter : Duration remaining */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef MLAN_PACK_START struct _IbssParamSet_t
+{
+ /** ATIM window value */
+ t_u16 atim_window;
+} MLAN_PACK_END IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** CF/IBSS parameters sets */
+ union
+ {
+ /** CF parameter set */
+ CfParamSet_t cf_param_set[1];
+ /** IBSS parameter set */
+ IbssParamSet_t ibss_param_set[1];
+ } cf_ibss;
+} MLAN_PACK_END MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef MLAN_PACK_START struct _FhParamSet_t
+{
+ /** FH parameter : Dwell time */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END FhParamSet_t;
+
+/** DsParamSet_t */
+typedef MLAN_PACK_START struct _DsParamSet_t
+{
+ /** Current channel number */
+ t_u8 current_chan;
+} MLAN_PACK_END DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PhyParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** FH/DS parameters */
+ union
+ {
+ /** FH parameter set */
+ FhParamSet_t fh_param_set[1];
+ /** DS parameter set */
+ DsParamSet_t ds_param_set[1];
+ } fh_ds;
+} MLAN_PACK_END MrvlIEtypes_PhyParamSet_t;
+
+/* Auth type to be used in the Authentication portion of an Assoc seq */
+/** MrvlIEtypes_AuthType_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_AuthType_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u16 auth_type;
+} MLAN_PACK_END MrvlIEtypes_AuthType_t;
+
+/** MrvlIETypes_VendorParamSet_t */
+typedef struct _MrvlIETypes_VendorParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Information element */
+ t_u8 ie[MLAN_MAX_VSIE_LEN];
+} MrvlIETypes_VendorParamSet_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RsnParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSN IE */
+ t_u8 rsn_ie[1];
+} MLAN_PACK_END MrvlIEtypes_RsnParamSet_t;
+
+/** Key_param_set fixed length */
+#define KEYPARAMSET_FIXED_LEN 6
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtype_KeyParamSet_t
+{
+ /** Type ID */
+ t_u16 type;
+ /** Length of Payload */
+ t_u16 length;
+ /** Type of Key: WEP=0, TKIP=1, AES=2 */
+ t_u16 key_type_id;
+ /** Key Control Info specific to a key_type_id */
+ t_u16 key_info;
+ /** Length of key */
+ t_u16 key_len;
+ /** Key material of size key_len */
+ t_u8 key[50];
+} MLAN_PACK_END MrvlIEtype_KeyParamSet_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_KEY_MATERIAL
+{
+ /** Action */
+ t_u16 action;
+ /** Key parameter set */
+ MrvlIEtype_KeyParamSet_t key_param_set;
+} MLAN_PACK_END HostCmd_DS_802_11_KEY_MATERIAL;
+
+/* Definition of firmware host command */
+/** HostCmd_DS_GEN */
+typedef struct _HostCmd_DS_GEN
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} HostCmd_DS_GEN;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PERIOD
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+
+ /** Sleep Period in msec */
+ t_u16 sleep_pd;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PARAMS
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** Sleep clock error in ppm */
+ t_u16 error;
+ /** Wakeup offset in usec */
+ t_u16 offset;
+ /** Clock stabilization time in usec */
+ t_u16 stable_time;
+ /** Control periodic calibration */
+ t_u8 cal_control;
+ /** Control the use of external sleep clock */
+ t_u8 external_sleep_clk;
+ /** Reserved field, should be set to zero */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/** Sleep response control */
+typedef enum _sleep_resp_ctrl
+{
+ RESP_NOT_NEEDED = 0,
+ RESP_NEEDED,
+} sleep_resp_ctrl;
+
+/** Structure definition for the new ieee power save parameters*/
+typedef struct __ps_param
+{
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+ /** Num dtims */
+ t_u16 multiple_dtims;
+ /** becaon miss interval */
+ t_u16 bcn_miss_timeout;
+ /** local listen interval */
+ t_u16 local_listen_interval;
+ /** Adhoc awake period */
+ t_u16 adhoc_wake_period;
+ /** mode - (0x01 - firmware to automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL mode ) */
+ t_u16 mode;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+} ps_param;
+
+/** Structure definition for the new auto deep sleep command */
+typedef struct __auto_ds_param
+{
+ /** Deep sleep inactivity timeout */
+ t_u16 deep_sleep_timeout;
+} auto_ds_param;
+
+/** Structure definition for sleep confirmation in the new ps command */
+typedef struct __sleep_confirm_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} sleep_confirm_param;
+
+/** Structure definition for new power save command */
+typedef MLAN_PACK_START struct _HostCmd_DS_PS_MODE_ENH
+{
+ /** Action */
+ t_u16 action;
+ /** Data speciifc to action */
+ /* For IEEE power save data will be as UINT16 mode (0x01 - firmware to
+ automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL
+ mode ) UINT16 NullpacketInterval UINT16 NumDtims UINT16
+ BeaconMissInterval UINT16 locallisteninterval UINT16 adhocawakeperiod */
+
+ /* For auto deep sleep */
+ /* UINT16 Deep sleep inactivity timeout */
+
+ /* For PS sleep confirm UINT16 responeCtrl - 0x00 - reponse from fw not
+ needed, 0x01 - response from fw is needed */
+
+ union
+ {
+ /** PS param definition */
+ ps_param opt_ps;
+ /** Auto ds param definition */
+ auto_ds_param auto_ds;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_PS_MODE_ENH;
+
+/** HostCmd_DS_GET_HW_SPEC */
+typedef MLAN_PACK_START struct _HostCmd_DS_GET_HW_SPEC
+{
+ /** HW Interface version number */
+ t_u16 hw_if_version;
+ /** HW version number */
+ t_u16 version;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Max no of Multicast address */
+ t_u16 num_of_mcast_adr;
+ /** MAC address */
+ t_u8 permanent_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Region Code */
+ t_u16 region_code;
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+ /** FW release number, example 0x1234=1.2.3.4 */
+ t_u32 fw_release_number;
+ /** Reserved field */
+ t_u32 reserved_1;
+ /** Reserved field */
+ t_u32 reserved_2;
+ /** Reserved field */
+ t_u32 reserved_3;
+ /** FW/HW Capability */
+ t_u32 fw_cap_info;
+ /** 802.11n Device Capabilities */
+ t_u32 dot_11n_dev_cap;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 dev_mcs_support;
+ /** Valid end port at init */
+ t_u16 mp_end_port;
+ /* Reserved */
+ t_u16 reserved_4;
+} MLAN_PACK_END HostCmd_DS_GET_HW_SPEC;
+
+/** HostCmd_DS_CMD_802_11_RSSI_INFO */
+typedef struct _HostCmd_DS_802_11_RSSI_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for Beacon */
+ t_u16 nbcn;
+ /** Reserved field 0 */
+ t_u16 reserved[9];
+ /** Reserved field 1 */
+ t_u64 reserved_1;
+} HostCmd_DS_802_11_RSSI_INFO;
+
+/** HostCmd_DS_802_11_RSSI_INFO_RSP */
+typedef struct _HostCmd_DS_802_11_RSSI_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for beacon */
+ t_u16 nbcn;
+ /** Last Data RSSI in dBm */
+ t_s16 data_rssi_last;
+ /** Last Data NF in dBm */
+ t_s16 data_nf_last;
+ /** AVG DATA RSSI in dBm */
+ t_s16 data_rssi_avg;
+ /** AVG DATA NF in dBm */
+ t_s16 data_nf_avg;
+ /** Last BEACON RSSI in dBm */
+ t_s16 bcn_rssi_last;
+ /** Last BEACON NF in dBm */
+ t_s16 bcn_nf_last;
+ /** AVG BEACON RSSI in dBm */
+ t_s16 bcn_rssi_avg;
+ /** AVG BEACON NF in dBm */
+ t_s16 bcn_nf_avg;
+ /** Last RSSI Beacon TSF */
+ t_u64 tsf_bcn;
+} HostCmd_DS_802_11_RSSI_INFO_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef struct _HostCmd_DS_802_11_MAC_ADDRESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+} HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_DS_MAC_CONTROL */
+typedef struct _HostCmd_DS_MAC_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+} HostCmd_DS_MAC_CONTROL;
+
+/** HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_MULTICAST_ADR
+{
+ /** Action */
+ t_u16 action;
+ /** Number of addresses */
+ t_u16 num_of_adrs;
+ /** List of MAC */
+ t_u8 mac_list[MLAN_MAC_ADDR_LENGTH * MLAN_MAX_MULTICAST_LIST_SIZE];
+} MLAN_PACK_END HostCmd_DS_MAC_MULTICAST_ADR;
+
+/** HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_DEAUTHENTICATE
+{
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Deauthentication resaon code */
+ t_u16 reason_code;
+} MLAN_PACK_END HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE
+{
+ /** Peer STA address */
+ t_u8 peer_sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+
+ /**
+ * MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_PhyParamSet_t PhyParamSet;
+ * MrvlIEtypes_SsParamSet_t SsParamSet;
+ * MrvlIEtypes_RatesParamSet_t RatesParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_CMD_802_11_ASSOCIATE response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE_RSP
+{
+ /** Association response structure */
+ IEEEtypes_AssocRsp_t assoc_rsp;
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START
+{
+ /** AdHoc SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_RESULT
+{
+ /** Padding */
+ t_u8 pad[3];
+ /** AdHoc BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_RESULT;
+
+/** AdHoc_BssDesc_t */
+typedef MLAN_PACK_START struct _AdHoc_BssDesc_t
+{
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Local time */
+ t_u8 local_time[8];
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+ * It is used in the Adhoc join command and will cause a
+ * binary layout mismatch with the firmware
+ */
+} MLAN_PACK_END AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN
+{
+ /** AdHoc BSS descriptor */
+ AdHoc_BssDesc_t bss_descriptor;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Reserved field */
+ t_u16 reserved2;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_PULL_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** The delay of pulling up in us */
+ t_u16 pull_up;
+ /** The delay of pulling down in us */
+ t_u16 pull_down;
+} MLAN_PACK_END HostCmd_DS_SDIO_PULL_CTRL;
+
+/** HostCmd_DS_802_11_GET_LOG */
+typedef struct _HostCmd_DS_802_11_GET_LOG
+{
+ /** Number of multicast transmitted frames */
+ t_u32 mcast_tx_frame;
+ /** Number of failures */
+ t_u32 failed;
+ /** Number of retries */
+ t_u32 retry;
+ /** Number of multiretries */
+ t_u32 multiretry;
+ /** Number of duplicate frames */
+ t_u32 frame_dup;
+ /** Number of RTS success */
+ t_u32 rts_success;
+ /** Number of RTS failure */
+ t_u32 rts_failure;
+ /** Number of acknowledgement failure */
+ t_u32 ack_failure;
+ /** Number of fragmented packets received */
+ t_u32 rx_frag;
+ /** Number of multicast frames received */
+ t_u32 mcast_rx_frame;
+ /** FCS error */
+ t_u32 fcs_error;
+ /** Number of transmitted frames */
+ t_u32 tx_frame;
+ /** Reserved field */
+ t_u32 reserved;
+ /** Number of WEP icv error for each key */
+ t_u32 wep_icv_err_cnt[4];
+} HostCmd_DS_802_11_GET_LOG;
+
+/**_HostCmd_TX_RATE_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_TX_RATE_QUERY
+{
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+} MLAN_PACK_END HostCmd_TX_RATE_QUERY;
+
+/** HS Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+typedef enum _Host_Sleep_Action
+{
+ HS_CONFIGURE = 0x0001,
+ HS_ACTIVATE = 0x0002,
+} Host_Sleep_Action;
+
+typedef MLAN_PACK_START struct _hs_config_param
+{
+ /** bit0=1: non-unicast data
+ * bit1=1: unicast data
+ * bit2=1: mac events
+ * bit3=1: magic packet
+ */
+ t_u32 conditions;
+ /** GPIO */
+ t_u8 gpio;
+ /** in milliseconds */
+ t_u8 gap;
+} MLAN_PACK_END hs_config_param;
+
+/** Structure definition for activating enhanced hs */
+typedef MLAN_PACK_START struct __hs_activate_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} MLAN_PACK_END hs_activate_param;
+
+/** HostCmd_DS_802_11_HS_CFG_ENH */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_HS_CFG_ENH
+{
+ /** Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+ t_u16 action;
+
+ union
+ {
+ /** Configure enhanced hs */
+ hs_config_param hs_config;
+ /** Activate enhanced hs */
+ hs_activate_param hs_activate;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_HS_CFG_ENH;
+
+/** HostCmd_DS_802_11_BCA_TIMESHARE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BCA_TIMESHARE
+{
+ /** Action */
+ t_u16 action;
+ /** Type: WLAN, BT */
+ t_u16 traffic_type;
+ /** 20msec - 60000msec */
+ t_u32 timeshare_interval;
+ /** PTA arbiter time in msec */
+ t_u32 bt_time;
+} MLAN_PACK_END HostCmd_DS_802_11_BCA_TIMESHARE;
+
+/** SNMP_MIB_INDEX */
+typedef enum _SNMP_MIB_INDEX
+{
+ OpRateSet_i = 1,
+ DtimPeriod_i = 3,
+ RtsThresh_i = 5,
+ ShortRetryLim_i = 6,
+ LongRetryLim_i = 7,
+ FragThresh_i = 8,
+ Dot11D_i = 9,
+ Dot11H_i = 10,
+ WwsMode_i = 17
+} SNMP_MIB_INDEX;
+
+/** max SNMP buf size */
+#define MAX_SNMP_BUF_SIZE 128
+
+/** HostCmd_CMD_802_11_SNMP_MIB */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SNMP_MIB
+{
+ /** SNMP query type */
+ t_u16 query_type;
+ /** SNMP object ID */
+ t_u16 oid;
+ /** SNMP buffer size */
+ t_u16 buf_size;
+ /** Value */
+ t_u8 value[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SNMP_MIB;
+
+/** Radio on */
+#define RADIO_ON 0x01
+/** Radio off */
+#define RADIO_OFF 0x00
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RADIO_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Control */
+ t_u16 control;
+} MLAN_PACK_END HostCmd_DS_802_11_RADIO_CONTROL;
+
+/** MrvlRateScope_t */
+typedef MLAN_PACK_START struct _MrvlRateScope_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Bitmap of HR/DSSS rates */
+ t_u16 hr_dsss_rate_bitmap;
+ /** Bitmap of OFDM rates */
+ t_u16 ofdm_rate_bitmap;
+ /** Bitmap of HT-MCSs allowed for initial rate */
+ t_u16 ht_mcs_rate_bitmap[8];
+} MLAN_PACK_END MrvlRateScope_t;
+
+/** MrvlRateDropControl_t */
+typedef MLAN_PACK_START struct _MrvlRateDropControl_t
+{
+ /** Header Length */
+ t_u16 length;
+ /** Rate Information */
+ t_u32 rate_info[1];
+} MLAN_PACK_END MrvlRateDropControl_t;
+
+/** MrvlRateDropPattern_t */
+typedef MLAN_PACK_START struct _MrvlRateDropPattern_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Rate Drop Mode */
+ t_u32 rate_drop_mode;
+ /* MrvlRateDropControl_t RateDropControl[0]; */
+} MLAN_PACK_END MrvlRateDropPattern_t;
+
+/** HostCmd_DS_TX_RATE_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_RATE_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Tx Rate Configuration Index */
+ t_u16 cfg_index;
+ /* MrvlRateScope_t RateScope; MrvlRateDropPattern_t RateDrop; */
+} MLAN_PACK_END HostCmd_DS_TX_RATE_CFG;
+
+/** Power_Group_t */
+typedef MLAN_PACK_START struct _Power_Group_t
+{
+ /** Modulation Class */
+ t_u8 modulation_class;
+ /** MCS Code or Legacy RateID */
+ t_u8 first_rate_code;
+ /** MCS Code or Legacy RateID */
+ t_u8 last_rate_code;
+ /** Power Adjustment Step */
+ t_s8 power_step;
+ /** Minimal Tx Power Level [dBm] */
+ t_s8 power_min;
+ /** Maximal Tx Power Level [dBm] */
+ t_s8 power_max;
+ /** 0: HTBW20, 1: HTBW40 */
+ t_u8 ht_bandwidth;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END Power_Group_t;
+
+/** MrvlTypes_Power_Group_t */
+typedef MLAN_PACK_START struct _MrvlTypes_Power_Group_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /* Power_Group_t PowerGroups */
+} MLAN_PACK_END MrvlTypes_Power_Group_t;
+
+/** HostCmd_CMD_TXPWR_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TXPWR_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Power group configuration index */
+ t_u16 cfg_index;
+ /** Power group configuration mode */
+ t_u32 mode;
+ /* MrvlTypes_Power_Group_t PowerGrpCfg[0] */
+} MLAN_PACK_END HostCmd_DS_TXPWR_CFG;
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command process module to configure the firmware
+ * scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef MLAN_PACK_START struct _wlan_scan_cmd_config
+{
+ /**
+ * BSS Type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+
+ /**
+ * Specific BSSID used to filter scan results in the firmware
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ /**
+ * Length of TLVs sent in command starting at tlvBuffer
+ */
+ t_u32 tlv_buf_len;
+
+ /**
+ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+ * TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+ */
+ t_u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
+ here */
+} MLAN_PACK_END wlan_scan_cmd_config;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan
+{
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 0, Passive = 1 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid
+{
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief Reserved
+ */
+ t_u8 reserved;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} MLAN_PACK_END wlan_get_scan_table_info;
+
+/** Generic structure defined for parsing WPA/RSN IEs for GTK/PTK OUIs */
+typedef MLAN_PACK_START struct
+{
+ /** Group key oui */
+ t_u8 GrpKeyOui[4];
+ /** Number of PTKs */
+ t_u8 PtkCnt[2];
+ /** Ptk body starts here */
+ t_u8 PtkBody[4];
+} MLAN_PACK_END IEBody;
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN
+{
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN;
+
+/** HostCmd_DS_802_11_SCAN_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_RSP
+{
+ /** Size of BSS descriptor */
+ t_u16 bss_descript_size;
+ /** Numner of sets */
+ t_u8 number_of_sets;
+ /** BSS descriptor and TLV buffer */
+ t_u8 bss_desc_and_tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY
+{
+ /** Flush */
+ t_u8 flush;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
+{
+ /** Report condition */
+ t_u32 report_condition;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** MrvlIEtypes_DomainParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_DomainParamSet
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END MrvlIEtypes_DomainParamSet_t;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+/** HostCmd_DS_11N_ADDBA_REQ */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_REQ
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 add_req_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_REQ;
+
+/** HostCmd_DS_11N_ADDBA_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_RSP
+{
+ /** Result of the ADDBA Response Operation */
+ t_u8 add_rsp_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Status Code */
+ t_u16 status_code;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_RSP;
+
+/** HostCmd_DS_11N_DELBA */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_DELBA
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 del_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u16 del_ba_param_set;
+ /** Reason Code sent for DELBA */
+ t_u16 reason_code;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END HostCmd_DS_11N_DELBA;
+
+/** HostCmd_DS_11N_BATIMEOUT */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_BATIMEOUT
+{
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u8 origninator;
+} MLAN_PACK_END HostCmd_DS_11N_BATIMEOUT;
+
+/** HostCmd_DS_11N_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** HTTxCap */
+ t_u16 ht_tx_cap;
+ /** HTTxInfo */
+ t_u16 ht_tx_info;
+} MLAN_PACK_END HostCmd_DS_11N_CFG;
+
+/** HostCmd_DS_TXBUF_CFG*/
+typedef MLAN_PACK_START struct _HostCmd_DS_TXBUF_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Buffer Size */
+ t_u16 buff_size;
+ /** End Port_for Multiport */
+ t_u16 mp_end_port;
+ /** Reserved */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_TXBUF_CFG;
+
+/** HostCmd_DS_AMSDU_AGGR_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_AMSDU_AGGR_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** Get the current Buffer Size valid */
+ t_u16 curr_buf_size;
+} MLAN_PACK_END HostCmd_DS_AMSDU_AGGR_CTRL;
+
+/** HostCmd_DS_802_11_LDO_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_LDO_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** PM Source: 0 = LDO_INTERNAL, 1 = LDO_EXTERNAL */
+ t_u16 pmsource;
+} MLAN_PACK_END HostCmd_DS_802_11_LDO_CFG;
+
+/** HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG
+{
+ /** Action */
+ t_u16 action;
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Length of clocks */
+ t_u16 sys_clk_len;
+ /** System clocks */
+ t_u16 sys_clk[16];
+} MLAN_PACK_END HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef struct _MrvlIEtypes_WmmParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM IE */
+ t_u8 wmm_ie[1];
+} MrvlIEtypes_WmmParamSet_t;
+
+/** MrvlIEtypes_WmmQueueStatus_t */
+typedef struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Queue index */
+ t_u8 queue_index;
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Medium time allocation in 32us units*/
+ t_u16 medium_time;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Reserved */
+ t_u32 reserved;
+} MrvlIEtypes_WmmQueueStatus_t;
+
+/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE 63
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES 256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS 7
+
+/**
+ * @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ * Used to retrieve the status of each WMM AC Queue in TLV
+ * format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ * parameter IE advertised by the AP.
+ *
+ * Used in response to a EVENT_WMM_STATUS_CHANGE event signaling
+ * a QOS change on one of the ACs or a change in the WMM Parameter in
+ * the Beacon.
+ *
+ * TLV based command, byte arrays used for max sizing purpose. There are no
+ * arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ /** Queue status TLV */
+ t_u8 queue_status_tlv[sizeof(MrvlIEtypes_WmmQueueStatus_t) * MAX_AC_QUEUES];
+ /** WMM parameter TLV */
+ t_u8 wmm_param_tlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+}
+MLAN_PACK_END HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_status_code; /**< IEEE status code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+ t_u8 addts_extra_ie_buf[WMM_ADDTS_EXTRA_IE_BYTES]; /**< ADDTS extra IE buffer */
+} MLAN_PACK_END HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_reason_code; /**< IEEE reason code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+} MLAN_PACK_END HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ * Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ /** @brief MSDU lifetime expiry per 802.11e
+ *
+ * - Ignored if 0 on a set command
+ * - Set to the 802.11e specified 500 TUs when defaulted
+ */
+ t_u16 msdu_lifetime_expiry;
+ t_u8 tlv_buffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; /**< Not supported yet */
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ * Turn statistical collection on/off for a given AC or retrieve the
+ * accumulated stats for an AC and clear them in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_stats_action_e action; /**< Start, Stop, or Get */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 pkt_count; /**< Number of successful packets transmitted */
+ t_u16 pkt_loss; /**< Packets lost; not included in pktCount */
+ t_u32 avg_queue_delay; /**< Average Queue delay in microseconds */
+ t_u32 avg_tx_delay; /**< Average Transmission delay in microseconds */
+ t_u16 used_time; /**< Calculated used time - units of 32 microseconds */
+ t_u16 policed_time; /**< Calculated policed time - units of 32 microseconds */
+ /** @brief Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[WMM_STATS_PKTS_HIST_BINS];
+ /** Reserved */
+ t_u16 reserved_1;
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_TS_STATUS firmware cmd
+ *
+ * Query the firmware to get the status of the WMM Traffic Streams
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END HostCmd_DS_WMM_TS_STATUS;
+
+/** Firmware status for a specific AC */
+typedef struct
+{
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+} WmmAcStatus_t;
+
+/** Local Power Capability */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PowerCapability_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Minmum power */
+ t_s8 min_power;
+ /** Maximum power */
+ t_s8 max_power;
+} MLAN_PACK_END MrvlIEtypes_PowerCapability_t;
+
+/** HT Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END MrvlIETypes_HTCap_t;
+
+/** HT Information element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTInfo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END MrvlIETypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence element */
+typedef MLAN_PACK_START struct _MrvlIETypes_2040BSSCo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END MrvlIETypes_2040BSSCo_t;
+
+/** Extended Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END MrvlIETypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters element */
+typedef MLAN_PACK_START struct _MrvlIETypes_OverlapBSSScanParam_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END MrvlIETypes_OverlapBSSScanParam_t;
+
+/** Set of MCS values that STA desires to use within the BSS */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTOperationalMCSSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** Bitmap indicating MCSs that STA desires to use within the BSS */
+ t_u8 ht_operational_mcs_bitmap[16];
+} MLAN_PACK_END MrvlIETypes_HTOperationalMCSSet_t;
+
+/** MrvlIEtypes_PMK_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PMK_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PMK */
+ t_u8 pmk[1];
+} MLAN_PACK_END MrvlIEtypes_PMK_t;
+/** MrvlIEtypes_Passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Passphrase_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Passphrase */
+ char passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_Passphrase_t;
+/* unicastCipher -
+ * Bit 0 : RFU
+ * Bit 1 : RFU
+ * Bit 2 : TKIP
+ * Bit 3 : AES CCKM
+ * Bit 2-7 : RFU
+ * multicastCipher -
+ * Bit 0 : WEP40
+ * Bit 1 : WEP104
+ * Bit 2 : TKIP
+ * Bit 3 : AES
+ * Bit 4-7 : Reserved for now
+ */
+/** MrvlIEtypes_Cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END MrvlIEtypes_Cipher_t;
+/* rsnMode -
+ * Bit 0 : No RSN
+ * Bit 1-2 : RFU
+ * Bit 3 : WPA
+ * Bit 4 : WPA-NONE
+ * Bit 5 : WPA2
+ * Bit 6 : AES CCKM
+ * Bit 7-15 : RFU
+ */
+/** MrvlIEtypes_Cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_EncrProto_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** EncrProto */
+ t_u16 rsn_mode;
+} MLAN_PACK_END MrvlIEtypes_EncrProto_t;
+
+/** MrvlIEtypes_Bssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bssid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_Bssid_t;
+
+/*
+ * This struct will handle GET,SET,CLEAR function for embedded
+ * supplicant.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PMK
+ */
+/** HostCmd_DS_802_11_SUPPLICANT_PMK */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PMK
+{
+ /** CMD Action GET/SET/CLEAR */
+ t_u16 action;
+ /** CacheResult initialized to 0 */
+ t_u16 cache_result;
+ /** TLV Buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsidParamSet_t SsidParamSet;
+ * MrvlIEtypes_PMK_t Pmk;
+ * MrvlIEtypes_Passphrase_t Passphrase;
+ * MrvlIEtypes_Bssid_t Bssid;
+ **/
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PMK;
+
+/*
+ * This struct will GET the Supplicant supported bitmaps
+ * The GET_CURRENT action will get the network profile used
+ * for the current assocation.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PROFILE
+ */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PROFILE
+{
+ /** GET/SET/GET_CURRENT */
+ t_u16 action;
+ /** Reserved */
+ t_u16 reserved;
+ /** TLVBuffer */
+ t_u8 tlv_buf[1];
+ /* MrvlIEtypes_EncrProto_t */
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PROFILE;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_CHANNEL
+{
+ /** Action */
+ t_u16 action;
+ /** Current channel */
+ t_u16 current_channel;
+ /** RF type */
+ t_u16 rf_type;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Reserved */
+ t_u8 reserved_1[32];
+} MLAN_PACK_END HostCmd_DS_802_11_RF_CHANNEL;
+
+/** HostCmd_DS_VERSION_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_VERSION_EXT
+{
+ /** Selected version string */
+ t_u8 version_str_sel;
+ /** Version string */
+ char version_str[128];
+} MLAN_PACK_END HostCmd_DS_VERSION_EXT;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_ANTENNA
+{
+ /** Action */
+ t_u16 action;
+ /** Number of antennas or 0xffff(diversity) */
+ t_u16 antenna_mode;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_DS_802_11_IBSS_STATUS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_IBSS_STATUS
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** ATIM window interval */
+ t_u16 atim_window;
+ /** User G rate protection */
+ t_u16 use_g_rate_protect;
+} MLAN_PACK_END HostCmd_DS_802_11_IBSS_STATUS;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC register offset */
+ t_u16 offset;
+ /** MAC register value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_BBP_REG_ACCESS
+{
+ /** Acion */
+ t_u16 action;
+ /** BBP register offset */
+ t_u16 offset;
+ /** BBP register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_BBP_REG_ACCESS;
+
+/** HostCmd_CMD_RF_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_RF_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** RF register offset */
+ t_u16 offset;
+ /** RF register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_CMD_PMIC_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_PMIC_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** PMIC register offset */
+ t_u16 offset;
+ /** PMIC register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_PMIC_REG_ACCESS;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_EEPROM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+
+ /** multiple 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value;
+} MLAN_PACK_END HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_MEM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MEM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MEM_ACCESS;
+
+/** HostCmd_DS_INACTIVITY_TIMEOUT_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_INACTIVITY_TIMEOUT_EXT
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** uS, 0 means 1000uS(1ms) */
+ t_u16 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u16 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u16 mcast_timeout;
+ /** Timeout for additional RX traffic after Null PM1 packet exchange */
+ t_u16 ps_entry_timeout;
+ /** Reserved to further expansion */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_INACTIVITY_TIMEOUT_EXT;
+
+/**
+ * @brief 802.11h Local Power Constraint Marvell extended TLV
+ */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t header; /**< Marvell TLV header: ID/Len */
+ t_u8 chan; /**< Channel local constraint applies to */
+
+ /** Power constraint included in beacons and used by fw to offset 11d info */
+ t_u8 constraint;
+
+} MLAN_PACK_END MrvlIEtypes_LocalPowerConstraint_t;
+
+/*
+ *
+ * Data structures for driver/firmware command processing
+ *
+ */
+
+/** TPC Info structure sent in CMD_802_11_TPC_INFO command to firmware */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypes_LocalPowerConstraint_t local_constraint; /**< Local constraint */
+ MrvlIEtypes_PowerCapability_t power_cap; /**< Power Capability */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_INFO;
+
+/** TPC Request structure sent in CMD_802_11_TPC_ADAPT_REQ command to firmware */
+typedef MLAN_PACK_START struct
+{
+ t_u8 dest_mac[MLAN_MAC_ADDR_LENGTH]; /**< Destination STA address */
+ t_u16 timeout; /**< Response timeout in ms */
+ t_u8 rate_index; /**< IEEE Rate index to send request */
+
+} MLAN_PACK_END HostCmd_TpcRequest;
+
+/** TPC Response structure received from the CMD_802_11_TPC_ADAPT_REQ command */
+typedef MLAN_PACK_START struct
+{
+ t_u8 tpc_ret_code; /**< Firmware command result status code */
+ t_s8 tx_power; /**< Reported TX Power from the TPC Report element */
+ t_s8 link_margin; /**< Reported link margin from the TPC Report element */
+ t_s8 rssi; /**< RSSI of the received TPC Report frame */
+
+} MLAN_PACK_END HostCmd_TpcResponse;
+
+/** CMD_802_11_TPC_ADAPT_REQ substruct. Union of the TPC request and response */
+typedef MLAN_PACK_START union
+{
+ HostCmd_TpcRequest req; /**< Request struct sent to firmware */
+ HostCmd_TpcResponse resp; /**< Response struct received from firmware */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_ADAPT_REQ;
+
+/** CMD_802_11_CHAN_SW_ANN firmware command substructure */
+typedef MLAN_PACK_START struct
+{
+ t_u8 switch_mode; /**< Set to 1 for a quiet switch request, no STA tx */
+ t_u8 new_chan; /**< Requested new channel */
+ t_u8 switch_count; /**< Number of TBTTs until the switch is to occur */
+} MLAN_PACK_END HostCmd_DS_802_11_CHAN_SW_ANN;
+
+/**
+ * @brief Enumeration of measurement types, including max supported
+ * enum for 11h/11k
+ */
+typedef MLAN_PACK_START enum
+{
+ WLAN_MEAS_BASIC = 0, /**< 11h: Basic */
+ WLAN_MEAS_NUM_TYPES, /**< Number of enumerated measurements */
+ WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_BASIC, /**< Max 11h measurement */
+
+} MLAN_PACK_END MeasType_t;
+
+/**
+ * @brief Mode octet of the measurement request element (7.3.2.21)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+#else
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN */
+
+} MLAN_PACK_END MeasReqMode_t;
+
+/**
+ * @brief Common measurement request structure (7.3.2.21.1 to 7.3.2.21.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measure */
+ t_u64 start_time; /**< TSF Start time of measurement (0 for immediate) */
+ t_u16 duration; /**< TU duration of the measurement */
+
+} MLAN_PACK_END MeasReqCommonFormat_t;
+
+/**
+ * @brief Basic measurement request structure (7.3.2.21.1)
+ */
+typedef MeasReqCommonFormat_t MeasReqBasic_t;
+
+/**
+ * @brief CCA measurement request structure (7.3.2.21.2)
+ */
+typedef MeasReqCommonFormat_t MeasReqCCA_t;
+
+/**
+ * @brief RPI measurement request structure (7.3.2.21.3)
+ */
+typedef MeasReqCommonFormat_t MeasReqRPI_t;
+
+/**
+ * @brief Union of the availble measurement request types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasReqBasic_t basic; /**< Basic measurement request */
+ MeasReqCCA_t cca; /**< CCA measurement request */
+ MeasReqRPI_t rpi; /**< RPI measurement request */
+
+} MeasRequest_t;
+
+/**
+ * @brief Mode octet of the measurement report element (7.3.2.22)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN
+ t_u8 rsvd3_7:5; /**< Reserved */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+#else
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 rsvd3_7:5; /**< Reserved */
+#endif /* BIG_ENDIAN */
+
+} MLAN_PACK_END MeasRptMode_t;
+
+/**
+ * @brief Basic measurement report (7.3.2.22.1)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ MeasRptBasicMap_t map; /**< Basic measurement report */
+
+} MLAN_PACK_END MeasRptBasic_t;
+
+/**
+ * @brief CCA measurement report (7.3.2.22.2)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 busy_fraction; /**< Fractional duration CCA indicated chan busy */
+
+} MLAN_PACK_END MeasRptCCA_t;
+
+/**
+ * @brief RPI measurement report (7.3.2.22.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 density[8]; /**< RPI Density histogram report */
+
+} MLAN_PACK_END MeasRptRPI_t;
+
+/**
+ * @brief Union of the availble measurement report types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasRptBasic_t basic; /**< Basic measurement report */
+ MeasRptCCA_t cca; /**< CCA measurement report */
+ MeasRptRPI_t rpi; /**< RPI measurement report */
+
+} MeasReport_t;
+
+/**
+ * @brief Structure passed to firmware to perform a measurement
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog toke */
+ MeasReqMode_t req_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasRequest_t req; /**< Measurement request data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REQUEST;
+
+/**
+ * @brief Structure passed back from firmware with a measurement report,
+ * also can be to send a measurement report to another STA
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog token */
+ MeasRptMode_t rpt_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasReport_t rpt; /**< Measurement report data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REPORT;
+
+/** HostCmd_DS_COMMAND */
+typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND
+{
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command Body */
+ union
+ {
+ /** Hardware specifications */
+ HostCmd_DS_GET_HW_SPEC hw_spec;
+ /** MAC control */
+ HostCmd_DS_MAC_CONTROL mac_ctrl;
+ /** MAC address */
+ HostCmd_DS_802_11_MAC_ADDRESS mac_addr;
+ /** MAC muticast address */
+ HostCmd_DS_MAC_MULTICAST_ADR mc_addr;
+ /** Get log */
+ HostCmd_DS_802_11_GET_LOG get_log;
+ /** RSSI information */
+ HostCmd_DS_802_11_RSSI_INFO rssi_info;
+ /** RSSI information response */
+ HostCmd_DS_802_11_RSSI_INFO_RSP rssi_info_rsp;
+ /** SNMP MIB */
+ HostCmd_DS_802_11_SNMP_MIB smib;
+ /** Radio control */
+ HostCmd_DS_802_11_RADIO_CONTROL radio;
+ /** RF channel */
+ HostCmd_DS_802_11_RF_CHANNEL rf_channel;
+ /** Tx rate query */
+ HostCmd_TX_RATE_QUERY tx_rate;
+ /** Tx rate configuration */
+ HostCmd_DS_TX_RATE_CFG tx_rate_cfg;
+ /** Tx power configuration */
+ HostCmd_DS_TXPWR_CFG txp_cfg;
+ /** RF antenna */
+ HostCmd_DS_802_11_RF_ANTENNA antenna;
+ /** Enhanced power save command */
+ HostCmd_DS_802_11_PS_MODE_ENH psmode_enh;
+ HostCmd_DS_802_11_HS_CFG_ENH opt_hs_cfg;
+ /** Scan */
+ HostCmd_DS_802_11_SCAN scan;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+
+ HostCmd_DS_802_11_BG_SCAN_QUERY bg_scan_query;
+ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bg_scan_query_resp;
+
+ /** Associate */
+ HostCmd_DS_802_11_ASSOCIATE associate;
+
+ /** Associate response */
+ HostCmd_DS_802_11_ASSOCIATE_RSP associate_rsp;
+ /** Deauthenticate */
+ HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+ /** Ad-Hoc start */
+ HostCmd_DS_802_11_AD_HOC_START adhoc_start;
+ /** Ad-Hoc result */
+ HostCmd_DS_802_11_AD_HOC_RESULT adhoc_result;
+ /** Ad-Hoc join */
+ HostCmd_DS_802_11_AD_HOC_JOIN adhoc_join;
+ /** Domain information */
+ HostCmd_DS_802_11D_DOMAIN_INFO domain_info;
+ /** Domain information response */
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP domain_info_resp;
+ HostCmd_DS_802_11_TPC_ADAPT_REQ tpc_req;
+ HostCmd_DS_802_11_TPC_INFO tpc_info;
+ HostCmd_DS_802_11_CHAN_SW_ANN chan_sw_ann;
+ HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+ /** Add BA request */
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ /** Add BA response */
+ HostCmd_DS_11N_ADDBA_RSP add_ba_rsp;
+ /** Delete BA entry */
+ HostCmd_DS_11N_DELBA del_ba;
+ /** Tx buffer configuration */
+ HostCmd_DS_TXBUF_CFG tx_buf;
+ /** AMSDU Aggr Ctrl configuration */
+ HostCmd_DS_AMSDU_AGGR_CTRL amsdu_aggr_ctrl;
+ /** 11n configuration */
+ HostCmd_DS_11N_CFG htcfg;
+ /** WMM status get */
+ HostCmd_DS_WMM_GET_STATUS get_wmm_status;
+ /** WMM ADDTS */
+ HostCmd_DS_WMM_ADDTS_REQ add_ts;
+ /** WMM DELTS */
+ HostCmd_DS_WMM_DELTS_REQ del_ts;
+ /** WMM set/get queue config */
+ HostCmd_DS_WMM_QUEUE_CONFIG queue_config;
+ /** WMM on/of/get queue statistics */
+ HostCmd_DS_WMM_QUEUE_STATS queue_stats;
+ /** WMM get traffic stream status */
+ HostCmd_DS_WMM_TS_STATUS ts_status;
+ /** Key material */
+ HostCmd_DS_802_11_KEY_MATERIAL key_material;
+ /** E-Supplicant PSK */
+ HostCmd_DS_802_11_SUPPLICANT_PMK esupplicant_psk;
+ /** E-Supplicant profile */
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE esupplicant_profile;
+ /** Extended version */
+ HostCmd_DS_VERSION_EXT verext;
+ /** Adhoc Coalescing */
+ HostCmd_DS_802_11_IBSS_STATUS ibss_coalescing;
+ /** LDO configuration */
+ HostCmd_DS_802_11_LDO_CFG ldo_cfg;
+ /** System clock configuration */
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG sys_clock_cfg;
+ /** MAC register access */
+ HostCmd_DS_MAC_REG_ACCESS mac_reg;
+ /** BBP register access */
+ HostCmd_DS_BBP_REG_ACCESS bbp_reg;
+ /** RF register access */
+ HostCmd_DS_RF_REG_ACCESS rf_reg;
+ /** PMIC register access */
+ HostCmd_DS_PMIC_REG_ACCESS pmic_reg;
+ /** EEPROM register access */
+ HostCmd_DS_802_11_EEPROM_ACCESS eeprom;
+ /** Memory access */
+ HostCmd_DS_MEM_ACCESS mem;
+
+ /** Inactivity timeout extend */
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT inactivity_to;
+ /** BCA Timeshare */
+ HostCmd_DS_802_11_BCA_TIMESHARE bca_timeshare;
+
+ /** Sleep period command */
+ HostCmd_DS_802_11_SLEEP_PERIOD sleep_pd;
+ /** Sleep params command */
+ HostCmd_DS_802_11_SLEEP_PARAMS sleep_param;
+
+ } params;
+} MLAN_PACK_END HostCmd_DS_COMMAND;
+
+typedef struct MLAN_PACK_START _opt_sleep_confirm_buffer
+{
+ /** Header for interface */
+ t_u8 hdr[4];
+ /** New power save command used to send sleep confirmation to the firmware */
+ HostCmd_DS_COMMAND ps_cfm_sleep;
+} MLAN_PACK_END opt_sleep_confirm_buffer;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+#endif /* !_MLAN_FW_H_ */
diff --git a/wlan_src/mlan/mlan_ieee.h b/wlan_src/mlan/mlan_ieee.h
new file mode 100755
index 0000000..139c6ab
--- /dev/null
+++ b/wlan_src/mlan/mlan_ieee.h
@@ -0,0 +1,832 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 11/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension*/
+#define WLAN_SUPPORTED_RATES_EXT 32
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound */
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+ COUNTRY_INFO = 7,
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \
+ MBIT(12) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN */
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t
+{
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t
+{
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t
+{
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t
+{
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t
+{
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t
+{
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+#else
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct
+{
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t
+{
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/wlan_src/mlan/mlan_init.c b/wlan_src/mlan/mlan_init.c
new file mode 100755
index 0000000..4f2bafc
--- /dev/null
+++ b/wlan_src/mlan/mlan_init.c
@@ -0,0 +1,654 @@
+/** @file mlan_init.c
+ *
+ * @brief This file contains the initialization for FW
+ * and HW.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_meas.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function adds a BSS priority table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param bss_num BSS number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_add_bsspriotbl(pmlan_adapter pmadapter, t_u8 bss_num)
+{
+ pmlan_private priv = pmadapter->priv[bss_num];
+ mlan_bssprio_node *pbssprio;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((status = pmadapter->callbacks.moal_malloc(sizeof(mlan_bssprio_node),
+ (t_u8 **) & pbssprio))) {
+ PRINTM(MERROR, "Allocation failed for add_bsspriotbl\n");
+ return status;
+ }
+
+ pbssprio->priv = priv;
+
+ util_init_list((pmlan_linked_list) pbssprio);
+
+ if (!pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur)
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pbssprio;
+
+ util_enqueue_list_tail(&pmadapter->bssprio_tbl[priv->bss_priority].
+ bssprio_head, (pmlan_linked_list) pbssprio,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function initializes the private structure
+ * and sets default values to the members of mlan_private.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_init_priv(pmlan_private priv)
+{
+ t_u32 i;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ priv->media_connected = MFALSE;
+ memset(priv->curr_addr, 0xff, MLAN_MAC_ADDR_LENGTH);
+
+ priv->pkt_tx_ctrl = 0;
+ priv->bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->data_rate = 0; /* Initially indicate the rate as auto */
+ priv->is_data_rate_auto = MTRUE;
+ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ priv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ priv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+ for (i = 0; i < sizeof(priv->wep_key) / sizeof(priv->wep_key[0]); i++)
+ memset(&priv->wep_key[i], 0, sizeof(mrvl_wep_key_t));
+ priv->wep_key_curr_index = 0;
+ priv->adhoc_aes_enabled = MFALSE;
+ priv->curr_pkt_filter =
+ HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+ HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+ priv->beacon_period = MLAN_BEACON_INTERVAL;
+ priv->pattempted_bss_desc = MNULL;
+ memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
+ priv->listen_interval = MLAN_DEFAULT_LISTEN_INTERVAL;
+
+ memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
+ memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
+ memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+ priv->assoc_rsp_size = 0;
+ priv->adhoc_auto_sel = MTRUE;
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->atim_window = 0;
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->tx_power_level = 0;
+ priv->max_tx_power_level = 0;
+ priv->min_tx_power_level = 0;
+ priv->tx_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->rxpd_rate = 0;
+ priv->rate_bitmap = 0;
+ priv->data_rssi_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->data_nf_last = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->bcn_nf_last = 0;
+ memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ memset(&priv->aes_key, 0, sizeof(priv->aes_key));
+ priv->wpa_ie_len = 0;
+ priv->wpa_is_gtk_set = MFALSE;
+
+ memset(&priv->mrvl_assoc_tlv_buf, 0, sizeof(priv->mrvl_assoc_tlv_buf));
+ priv->mrvl_assoc_tlv_buf_len = 0;
+ memset(&priv->wps, 0, sizeof(priv->wps));
+ memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+ priv->gen_ie_buf_len = 0;
+ memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
+
+ priv->wmm_required = MTRUE;
+ priv->wmm_enabled = MFALSE;
+ priv->wmm_qosinfo = 0;
+ priv->gen_null_pkg = MTRUE; /* Enable NULL Pkg generation */
+ pmadapter->callbacks.moal_init_lock(&priv->rx_pkt_lock);
+ priv->pcurr_bcn_buf = MNULL;
+ priv->curr_bcn_size = 0;
+ pmadapter->callbacks.moal_init_lock(&priv->curr_bcn_buf_lock);
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ priv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+
+ util_init_list_head(&priv->tx_ba_stream_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head(&priv->rx_reorder_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function allocates buffer for the members of adapter
+ * structure like command buffer and BSSID list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_allocate_adapter(pmlan_adapter pmadapter)
+{
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 buf_size;
+ BSSDescriptor_t *ptemp_scan_table;
+ t_u8 *head_ptr = MNULL;
+
+ ENTER();
+
+ /* Allocate buffer to store the BSSID list */
+ buf_size = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+ ret =
+ pmadapter->callbacks.moal_malloc(buf_size,
+ (t_u8 **) & ptemp_scan_table);
+ if (ret != MLAN_STATUS_SUCCESS || !ptemp_scan_table) {
+ PRINTM(MERROR, "Failed to allocate scan table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pscan_table = ptemp_scan_table;
+
+ /* Initialize cmd_free_q */
+ util_init_list_head(&pmadapter->cmd_free_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_pending_q */
+ util_init_list_head(&pmadapter->cmd_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize scan_pending_q */
+ util_init_list_head(&pmadapter->scan_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ /* Allocate command buffer */
+ ret = wlan_alloc_cmd_buffer(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate command buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; ++i) {
+ util_init_list_head(&pmadapter->bssprio_tbl[i].bssprio_head,
+ MTRUE, pmadapter->callbacks.moal_init_lock);
+
+ pmadapter->bssprio_tbl[i].bssprio_cur = MNULL;
+ }
+ ret =
+ pmadapter->callbacks.moal_malloc(MAX_MP_REGS + HEADER_ALIGNMENT,
+ (t_u8 **) & pmadapter->mp_regs_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mp_regs_buf) {
+ PRINTM(MERROR, "Failed to allocate mp_regs_buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->mp_regs =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mp_regs_buf, HEADER_ALIGNMENT);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ ret = wlan_alloc_sdio_mpa_buffers(pmadapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
+ SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ pmadapter->psleep_cfm =
+ wlan_alloc_mlan_buffer(&pmadapter->callbacks,
+ HEADER_ALIGNMENT +
+ sizeof(opt_sleep_confirm_buffer));
+
+ if (pmadapter->psleep_cfm) {
+ head_ptr =
+ (t_u8 *) ALIGN_ADDR(pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset,
+ HEADER_ALIGNMENT);
+ pmadapter->psleep_cfm->data_offset +=
+ (t_u32) (head_ptr -
+ (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes the adapter structure
+ * and sets default values to the members of adapter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_init_adapter(pmlan_adapter pmadapter)
+{
+ int i;
+
+ opt_sleep_confirm_buffer *sleep_cfm_buf = MNULL;
+
+ ENTER();
+ sleep_cfm_buf = (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->
+ data_offset);
+
+ pmadapter->cmd_sent = MFALSE;
+ pmadapter->data_sent = MTRUE;
+ pmadapter->mp_rd_bitmap = 0;
+ pmadapter->mp_wr_bitmap = 0;
+ pmadapter->curr_rd_port = 1;
+ pmadapter->curr_wr_port = 1;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ pmadapter->tx_eligibility[i] = 1;
+ }
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ pmadapter->mpa_tx.buf_len = 0;
+ pmadapter->mpa_tx.pkt_cnt = 0;
+ pmadapter->mpa_tx.start_port = 0;
+
+ pmadapter->mpa_tx.enabled = 0;
+ pmadapter->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ pmadapter->mpa_rx.buf_len = 0;
+ pmadapter->mpa_rx.pkt_cnt = 0;
+ pmadapter->mpa_rx.start_port = 0;
+
+ pmadapter->mpa_rx.enabled = 0;
+ pmadapter->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ pmadapter->cmd_resp_received = MFALSE;
+ pmadapter->event_received = MFALSE;
+ pmadapter->data_received = MFALSE;
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+
+ /* PnP and power profile */
+ pmadapter->surprise_removed = MFALSE;
+
+ /* Status variables */
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->need_to_wakeup = MFALSE;
+
+ /* Scan type */
+ pmadapter->scan_type = HostCmd_SCAN_TYPE_ACTIVE;
+ /* Scan mode */
+ pmadapter->scan_mode = HostCmd_BSS_MODE_ANY;
+ /* Scan time */
+ pmadapter->specific_scan_time = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+ pmadapter->active_scan_time = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ pmadapter->passive_scan_time = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+
+ pmadapter->num_in_scan_table = 0;
+ memset(pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->scan_probes = 0;
+
+ memset(pmadapter->bcn_buf, 0, sizeof(pmadapter->bcn_buf));
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ pmadapter->radio_on = RADIO_ON;
+ pmadapter->multiple_dtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ pmadapter->local_listen_interval = 0; /* default value in firmware
+ will be used */
+
+ pmadapter->is_deep_sleep = MFALSE;
+
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->delay_to_ps = 100;
+ pmadapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+ pmadapter->pm_wakeup_card_req = MFALSE;
+
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+
+ pmadapter->max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ pmadapter->tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+
+ pmadapter->is_hs_configured = MFALSE;
+ pmadapter->hs_cfg.params.hs_config.conditions = HOST_SLEEP_CFG_CANCEL;
+ pmadapter->hs_cfg.params.hs_config.gpio = 0;
+ pmadapter->hs_cfg.params.hs_config.gap = 0;
+ pmadapter->hs_activated = MFALSE;
+
+ memset(pmadapter->event_body, 0, sizeof(pmadapter->event_body));
+ pmadapter->hw_dot_11n_dev_cap = 0;
+ pmadapter->hw_dev_mcs_support = 0;
+ pmadapter->usr_dot_11n_dev_cap = 0;
+ pmadapter->usr_dev_mcs_support = 0;
+ pmadapter->chan_offset = 0;
+ pmadapter->adhoc_11n_enabled = MFALSE;
+
+ /* Initialize 802.11d */
+ wlan_11d_init(pmadapter);
+
+ wlan_meas_init(pmadapter);
+
+ wlan_11h_init(pmadapter);
+
+ wlan_wmm_init(pmadapter);
+ if (pmadapter->psleep_cfm) {
+ pmadapter->psleep_cfm->buf_type = MLAN_BUF_TYPE_CMD;
+ pmadapter->psleep_cfm->data_len = sizeof(HostCmd_DS_COMMAND);
+ memset(&sleep_cfm_buf->ps_cfm_sleep, 0, sizeof(HostCmd_DS_COMMAND));
+ sleep_cfm_buf->ps_cfm_sleep.command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->ps_cfm_sleep.size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_COMMAND));
+ sleep_cfm_buf->ps_cfm_sleep.result = 0;
+ sleep_cfm_buf->ps_cfm_sleep.params.psmode_enh.action =
+ wlan_cpu_to_le16(SLEEP_CONFIRM);
+ }
+ memset(&pmadapter->sleep_params, 0, sizeof(pmadapter->sleep_params));
+ memset(&pmadapter->sleep_period, 0, sizeof(pmadapter->sleep_period));
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->null_pkt_interval = 0;
+ pmadapter->fw_bands = 0;
+ pmadapter->config_bands = 0;
+ pmadapter->adhoc_start_band = 0;
+ pmadapter->pscan_channels = MNULL;
+ pmadapter->fw_release_number = 0;
+ pmadapter->fw_cap_info = 0;
+ memset(&pmadapter->upld_buf, 0, sizeof(pmadapter->upld_buf));
+ pmadapter->upld_len = 0;
+ pmadapter->event_cause = 0;
+ memset(&pmadapter->region_channel, 0, sizeof(pmadapter->region_channel));
+ pmadapter->region_code = 0;
+ pmadapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+ pmadapter->adhoc_awake_period = 0;
+ memset(&pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ pmadapter->arp_filter_size = 0;
+
+ LEAVE();
+ return;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function initializes firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+mlan_status
+wlan_init_fw(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ t_u8 i = 0;
+ t_u8 first_sta = MTRUE;
+
+ ENTER();
+
+ /* Allocate memory for member of adapter structure */
+ ret = wlan_allocate_adapter(pmadapter);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+
+ /* Initialize private structure */
+ wlan_init_priv(priv);
+
+ if ((ret = wlan_add_bsspriotbl(pmadapter, i))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ ret =
+ pmadapter->priv[i]->ops.init_cmd(pmadapter->priv[i],
+ first_sta);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ first_sta = MFALSE;
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif
+
+ if (util_peek_list(&pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ /* Send the first command in queue and return */
+ if (mlan_main_process(pmadapter) == MLAN_STATUS_FAILURE)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of adapter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_adapter(pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmadapter) {
+ PRINTM(MERROR, "The adapter is MNULL.\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_cancel_all_pending_cmd(pmadapter);
+ /* Free command buffer */
+ PRINTM(MINFO, "Free Command buffer\n");
+ wlan_free_cmd_buffer(pmadapter);
+
+ util_free_list_head(&pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head(&pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head(&pmadapter->scan_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmlan_cmd_timer);
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+
+ PRINTM(MINFO, "Free ScanTable\n");
+ if (pmadapter->pscan_table) {
+ pcb->moal_mfree((t_u8 *) pmadapter->pscan_table);
+ pmadapter->pscan_table = MNULL;
+ }
+
+ if (pmadapter->mp_regs_buf) {
+ pcb->moal_mfree((t_u8 *) pmadapter->mp_regs_buf);
+ pmadapter->mp_regs_buf = MNULL;
+ pmadapter->mp_regs = MNULL;
+ }
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ wlan_free_sdio_mpa_buffers(pmadapter);
+#endif
+ wlan_free_mlan_buffer(&pmadapter->callbacks, pmadapter->psleep_cfm);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief The cmdresp handler calls this function for init_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization callback succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware initialization callback failed.
+ */
+mlan_status
+wlan_init_fw_complete(IN pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Check if hardware is ready */
+ if (pmadapter->hw_status != WlanHardwareStatusReady)
+ status = MLAN_STATUS_FAILURE;
+
+ LEAVE();
+ /* Invoke callback */
+ return pcb->moal_init_fw_complete(pmadapter->pmoal_handle, status);
+}
+
+/**
+ * @brief The cmdresp handler calls this function for shutdown_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown callback succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware shutdown callback failed.
+ */
+mlan_status
+wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ pmadapter->hw_status = WlanHardwareStatusNotReady;
+ /* Invoke callback */
+ return pcb->moal_shutdown_fw_complete(pmadapter->pmoal_handle, status);
+}
+
+/**
+ * @brief This function deletes the BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_delete_bsspriotbl(pmlan_private priv)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio_node, *ptmp_node;
+ pmlan_list_head phead;
+
+ ENTER();
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; ++i) {
+ phead = &pmadapter->bssprio_tbl[i].bssprio_head;
+ if (phead) {
+ pbssprio_node = (mlan_bssprio_node *) util_peek_list(phead,
+ pmadapter->
+ callbacks.
+ moal_spin_lock,
+ pmadapter->
+ callbacks.
+ moal_spin_unlock);
+ while (pbssprio_node && ((pmlan_list_head) pbssprio_node != phead)) {
+ ptmp_node = pbssprio_node->pnext;
+ if (pbssprio_node->priv == priv) {
+ util_unlink_list(phead,
+ (pmlan_linked_list) pbssprio_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pmadapter->callbacks.moal_mfree((t_u8 *) pbssprio_node);
+ }
+ pbssprio_node = ptmp_node;
+ }
+ }
+ }
+
+ LEAVE();
+}
diff --git a/wlan_src/mlan/mlan_init.h b/wlan_src/mlan/mlan_init.h
new file mode 100755
index 0000000..742f1b8
--- /dev/null
+++ b/wlan_src/mlan/mlan_init.h
@@ -0,0 +1,76 @@
+/** @file mlan_init.h
+ *
+ * @brief This file defines the FW initialization data
+ * structures.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_INIT_H_
+#define _MLAN_INIT_H_
+
+/** Tx buffer size for firmware download*/
+#define FW_DNLD_TX_BUF_SIZE 620
+/** Rx buffer size for firmware download*/
+#define FW_DNLD_RX_BUF_SIZE 2048
+/** Max firmware retry */
+#define MAX_FW_RETRY 3
+
+/** Firmware has last block */
+#define FW_HAS_LAST_BLOCK 0x00000004
+
+/** Firmware data transmit size */
+#define FW_DATA_XMIT_SIZE \
+ sizeof(FWHeader) + DataLength + sizeof(t_u32)
+
+/** FWHeader */
+typedef struct _FWHeader
+{
+ /** FW download command */
+ t_u32 dnld_cmd;
+ /** FW base address */
+ t_u32 base_addr;
+ /** FW data length */
+ t_u32 data_length;
+ /** FW CRC */
+ t_u32 crc;
+} FWHeader;
+
+/** FWData */
+typedef struct _FWData
+{
+ /** FW data header */
+ FWHeader fw_header;
+ /** FW data sequence number */
+ t_u32 seq_num;
+ /** FW data buffer */
+ t_u8 data[1];
+} FWData;
+
+/** FWSyncHeader */
+typedef struct _FWSyncHeader
+{
+ /** FW sync header command */
+ t_u32 cmd;
+ /** FW sync header sequence number */
+ t_u32 seq_num;
+} FWSyncHeader;
+
+#ifdef BIG_ENDIAN
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x); { \
+ (x)->cmd = wlan_le32_to_cpu((x)->cmd); \
+ (x)->seq_num = wlan_le32_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x)
+#endif /* BIG_ENDIAN */
+
+#endif /* _MLAN_INIT_H_ */
diff --git a/wlan_src/mlan/mlan_ioctl.h b/wlan_src/mlan/mlan_ioctl.h
new file mode 100755
index 0000000..bdf5342
--- /dev/null
+++ b/wlan_src/mlan/mlan_ioctl.h
@@ -0,0 +1,1829 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid
+{
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+/** Enumeration for IOCTL request ID */
+enum
+{
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL,
+ MLAN_OID_SCAN_SPECIFIC_SSID,
+ MLAN_OID_SCAN_USER_CONFIG,
+ MLAN_OID_SCAN_CONFIG,
+
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START,
+ MLAN_OID_BSS_STOP,
+ MLAN_OID_BSS_MODE,
+ MLAN_OID_BSS_CHANNEL,
+ MLAN_OID_BSS_CHANNEL_LIST,
+ MLAN_OID_BSS_MAC_ADDR,
+ MLAN_OID_BSS_MULTICAST_LIST,
+ MLAN_OID_BSS_FIND_BSS,
+ MLAN_OID_IBSS_BCN_INTERVAL,
+ MLAN_OID_IBSS_ATIM_WINDOW,
+ MLAN_OID_IBSS_CHANNEL,
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL,
+ MLAN_OID_BAND_CFG,
+ MLAN_OID_ANT_CFG,
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS,
+ MLAN_OID_GET_SIGNAL,
+ MLAN_OID_GET_FW_INFO,
+ MLAN_OID_GET_VER_EXT,
+ MLAN_OID_GET_BSS_INFO,
+ MLAN_OID_GET_DEBUG_INFO,
+
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE,
+ MLAN_OID_SEC_CFG_WPA_ENABLED,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ MLAN_OID_SEC_CFG_PASSPHRASE,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED,
+ MLAN_OID_SEC_CFG_ESUPP_MODE,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG,
+ MLAN_OID_GET_DATA_RATE,
+ MLAN_OID_SUPPORTED_RATES,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG,
+ MLAN_OID_POWER_CFG_EXT,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS,
+ MLAN_OID_PM_CFG_HS_CFG,
+ MLAN_OID_PM_CFG_INACTIVITY_TO,
+ MLAN_OID_PM_CFG_DEEP_SLEEP,
+ MLAN_OID_PM_CFG_SLEEP_PD,
+ MLAN_OID_PM_CFG_PS_CFG,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE,
+ MLAN_OID_WMM_CFG_QOS,
+ MLAN_OID_TID_ELIG_TBL,
+ MLAN_OID_WMM_CFG_ADDTS,
+ MLAN_OID_WMM_CFG_DELTS,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG,
+ MLAN_OID_WMM_CFG_QUEUE_STATS,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS,
+ MLAN_OID_WMM_CFG_TS_STATUS,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX,
+ MLAN_OID_11N_HTCAP_CFG,
+ MLAN_OID_11N_CFG_ADDBA_REJECT,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL,
+ MLAN_OID_11N_CFG_ADDBA_PARAM,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+ MLAN_OID_11D_CFG_ENABLE,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW,
+ MLAN_OID_EEPROM_RD,
+ MLAN_OID_MEM_RW,
+
+ /* Bluetooth Coalescing Configuration Group */
+ MLAN_IOCTL_BCA_CFG = 0x000F0000,
+ MLAN_OID_BCA_TS,
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE,
+ MLAN_OID_MISC_REGION,
+ MLAN_OID_MISC_WARM_RESET,
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ MLAN_OID_MISC_SDIO_MPA_CTRL,
+#endif
+#ifdef MFG_CMD_SUPPORT
+ MLAN_OID_MISC_MFG_CMD,
+#endif
+ MLAN_OID_MISC_HOST_CMD,
+ MLAN_OID_MISC_LDO,
+ MLAN_OID_MISC_SYS_CLOCK,
+ MLAN_OID_MISC_WWS,
+ MLAN_OID_MISC_VS_IE,
+ MLAN_OID_MISC_INIT_SHUTDOWN,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum
+{
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL
+};
+
+/** Enumeration for generic enable/disable */
+enum
+{
+ MLAN_ACT_DISABLE = 0,
+ MLAN_ACT_ENABLE = 1
+};
+
+/** Enumeration for scan mode */
+enum
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum
+{
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE
+};
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows starting at bssInfoBuffer
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ t_u8 bss_info_buffer[1];
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params
+{
+ /** Scan channel time for specific scan */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan
+{
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req
+{
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp
+{
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg
+{
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union
+ {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum
+{
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum atim window */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list
+{
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Maximum channel number */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq
+{
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list
+{
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */
+typedef struct _mlan_ssid_bssid
+{
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+} mlan_ssid_bssid;
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union
+ {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/** Enumeration for band */
+enum
+{
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg
+{
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union
+ {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ t_u32 antenna;
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union
+ {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum
+{
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED
+};
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats
+{
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal
+{
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info
+{
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext
+{
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info
+{
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level */
+ t_u32 max_power_level;
+ /** Min power level */
+ t_u32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info
+{
+ /** Corresponds to IntCounter member of mlan_adapter */
+ t_u32 int_counter;
+ /** Corresponds to packets_out member of mlan_adapter.wmm */
+ t_u32 packets_out[MAX_NUM_TID];
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_BASTREAM_SUPPORTED];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u16 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u16 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+} mlan_debug_info, *pmlan_debug_info;
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info
+{
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union
+ {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ mlan_debug_info debug_info;
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum
+{
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/** Enumeration for encryption mode */
+enum
+{
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+};
+
+/** Enumeration for PSK */
+enum
+{
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** Maximum PMK length */
+#define MLAN_MAX_PMK_LENGTH 32
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+#define PN_SIZE 16
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key
+{
+ /** Key disable */
+ t_u32 key_disable;
+ /** Key index */
+ t_u32 key_index;
+ /** Current WEP key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t
+{
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t
+{
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_PMK_LENGTH];
+} mlan_pmk_t;
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase
+{
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union
+ {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode
+{
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union
+ {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** Enumeration for rate type */
+enum
+{
+ MLAN_RATE_INDEX,
+ MLAN_RATE_VALUE
+};
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t
+{
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type */
+ t_u32 rate_type;
+ /** Rate index or rate value if fixed rate */
+ t_u32 rate;
+} mlan_rate_cfg_t;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate
+{
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union
+ {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t
+{
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level */
+ t_u32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+
+/** The HT BW40 bit in Tx rate index */
+#define TX_RATE_HT_BW40_BIT MBIT(7)
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext
+{
+ /** Length of power_data */
+ t_u32 len;
+ /** Buffer of power configuration data */
+ t_u32 power_data[MAX_POWER_TABLE_SIZE];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union
+ {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg
+{
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: non-unicast data
+ * Bit1: unicast data
+ * Bit2: mac events
+ * Bit3: magic packet
+ */
+ t_u32 conditions;
+ /** GPIO */
+ t_u32 gpio;
+ /** Gap in milliseconds */
+ t_u32 gap;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time for auto deep sleep */
+#define DEEP_SLEEP_ILDE_TIME 100
+
+typedef struct _mlan_ds_auto_ds
+{
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */
+typedef struct _mlan_ds_inactivity_to
+{
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Minimum multiple DTIM */
+#define MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define IGNORE_MULTIPLE_DTIM 65534
+
+/** Minimum listen interval */
+#define MIN_LISTEN_INTERVAL 0
+
+/** Minimum adhoc awake period */
+#define MIN_ADHOC_AWAKE_PD 0
+/** Maximum adhoc awake period */
+#define MAX_ADHOC_AWAKE_PD 31
+/** Special adhoc awake period */
+#define SPECIAL_ADHOC_AWAKE_PD 255
+
+/** Minimum beacon miss timeout */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS */
+#define MAX_DELAY_TO_PS 65535
+/* Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg
+{
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Adhoc awake period */
+ t_u32 adhoc_awake_period;
+ /** Beacon miss timeout */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params
+{
+ /** Error */
+ t_u32 error;
+ /** Offset */
+ t_u32 offset;
+ /** Stable time */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union
+ {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+ mlan_ds_sleep_params sleep_params;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+ t_u8 tspec_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the ADDTS */
+ t_u8 addts_extra_ie_buf[MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< ADDTS extra IE buffer */
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u8 tspec_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} wlan_ioctl_wmm_ts_status_t,
+/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts
+{
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u8 tspec_data_len;
+ /** TSPEC to send in the ADDTS */
+ t_u8 tspec_data[MLAN_WMM_TSPEC_SIZE];
+ /** ADDTS extra IE buffer */
+ t_u8 extra_ie_buf[MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts
+{
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 tspec_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 tspec_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+typedef struct _mlan_ds_wmm_queue_config
+{
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union
+ {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** Set/get tid multi-port eligibility table for MLAN_OID_TID_ELIG_TBL */
+ t_u32 tid_tbl[MAX_NUM_TID];
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum
+{
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union
+ {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+typedef struct _mlan_ds_11n_addba_param
+{
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg
+{
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl
+{
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+typedef struct _mlan_ds_11n_aggr_prio_tbl
+{
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union
+ {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ t_u32 htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union
+ {
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for register type */
+enum
+{
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_PMIC,
+ MLAN_REG_CAU,
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw
+{
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom
+{
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw
+{
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union
+ {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** BCA Configuration Group */
+/*-----------------------------------------------------------------*/
+/** BCA Traffic type low */
+#define TRAFFIC_TYPE_LOW 0x0
+/** BCA Traffic type high */
+#define TRAFFIC_TYPE_HIGH 0x1
+/** BCA Traffic type medium */
+#define TRAFFIC_TYPE_MEDIUM 0x02
+/** BCA Traffic type medium high */
+#define TRAFFIC_TYPE_MEDIUMHIGH 0x03
+/** BCA Reset Traffic type */
+#define TRAFFIC_TYPE_RESET 0xffff
+/** BCA Minimum Timeshare interval value */
+#define MIN_TIMESHARE_INTERVAL 20
+/** BCA Maximum Timeshare interval value */
+#define MAX_TIMESHARE_INTERVAL 60000
+
+/** Type definition of mlan_ds_bca_ts for MLAN_OID_BCA_TS */
+typedef struct _mlan_ds_bca_ts
+{
+ /** Type: WLAN, BT */
+ t_u32 traffic_type;
+ /** Interval: 20msec - 60000msec */
+ t_u32 timeshare_interval;
+ /** PTA arbiter time in msec */
+ t_u32 bt_time;
+} mlan_ds_bca_ts;
+
+/** Type definition of mlan_ds_bca_cfg for MLAN_IOCTL_BCA_CFG */
+typedef struct _mlan_ds_bca_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BCA parameters */
+ union
+ {
+ /** BCS time share for MLAN_OID_BCA_TS */
+ mlan_ds_bca_ts bca_ts;
+ } param;
+} mlan_ds_bca_cfg, *pmlan_ds_bca_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER 2048
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum
+{
+ MLAN_IE_TYPE_GEN_IE = 0,
+ MLAN_IE_TYPE_ARP_FILTER,
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie
+{
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl
+{
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd
+{
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock
+{
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Maximum length of Vendor specific IE */
+#define MLAN_MAX_VSIE_LEN (256)
+/** Maximum number of Vendor specific IE */
+#define MLAN_MAX_VSIE_NUM (8)
+/** VSIE bit mask for scan */
+#define MLAN_VSIE_MASK_SCAN 0x01
+/** VSIE bit mask for associate */
+#define MLAN_VSIE_MASK_ASSOC 0x02
+/** VSIE bit mask for adhoc */
+#define MLAN_VSIE_MASK_ADHOC 0x04
+
+/** Type definition of mlan_ds_misc_vs_ie for MLAN_OID_MISC_VS_IE */
+typedef struct _mlan_ds_misc_vs_ie
+{
+ /** Position in the vendor specific IE array */
+ t_u32 id;
+ /** Bit 0-2: scan/assoc/ad-hoc */
+ t_u32 mask;
+ /** Information element */
+ t_u8 ie[MLAN_MAX_VSIE_LEN];
+} mlan_ds_misc_vs_ie;
+
+/** Enumeration for function init/shutdown */
+enum
+{
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union
+ {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+#ifdef MFG_CMD_SUPPORT
+ /** Mfg command for MLAN_OID_MISC_MFG_CMD */
+ mlan_ds_misc_cmd mfgcmd;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** LDO configuration for MLAN_OID_MISC_LDO */
+ t_u16 ldo_cfg;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Get/add/delete VSIE for MLAN_OID_MISC_VS_IE */
+ mlan_ds_misc_vs_ie vsie;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/wlan_src/mlan/mlan_join.c b/wlan_src/mlan/mlan_join.c
new file mode 100755
index 0000000..bd503a9
--- /dev/null
+++ b/wlan_src/mlan/mlan_join.c
@@ -0,0 +1,1740 @@
+/** @file mlan_join.c
+ *
+ * @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ * @sa mlan_join.h
+ */
+
+/******************************************************
+Change log:
+ 10/30/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_generic_ie(mlan_private * priv, t_u8 ** ppbuffer)
+{
+ int ret_len = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ /* Null Checks */
+ if (!ppbuffer)
+ return 0;
+ if (!(*ppbuffer))
+ return 0;
+
+ /*
+ * If there is a generic ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->gen_ie_buf_len) {
+ PRINTM(MINFO, "append generic %d to %p\n", priv->gen_ie_buf_len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(priv->gen_ie_buf_len);
+ memcpy(*ppbuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the generic IE buffer to the output buffer, advance pointer */
+ memcpy(*ppbuffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += priv->gen_ie_buf_len;
+ ret_len += priv->gen_ie_buf_len;
+
+ /* Reset the generic IE buffer */
+ priv->gen_ie_buf_len = 0;
+ }
+
+ /* return the length appended to the buffer */
+ return ret_len;
+}
+
+/**
+ * @brief Append TSF tracking info from the scan table for the target AP
+ *
+ * This function is called from the network join command prep. routine.
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ * - the TSF of the target AP from its previous beacon/probe response
+ * - the TSF timestamp of our local MAC at the time we observed the
+ * beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ppbuffer A pointer to command buffer pointer
+ * @param pbss_desc A pointer to the BSS Descriptor from the scan table of
+ * the AP we are trying to join
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_tsf_tlv(mlan_private * pmriv, t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ MrvlIEtypes_TsfTimestamp_t tsf_tlv;
+ t_u64 tsf_val;
+
+ /* Null Checks */
+ if (ppbuffer == 0)
+ return 0;
+ if (*ppbuffer == 0)
+ return 0;
+
+ memset(&tsf_tlv, 0x00, sizeof(MrvlIEtypes_TsfTimestamp_t));
+
+ tsf_tlv.header.type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+ tsf_tlv.header.len = wlan_cpu_to_le16(2 * sizeof(tsf_val));
+
+ memcpy(*ppbuffer, &tsf_tlv, sizeof(tsf_tlv.header));
+ *ppbuffer += sizeof(tsf_tlv.header);
+
+ /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
+ tsf_val = wlan_cpu_to_le64(pbss_desc->network_tsf);
+ memcpy(*ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ memcpy(&tsf_val, pbss_desc->time_stamp, sizeof(tsf_val));
+
+ PRINTM(MINFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
+ tsf_val, pbss_desc->network_tsf);
+
+ memcpy(*ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ return (sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)));
+}
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_common_rates(IN mlan_private * pmpriv,
+ IN t_u8 * rate1,
+ IN t_u32 rate1_size, IN t_u8 * rate2, IN t_u32 rate2_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ t_u8 *ptr = rate1;
+ t_u8 *tmp = MNULL;
+ t_u32 i, j;
+
+ ENTER();
+
+ ret = pcb->moal_malloc(rate1_size, &tmp);
+ if (ret != MLAN_STATUS_SUCCESS || !tmp) {
+ PRINTM(MERROR, "Failed to allocate buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memcpy(tmp, rate1, rate1_size);
+ memset(rate1, 0, rate1_size);
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ for (j = 0; tmp[j] && j < rate1_size; j++) {
+ /* Check common rate, excluding the bit for basic rate */
+ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+ *rate1++ = tmp[j];
+ break;
+ }
+ }
+ }
+
+ HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+ HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+ HEXDUMP("Common Rates", ptr, rate1 - ptr);
+ PRINTM(MINFO, "Tx DataRate is set to 0x%X\n", pmpriv->data_rate);
+
+ if (!pmpriv->is_data_rate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == pmpriv->data_rate) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ ptr++;
+ }
+ PRINTM(MMSG, "Previously set fixed data rate %#x is not "
+ "compatible with the network\n", pmpriv->data_rate);
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmp)
+ pcb->moal_mfree(tmp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create the intersection of the rates supported by a target BSS and
+ * our pmadapter settings for use in an assoc/join command.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc BSS Descriptor whose rates are used in the setup
+ * @param pout_rates Output: Octet array of rates common between the BSS
+ * and the pmadapter supported rates settings
+ * @param pout_rates_size Output: Number of rates/octets set in pout_rates
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_setup_rates_from_bssdesc(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 * pout_rates,
+ OUT t_u32 * pout_rates_size)
+{
+ t_u8 card_rates[WLAN_SUPPORTED_RATES];
+ t_u32 card_rates_size = 0;
+ ENTER();
+ /* Copy AP supported rates */
+ memcpy(pout_rates, pbss_desc->supported_rates, WLAN_SUPPORTED_RATES);
+ /* Get the STA supported rates */
+ card_rates_size = wlan_get_active_data_rates(pmpriv, card_rates);
+ /* Get the common rates between AP and STA supported rates */
+ if (wlan_get_common_rates(pmpriv, pout_rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ *pout_rates_size = 0;
+ PRINTM(MERROR, "wlan_get_common_rates failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *pout_rates_size =
+ MIN(wlan_strlen((char *) pout_rates), WLAN_SUPPORTED_RATES);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pnew_bss_desc A pointer to the newly associated AP's scan table entry
+ *
+ * @return N/A
+ */
+static t_void
+wlan_update_tsf_timestamps(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pnew_bss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 table_idx;
+ t_u64 new_tsf_base;
+ t_s64 tsf_delta;
+
+ ENTER();
+
+ memcpy(&new_tsf_base, pnew_bss_desc->time_stamp, sizeof(new_tsf_base));
+
+ tsf_delta = new_tsf_base - pnew_bss_desc->network_tsf;
+
+ PRINTM(MINFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+ pnew_bss_desc->network_tsf, new_tsf_base);
+
+ for (table_idx = 0; table_idx < pmadapter->num_in_scan_table; table_idx++) {
+ pmadapter->pscan_table[table_idx].network_tsf += tsf_delta;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Append a wapi IE
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a wapi TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppBuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_wapi_ie(mlan_private * priv, t_u8 ** ppBuffer)
+{
+ int retLen = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ /* Null Checks */
+ if (ppBuffer == 0)
+ return 0;
+ if (*ppBuffer == 0)
+ return 0;
+
+ /*
+ * If there is a wapi ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wapi_ie_len) {
+ PRINTM(MCMND, "append wapi ie %d to %p\n", priv->wapi_ie_len,
+ *ppBuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header.len = wlan_cpu_to_le16(priv->wapi_ie_len);
+ memcpy(*ppBuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += sizeof(ie_header);
+ retLen += sizeof(ie_header);
+
+ /* Copy the wapi IE buffer to the output buffer, advance pointer */
+ memcpy(*ppBuffer, priv->wapi_ie, priv->wapi_ie_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += priv->wapi_ie_len;
+ retLen += priv->wapi_ie_len;
+
+ }
+ /* return the length appended to the buffer */
+ return retLen;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepares command of association.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of BSSDescriptor_t from the
+ * scan table to assoc
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11_ASSOCIATE *passo = &cmd->params.associate;
+ BSSDescriptor_t *pbss_desc;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv;
+ MrvlIEtypes_PhyParamSet_t *pphy_tlv;
+ MrvlIEtypes_SsParamSet_t *pss_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ MrvlIEtypes_AuthType_t *pauth_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ t_u16 tmp_cap;
+ t_u8 *pos;
+
+ ENTER();
+
+ pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ pos = (t_u8 *) passo;
+
+ wlan_cfg_tx_buf(pmpriv, pbss_desc);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ memcpy(passo->peer_sta_addr,
+ pbss_desc->mac_address, sizeof(passo->peer_sta_addr));
+ pos += sizeof(passo->peer_sta_addr);
+
+ /* Set the listen interval */
+ passo->listen_interval = wlan_cpu_to_le16(pmpriv->listen_interval);
+ /* Set the beacon period */
+ passo->beacon_period = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ pos += sizeof(passo->cap_info);
+ pos += sizeof(passo->listen_interval);
+ pos += sizeof(passo->beacon_period);
+ pos += sizeof(passo->dtim_period);
+
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len = (t_u16) pbss_desc->ssid.ssid_len;
+ memcpy(pssid_tlv->ssid, pbss_desc->ssid.ssid, pssid_tlv->header.len);
+ pos += sizeof(pssid_tlv->header) + pssid_tlv->header.len;
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+
+ pphy_tlv = (MrvlIEtypes_PhyParamSet_t *) pos;
+ pphy_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+ pphy_tlv->header.len = sizeof(pphy_tlv->fh_ds.ds_param_set);
+ memcpy(&pphy_tlv->fh_ds.ds_param_set,
+ &pbss_desc->phy_param_set.ds_param_set.current_chan,
+ sizeof(pphy_tlv->fh_ds.ds_param_set));
+ pos += sizeof(pphy_tlv->header) + pphy_tlv->header.len;
+ pphy_tlv->header.len = wlan_cpu_to_le16(pphy_tlv->header.len);
+
+ pss_tlv = (MrvlIEtypes_SsParamSet_t *) pos;
+ pss_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CF);
+ pss_tlv->header.len = sizeof(pss_tlv->cf_ibss.cf_param_set);
+ pos += sizeof(pss_tlv->header) + pss_tlv->header.len;
+ pss_tlv->header.len = wlan_cpu_to_le16(pss_tlv->header.len);
+
+ /* Get the common rates supported between the driver and the BSS Desc */
+ if (wlan_setup_rates_from_bssdesc(pmpriv, pbss_desc, rates, &rates_size)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the data rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(&pmpriv->curr_bss_params.data_rates, rates, rates_size);
+
+ /* Setup the Rates TLV in the association command */
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(prates_tlv->rates, rates, rates_size);
+ pos += sizeof(prates_tlv->header) + rates_size;
+ PRINTM(MINFO, "ASSOC_CMD: Rates size = %d\n", rates_size);
+
+ /* Add the Authentication type to be used for Auth frames if needed */
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO) {
+ pauth_tlv = (MrvlIEtypes_AuthType_t *) pos;
+ pauth_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ pauth_tlv->header.len = sizeof(pauth_tlv->auth_type);
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16((t_u16) pmpriv->sec_info.authentication_mode);
+ else
+ pauth_tlv->auth_type = wlan_cpu_to_le16(MLAN_AUTH_MODE_OPEN);
+ pos += sizeof(pauth_tlv->header) + pauth_tlv->header.len;
+ pauth_tlv->header.len = wlan_cpu_to_le16(pauth_tlv->header.len);
+ }
+
+ if (IS_SUPPORT_MULTI_BANDS(pmpriv->adapter)
+ && !(ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
+ && (pmpriv->adapter->config_bands & BAND_GN
+ || pmpriv->adapter->config_bands & BAND_AN)
+ && (pbss_desc->pht_cap)
+ )
+ ) {
+ /* Append a channel TLV for the channel the attempted AP was found on */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pchan_tlv->chan_scan_param, 0x00, sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "Assoc: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "Assoc: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+ if (!pmpriv->wps.session_enable) {
+ if ((pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE
+ or
+ WPA2_IE
+ */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
+ && (pmpriv->adapter->config_bands & BAND_GN
+ || pmpriv->adapter->config_bands & BAND_AN))
+ wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ /** Append vendor specific IE TLV */
+ wlan_cmd_append_vsie_tlv(pmpriv, MLAN_VSIE_MASK_ASSOC, &pos);
+
+ wlan_wmm_process_association_req(pmpriv, &pos, &pbss_desc->wmm_ie,
+ pbss_desc->pht_cap);
+ if (pmpriv->sec_info.wapi_enabled && pmpriv->wapi_ie_len) {
+ wlan_cmd_append_wapi_ie(pmpriv, &pos);
+ }
+
+ wlan_cmd_append_generic_ie(pmpriv, &pos);
+
+ wlan_cmd_append_tsf_tlv(pmpriv, &pos, pbss_desc);
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so adhoc/infra 11h
+ * behavior can be properly triggered. pos modified if data is appended
+ */
+ wlan_11h_process_join(pmpriv, &pos, &passo->cap_info,
+ pbss_desc->phy_param_set.ds_param_set.current_chan,
+ &pbss_desc->wlan_11h_bss_info);
+
+ cmd->size = wlan_cpu_to_le16((t_u16) (pos - (t_u8 *) passo) + S_DS_GEN);
+
+ /* Set the Capability info at last */
+ memcpy(&tmp_cap, &pbss_desc->cap_info, sizeof(passo->cap_info));
+ tmp_cap &= CAPINFO_MASK;
+ PRINTM(MINFO, "ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(&passo->cap_info, &tmp_cap, sizeof(passo->cap_info));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info/Error Return(t_u16): |
+ * | 0xFFFF(-1): Internal error |
+ * | 0xFFFE(-2): Authentication unhandled message |
+ * | 0xFFFD(-3): Authentication refused |
+ * | 0xFFFC(-4): Timeout waiting for AP response |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): |
+ * | If cap_info is -1: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status_code |
+ * | will be set to 1. |
+ * | |
+ * | If cap_info is -2: |
+ * | An authentication frame was received but was |
+ * | not handled by the firmware. IEEE Status |
+ * | code for the failure is returned. |
+ * | |
+ * | If cap_info is -3: |
+ * | An authentication frame was received and the |
+ * | status_code is the IEEE Status reported in the |
+ * | response. |
+ * | |
+ * | If cap_info is -4: |
+ * | (1) Association response timeout |
+ * | (2) Authentication response timeout |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): 0xFFFF |
+ * .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info(t_u16): IEEE Capability |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): IEEE Status Code |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): IEEE Association ID |
+ * .------------------------------------------------------------.
+ * | IEEE IEs(variable): Any received IEs comprising the |
+ * | remaining portion of a received |
+ * | association response frame. |
+ * .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ IEEEtypes_AssocRsp_t *passoc_rsp;
+ BSSDescriptor_t *pbss_desc;
+ t_u8 enable_data = MTRUE;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ passoc_rsp = (IEEEtypes_AssocRsp_t *) & resp->params;
+ passoc_rsp->status_code = wlan_le16_to_cpu(passoc_rsp->status_code);
+
+ HEXDUMP("ASSOC_RESP:", (t_u8 *) & resp->params, (resp->size - S_DS_GEN));
+
+ pmpriv->assoc_rsp_size = MIN(resp->size - S_DS_GEN,
+ sizeof(pmpriv->assoc_rsp_buf));
+
+ memcpy(pmpriv->assoc_rsp_buf, &resp->params, pmpriv->assoc_rsp_size);
+
+ if (passoc_rsp->status_code) {
+ pmpriv->adapter->dbg.num_cmd_assoc_failure++;
+ PRINTM(MERROR, "ASSOC_RESP: Association Failed, "
+ "status code = %d, error = 0x%x, a_id = 0x%x\n",
+ wlan_le16_to_cpu(passoc_rsp->status_code),
+ wlan_le16_to_cpu(*(t_u16 *) & passoc_rsp->capability),
+ wlan_le16_to_cpu(passoc_rsp->a_id));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ /* Set the attempted BSSID Index to current */
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ PRINTM(MINFO, "ASSOC_RESP: %s\n", pbss_desc->ssid.ssid);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ /* Update curr_bss_params */
+ pmpriv->curr_bss_params.bss_descriptor.channel
+ = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ /*
+ * Adjust the timestamps in the scan table to be relative to the newly
+ * associated AP's TSF
+ */
+ wlan_update_tsf_timestamps(pmpriv, pbss_desc);
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE)
+ pmpriv->curr_bss_params.wmm_enabled = MTRUE;
+ else
+ pmpriv->curr_bss_params.wmm_enabled = MFALSE;
+
+ if ((pmpriv->wmm_required
+ || (pbss_desc->pht_cap &&
+ (pbss_desc->pht_cap->ieee_hdr.element_id == HT_CAPABILITY))
+ ) && pmpriv->curr_bss_params.wmm_enabled)
+ pmpriv->wmm_enabled = MTRUE;
+ else
+ pmpriv->wmm_enabled = MFALSE;
+
+ pmpriv->curr_bss_params.wmm_uapsd_enabled = MFALSE;
+
+ if (pmpriv->wmm_enabled == MTRUE)
+ pmpriv->curr_bss_params.wmm_uapsd_enabled
+ = pbss_desc->wmm_ie.qos_info.qos_uapsd;
+
+ PRINTM(MINFO, "ASSOC_RESP: curr_pkt_filter is 0x%x\n",
+ pmpriv->curr_pkt_filter);
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)
+ pmpriv->wpa_is_gtk_set = MFALSE;
+
+ if (pmpriv->wmm_enabled)
+ /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
+ enable_data = MFALSE;
+ else
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ wlan_wmm_setup_queues(pmpriv);
+
+ if (enable_data) {
+ PRINTM(MINFO, "Post association, re-enabling data flow\n");
+ }
+
+ ret =
+ wlan_11d_parse_dnld_countryinfo(pmpriv,
+ &pmpriv->curr_bss_params.
+ bss_descriptor);
+
+ /* Reset SNR/NF/RSSI values */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+ pmpriv->rxpd_rate = 0;
+ pmpriv->rxpd_htinfo = 0;
+
+ wlan_save_curr_bcn(pmpriv);
+
+ pmpriv->adapter->dbg.num_cmd_assoc_success++;
+
+ PRINTM(MINFO, "ASSOC_RESP: Associated\n");
+ pevent->bss_num = pmpriv->bss_num;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy((t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Add the ra_list here for infra mode as there will be only 1 ra always */
+ wlan_ralist_add(pmpriv, pmpriv->curr_bss_params.bss_descriptor.mac_address);
+
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+
+ /* Send OBSS scan param to the application if available */
+ wlan_2040_coex_event(pmpriv);
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (passoc_rsp->status_code)
+ pioctl_req->status_code =
+ wlan_le16_to_cpu(passoc_rsp->status_code);
+ else
+ pioctl_req->status_code = MLAN_ERROR_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_start.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_START *padhoc_start = &cmd->params.adhoc_start;
+ BSSDescriptor_t *pbss_desc;
+ t_u32 cmd_append_size = 0;
+ t_u32 i;
+ t_u16 tmp_cap;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ /* wpa ie for WPA_NONE AES */
+ const t_u8 wpa_ie[24] = { 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
+ 0x00, 0x50, 0xf2, 0x04, 0x01, 0x00, 0x00, 0x50,
+ 0xf2, 0x00, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x00
+ };
+ t_u8 *pos = (t_u8 *) padhoc_start + sizeof(HostCmd_DS_802_11_AD_HOC_START);
+
+ ENTER();
+
+ if (!pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. HostCmd_DS_802_11_AD_HOC_START command
+ * 2. pbss_desc
+ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+ * probe delay, and Cap info.
+ * Firmware will fill up beacon period, Basic rates
+ * and operational rates.
+ */
+
+ memset(padhoc_start->ssid, 0, MLAN_MAX_SSID_LENGTH);
+
+ memcpy(padhoc_start->ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: SSID = %s\n", padhoc_start->ssid);
+
+ memset(pbss_desc->ssid.ssid, 0, MLAN_MAX_SSID_LENGTH);
+ memcpy(pbss_desc->ssid.ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len);
+
+ pbss_desc->ssid.ssid_len = ((mlan_802_11_ssid *) pdata_buf)->ssid_len;
+
+ /* Set the BSS mode */
+ padhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+ pbss_desc->bss_mode = MLAN_BSS_MODE_IBSS;
+ padhoc_start->beacon_period = wlan_cpu_to_le16(pmpriv->beacon_period);
+ pbss_desc->beacon_period = pmpriv->beacon_period;
+
+ /* Set Physical param set */
+/** Parameter IE Id */
+#define DS_PARA_IE_ID 3
+/** Parameter IE length */
+#define DS_PARA_IE_LEN 1
+
+ padhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+ padhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+ if (!wlan_get_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band, (t_u16) pmpriv->adhoc_channel,
+ pmadapter->region_channel)) {
+
+ chan_freq_power_t *cfp;
+ cfp =
+ wlan_get_cfp_by_band_and_channel(pmadapter,
+ pmadapter->adhoc_start_band,
+ FIRST_VALID_CHANNEL,
+ pmadapter->region_channel);
+ if (cfp)
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ }
+
+ ASSERT(pmpriv->adhoc_channel);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+ pmpriv->adhoc_channel);
+
+ pmpriv->curr_bss_params.bss_descriptor.channel = pmpriv->adhoc_channel;
+ pmpriv->curr_bss_params.band = pmadapter->adhoc_start_band;
+
+ pbss_desc->channel = pmpriv->adhoc_channel;
+ padhoc_start->phy_param_set.ds_param_set.current_chan =
+ pmpriv->adhoc_channel;
+
+ memcpy(&pbss_desc->phy_param_set,
+ &padhoc_start->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ pbss_desc->network_type_use = Wlan802_11DS;
+
+ /* Set IBSS param set */
+/** IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID 6
+/** IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN 2
+
+ padhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+ padhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+ padhoc_start->ss_param_set.ibss_param_set.atim_window
+ = wlan_cpu_to_le16(pmpriv->atim_window);
+ pbss_desc->atim_window = pmpriv->atim_window;
+ memcpy(&pbss_desc->ss_param_set,
+ &padhoc_start->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ /* Set Capability info */
+ padhoc_start->cap.ess = 0;
+ padhoc_start->cap.ibss = 1;
+ pbss_desc->cap_info.ibss = 1;
+
+ /* Set up privacy in pbss_desc */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+/** Ad-Hoc capability privacy on */
+#define AD_HOC_CAP_PRIVACY_ON 1
+ PRINTM(MINFO, "ADHOC_S_CMD: wep_status set, Privacy to WEP\n");
+ pbss_desc->privacy = Wlan802_11PrivFilter8021xWEP;
+ padhoc_start->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ PRINTM(MWARN, "ADHOC_S_CMD: wep_status NOT set, Setting "
+ "Privacy to ACCEPT ALL\n");
+ pbss_desc->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ memset(padhoc_start->DataRate, 0, sizeof(padhoc_start->DataRate));
+ wlan_get_active_data_rates(pmpriv, padhoc_start->DataRate);
+ if ((pmadapter->adhoc_start_band & BAND_G) &&
+ (pmpriv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, MNULL, &pmpriv->curr_pkt_filter);
+
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_S_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(padhoc_start->DataRate) && padhoc_start->DataRate[i];
+ i++);
+
+ pmpriv->curr_bss_params.num_of_rates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS rate structure */
+ memcpy(&pmpriv->curr_bss_params.data_rates,
+ &padhoc_start->DataRate, pmpriv->curr_bss_params.num_of_rates);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
+ padhoc_start->DataRate[0], padhoc_start->DataRate[1],
+ padhoc_start->DataRate[2], padhoc_start->DataRate[3]);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pchan_tlv->chan_scan_param, 0x00, sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type(pmpriv->curr_bss_params.band);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ /** Append vendor specific IE TLV */
+ cmd_append_size +=
+ wlan_cmd_append_vsie_tlv(pmpriv, MLAN_VSIE_MASK_ADHOC, &pos);
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, pmpriv->curr_bss_params.band)) {
+ PRINTM(MERROR, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h start API to add any 11h flags/elements as TLV parameters
+ */
+ cmd_append_size += wlan_11h_process_start(pmpriv, &pos, &padhoc_start->cap,
+ pmpriv->adhoc_channel,
+ &pbss_desc->wlan_11h_bss_info);
+
+ if (pmpriv->sec_info.ewpa_enabled) {
+ memcpy(pmpriv->wpa_ie, wpa_ie, sizeof(wpa_ie));
+ pmpriv->wpa_ie_len = sizeof(wpa_ie);
+ }
+
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ WPA2_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "ADHOC_S_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+
+ if (pmadapter->adhoc_11n_enabled == MTRUE) {
+ {
+ pht_cap = (MrvlIETypes_HTCap_t *) pos;
+ memset(pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+ SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+ SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+ SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+ SETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);
+ SETHT_DSSSCCK40(pht_cap->ht_cap.ht_cap_info);
+ pht_cap->ht_cap.ampdu_param = MAX_RX_AMPDU_SIZE_64K;
+ pht_cap->ht_cap.supported_mcs_set[0] = 0xff;
+ HEXDUMP("ADHOC_START: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ pos += sizeof(MrvlIETypes_HTCap_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+ {
+ pht_info = (MrvlIETypes_HTInfo_t *) pos;
+ memset(pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+ pht_info->ht_info.pri_chan =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+ if (pmadapter->chan_offset) {
+ pht_info->ht_info.field2 = pmadapter->chan_offset;
+ SET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+ pht_info->ht_info.field3 = NON_GREENFIELD_STAS;
+ pht_info->ht_info.basic_mcs_set[0] = 0xff;
+ HEXDUMP("ADHOC_START: HT_INFORMATION IE", (t_u8 *) pht_info,
+ sizeof(MrvlIETypes_HTInfo_t));
+ pos += sizeof(MrvlIETypes_HTInfo_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+ }
+ }
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_START)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(&tmp_cap, &padhoc_start->cap, sizeof(t_u16));
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(&padhoc_start->cap, &tmp_cap, sizeof(t_u16));
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_join.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void cast of BSSDescriptor_t from the
+ * scan table to join
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11_AD_HOC_JOIN *padhoc_join = &cmd->params.adhoc_join;
+ BSSDescriptor_t *pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ t_u32 cmd_append_size = 0;
+ t_u16 tmp_cap;
+ t_u32 i, rates_size = 0;
+ t_u16 curr_pkt_filter;
+ t_u8 *pos = (t_u8 *) padhoc_join + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
+
+ ENTER();
+
+/** Use G protection */
+#define USE_G_PROTECTION 0x02
+ if (pbss_desc->erp_flags & USE_G_PROTECTION) {
+ curr_pkt_filter =
+ pmpriv->curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &curr_pkt_filter);
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_J_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+ padhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+ padhoc_join->bss_descriptor.beacon_period
+ = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ memcpy(&padhoc_join->bss_descriptor.bssid,
+ &pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ memcpy(&padhoc_join->bss_descriptor.ssid,
+ &pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len);
+
+ memcpy(&padhoc_join->bss_descriptor.phy_param_set,
+ &pbss_desc->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ memcpy(&padhoc_join->bss_descriptor.ss_param_set,
+ &pbss_desc->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ memcpy(&tmp_cap, &pbss_desc->cap_info, sizeof(IEEEtypes_CapInfo_t));
+
+ tmp_cap &= CAPINFO_MASK;
+
+ PRINTM(MINFO, "ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ memcpy(&padhoc_join->bss_descriptor.cap, &tmp_cap,
+ sizeof(IEEEtypes_CapInfo_t));
+
+ /* Information on BSSID descriptor passed to FW */
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
+ padhoc_join->bss_descriptor.bssid[0],
+ padhoc_join->bss_descriptor.bssid[1],
+ padhoc_join->bss_descriptor.bssid[2],
+ padhoc_join->bss_descriptor.bssid[3],
+ padhoc_join->bss_descriptor.bssid[4],
+ padhoc_join->bss_descriptor.bssid[5],
+ padhoc_join->bss_descriptor.ssid);
+
+ for (i = 0; pbss_desc->supported_rates[i] && i < WLAN_SUPPORTED_RATES; i++);
+ rates_size = i;
+
+ /* Copy Data Rates from the Rates recorded in scan response */
+ memset(padhoc_join->bss_descriptor.data_rates, 0,
+ sizeof(padhoc_join->bss_descriptor.data_rates));
+ memcpy(padhoc_join->bss_descriptor.data_rates, pbss_desc->supported_rates,
+ rates_size);
+
+ HEXDUMP("Adapted Rates:", padhoc_join->bss_descriptor.data_rates,
+ rates_size);
+
+ /* Copy the adhoc join rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(&pmpriv->curr_bss_params.data_rates, pbss_desc->supported_rates,
+ rates_size);
+
+ /* Copy the channel information */
+ pmpriv->curr_bss_params.bss_descriptor.channel = pbss_desc->channel;
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled)
+ padhoc_join->bss_descriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+
+ if (IS_SUPPORT_MULTI_BANDS(pmpriv->adapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pchan_tlv->chan_scan_param, 0x00, sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so
+ * adhoc/infra 11h behavior can be properly triggered.
+ * pos modified if data is appended
+ */
+ cmd_append_size += wlan_11h_process_join(pmpriv, &pos,
+ &padhoc_join->bss_descriptor.cap,
+ pbss_desc->channel,
+ &pbss_desc->wlan_11h_bss_info);
+
+ if (pmpriv->sec_info.wpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ WPA2_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(prsn_ie_tlv->rsn_ie, &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info))
+ cmd_append_size += wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ /** Append vendor specific IE TLV */
+ cmd_append_size +=
+ wlan_cmd_append_vsie_tlv(pmpriv, MLAN_VSIE_MASK_ADHOC, &pos);
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(&tmp_cap, &padhoc_join->bss_descriptor.cap,
+ sizeof(IEEEtypes_CapInfo_t));
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+
+ memcpy(&padhoc_join->bss_descriptor.cap,
+ &tmp_cap, sizeof(IEEEtypes_CapInfo_t));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_start and
+ * ad_hoc_join
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ HostCmd_DS_802_11_AD_HOC_RESULT *padhoc_result;
+ BSSDescriptor_t *pbss_desc;
+ t_u16 command = resp->command;
+ t_u16 result = resp->result;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ padhoc_result = &resp->params.adhoc_result;
+
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ PRINTM(MERROR, "ADHOC_RESP Failed\n");
+ if (pmpriv->media_connected == MTRUE)
+ wlan_reset_connect_state(pmpriv);
+
+ memset(&pmpriv->curr_bss_params.bss_descriptor,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+ PRINTM(MINFO, "ADHOC_S_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(pbss_desc->mac_address,
+ padhoc_result->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ pmpriv->adhoc_state = ADHOC_STARTED;
+ } else {
+ /*
+ * Now the join cmd should be successful.
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ PRINTM(MINFO, "ADHOC_J_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /*
+ * Make a copy of current BSSID descriptor, only needed for join since
+ * the current descriptor is already being used for adhoc start
+ */
+ memcpy(&pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ pmpriv->adhoc_state = ADHOC_JOINED;
+ }
+
+ PRINTM(MINFO, "ADHOC_RESP: Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[0],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[1],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[2],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[3],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[4],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[5]);
+
+ pevent->bss_num = pmpriv->bss_num;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy((t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+ wlan_save_curr_bcn(pmpriv);
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ pioctl_req->status_code = MLAN_ERROR_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Associated to a specific BSS discovered in a scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor to associate with.
+ *
+ * @return MLAN_STATUS_SUCCESS or < 0 if error
+ */
+mlan_status
+wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 current_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ ENTER();
+
+ /* Return error if the pmadapter or table entry is not marked as infra */
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_INFRA) ||
+ (pbss_desc->bss_mode != MLAN_BSS_MODE_INFRA)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(¤t_bssid,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(current_bssid));
+
+ /* Clear any past association response stored for application retrieval */
+ pmpriv->assoc_rsp_size = 0;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param padhoc_ssid The ssid of the Adhoc Network
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * padhoc_ssid)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmpriv->adhoc_auto_sel)
+ && ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ )
+ ) {
+ pmpriv->adhoc_channel = wlan_11h_get_adhoc_start_channel(pmpriv);
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if (wlan_11h_radar_detect_required(pmpriv, pmpriv->adhoc_channel)) {
+ /*
+ * Radar detection is required for this channel, make sure
+ * 11h is activated in the firmware
+ */
+ wlan_11h_activate(pmpriv, MTRUE);
+
+ /* Check for radar on the channel */
+ if (wlan_11h_radar_detected(pmpriv, pmpriv->adhoc_channel)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "Adhoc Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, padhoc_ssid);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid =%s\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid_len =%u\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid =%s\n", pbss_desc->ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid len =%u\n", pbss_desc->ssid.ssid_len);
+
+ /* Check if the requested SSID is already joined */
+ if (pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+ !wlan_ssid_cmp(pmadapter, &pbss_desc->ssid,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid) &&
+ (pmpriv->curr_bss_params.bss_descriptor.bss_mode ==
+ MLAN_BSS_MODE_IBSS)) {
+
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join");
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %c\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send Deauthentication Request or Stop the AdHoc network depending on mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to mlan_ioctl_req structure
+ * @param mac A pointer to mlan_802_11_mac_addr structure
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req, IN mlan_802_11_mac_addr * mac)
+{
+ mlan_802_11_mac_addr mac_address;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (mac) {
+ if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
+ memcpy((t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ else {
+ memcpy((t_u8 *) & mac_address,
+ (t_u8 *) mac, MLAN_MAC_ADDR_LENGTH);
+ }
+ } else {
+ memcpy((t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ }
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, &mac_address);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+
+ } else if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert band to radio type used in channel TLV
+ *
+ * @param band Band enumeration to convert to a channel TLV radio type
+ *
+ * @return Radio type designator for use in a channel TLV
+ */
+t_u8
+wlan_band_to_radio_type(IN t_u8 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ default:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
diff --git a/wlan_src/mlan/mlan_join.h b/wlan_src/mlan/mlan_join.h
new file mode 100755
index 0000000..4e934d9
--- /dev/null
+++ b/wlan_src/mlan/mlan_join.h
@@ -0,0 +1,33 @@
+/** @file mlan_join.h
+ *
+ * @brief This file defines the interface for the WLAN infrastructure
+ * and adhoc join routines.
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in mlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ * @sa mlan_join.c
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_JOIN_H_
+#define _MLAN_JOIN_H_
+
+/** Size of buffer allocated to store the association response from firmware */
+#define MRVDRV_ASSOC_RSP_BUF_SIZE 500
+
+/** Size of buffer allocated to store IEs passed to firmware in the assoc req */
+#define MRVDRV_GENIE_BUF_SIZE 256
+
+/** Size of buffer allocated to store TLVs passed to firmware in the assoc req */
+#define MRVDRV_ASSOC_TLV_BUF_SIZE 256
+
+#endif /* _MLAN_JOIN_H_ */
diff --git a/wlan_src/mlan/mlan_main.h b/wlan_src/mlan/mlan_main.h
new file mode 100755
index 0000000..60a0aba
--- /dev/null
+++ b/wlan_src/mlan/mlan_main.h
@@ -0,0 +1,1835 @@
+/** @file mlan_main.h
+ *
+ * @brief This file defines the private and adapter data
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_MAIN_H_
+#define _MLAN_MAIN_H_
+
+#ifdef DEBUG_LEVEL1
+/** Log debug message */
+#ifdef __GNUC__
+#define PRINTM(level, pformat, args...) \
+do { \
+ extern mlan_adapter *g_pmadapter; \
+ if (g_pmadapter->callbacks.moal_print) \
+ g_pmadapter->callbacks.moal_print(level, pformat, ## args); \
+} while (0)
+#else
+#define PRINTM(level, pformat, ...) \
+do { \
+ extern mlan_adapter *g_pmadapter; \
+ if (g_pmadapter->callbacks.moal_print) \
+ g_pmadapter->callbacks.moal_print(level, pformat, __VA_ARGS__); \
+} while (0)
+#endif /* __GNUC__ */
+
+/** Max hex dump data length */
+#define MAX_DATA_DUMP_LEN 48
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) \
+do { \
+ extern mlan_adapter *g_pmadapter; \
+ if (g_pmadapter->callbacks.moal_print) \
+ g_pmadapter->callbacks.moal_print(MHEX_DUMP | level, x, y, z); \
+} while (0)
+#else
+/** Log debug message */
+#define PRINTM(level, pformat, args...) do {} while (0)
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+#endif /* DEBUG_LEVEL1 */
+
+#ifdef DEBUG_LEVEL2
+/** Log entry point for debugging */
+#define ENTER() \
+do { \
+ PRINTM(MENTRY, "Enter: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Log exit point for debugging */
+#define LEAVE() \
+do { \
+ PRINTM(MENTRY, "Leave: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Hexdump for level-2 debugging */
+#define HEXDUMP(x,y,z) \
+do { \
+ extern mlan_adapter *g_pmadapter; \
+ if (g_pmadapter->callbacks.moal_print) \
+ g_pmadapter->callbacks.moal_print(MHEX_DUMP | MINFO, x, y, z); \
+} while (0)
+#else
+/** Log entry point for debugging */
+#define ENTER() do {} while (0)
+
+/** Log exit point for debugging */
+#define LEAVE() do {} while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+/** Find minimum */
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+extern struct _mlan_adapter *g_pmadapter;
+#ifdef memset
+#undef memset
+#endif
+/** Memset routine */
+#define memset(s, c, len) \
+ g_pmadapter->callbacks.moal_memset(s, c, len)
+
+#ifdef memmove
+#undef memmove
+#endif
+/** Memmove routine */
+#define memmove(dest, src, len) \
+ g_pmadapter->callbacks.moal_memmove(dest, src, len)
+
+#ifdef memcpy
+#undef memcpy
+#endif
+/** Memcpy routine */
+#define memcpy(to, from, len) \
+ g_pmadapter->callbacks.moal_memcpy(to, from, len)
+
+#ifdef memcmp
+#undef memcmp
+#endif
+/** Memcmp routine */
+#define memcmp(s1, s2, len) \
+ g_pmadapter->callbacks.moal_memcmp(s1, s2, len)
+
+/** Find number of elements */
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+/** SWAP: swap t_u8 */
+#define SWAP_U8(a,b) {t_u8 t; t=a; a=b; b=t;}
+
+/** SWAP: swap t_u8 */
+#define SWAP_U16(a,b) {t_u16 t; t=a; a=b; b=t;}
+
+/** MLAN MNULL pointer */
+#define MNULL (0)
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+((t_u16)((((t_u16)(x) & 0x00ffU) << 8) | \
+ (((t_u16)(x) & 0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+((t_u32)((((t_u32)(x) & 0x000000ffUL) << 24) | \
+ (((t_u32)(x) & 0x0000ff00UL) << 8) | \
+ (((t_u32)(x) & 0x00ff0000UL) >> 8) | \
+ (((t_u32)(x) & 0xff000000UL) >> 24)))
+
+/** 64 bits byte swap */
+#define swap_byte_64(x) \
+((t_u64)((t_u64)(((t_u64)(x) & 0x00000000000000ffULL) << 56) | \
+ (t_u64)(((t_u64)(x) & 0x000000000000ff00ULL) << 40) | \
+ (t_u64)(((t_u64)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (t_u64)(((t_u64)(x) & 0x00000000ff000000ULL) << 8) | \
+ (t_u64)(((t_u64)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (t_u64)(((t_u64)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (t_u64)(((t_u64)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (t_u64)(((t_u64)(x) & 0xff00000000000000ULL) >> 56) ))
+
+#ifdef BIG_ENDIAN
+/** Convert n/w to host */
+#define mlan_ntohs(x) x
+/** Convert host to n/w */
+#define mlan_htons(x) x
+/** Convert from 16 bit little endian format to CPU format */
+#define wlan_le16_to_cpu(x) swap_byte_16(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define wlan_le32_to_cpu(x) swap_byte_32(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define wlan_le64_to_cpu(x) swap_byte_64(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define wlan_cpu_to_le16(x) swap_byte_16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define wlan_cpu_to_le32(x) swap_byte_32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define wlan_cpu_to_le64(x) swap_byte_64(x)
+#else
+/** Convert n/w to host */
+#define mlan_ntohs(x) swap_byte_16(x)
+/** Convert host to n/w */
+#define mlan_htons(x) swap_byte_16(x)
+/** Do nothing */
+#define wlan_le16_to_cpu(x) x
+/** Do nothing */
+#define wlan_le32_to_cpu(x) x
+/** Do nothing */
+#define wlan_le64_to_cpu(x) x
+/** Do nothing */
+#define wlan_cpu_to_le16(x) x
+/** Do nothing */
+#define wlan_cpu_to_le32(x) x
+/** Do nothing */
+#define wlan_cpu_to_le64(x) x
+#endif /* BIG_ENDIAN */
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x); \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ }
+
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x); \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ }
+
+/** Assertion */
+#ifndef ASSERT
+#define ASSERT(cond) \
+do { \
+ if (!(cond)) \
+ return MLAN_STATUS_FAILURE; \
+} while(0)
+#endif /* !ASSERT */
+
+/** Header alignment */
+#define HEADER_ALIGNMENT 8
+
+/** Upload size */
+#define WLAN_UPLD_SIZE (2312)
+
+/** Maximum event buffer size */
+#define MAX_EVENT_SIZE 1024
+
+/** Maximum buffer size for ARP filter */
+#define ARP_FILTER_MAX_BUF_SIZE 68
+
+/** 10 seconds */
+#define MRVDRV_TIMER_10S 10000
+/** 5 seconds */
+#define MRVDRV_TIMER_5S 5000
+/** 1 second */
+#define MRVDRV_TIMER_1S 1000
+
+/** Maximum size of multicast list */
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+/** Maximum size of channel */
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+/** WEP list macros & data structures */
+/** Size of key buffer in bytes */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16
+/** Maximum length of WPA key */
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+/** Default listen interval */
+#define MLAN_DEFAULT_LISTEN_INTERVAL 10
+
+/** Maximum number of region codes */
+#define MRVDRV_MAX_REGION_CODE 7
+
+/** Default factor for calculating beacon average */
+#define DEFAULT_BCN_AVG_FACTOR 8
+/** Default factor for calculating data average */
+#define DEFAULT_DATA_AVG_FACTOR 8
+
+/** The first valid channel for use */
+#define FIRST_VALID_CHANNEL 0xff
+/** Default Ad-Hoc channel */
+#define DEFAULT_AD_HOC_CHANNEL 6
+/** Default Ad-Hoc channel A */
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** Power Save definitions */
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 1
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Default multiple DTIM */
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+/** Number of WEP keys */
+#define MRVL_NUM_WEP_KEY (4)
+
+/** Default beacon missing timeout */
+#define DEFAULT_BCN_MISS_TIMEOUT 5
+
+/**
+ * Maximum buffer space for beacons retrieved from scan responses
+ * 4000 has successfully stored up to 40 beacons
+ * 6000 has successfully stored the max scan results (max 64)
+ */
+#define MAX_SCAN_BEACON_BUFFER 6000
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ * For each scan response stored, allocate an extra byte pad at the end to
+ * allow easy expansion to store a beacon in the same memory a probe response
+ * previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD 6
+
+/** Scan time specified in the channel TLV for each channel for passive scans */
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for active scans */
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for specific scans */
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 110
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (10s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
+
+/** Offset for GTK as it has version to skip past for GTK */
+#define RSN_GTK_OUI_OFFSET 2
+
+/** If OUI is not found */
+#define MLAN_OUI_NOT_PRESENT 0
+/** If OUI is found */
+#define MLAN_OUI_PRESENT 1
+
+/** RF antenna select 1 */
+#define RF_ANTENNA_1 0x1
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO 0xFFFF
+
+/** Is cmd_resp, event or data packet received? */
+#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
+ adapter->event_received || \
+ adapter->data_received)
+
+/** Type command */
+#define MLAN_TYPE_CMD 1
+/** Type data */
+#define MLAN_TYPE_DATA 0
+/** Type event */
+#define MLAN_TYPE_EVENT 3
+
+/** Maximum numbfer of registers to read for multiple port */
+#define MAX_MP_REGS 40
+/** Maximum port */
+#define MAX_PORT 16
+
+/** Multi port aggregation packet limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT (8)
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** Multi port TX aggregation buffer size */
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** Max bitmap rate size */
+#define MAX_BITMAP_RATES_SIZE 10
+
+/** Info for debug purpose */
+typedef struct _wlan_dbg
+{
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+} wlan_dbg;
+
+/** Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS
+{
+ WlanHardwareStatusReady,
+ WlanHardwareStatusInitializing,
+ WlanHardwareStatusInitdone,
+ WlanHardwareStatusReset,
+ WlanHardwareStatusClosing,
+ WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE
+{
+ Wlan802_11PowerModeCAM,
+ Wlan802_11PowerModePSP
+} WLAN_802_11_POWER_MODE;
+
+/** tx param */
+typedef struct _mlan_tx_param
+{
+ /** next packet length */
+ t_u32 next_pkt_len;
+} mlan_tx_param;
+
+/** PS_STATE */
+typedef enum _PS_STATE
+{
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP_CFM,
+ PS_STATE_SLEEP
+} PS_STATE;
+
+/** Minimum flush timer for win size of 1 is 50 ms */
+#define MIN_FLUSH_TIMER_MS 50
+/** Tx BA stream table */
+typedef struct _TxBAStreamTbl TxBAStreamTbl;
+
+/** Add BA parameter data structure */
+typedef struct
+{
+ /** Window size for initiator */
+ t_u32 tx_win_size;
+ /** Window size for receiver */
+ t_u32 rx_win_size;
+ /** Block ack timeout */
+ t_u32 timeout;
+} add_ba_param_t;
+
+/** Tx aggregation data structure */
+typedef struct _txAggr_t
+{
+ /** AMPDU user */
+ t_u8 ampdu_user;
+ /** AMPDU AP */
+ t_u8 ampdu_ap;
+ /** AMSDU */
+ t_u8 amsdu;
+} tx_aggr_t;
+
+/** RA list table */
+typedef struct _raListTbl raListTbl;
+
+/** RA list table */
+struct _raListTbl
+{
+ /** Pointer to previous node */
+ raListTbl *pprev;
+ /** Pointer to next node */
+ raListTbl *pnext;
+ /** Buffer list head */
+ mlan_list_head buf_head;
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+
+ /** total size of packets in RA list */
+ t_u32 total_pkts_size;
+ /** is 11n enabled */
+ t_u32 is_11n_enabled;
+};
+
+/** TID table */
+typedef struct _tidTbl
+{
+ /** RA list head */
+ mlan_list_head ra_list;
+ /** Current RA list */
+ raListTbl *ra_list_curr;
+} tid_tbl_t;
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY 7
+/** HIGHEST priority TID */
+#define HIGH_PRIO_TID 7
+/** LEAST priority TID */
+#define LOW_PRIO_TID 0
+
+/** Struct of WMM DESC */
+typedef struct _wmm_desc
+{
+ /** TID table */
+ tid_tbl_t tid_tbl_ptr[MAX_NUM_TID];
+ /** Packets out */
+ t_u32 packets_out[MAX_NUM_TID];
+ /** Spin lock to protect ra_list */
+ t_void *ra_list_spinlock;
+
+ /** AC status */
+ WmmAcStatus_t ac_status[MAX_AC_QUEUES];
+ /** AC downgraded values */
+ mlan_wmm_ac_e ac_down_graded_vals[MAX_AC_QUEUES];
+
+ /** Max driver packet delay sent to the firmware for expiry eval */
+ t_u32 drv_pkt_delay_max;
+
+ /** WMM queue priority table */
+ t_u8 queue_priority[MAX_AC_QUEUES];
+ /** User priority packet transmission control */
+ t_u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
+
+} wmm_desc_t;
+
+/** Security structure */
+typedef struct _wlan_802_11_security_t
+{
+ /** WPA enabled flag */
+ t_u8 wpa_enabled;
+ /** E-Supplicant enabled flag */
+ t_u8 ewpa_enabled;
+ /** WPA2 enabled flag */
+ t_u8 wpa2_enabled;
+ /** WAPI enabled flag */
+ t_u8 wapi_enabled;
+ /** WAPI key on flag */
+ t_u8 wapi_key_on;
+ /** WEP status */
+ WLAN_802_11_WEP_STATUS wep_status;
+ /** Authentication mode */
+ t_u32 authentication_mode;
+ /** Encryption mode */
+ t_u32 encryption_mode;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct
+{
+ /** BSS descriptor */
+ BSSDescriptor_t bss_descriptor;
+ /** WMM enable? */
+ t_u8 wmm_enabled;
+ /** Uapsd enable?*/
+ t_u8 wmm_uapsd_enabled;
+ /** Band */
+ t_u8 band;
+ /** Number of rates supported */
+ t_u32 num_of_rates;
+ /** Supported rates*/
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+} current_bss_params_t;
+
+/** Sleep_params */
+typedef struct _sleep_params_t
+{
+ /** Sleep parameter error */
+ t_u16 sp_error;
+ /** Sleep parameter offset */
+ t_u16 sp_offset;
+ /** Sleep parameter stable time */
+ t_u16 sp_stable_time;
+ /** Sleep parameter calibration control */
+ t_u8 sp_cal_control;
+ /** Sleep parameter external sleep clock */
+ t_u8 sp_ext_sleep_clk;
+ /** Sleep parameter reserved */
+ t_u16 sp_reserved;
+} sleep_params_t;
+
+/** Sleep_period */
+typedef struct sleep_period_t
+{
+ /** Sleep period */
+ t_u16 period;
+ /** Reserved */
+ t_u16 reserved;
+} sleep_period_t;
+
+/** mrvl_wep_key_t */
+typedef struct _mrvl_wep_key_t
+{
+ /** Length */
+ t_u32 length;
+ /** WEP key index */
+ t_u32 key_index;
+ /** WEP key length */
+ t_u32 key_length;
+ /** WEP keys */
+ t_u8 key_material[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} mrvl_wep_key_t;
+
+/** Maximum number of region channel */
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _chan_freq_power_t
+{
+ /** Channel Number */
+ t_u16 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+ /** Max allowed Tx power level */
+ t_u16 max_tx_power;
+ /** TRUE:channel unsupported; FLASE:supported */
+ t_u8 unsupported;
+} chan_freq_power_t;
+
+/** Region-band mapping table */
+typedef struct _region_chan_t
+{
+ /** TRUE if this entry is valid */
+ t_u8 valid;
+ /** Region code for US, Japan ... */
+ t_u8 region;
+ /** Band B/G/A, used for BAND_CONFIG cmd */
+ t_u8 band;
+ /** Actual No. of elements in the array below */
+ t_u8 num_cfp;
+ /** chan-freq-txpower mapping table */
+ chan_freq_power_t *pcfp;
+} region_chan_t;
+
+/** State of 11d */
+typedef enum
+{
+ DISABLE_11D = 0,
+ ENABLE_11D = 1,
+} state_11d_t;
+
+/** Domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** No. of subband */
+ t_u8 no_of_sub_band;
+ /** Subband data */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state
+{
+ /** True for enabling 11D */
+ state_11d_t enable_11d;
+ /** True for user enabling 11D */
+ state_11d_t user_enable_11d;
+} wlan_802_11d_state_t;
+
+/** Vendor specific configuration IE */
+typedef struct _vendor_spec_cfg_ie
+{
+ /** Bit 0-2: scan/assoc/ad-hoc */
+ t_u16 mask;
+ /** Optional, 0/1: gen_ie/vs_ie */
+ t_u16 flag;
+ /** Information element */
+ t_u8 ie[MLAN_MAX_VSIE_LEN];
+} vendor_spec_cfg_ie;
+
+/** Data structure for WPS information */
+typedef struct
+{
+ /** Session enable flag */
+ t_u8 session_enable;
+} wps_t;
+
+/** mlan_operations data structure */
+typedef struct _mlan_operations
+{
+ /** cmd init handler */
+ mlan_status(*init_cmd) (IN t_void * priv, IN t_u8 first_sta);
+ /** ioctl handler */
+ mlan_status(*ioctl) (t_void * adapter, pmlan_ioctl_req pioctl_req);
+ /** cmd handler */
+ mlan_status(*prepare_cmd) (IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf);
+ /** cmdresp handler */
+ mlan_status(*process_cmdresp) (IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl);
+ /** rx handler */
+ mlan_status(*process_rx_packet) (IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+ /** event handler */
+ mlan_status(*process_event) (IN t_void * priv);
+ /** txpd handler */
+ t_void *(*process_txpd) (IN t_void * priv, IN pmlan_buffer pmbuf);
+ /** bss_type */
+ t_u8 bss_type;
+} mlan_operations;
+
+/** Private structure for MLAN */
+typedef struct _mlan_private
+{
+ /** Pointer to mlan_adapter */
+ struct _mlan_adapter *adapter;
+ /** BSS number */
+ t_u8 bss_num;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS Priority */
+ t_u8 bss_priority;
+ /** Frame type */
+ t_u8 frame_type;
+ /** MAC address information */
+ t_u8 curr_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Media connection status */
+ t_u8 media_connected;
+
+ /** Current packet filter */
+ t_u16 curr_pkt_filter;
+ /** Infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Tx packet control */
+ t_u32 pkt_tx_ctrl;
+ /** Gen NULL pkg */
+ t_u16 gen_null_pkg;
+
+ /** Tx power level */
+ t_u16 tx_power_level;
+ /** Maximum Tx power level */
+ t_u8 max_tx_power_level;
+ /** Minimum Tx power level */
+ t_u8 min_tx_power_level;
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** tx ht_info */
+ t_u8 tx_htinfo;
+ /** rxpd_htinfo */
+ t_u8 rxpd_htinfo;
+ /** Rx PD rate */
+ t_u8 rxpd_rate;
+ /** Rate bitmap */
+ t_u16 rate_bitmap;
+ /** Bitmap rates */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** Data rate */
+ t_u32 data_rate;
+ /** Automatic data rate flag */
+ t_u8 is_data_rate_auto;
+ /** Factor for calculating beacon average */
+ t_u16 bcn_avg_factor;
+ /** Factor for calculating data average */
+ t_u16 data_avg_factor;
+ /** Last data RSSI */
+ t_s16 data_rssi_last;
+ /** Last data Noise Floor */
+ t_s16 data_nf_last;
+ /** Average data RSSI */
+ t_s16 data_rssi_avg;
+ /** Averag data Noise Floor */
+ t_s16 data_nf_avg;
+ /** Last beacon RSSI */
+ t_s16 bcn_rssi_last;
+ /** Last beacon Noise Floor */
+ t_s16 bcn_nf_last;
+ /** Average beacon RSSI */
+ t_s16 bcn_rssi_avg;
+ /** Average beacon Noise Floor */
+ t_s16 bcn_nf_avg;
+
+ /** Attempted BSS descriptor */
+ BSSDescriptor_t *pattempted_bss_desc;
+ /** Prevous SSID */
+ mlan_802_11_ssid prev_ssid;
+ /** Previous BSSID */
+ t_u8 prev_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ /** Current SSID/BSSID related parameters*/
+ current_bss_params_t curr_bss_params;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** ATIM window */
+ t_u16 atim_window;
+
+ /** AdHoc channel */
+ t_u8 adhoc_channel;
+ /** AdHoc link sensed flag */
+ t_u8 adhoc_is_link_sensed;
+ /** AdHoc G rate */
+ t_u8 adhoc_state;
+ /** AdHoc autoselect */
+ t_u8 adhoc_auto_sel;
+
+ /** Security related */
+ /** Encryption parameter */
+ wlan_802_11_security_t sec_info;
+ /** WEP keys */
+ mrvl_wep_key_t wep_key[MRVL_NUM_WEP_KEY];
+ /** Current WEP key index */
+ t_u16 wep_key_curr_index;
+ /** Encryption Key*/
+ t_u8 wpa_ie[256];
+ /** WPA IE length */
+ t_u8 wpa_ie_len;
+ /** GTK set flag */
+ t_u8 wpa_is_gtk_set;
+ /** AES key material */
+ HostCmd_DS_802_11_KEY_MATERIAL aes_key;
+ /** WAPI IE */
+ t_u8 wapi_ie[256];
+ /** WAPI IE length */
+ t_u8 wapi_ie_len;
+
+ /** Advanced Encryption Standard */
+ t_u8 adhoc_aes_enabled;
+
+ /** WMM required */
+ t_u8 wmm_required;
+ /** WMM enabled */
+ t_u8 wmm_enabled;
+ /** WMM qos info */
+ t_u8 wmm_qosinfo;
+ /** WMM related variable*/
+ wmm_desc_t wmm;
+
+ /** Pointer to the Transmit BA stream table*/
+ mlan_list_head tx_ba_stream_tbl_ptr;
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ tx_aggr_t aggr_prio_tbl[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Struct to store ADDBA parameters */
+ add_ba_param_t add_ba_param;
+ /** Pointer to the Receive Reordering table*/
+ mlan_list_head rx_reorder_tbl_ptr;
+ /** Lock for Rx packets */
+ t_void *rx_pkt_lock;
+
+ /** Buffer to store the association response for application retrieval */
+ t_u8 assoc_rsp_buf[MRVDRV_ASSOC_RSP_BUF_SIZE];
+ /** Length of the data stored in assoc_rsp_buf */
+ t_u32 assoc_rsp_size;
+
+ /** Generice IEEE IEs passed from the application to be inserted into the
+ * association request to firmware
+ */
+ t_u8 gen_ie_buf[MRVDRV_GENIE_BUF_SIZE];
+ /** Length of the data stored in gen_ie_buf */
+ t_u8 gen_ie_buf_len;
+ /** Vendor specific configuration IEs */
+ vendor_spec_cfg_ie vs_ie[MLAN_MAX_VSIE_NUM];
+
+ /** Buffer for TLVs passed from the application to be inserted into the
+ * association request to firmware
+ */
+ t_u8 mrvl_assoc_tlv_buf[MRVDRV_ASSOC_TLV_BUF_SIZE];
+ /** Length of the data stored in mrvl_assoc_tlv_buf */
+ t_u8 mrvl_assoc_tlv_buf_len;
+ t_u8 *pcurr_bcn_buf;
+ t_u32 curr_bcn_size;
+ t_void *curr_bcn_buf_lock;
+
+ /** WPS */
+ wps_t wps;
+ /** function table */
+ mlan_operations ops;
+
+} mlan_private, *pmlan_private;
+
+/** BA stream status */
+typedef enum
+{
+ BA_STREAM_NOT_SETUP = 0,
+ BA_STREAM_SETUP_INPROGRESS,
+ BA_STREAM_SETUP_COMPLETE
+} baStatus_e;
+
+/** Tx BA stream table */
+struct _TxBAStreamTbl
+{
+ /** TxBAStreamTbl previous node */
+ TxBAStreamTbl *pprev;
+ /** TxBAStreamTbl next node */
+ TxBAStreamTbl *pnext;
+ /** TID */
+ int tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** BA stream status */
+ baStatus_e ba_status;
+};
+
+/** RX reorder table */
+typedef struct _RxReorderTbl RxReorderTbl;
+
+typedef struct
+{
+ /** Timer for flushing */
+ t_void *timer;
+ /** Timer set flag */
+ t_u8 timer_is_set;
+ /** RxReorderTbl ptr */
+ RxReorderTbl *ptr;
+ /** Priv pointer */
+ mlan_private *priv;
+} reorder_tmr_cnxt_t;
+
+/** RX reorder table */
+struct _RxReorderTbl
+{
+ /** RxReorderTbl previous node */
+ RxReorderTbl *pprev;
+ /** RxReorderTbl next node */
+ RxReorderTbl *pnext;
+ /** TID */
+ int tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ int start_win;
+ /** Window size */
+ int win_size;
+ /** Pointer to pointer to RxReorderTbl */
+ t_void **rx_reorder_ptr;
+ /** Timer context */
+ reorder_tmr_cnxt_t timer_context;
+};
+
+/** BSS priority node */
+typedef struct _mlan_bssprio_node mlan_bssprio_node;
+
+/** BSS priority node */
+struct _mlan_bssprio_node
+{
+ /** Pointer to previous node */
+ mlan_bssprio_node *pprev;
+ /** Pointer to next node */
+ mlan_bssprio_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+};
+
+/** BSS priority table */
+typedef struct _mlan_bssprio_tbl mlan_bssprio_tbl;
+
+/** BSS priority table */
+struct _mlan_bssprio_tbl
+{
+ /** BSS priority list head */
+ mlan_list_head bssprio_head;
+ /** Current priority node */
+ mlan_bssprio_node *bssprio_cur;
+};
+
+/** cmd_ctrl_node */
+typedef struct _cmd_ctrl_node cmd_ctrl_node;
+
+/** _cmd_ctrl_node */
+struct _cmd_ctrl_node
+{
+ /** Pointer to previous node */
+ cmd_ctrl_node *pprev;
+ /** Pointer to next node */
+ cmd_ctrl_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+ /** Command OID for sub-command use */
+ t_u32 cmd_oid;
+ /** Command flag */
+ t_u32 cmd_flag;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *cmdbuf;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *respbuf;
+ /** Command parameter */
+ t_void *pdata_buf;
+ /** Pointer to mlan_ioctl_req if command is from IOCTL */
+ t_void *pioctl_buf;
+ /** pre_allocated mlan_buffer for cmd */
+ mlan_buffer *pmbuf;
+};
+
+/** 802.11h State information kept in the 'mlan_adapter' of the driver */
+typedef struct
+{
+ t_u32 is_11h_enabled; /**< Enables/disables 11h in the driver (adhoc start) */
+ t_u32 is_11h_active; /**< Indicates whether 11h is active in the firmware */
+ t_u32 tx_disabled; /**< Set when driver receives a STOP TX event from fw */
+
+ /** Minimum TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 min_tx_power_capability;
+
+ /** Maximum TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 max_tx_power_capability;
+
+ /** User provisioned local power constraint sent in association requests */
+ t_s8 usr_def_power_constraint;
+
+ /** Quiet IE */
+ IEEEtypes_Quiet_t quiet_ie;
+
+} wlan_11h_state_t;
+
+/**
+ * @brief Driver measurement state held in 'mlan_adapter' structure
+ *
+ * Used to record a measurement request that the driver is pending on
+ * the result (received measurement report).
+ */
+typedef struct
+{
+ /**
+ * Dialog token of a pending measurement request/report. Used to
+ * block execution while waiting for the specific dialog token
+ */
+ t_u8 meas_rpt_pend_on;
+
+ /**
+ * Measurement report received from the firmware that we were pending on
+ */
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt_returned;
+
+} wlan_meas_state_t;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** data structure for SDIO MPA TX */
+typedef struct _sdio_mpa_tx
+{
+ /** allocated buf for tx aggreation */
+ t_u8 *head_ptr;
+ /** multiport tx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport tx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport tx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport tx aggregation ports */
+ t_u16 ports;
+ /** multiport tx aggregation starting port */
+ t_u16 start_port;
+ /** multiport tx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport tx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport tx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_tx;
+#endif
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** data structure for SDIO MPA RX */
+typedef struct _sdio_mpa_rx
+{
+ /** allocated buf for rx aggreation */
+ t_u8 *head_ptr;
+ /** multiport rx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport rx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport rx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport rx aggregation ports */
+ t_u16 ports;
+ /** multiport rx aggregation starting port */
+ t_u16 start_port;
+
+ /** multiport rx aggregation mbuf array */
+ pmlan_buffer mbuf_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+ /** multiport rx aggregation pkt len array */
+ t_u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+
+ /** multiport rx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport rx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport rx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** Adapter data structure for MLAN */
+typedef struct _mlan_adapter
+{
+ /** MOAL handle structure */
+ t_void *pmoal_handle;
+ /** Private pointer */
+ pmlan_private priv[MLAN_MAX_BSS_NUM];
+ /** Priority table for bss */
+ mlan_bssprio_tbl bssprio_tbl[MLAN_MAX_BSS_NUM];
+ /** Callback table */
+ mlan_callbacks callbacks;
+ /** mlan_lock for init/shutdown */
+ t_void *pmlan_lock;
+ /** main_proc_lock for main_process */
+ t_void *pmain_proc_lock;
+ /** mlan_processing */
+ t_u32 mlan_processing;
+ /** Max tx buf size */
+ t_u16 max_tx_buf_size;
+ /** Tx buf size */
+ t_u16 tx_buf_size;
+ /** IO port */
+ t_u32 ioport;
+
+ /** STATUS variables */
+ WLAN_HARDWARE_STATUS hw_status;
+ /** PnP SUPPORT */
+ t_u8 surprise_removed;
+
+ /** Radio on flag */
+ t_u16 radio_on;
+
+ /** Firmware release number */
+ t_u32 fw_release_number;
+
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+
+ /** Firmware capability information */
+ t_u32 fw_cap_info;
+
+ /** Interrupt status */
+ t_u8 sdio_ireg;
+ /** SDIO multiple port read bitmap */
+ t_u16 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u16 mp_wr_bitmap;
+ /** SDIO end port from txbufcfg */
+ t_u16 mp_end_port;
+ /** SDIO port mask calculated based on txbufcfg end port */
+ t_u16 mp_data_port_mask;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Array to store values of SDIO multiple port group registers */
+ t_u8 *mp_regs;
+ /** allocated buf to read SDIO multiple port group registers */
+ t_u8 *mp_regs_buf;
+ /** Array to store data transfer eligibility based on tid (QoS-over-SDIO) */
+ t_u8 tx_eligibility[MAX_NUM_TID];
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** data structure for SDIO MPA TX */
+ sdio_mpa_tx mpa_tx;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** data structure for SDIO MPA RX */
+ sdio_mpa_rx mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ /** Event cause */
+ t_u32 event_cause;
+ /** Event buffer */
+ pmlan_buffer pmlan_buffer_event;
+ /** Upload length */
+ t_u32 upld_len;
+ /** Upload buffer*/
+ t_u8 upld_buf[WLAN_UPLD_SIZE];
+ /** Data sent:
+ * TRUE - Data is sent to fw, no Tx Done received
+ * FALSE - Tx done received for previous Tx
+ */
+ t_u8 data_sent;
+ /** CMD sent:
+ * TRUE - CMD is sent to fw, no CMD Done received
+ * FALSE - CMD done received for previous CMD
+ */
+ t_u8 cmd_sent;
+ /** CMD Response received:
+ * TRUE - CMD is response is received from fw, and yet to process
+ * FALSE - No cmd response to process
+ */
+ t_u8 cmd_resp_received;
+ /** Event received:
+ * TRUE - Event received from fw, and yet to process
+ * FALSE - No events to process
+ */
+ t_u8 event_received;
+
+ /** Data received:
+ * TRUE - Event received from fw, and yet to process
+ * FALSE - No events to process
+ */
+ t_u8 data_received;
+
+ /** Command-related variables */
+ /** Command sequence number */
+ t_u16 seq_num;
+ /** Command controller nodes */
+ cmd_ctrl_node *cmd_pool;
+ /** Current Command */
+ cmd_ctrl_node *curr_cmd;
+ /** mlan_lock for command */
+ t_void *pmlan_cmd_lock;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Last init fw command id */
+ t_u16 last_init_cmd;
+ /** Command timer */
+ t_void *pmlan_cmd_timer;
+ /** Command timer set flag */
+ t_u8 cmd_timer_is_set;
+
+ /** Command Queues */
+ /** Free command buffers */
+ mlan_list_head cmd_free_q;
+ /** Pending command buffers */
+ mlan_list_head cmd_pending_q;
+ /** Command queue for scanning */
+ mlan_list_head scan_pending_q;
+ /** mlan_processing */
+ t_u32 scan_processing;
+
+ /** Region code */
+ t_u16 region_code;
+ /** Region Channel data */
+ region_chan_t region_channel[MAX_REGION_CHANNEL_NUM];
+ /** FSM variable for 11d support */
+ wlan_802_11d_state_t state_11d;
+ /** Universal Channel data */
+ region_chan_t universal_channel[MAX_REGION_CHANNEL_NUM];
+ /** Parsed region channel */
+ parsed_region_chan_11d_t parsed_region_chan;
+ /** 11D and Domain Regulatory Data */
+ wlan_802_11d_domain_reg_t domain_reg;
+ /** FSM variable for 11h support */
+ wlan_11h_state_t state_11h;
+ /** FSM variable for MEAS support */
+ wlan_meas_state_t state_meas;
+ /** Scan table */
+ BSSDescriptor_t *pscan_table;
+
+ /** Number of records in the scan table */
+ t_u32 num_in_scan_table;
+ /** Scan probes */
+ t_u16 scan_probes;
+
+ /** Scan type */
+ t_u8 scan_type;
+ /** Scan mode */
+ t_u32 scan_mode;
+ /** Specific scan time */
+ t_u16 specific_scan_time;
+ /** Active scan time */
+ t_u16 active_scan_time;
+ /** Passive scan time */
+ t_u16 passive_scan_time;
+
+ /** Beacon buffer */
+ t_u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
+ /** Pointer to valid beacon buffer end */
+ t_u8 *pbcn_buf_end;
+
+ /** F/W supported bands */
+ t_u8 fw_bands;
+ /** User selected band to start adhoc network */
+ t_u8 adhoc_start_band;
+ /** User selected bands */
+ t_u8 config_bands;
+ /** Pointer to channel list last sent to the firmware for scanning */
+ ChanScanParamSet_t *pscan_channels;
+
+ /** Tx lock flag */
+ t_u8 tx_lock_flag;
+
+ /** sleep_params_t */
+ sleep_params_t sleep_params;
+ /** sleep_period_t (Enhanced Power Save) */
+ sleep_period_t sleep_period;
+
+ /** Power Save mode */
+ /**
+ * Wlan802_11PowerModeCAM = disable
+ * Wlan802_11PowerModePSP = enable
+ */
+ t_u16 ps_mode;
+ /** Power Save state */
+ t_u32 ps_state;
+ /** Need to wakeup flag */
+ t_u8 need_to_wakeup;
+
+ /** Multiple DTIM */
+ t_u16 multiple_dtim;
+ /** Local listen interval */
+ t_u16 local_listen_interval;
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+
+ /** Power save confirm sleep command buffer */
+ pmlan_buffer psleep_cfm;
+ /** Beacon miss timeout */
+ t_u16 bcn_miss_time_out;
+
+ /** AdHoc awake period */
+ t_u16 adhoc_awake_period;
+
+ /** Deep Sleep flag */
+ t_u8 is_deep_sleep;
+
+ /** delay null pkt flag */
+ t_u8 delay_null_pkt;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+ /** Enhanced PS mode */
+ t_u16 enhanced_ps_mode;
+ /** Device wakeup required flag */
+ t_u8 pm_wakeup_card_req;
+
+ /** Number of wakeup tries */
+ t_u32 pm_wakeup_fw_try;
+
+ /** Host Sleep configured flag */
+ t_u8 is_hs_configured;
+ /** Host Sleep configuration */
+ HostCmd_DS_802_11_HS_CFG_ENH hs_cfg;
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Event body */
+ t_u8 event_body[MAX_EVENT_SIZE];
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** 802.11n Device Capabilities */
+ t_u32 usr_dot_11n_dev_cap;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 usr_dev_mcs_support;
+ /** Enable 11n support for adhoc start */
+ t_u8 adhoc_11n_enabled;
+ /** Adhoc Secondary Channel Offset */
+ t_u8 chan_offset;
+
+#ifdef MFG_CMD_SUPPORT
+ t_u32 mfg_mode;
+#endif
+ /** Debug */
+ wlan_dbg dbg;
+
+ /** ARP filter buffer */
+ t_u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
+ /** ARP filter buffer size */
+ t_u32 arp_filter_size;
+
+} mlan_adapter, *pmlan_adapter;
+
+/* Function prototype */
+/** Download firmware */
+mlan_status wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw);
+
+/** Initialize firmware */
+mlan_status wlan_init_fw(IN pmlan_adapter pmadapter);
+
+/** Initialize firmware complete */
+mlan_status wlan_init_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Shutdown firmware */
+mlan_status wlan_shutdown_fw(IN pmlan_adapter pmadapter);
+
+/** Shutdown firmware complete */
+mlan_status wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Receive event */
+mlan_status wlan_recv_event(pmlan_private priv,
+ mlan_event_id event_id, t_void * pmevent);
+
+/** Initialize mlan_adapter structure */
+t_void wlan_init_adapter(IN pmlan_adapter pmadapter);
+
+/** Deletes the BSS priority table */
+t_void wlan_delete_bsspriotbl(pmlan_private priv);
+
+/** Initialize mlan_private structure */
+t_void wlan_init_priv(IN pmlan_private priv);
+
+/** Process event */
+mlan_status wlan_process_event(pmlan_adapter pmadapter);
+
+/** Prepare command */
+mlan_status wlan_prepare_cmd(IN pmlan_private priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf);
+
+/** cmd timeout handler */
+t_void wlan_cmd_timeout_func(t_void * FunctionContext);
+/** process host cmd */
+mlan_status wlan_misc_ioctl_host_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process init/shutdown cmd*/
+mlan_status wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process debug info */
+mlan_status wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+/** Free adapter */
+t_void wlan_free_adapter(pmlan_adapter pmadapter);
+/** Allocate command buffer */
+mlan_status wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Free command buffer */
+mlan_status wlan_free_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Request command lock */
+t_void wlan_request_cmd_lock(mlan_adapter * pmadapter);
+/** Release command lock */
+t_void wlan_release_cmd_lock(mlan_adapter * pmadapter);
+/**Cancel pending command */
+void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter);
+/**Cancel pending ioctl */
+void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** Insert command to free queue */
+t_void wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Insert command to pending queue */
+t_void wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 addtail);
+
+/** Execute next command */
+mlan_status wlan_exec_next_cmd(mlan_adapter * pmadapter);
+/** Proecess command response */
+mlan_status wlan_process_cmdresp(mlan_adapter * pmadapter);
+/** Handle received packet, has extra handling for aggregate packets */
+mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Process transmission */
+mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param);
+/** Transmit a null data packet */
+mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+mlan_status wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size,
+ t_u32 mpa_rx_buf_size);
+
+mlan_status wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter);
+#endif
+
+/** Process write data complete */
+mlan_status wlan_write_data_complete(pmlan_adapter pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Process receive packet complete */
+mlan_status wlan_recv_packet_complete(t_void * pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Clean Tx Rx queues */
+t_void wlan_clean_txrx(pmlan_private priv);
+
+/** Check if this is the last packet */
+t_u8 wlan_check_last_packet_indication(pmlan_private priv);
+
+/** function to allocate a mlan_buffer */
+pmlan_buffer wlan_alloc_mlan_buffer(pmlan_callbacks pcb, t_u32 data_len);
+/** function to free a mlan_buffer */
+t_void wlan_free_mlan_buffer(pmlan_callbacks pcb, pmlan_buffer pmbuf);
+
+/** Check Power Save condition */
+t_void wlan_check_ps_cond(mlan_adapter * pmadapter);
+
+/** Process sleep confirm command response */
+void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 len);
+
+/** Perform hs related activities on receving the power up interrupt */
+void wlan_process_hs_config(pmlan_adapter pmadapter);
+
+mlan_status wlan_pm_reset_card(pmlan_adapter adapter);
+mlan_status wlan_pm_wakeup_card(pmlan_adapter pmadapter);
+
+t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated);
+/** Handles the command response of hs_cfg */
+mlan_status wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Sends HS_WAKEUP event to applications */
+t_void wlan_host_sleep_wakeup_event(pmlan_private priv);
+
+/** Process received packet */
+mlan_status wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** ioctl handler for station mode */
+mlan_status mlan_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req);
+
+/** cmd handler for station mode */
+mlan_status mlan_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf);
+
+/** cmdresp handler for station mode */
+mlan_status mlan_process_sta_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl);
+
+/** rx handler for station mode */
+mlan_status mlan_process_sta_rx_packet(IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+
+/** event handler for station mode */
+mlan_status mlan_process_sta_event(IN t_void * priv);
+
+/** fill txpd for station mode */
+t_void *mlan_process_sta_txpd(IN t_void * priv, IN pmlan_buffer pmbuf);
+
+/** send init cmd to firmware for station mode */
+mlan_status mlan_sta_init_cmd(IN t_void * priv, IN t_u8 first_sta);
+
+/** Scan for networks */
+mlan_status wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in);
+
+/** Scan for specific SSID */
+mlan_status wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * preq_ssid);
+
+/** Scan command handler */
+mlan_status wlan_cmd_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+
+/** Queue scan command handler */
+t_void wlan_queue_scan_cmd(IN mlan_private * pmpriv,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Handler for scan command response */
+mlan_status wlan_ret_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Find an SSID in a list */
+t_s32 wlan_find_ssid_in_list(IN pmlan_private pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find a BSSID in a list */
+t_s32 wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find best network */
+mlan_status wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid);
+
+/** Compare two SSIDs */
+t_s32 wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2);
+
+/** Associate */
+mlan_status wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Associate command handler */
+mlan_status wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for association command response */
+mlan_status wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Reset connected state */
+t_void wlan_reset_connect_state(pmlan_private priv);
+
+t_void wlan_2040_coex_event(pmlan_private pmpriv);
+
+/** convert band to radio type */
+t_u8 wlan_band_to_radio_type(IN t_u8 band);
+
+/** Disconnect */
+mlan_status wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req,
+ IN mlan_802_11_mac_addr * mac);
+
+/** Ad-Hoc start */
+mlan_status wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * padhoc_ssid);
+
+/** Ad-Hoc join */
+mlan_status wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Ad-Hoc start command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Ad-Hoc command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for Ad-Hoc commands */
+mlan_status wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Handler for bgscan query commands */
+mlan_status wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+
+/* 802.11D related functions */
+/** Initialize 11D */
+t_void wlan_11d_init(mlan_adapter * pmadapter);
+/** Enable 11D */
+mlan_status wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf,
+ state_11d_t flag);
+/** Set universal table */
+mlan_status wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band);
+/** Get 11D state */
+state_11d_t wlan_11d_get_state(mlan_private * pmpriv);
+/** Create 11D country information for downloading */
+mlan_status wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band);
+/** Get scan type */
+t_u8 wlan_11d_get_scan_type(pmlan_adapter pmadapter, t_u8 chan,
+ parsed_region_chan_11d_t * parsed_region_chan);
+/** Set 11D universal table */
+int wlan_set_universal_table(mlan_private * pmpriv, t_u8 band);
+/** Command handler for 11D country info */
+mlan_status wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd,
+ t_u16 cmd_action);
+/** Handler for 11D country info command response */
+mlan_status wlan_ret_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * resp);
+/** Parse 11D country info */
+mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pBSSDesc);
+/** Prepare 11D domain information for download */
+mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv);
+/** Parse 11D country information */
+mlan_status wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
+ IEEEtypes_CountryInfoFullSet_t *
+ country_info, t_u8 band,
+ parsed_region_chan_11d_t *
+ parsed_region_chan);
+
+/** Convert channel to frequency */
+t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band);
+/** Get Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band, t_u16 channel,
+ region_chan_t *
+ region_channel);
+/** Find Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel);
+/** Find Channel-Frequency-Power by band and frequecy */
+chan_freq_power_t *wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter,
+ t_u8 band, t_u32 freq);
+/** Get region Channel-Frequency-Power tabel */
+chan_freq_power_t *wlan_get_region_cfp_table(pmlan_adapter pmadapter,
+ t_u8 region, t_u8 band,
+ int *cfp_no);
+/** Get Tx power of channel from Channel-Frequency-Power */
+t_u8 wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel);
+/** Convert index into data rate */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 ht_info);
+t_u32 wlan_find_freq_from_band_chan(t_u8, t_u8);
+/** Set region table */
+mlan_status wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band);
+/** Append the vendor specific TLV */
+int wlan_cmd_append_vsie_tlv(mlan_private * pmpriv, t_u16 vsie_mask,
+ t_u8 ** ppbuffer);
+
+/* Rate related functions */
+/** Convert index into data rate */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 ht_info);
+/** Get active data rates */
+t_u32 wlan_get_active_data_rates(mlan_private * pmpriv,
+ WLAN_802_11_RATES rates);
+/** Get supported data rates */
+t_u32 wlan_get_supported_rates(mlan_private * pmpriv, WLAN_802_11_RATES rates);
+/** Convert data rate to index */
+t_u8 wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate);
+/** Check if rate is auto */
+t_u8 wlan_is_rate_auto(mlan_private * pmpriv);
+/** Get rate index */
+int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rateBitmap, int size);
+/** Region code index table */
+extern t_u16 region_code_index[MRVDRV_MAX_REGION_CODE];
+
+/* Save a beacon buffer of the current bss descriptor */
+t_void wlan_save_curr_bcn(IN mlan_private * pmpriv);
+/* Restore a beacon buffer of the current bss descriptor */
+t_void wlan_restore_curr_bcn(IN mlan_private * pmpriv);
+/* Free a beacon buffer of the current bss descriptor */
+t_void wlan_free_curr_bcn(IN mlan_private * pmpriv);
+
+/**
+ * @brief RA based queueing
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+queuing_ra_based(pmlan_private priv)
+{
+ /*
+ * Currently we assume if we are in Infra, then DA=RA. This might not be
+ * true in the future
+ */
+ if ((priv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ (priv->bss_type == MLAN_BSS_TYPE_STA))
+ return MFALSE;
+
+ return MTRUE;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param pos The position for copy
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ *
+ * @return Number of Rates copied
+ */
+static INLINE t_u32
+wlan_copy_rates(t_u8 * dest, t_u32 pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(WLAN_802_11_RATES))
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief strlen
+ *
+ * @param str A pointer to string
+ *
+ * @return Length of string
+ */
+static INLINE t_u32
+wlan_strlen(const t_s8 * str)
+{
+ t_u32 i;
+
+ for (i = 0; str[i] != 0; i++) {
+ }
+ return i;
+}
+
+/** delay unit */
+typedef enum _delay_unit
+{
+ USEC,
+ MSEC,
+ SEC,
+} t_delay_unit;
+
+/** delay function */
+t_void wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u);
+
+/** delay function wrapper */
+#define wlan_delay(p, n) wlan_delay_func(p, n, SEC)
+/** delay function wrapper */
+#define wlan_mdelay(p, n) wlan_delay_func(p, n, MSEC)
+/** delay function wrapper */
+#define wlan_udelay(p, n) wlan_delay_func(p, n, USEC)
+
+/** Function to check if any command is pending in the queue */
+#define IS_COMMAND_PENDING(pmadapter) ((cmd_ctrl_node *)util_peek_list(&pmadapter->cmd_pending_q,\
+ pmadapter->callbacks.moal_spin_lock,\
+ pmadapter->callbacks.moal_spin_unlock))
+
+/**
+ * @brief This function returns first available priv
+ * based on the bss_type
+ *
+ * @param handle A pointer to mlan_adapter
+ * @param bss_type BSS type or MLAN_BSS_TYPE_ANY
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *
+wlan_get_priv(mlan_adapter * pmadapter, mlan_bss_type bss_type)
+{
+ int i;
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ if (bss_type == MLAN_BSS_TYPE_ANY ||
+ pmadapter->priv[i]->bss_type == bss_type)
+ break;
+ }
+ }
+ return ((i < MLAN_MAX_BSS_NUM) ? pmadapter->priv[i] : MNULL);
+}
+
+#endif /* !_MLAN_MAIN_H_ */
diff --git a/wlan_src/mlan/mlan_meas.c b/wlan_src/mlan/mlan_meas.c
new file mode 100755
index 0000000..292ac67
--- /dev/null
+++ b/wlan_src/mlan/mlan_meas.c
@@ -0,0 +1,488 @@
+/**
+ * @file mlan_meas.c
+ *
+ * @brief Implementation of measurement interface code with the app/firmware
+ *
+ * Driver implementation for sending and retrieving measurement requests
+ * and responses.
+ *
+ * Current use is limited to 802.11h.
+ *
+ * Requires use of the following preprocessor define:
+ * - ENABLE_MEAS
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/24/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_meas.h"
+
+/** Default measurement duration when not provided by the application */
+#define WLAN_MEAS_DEFAULT_MEAS_DURATION 1000U /* TUs */
+
+#ifdef DEBUG_LEVEL2
+/** String descriptions of the different measurement enums. Debug display */
+static const char *meas_type_str[WLAN_MEAS_NUM_TYPES] = {
+ "basic",
+};
+
+/**
+ * @brief Retrieve the measurement string representation of a meas_type enum
+ * Used for debug display only
+ *
+ * @param meas_type Measurement type enumeration input for string lookup
+ *
+ * @return Constant string representing measurement type
+ */
+static const char *
+wlan_meas_get_meas_type_str(MeasType_t meas_type)
+{
+ if (meas_type <= WLAN_MEAS_11H_MAX_TYPE)
+ return meas_type_str[meas_type];
+
+ return "Invld";
+}
+#endif
+
+/**
+ * @brief Debug print display of the input measurement request
+ *
+ * @param pmeas_req Pointer to the measurement request to display
+ *
+ * @return void
+ */
+static void
+wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req)
+{
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+
+ PRINTM(MINFO, "Meas: Req: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_req->mac_addr[0],
+ pmeas_req->mac_addr[1],
+ pmeas_req->mac_addr[2],
+ pmeas_req->mac_addr[3],
+ pmeas_req->mac_addr[4], pmeas_req->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Req: dlgTkn: %d\n", pmeas_req->dialog_token);
+ PRINTM(MINFO, "Meas: Req: mode: dm[%c] rpt[%c] req[%c]\n",
+ pmeas_req->req_mode.duration_mandatory ? 'X' : ' ',
+ pmeas_req->req_mode.report ? 'X' : ' ',
+ pmeas_req->req_mode.request ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Req: : en[%c] par[%c]\n",
+ pmeas_req->req_mode.enable ? 'X' : ' ',
+ pmeas_req->req_mode.parallel ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Req: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_req->meas_type));
+#endif
+
+ switch (pmeas_req->meas_type) {
+ case WLAN_MEAS_BASIC:
+ /* Lazy cheat, fields of bas, cca, rpi union match on the request */
+ PRINTM(MINFO, "Meas: Req: chan: %u\n", pmeas_req->req.basic.channel);
+ PRINTM(MINFO, "Meas: Req: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_req->req.basic.start_time));
+ PRINTM(MINFO, "Meas: Req: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_req->req.basic.duration));
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Req: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+}
+
+/**
+ * @brief Debug print display of the input measurement report
+ *
+ * @param pmeas_rpt Pointer to measurement report to display
+ *
+ * @return void
+ */
+static void
+wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ PRINTM(MINFO, "Meas: Rpt: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_rpt->mac_addr[0],
+ pmeas_rpt->mac_addr[1],
+ pmeas_rpt->mac_addr[2],
+ pmeas_rpt->mac_addr[3],
+ pmeas_rpt->mac_addr[4], pmeas_rpt->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Rpt: dlgTkn: %d\n", pmeas_rpt->dialog_token);
+
+ PRINTM(MINFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n",
+ *(t_u8 *) & pmeas_rpt->rpt_mode,
+ pmeas_rpt->rpt_mode.refused ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.incapable ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.late ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Rpt: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_rpt->meas_type));
+#endif
+
+ switch (pmeas_rpt->meas_type) {
+ case WLAN_MEAS_BASIC:
+ PRINTM(MINFO, "Meas: Rpt: chan: %u\n", pmeas_rpt->rpt.basic.channel);
+ PRINTM(MINFO, "Meas: Rpt: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_rpt->rpt.basic.start_time));
+ PRINTM(MINFO, "Meas: Rpt: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_rpt->rpt.basic.duration));
+ PRINTM(MINFO, "Meas: Rpt: bas: (%x): unmsd[%c], radar[%c]\n",
+ *(t_u8 *) & (pmeas_rpt->rpt.basic.map),
+ pmeas_rpt->rpt.basic.map.unmeasured ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.radar ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Rpt: bas: unidSig[%c] ofdm[%c] bss[%c]\n",
+ pmeas_rpt->rpt.basic.map.unidentified_sig ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.ofdm_preamble ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.bss ? 'X' : ' ');
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Rpt: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * Callback from command processing when a measurement report is received
+ * from the firmware. Perform the following when a report is received:
+ *
+ * -# Debug displays the report if compiled with the appropriate flags
+ * -# If we are pending on a specific measurement report token, and it
+ * matches the received report's token, store the report and wake up
+ * any pending threads
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ * passing a HostCmd_DS_MEASUREMENT_REPORT structure.
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmdresp_get_report(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt = &resp->params.meas_rpt;
+
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: %#x-%u, Seq=%u, Ret=%u\n",
+ resp->command, resp->size, resp->seq_num, resp->result);
+
+ /* Debug displays the measurement report */
+ wlan_meas_dump_meas_rpt(pmeas_rpt);
+
+ /*
+ * Check if we are pending on a measurement report and it matches
+ * the dialog token of the received report:
+ */
+ if (pmadapter->state_meas.meas_rpt_pend_on
+ && pmadapter->state_meas.meas_rpt_pend_on == pmeas_rpt->dialog_token) {
+ PRINTM(MINFO, "Meas: Rpt: RCV'd Pend on meas #%d\n",
+ pmadapter->state_meas.meas_rpt_pend_on);
+
+ /* Clear the pending report indicator */
+ pmadapter->state_meas.meas_rpt_pend_on = 0;
+
+ /* Copy the received report into the measurement state for retrieval */
+ memcpy(&pmadapter->state_meas.meas_rpt_returned, pmeas_rpt,
+ sizeof(pmadapter->state_meas.meas_rpt_returned));
+
+ /*
+ * Wake up any threads pending on the wait queue
+ */
+ }
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_MEASURMENT_REPORT firmware command
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_MEASUREMENT_REQUEST passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmd_request(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req =
+ (HostCmd_DS_MEASUREMENT_REQUEST *) pinfo_buf;
+
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REQUEST;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REQUEST) + S_DS_GEN;
+
+ memcpy(&pcmd_ptr->params.meas_req, pmeas_req,
+ sizeof(pcmd_ptr->params.meas_req));
+
+ PRINTM(MINFO, "Meas: Req: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+
+ wlan_meas_dump_meas_req(pmeas_req);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * The firmware will send a EVENT_MEAS_REPORT_RDY event when it
+ * completes or receives a measurement report. The event response
+ * handler will then start a HostCmd_CMD_MEASUREMENT_REPORT firmware command
+ * which gets completed for transmission to the firmware in this routine.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_meas_cmd_get_report(mlan_private * pmpriv, HostCmd_DS_COMMAND * pcmd_ptr)
+{
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REPORT;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REPORT) + S_DS_GEN;
+
+ memset(&pcmd_ptr->params.meas_rpt, 0x00, sizeof(pcmd_ptr->params.meas_rpt));
+
+ /*
+ * Set the meas_rpt.mac_addr to our mac address to get a meas report,
+ * setting the mac to another STA address instructs the firmware
+ * to transmit this measurement report frame instead
+ */
+ memcpy(pcmd_ptr->params.meas_rpt.mac_addr, pmpriv->curr_addr,
+ sizeof(pcmd_ptr->params.meas_rpt.mac_addr));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initialize any needed structures for the measurement code
+ *
+ * @param pmadapter mlan_adapter structure
+ *
+ * @return void
+ */
+void
+wlan_meas_init(mlan_adapter * pmadapter)
+{
+ ENTER();
+ LEAVE();
+}
+
+/**
+ * @brief Send the input measurement request to the firmware.
+ *
+ * If the dialog token in the measurement request is set to 0, the function
+ * will use an local static auto-incremented token in the measurement
+ * request. This ensures the dialog token is always set.
+ *
+ * If wait_for_resp_timeout is set, the function will block its return on
+ * a timeout or returned measurement report that matches the requests
+ * dialog token.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pmeas_req Pointer to the measurement request to send
+ * @param wait_for_resp_timeout Timeout value of the measurement request
+ * in ms.
+ * @param pmeas_rpt Output parameter: Pointer for the resulting
+ * measurement report
+ *
+ * @return
+ * - 0 for success
+ * - -ETIMEDOUT if the measurement report does not return before
+ * the timeout expires
+ * - Error return from wlan_prepare_cmd routine otherwise
+ */
+int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ static t_u8 auto_dialog_tok = 0;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ int ret;
+ t_u32 calc_timeout;
+
+ ENTER();
+
+ /* If dialogTok was set to 0 or not provided, autoset */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : ++auto_dialog_tok);
+
+ /* Check for rollover of the dialog token. Avoid using 0 as a token */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : 1);
+
+ /*
+ * If the request is to pend waiting for the result, set the dialog token
+ * of this measurement request in the state structure. The measurement
+ * report handling routines can then check the incoming measurement
+ * reports for a match with this dialog token.
+ */
+ if (wait_for_resp_timeout) {
+ pmeas_state->meas_rpt_pend_on = pmeas_req->dialog_token;
+ PRINTM(MINFO, "Meas: Req: START Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ }
+
+ /* Send the measurement request to the firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEASUREMENT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, MNULL, (void *) pmeas_req);
+
+ /*
+ * If the measurement request was sent successfully, and the function
+ * must wait for the report, suspend execution until the meas_rpt_pend_on
+ * variable in the state structure has been reset to 0 by the report
+ * handling routines.
+ */
+ if (!ret && wait_for_resp_timeout) {
+ /* Add ~25% overhead to the timeout for firmware overhead */
+ calc_timeout = wait_for_resp_timeout + (wait_for_resp_timeout >> 2);
+
+ PRINTM(MINFO, "Meas: Req: TIMEOUT set to %d ms\n", calc_timeout);
+
+ /* extra 10 ms for the driver overhead - helps with small meas */
+ calc_timeout += 10;
+
+ PRINTM(MINFO, "Meas: Req: TIMEOUT set to %d milliseconds\n",
+ calc_timeout);
+
+ if (pmeas_state->meas_rpt_pend_on) {
+ PRINTM(MINFO, "Meas: Req: TIMEOUT Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ PRINTM(MINFO, "Meas: Req: DONE Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ memcpy(pmeas_rpt, &pmeas_state->meas_rpt_returned,
+ sizeof(HostCmd_DS_MEASUREMENT_REPORT));
+ }
+ }
+
+ /*
+ * The measurement request failed or we are not waiting for a response.
+ * In either case, the rpt_pend_on variable should be zero.
+ */
+ pmeas_state->meas_rpt_pend_on = 0;
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief Prepare the HostCmd_DS_Command structure for a measurement command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer passthrough with data necessary for a
+ * specific command type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+int
+wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ ret = wlan_meas_cmd_request(pmpriv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_get_report(pmpriv, pcmd_ptr);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware for a measurement
+ * command
+ *
+ * Use the Command field to determine if the command response being
+ * is for meas. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_802_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ PRINTM(MINFO, "Meas: Req Resp: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_get_report(pmpriv, resp);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_meas.h b/wlan_src/mlan/mlan_meas.h
new file mode 100755
index 0000000..97c7ffe
--- /dev/null
+++ b/wlan_src/mlan/mlan_meas.h
@@ -0,0 +1,45 @@
+/**
+ * @file mlan_meas.h
+ *
+ * @brief Interface for the measurement module implemented in mlan_meas.c
+ *
+ * Driver interface functions and type declarations for the measurement module
+ * implemented in mlan_meas.c
+ *
+ * @sa mlan_meas.c
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/25/2009: initial version
+************************************************************/
+
+#ifndef _MLAN_MEAS_H_
+#define _MLAN_MEAS_H_
+
+#include "mlan_fw.h"
+
+/* Initialize the measurement code on startup */
+extern void wlan_meas_init(mlan_adapter * pmadapter);
+
+/* Send a given measurement request to the firmware, report back the result */
+extern int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt);
+
+/* Setup a measurement command before it is sent to the firmware */
+extern int wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/* Handle a given measurement command response from the firmware */
+extern int wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp);
+
+#endif /* _MLAN_MEAS_H_ */
diff --git a/wlan_src/mlan/mlan_misc.c b/wlan_src/mlan/mlan_misc.c
new file mode 100755
index 0000000..8e78f2e
--- /dev/null
+++ b/wlan_src/mlan/mlan_misc.c
@@ -0,0 +1,406 @@
+/**
+ * @file mlan_misc.c
+ *
+ * @brief This file include Miscellaneous functions for MLAN module
+ *
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief send host cmd
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_host_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0,
+ 0,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function init/shutdown command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd;
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT)
+ cmd = HostCmd_CMD_FUNC_INIT;
+ else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN)
+ cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+ else {
+ PRINTM(MERROR, "Unsupported parameter\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get debug information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ memcpy(pmpriv->wmm.packets_out, info->param.debug_info.packets_out,
+ sizeof(pmpriv->wmm.packets_out));
+ pmadapter->max_tx_buf_size =
+ (t_u16) info->param.debug_info.max_tx_buf_size;
+ pmadapter->tx_buf_size = (t_u16) info->param.debug_info.tx_buf_size;
+ pmadapter->ps_mode = info->param.debug_info.ps_mode;
+ pmadapter->ps_state = info->param.debug_info.ps_state;
+ pmadapter->is_deep_sleep = info->param.debug_info.is_deep_sleep;
+ pmadapter->pm_wakeup_card_req =
+ info->param.debug_info.pm_wakeup_card_req;
+ pmadapter->pm_wakeup_fw_try = info->param.debug_info.pm_wakeup_fw_try;
+ pmadapter->is_hs_configured = info->param.debug_info.is_hs_configured;
+ pmadapter->hs_activated = info->param.debug_info.hs_activated;
+
+ pmadapter->dbg.num_cmd_host_to_card_failure =
+ info->param.debug_info.num_cmd_host_to_card_failure;
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure =
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure;
+ pmadapter->dbg.num_tx_host_to_card_failure =
+ info->param.debug_info.num_tx_host_to_card_failure;
+ pmadapter->dbg.num_event_deauth =
+ info->param.debug_info.num_event_deauth;
+ pmadapter->dbg.num_event_disassoc =
+ info->param.debug_info.num_event_disassoc;
+ pmadapter->dbg.num_event_link_lost =
+ info->param.debug_info.num_event_link_lost;
+ pmadapter->dbg.num_cmd_deauth = info->param.debug_info.num_cmd_deauth;
+ pmadapter->dbg.num_cmd_assoc_success =
+ info->param.debug_info.num_cmd_assoc_success;
+ pmadapter->dbg.num_cmd_assoc_failure =
+ info->param.debug_info.num_cmd_assoc_failure;
+ pmadapter->dbg.num_tx_timeout = info->param.debug_info.num_tx_timeout;
+ pmadapter->dbg.num_cmd_timeout = info->param.debug_info.num_cmd_timeout;
+ pmadapter->dbg.timeout_cmd_id = info->param.debug_info.timeout_cmd_id;
+ pmadapter->dbg.timeout_cmd_act = info->param.debug_info.timeout_cmd_act;
+ memcpy(pmadapter->dbg.last_cmd_id, info->param.debug_info.last_cmd_id,
+ sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(pmadapter->dbg.last_cmd_act, info->param.debug_info.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ pmadapter->dbg.last_cmd_index = info->param.debug_info.last_cmd_index;
+ memcpy(pmadapter->dbg.last_cmd_resp_id,
+ info->param.debug_info.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ pmadapter->dbg.last_cmd_resp_index =
+ info->param.debug_info.last_cmd_resp_index;
+ memcpy(pmadapter->dbg.last_event, info->param.debug_info.last_event,
+ sizeof(pmadapter->dbg.last_event));
+ pmadapter->dbg.last_event_index =
+ info->param.debug_info.last_event_index;
+
+ pmadapter->data_sent = info->param.debug_info.data_sent;
+ pmadapter->cmd_sent = info->param.debug_info.cmd_sent;
+ pmadapter->mp_rd_bitmap = info->param.debug_info.mp_rd_bitmap;
+ pmadapter->mp_wr_bitmap = info->param.debug_info.mp_wr_bitmap;
+ pmadapter->curr_rd_port = info->param.debug_info.curr_rd_port;
+ pmadapter->curr_wr_port = info->param.debug_info.curr_wr_port;
+ pmadapter->cmd_resp_received = info->param.debug_info.cmd_resp_received;
+ } else { /* MLAN_ACT_GET */
+ memcpy(info->param.debug_info.packets_out, pmpriv->wmm.packets_out,
+ sizeof(pmpriv->wmm.packets_out));
+ info->param.debug_info.max_tx_buf_size =
+ (t_u32) pmadapter->max_tx_buf_size;
+ info->param.debug_info.tx_buf_size = (t_u32) pmadapter->tx_buf_size;
+ info->param.debug_info.rx_tbl_num =
+ wlan_get_rxreorder_tbl(pmpriv, info->param.debug_info.rx_tbl);
+ info->param.debug_info.tx_tbl_num =
+ wlan_get_txbastream_tbl(pmpriv, info->param.debug_info.tx_tbl);
+ info->param.debug_info.ps_mode = pmadapter->ps_mode;
+ info->param.debug_info.ps_state = pmadapter->ps_state;
+ info->param.debug_info.is_deep_sleep = pmadapter->is_deep_sleep;
+
+ info->param.debug_info.pm_wakeup_card_req =
+ pmadapter->pm_wakeup_card_req;
+ info->param.debug_info.pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try;
+ info->param.debug_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.debug_info.hs_activated = pmadapter->hs_activated;
+
+ info->param.debug_info.num_cmd_host_to_card_failure
+ = pmadapter->dbg.num_cmd_host_to_card_failure;
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure
+ = pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+ info->param.debug_info.num_tx_host_to_card_failure
+ = pmadapter->dbg.num_tx_host_to_card_failure;
+ info->param.debug_info.num_event_deauth =
+ pmadapter->dbg.num_event_deauth;
+ info->param.debug_info.num_event_disassoc =
+ pmadapter->dbg.num_event_disassoc;
+ info->param.debug_info.num_event_link_lost =
+ pmadapter->dbg.num_event_link_lost;
+ info->param.debug_info.num_cmd_deauth = pmadapter->dbg.num_cmd_deauth;
+ info->param.debug_info.num_cmd_assoc_success =
+ pmadapter->dbg.num_cmd_assoc_success;
+ info->param.debug_info.num_cmd_assoc_failure =
+ pmadapter->dbg.num_cmd_assoc_failure;
+ info->param.debug_info.num_tx_timeout = pmadapter->dbg.num_tx_timeout;
+ info->param.debug_info.num_cmd_timeout = pmadapter->dbg.num_cmd_timeout;
+ info->param.debug_info.timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
+ info->param.debug_info.timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
+ memcpy(info->param.debug_info.last_cmd_id, pmadapter->dbg.last_cmd_id,
+ sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(info->param.debug_info.last_cmd_act, pmadapter->dbg.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ info->param.debug_info.last_cmd_index = pmadapter->dbg.last_cmd_index;
+ memcpy(info->param.debug_info.last_cmd_resp_id,
+ pmadapter->dbg.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ info->param.debug_info.last_cmd_resp_index =
+ pmadapter->dbg.last_cmd_resp_index;
+ memcpy(info->param.debug_info.last_event, pmadapter->dbg.last_event,
+ sizeof(pmadapter->dbg.last_event));
+ info->param.debug_info.last_event_index =
+ pmadapter->dbg.last_event_index;
+
+ info->param.debug_info.mp_rd_bitmap = pmadapter->mp_rd_bitmap;
+ info->param.debug_info.mp_wr_bitmap = pmadapter->mp_wr_bitmap;
+ info->param.debug_info.curr_rd_port = pmadapter->curr_rd_port;
+ info->param.debug_info.curr_wr_port = pmadapter->curr_wr_port;
+ info->param.debug_info.data_sent = pmadapter->data_sent;
+ info->param.debug_info.cmd_sent = pmadapter->cmd_sent;
+ info->param.debug_info.cmd_resp_received = pmadapter->cmd_resp_received;
+ }
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_wakeup_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ PRINTM(MCMND, "Wakeup device...\n");
+ ret =
+ pcb->moal_write_reg(pmadapter->pmoal_handle, CONFIGURATION_REG,
+ HOST_POWER_UP);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function resets the PM setting of the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_reset_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ ret = pcb->moal_write_reg(pmadapter->pmoal_handle, CONFIGURATION_REG, 0);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function allocates a mlan_buffer.
+ *
+ * @param pcb Pointer to mlan_callbacks
+ * @param data_len Data length
+ *
+ * @return mlan_buffer pointer or MNULL
+ */
+pmlan_buffer
+wlan_alloc_mlan_buffer(pmlan_callbacks pcb, t_u32 data_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = MNULL;
+ t_u32 buf_size = sizeof(mlan_buffer) + data_len;
+
+ ENTER();
+
+ ret = pcb->moal_malloc(buf_size, (t_u8 **) & pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ pmbuf = MNULL;
+ goto exit;
+ }
+
+ memset(pmbuf, 0, sizeof(mlan_buffer));
+
+ pmbuf->pdesc = MNULL;
+ pmbuf->pbuf = (t_u8 *) pmbuf + sizeof(mlan_buffer);
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = data_len;
+
+ exit:
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function frees a mlan_buffer.
+ *
+ * @param pcb Pointer to mlan_callbacks
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_mlan_buffer(pmlan_callbacks pcb, pmlan_buffer pmbuf)
+{
+ ENTER();
+
+ if (pcb && pmbuf)
+ pcb->moal_mfree((t_u8 *) pmbuf);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Delay function implementation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param delay Delay value
+ * @param u Units of delay (sec, msec or usec)
+ */
+t_void
+wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u)
+{
+ t_u32 now_tv_sec, now_tv_usec;
+ t_u32 upto_tv_sec, upto_tv_usec;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ pcb->moal_get_system_time(&upto_tv_sec, &upto_tv_usec);
+
+ switch (u) {
+ case SEC:
+ upto_tv_sec += delay;
+ break;
+ case MSEC:
+ delay *= 1000;
+ case USEC:
+ upto_tv_sec += (delay / 1000000);
+ upto_tv_usec += (delay % 1000000);
+ break;
+ }
+
+ do {
+ pcb->moal_get_system_time(&now_tv_sec, &now_tv_usec);
+ if (now_tv_sec > upto_tv_sec)
+ return;
+
+ if ((now_tv_sec == upto_tv_sec) && (now_tv_usec >= upto_tv_usec))
+ return;
+ } while (MTRUE);
+
+ return;
+}
diff --git a/wlan_src/mlan/mlan_module.c b/wlan_src/mlan/mlan_module.c
new file mode 100755
index 0000000..29f22be
--- /dev/null
+++ b/wlan_src/mlan/mlan_module.c
@@ -0,0 +1,28 @@
+/** @file mlan_module.c
+ *
+ * @brief This file declares the exported symbols from MLAN.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 12/08/2008: initial version
+******************************************************/
+
+#ifdef LINUX
+#include <linux/module.h>
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+
+EXPORT_SYMBOL(mlan_register);
+EXPORT_SYMBOL(mlan_unregister);
+EXPORT_SYMBOL(mlan_init_fw);
+EXPORT_SYMBOL(mlan_dnld_fw);
+EXPORT_SYMBOL(mlan_shutdown_fw);
+EXPORT_SYMBOL(mlan_send_packet);
+EXPORT_SYMBOL(mlan_ioctl);
+EXPORT_SYMBOL(mlan_main_process);
+EXPORT_SYMBOL(mlan_interrupt);
+#endif /* LINUX */
diff --git a/wlan_src/mlan/mlan_scan.c b/wlan_src/mlan/mlan_scan.c
new file mode 100755
index 0000000..d0f6c49
--- /dev/null
+++ b/wlan_src/mlan/mlan_scan.c
@@ -0,0 +1,3219 @@
+/** @file mlan_scan.c
+ *
+ * @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending scan commands to the firmware.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/** The maximum number of channels the firmware can scan per command */
+#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
+
+/**
+ * Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+/** Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE (sizeof(MrvlIEtypesHeader_t) \
+ + (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN \
+ * sizeof(ChanScanParamSet_t)))
+
+/** Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE (sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
+
+/** Memory needed to store a max number/size WildCard SSID TLV for a firmware scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE \
+ (MRVDRV_MAX_SSID_LIST_LENGTH * (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + MRVDRV_MAX_SSID_LENGTH))
+
+/** Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config) \
+ + sizeof(MrvlIEtypes_NumProbes_t) \
+ + sizeof(MrvlIETypes_HTCap_t) \
+ + CHAN_TLV_MAX_SIZE \
+ + RATE_TLV_MAX_SIZE \
+ + WILDCARD_SSID_TLV_MAX_SIZE)
+
+/** Macro to enable/disable SSID checking before storing a scan table */
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) wlan_ssid_valid(&bssidEntry.ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) MTRUE
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/**
+ * Interally used to send a configured scan cmd between driver routines
+ */
+typedef union
+{
+ /** Scan configuration (variable length) */
+ wlan_scan_cmd_config config;
+ /** Max allocated block */
+ t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+} wlan_scan_cmd_config_tlv;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+t_u8 wpa_oui_aes[] = { 0x00, 0x50, 0xf2, 0x04 }; /* AES */
+t_u8 rsn_oui_aes[] = { 0x00, 0x0f, 0xac, 0x04 }; /* AES */
+
+/**
+ * @brief This function will parse a given IE for a given OUI
+ *
+ * Parse a given WPA/RSN IE to find if it has a given oui in PTK,
+ * if no OUI found for PTK it returns 0.
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find OUI, 1 on success.
+ */
+static t_u8
+search_oui_in_ie(IEBody * ie_body, t_u8 * oui)
+{
+ t_u8 count;
+
+ count = ie_body->PtkCnt[0];
+
+ /* There could be multiple OUIs for PTK hence 1) Take the length. 2) Check
+ all the OUIs for AES. 3) If one of them is AES then pass success. */
+ while (count) {
+ if (!memcmp(ie_body->PtkBody, oui, sizeof(ie_body->PtkBody))) {
+ return MLAN_OUI_PRESENT;
+ }
+
+ --count;
+ if (count) {
+ ie_body = (IEBody *) ((t_u8 *) ie_body + sizeof(ie_body->PtkBody));
+ }
+ }
+
+ PRINTM(MINFO, "PTK not AES\n");
+ return MLAN_OUI_NOT_PRESENT;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if RSN IE has AES
+ * OUI in it. If RSN IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_rsn_aes_present(BSSDescriptor_t * pbss_desc)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ if (((pbss_desc->prsn_ie) && ((*(pbss_desc->prsn_ie)).
+ ieee_hdr.element_id == RSN_IE))) {
+ ie_body = (IEBody *) (((t_u8 *) pbss_desc->prsn_ie->data) +
+ RSN_GTK_OUI_OFFSET);
+ oui = rsn_oui_aes;
+ if ((ret = search_oui_in_ie(ie_body, oui)))
+ return ret;
+ }
+ return ret;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if WPA IE has AES
+ * OUI in it. If WPA IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_wpa_aes_present(BSSDescriptor_t * pbss_desc)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ if (((pbss_desc->pwpa_ie) && ((*(pbss_desc->pwpa_ie)).
+ vend_hdr.element_id == WPA_IE))) {
+ ie_body = (IEBody *) pbss_desc->pwpa_ie->data;
+ oui = wpa_oui_aes;
+ if ((ret = search_oui_in_ie(ie_body, oui)))
+ return ret;
+ }
+ return ret;
+}
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 0 1 0 0 x 1x 1 x yes WPA
+ * 0 0 1 0 x 1x x 1 yes WPA2
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ *
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ *
+ * @param pmpriv A pointer to mlan_private
+ * @param index Index in scan table to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in ScanTable, or negative value if error
+ */
+static t_s32
+wlan_is_network_compatible(IN mlan_private * pmpriv,
+ IN t_u32 index, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ pbss_desc = &pmadapter->pscan_table[index];
+
+ /* Don't check for compatibility if roaming */
+ if ((pmpriv->media_connected == MTRUE)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && (pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
+ LEAVE();
+ return index;
+ }
+
+ if ((pbss_desc->bss_mode == mode) &&
+ (pmpriv->sec_info.ewpa_enabled == MTRUE)) {
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
+ ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && !is_wpa_aes_present(pbss_desc)
+ && !is_rsn_aes_present(pbss_desc)) {
+ PRINTM(MINFO, "AES not supported by AP when 11n enabled\n");
+ LEAVE();
+ return -1;
+ }
+ LEAVE();
+ return index;
+ } else {
+ PRINTM(MINFO, "ewpa_enabled: Ignore none WPA/WPA2 AP\n");
+ LEAVE();
+ return -1;
+ }
+ }
+
+ if (pmpriv->wps.session_enable == MTRUE) {
+ PRINTM(MINFO, "Return success directly in WPS period\n");
+ LEAVE();
+ return index;
+ }
+ if (pmpriv->sec_info.wapi_enabled &&
+ (pbss_desc->pwapi_ie &&
+ ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
+ PRINTM(MINFO, "Return success for WAPI AP\n");
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->bss_mode == mode) {
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE &&
+ !pbss_desc->privacy) {
+ /* No security */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && !pmpriv->adhoc_aes_enabled && pbss_desc->privacy) {
+ /* Static WEP enabled */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && !is_wpa_aes_present(pbss_desc)) {
+ PRINTM(MINFO, "AES not supported by AP when 11n enabled\n");
+ LEAVE();
+ return -1;
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA2 enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && !is_rsn_aes_present(pbss_desc)) {
+ PRINTM(MINFO, "AES not supported by AP when 11n enabled\n");
+ LEAVE();
+ return -1;
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Ad-hoc AES enabled */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode != MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Dynamic WEP enabled */
+ PRINTM(MINFO, "wlan_is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x wpa2_ie=%#x EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0, pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ LEAVE();
+ return index;
+ }
+
+ /* Security doesn't match */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ LEAVE();
+ return -1;
+ }
+
+ /* Mode doesn't match */
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @return index in BSSID list
+ */
+static t_s32
+wlan_find_best_network_in_list(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 mode = pmpriv->bss_mode;
+ t_s32 best_net = -1;
+ t_s32 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return best_net;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan configuration parameters
+ * @param pscan_chan_list Output parameter: Resulting channel list to scan
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+ * increase the number of channels sent in a scan
+ * command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return n/a
+ */
+static t_void
+wlan_scan_create_channel_list(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ IN t_u8 filtered_scan)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx;
+ t_u32 next_chan;
+ t_u8 scan_type;
+
+ ENTER();
+
+ chan_idx = 0;
+
+ /* Set the default scan type to the user specified type, will later be
+ changed to passive on a per channel basis if restricted by regulatory
+ requirements (11d or 11h) */
+ scan_type = pmadapter->scan_type;
+
+ for (region_idx = 0;
+ region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
+
+ if (wlan_11d_get_state(pmpriv) == ENABLE_11D &&
+ pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ for (next_chan = 0;
+ next_chan < pscan_region->num_cfp; next_chan++, chan_idx++) {
+
+ cfp = pscan_region->pcfp + next_chan;
+
+ if (wlan_11d_get_state(pmpriv) == ENABLE_11D)
+ scan_type =
+ wlan_11d_get_scan_type(pmadapter, (t_u8) cfp->channel,
+ &pmadapter->parsed_region_chan);
+
+ switch (pscan_region->band) {
+ case BAND_A:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_A;
+ if (wlan_11h_radar_detect_required(pmpriv, cfp->channel)) {
+ scan_type = HostCmd_SCAN_TYPE_PASSIVE;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ default:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].scan_time) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16((t_u16) puser_scan_in->chan_list[0].
+ scan_time);
+ } else if (scan_type == HostCmd_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ } else {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->active_scan_time);
+ }
+
+ if (scan_type == HostCmd_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MTRUE;
+ } else {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ pscan_chan_list[chan_idx].chan_number = (t_u8) cfp->channel;
+
+ if (filtered_scan) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ pscan_chan_list[chan_idx].chan_scan_mode.disable_chan_filt =
+ MTRUE;
+ }
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into max_chan_per_scan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param max_chan_per_scan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscan_cfg_out Scan configuration used for this scan.
+ * @param pchan_tlv_out Pointer in the pscan_cfg_out where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscan_chan_list List of channels to scan in max_chan_per_scan segments
+ *
+ * @return MLAN_STATUS_SUCCESS or error return otherwise
+ */
+static mlan_status
+wlan_scan_channel_list(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN t_u32 max_chan_per_scan,
+ IN t_u8 filtered_scan,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t * pchan_tlv_out,
+ IN ChanScanParamSet_t * pscan_chan_list)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ChanScanParamSet_t *ptmp_chan_list;
+ ChanScanParamSet_t *pstart_chan;
+
+ t_u32 tlv_idx;
+ t_u32 total_scan_time;
+ t_u32 done_early;
+
+ ENTER();
+
+ if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
+ PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n",
+ pscan_cfg_out, pchan_tlv_out, pscan_chan_list);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list */
+ ptmp_chan_list = pscan_chan_list;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ commands for each max_chan_per_scan channels (or for 1,6,11 individually
+ if configured accordingly) */
+ while (ptmp_chan_list->chan_number) {
+
+ tlv_idx = 0;
+ total_scan_time = 0;
+ pchan_tlv_out->header.len = 0;
+ pstart_chan = ptmp_chan_list;
+ done_early = MFALSE;
+
+ /*
+ * Construct the Channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlv_idx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel list)
+ * - done_early is set (controlling individual scanning of 1,6,11)
+ */
+ while (tlv_idx < max_chan_per_scan && ptmp_chan_list->chan_number &&
+ !done_early) {
+
+ PRINTM(MINFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
+ ptmp_chan_list->chan_number,
+ ptmp_chan_list->radio_type,
+ ptmp_chan_list->chan_scan_mode.passive_scan,
+ ptmp_chan_list->chan_scan_mode.disable_chan_filt,
+ wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
+
+ /* Copy the current channel TLV to the command being prepared */
+ memcpy(pchan_tlv_out->chan_scan_param + tlv_idx,
+ ptmp_chan_list, sizeof(pchan_tlv_out->chan_scan_param));
+
+ /* Increment the TLV header length by the size appended */
+ pchan_tlv_out->header.len += sizeof(pchan_tlv_out->chan_scan_param);
+
+ /*
+ * The tlv buffer length is set to the number of bytes of the
+ * between the channel tlv pointer and the start of the
+ * tlv buffer. This compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscan_cfg_out->tlv_buf_len = (t_u32) ((t_u8 *) pchan_tlv_out
+ - pscan_cfg_out->tlv_buf);
+
+ /* Add the size of the channel tlv header and the data length */
+ pscan_cfg_out->tlv_buf_len += (sizeof(pchan_tlv_out->header)
+ + pchan_tlv_out->header.len);
+
+ /* Increment the index to the channel tlv we are constructing */
+ tlv_idx++;
+
+ /* Count the total scan time per command */
+ total_scan_time += wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
+
+ done_early = MFALSE;
+
+ /* Stop the loop if the *current* channel is in the 1,6,11 set and
+ we are not filtering on a BSSID or SSID. */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+
+ /* Increment the tmp pointer to the next channel to be scanned */
+ ptmp_chan_list++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11 set. This
+ will cause it to be the only channel scanned on the next
+ interation */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+ }
+
+ /* The total scan time should be less than scan command timeout value */
+ if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+ PRINTM(MMSG,
+ "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+ total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pchan_tlv_out->header.len = wlan_cpu_to_le16(pchan_tlv_out->header.len);
+
+ pmpriv->adapter->pscan_channels = pstart_chan;
+
+ /* Send the scan command to the firmware with the specified cfg */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SCAN,
+ HostCmd_ACT_GEN_SET,
+ 0, pioctl_buf, pscan_cfg_out);
+ if (ret)
+ break;
+ }
+
+ LEAVE();
+
+ if (ret) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in issue scan commands
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - Channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan configuration parameters
+ * @param pscan_cfg_out Output parameter: Resulting scan configuration
+ * @param ppchan_list_out Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscan_chan_list Output parameter: Pointer to the resulting
+ * channel list to scan
+ * @param pmax_chan_per_scan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfiltered_scan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscan_current_only Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return n/a
+ */
+static t_void
+wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t **
+ ppchan_list_out,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ OUT t_u8 * pmax_chan_per_scan,
+ OUT t_u8 * pfiltered_scan,
+ OUT t_u8 * pscan_current_only)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *ptlv_pos;
+ t_u32 num_probes;
+ t_u32 ssid_len;
+ t_u32 chan_idx;
+ t_u32 scan_type;
+ t_u16 scan_dur;
+ t_u8 channel;
+ t_u8 radio_type;
+ t_u32 ssid_idx;
+ t_u8 ssid_filter;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ MrvlIETypes_HTCap_t *pht_cap;
+
+ ENTER();
+
+ /* The tlv_buf_len is calculated for each scan command. The TLVs added in
+ this routine will be preserved since the routine that sends the command
+ will append channelTLVs at *ppchan_list_out. The difference between the
+ *ppchan_list_out and the tlv_buf start will be used to calculate the
+ size of anything we add in this routine. */
+ pscan_cfg_out->tlv_buf_len = 0;
+
+ /* Running tlv pointer. Assigned to ppchan_list_out at end of function so
+ later routines know where channels can be added to the command buf */
+ ptlv_pos = pscan_cfg_out->tlv_buf;
+
+ /* Initialize the scan as un-filtered; the flag is later set to TRUE below
+ if a SSID or BSSID filter is sent in the command */
+ *pfiltered_scan = MFALSE;
+
+ /* Initialize the scan as not being only on the current channel. If the
+ channel list is customized, only contains one channel, and is the active
+ channel, this is set true and data flow is not halted. */
+ *pscan_current_only = MFALSE;
+
+ if (puser_scan_in) {
+
+ /* Default the ssid_filter flag to TRUE, set false under certain
+ wildcard conditions and qualified by the existence of an SSID list
+ before marking the scan as filtered */
+ ssid_filter = MTRUE;
+
+ /* Set the bss type scan filter, use Adapter setting if unset */
+ pscan_cfg_out->bss_mode =
+ (puser_scan_in->bss_mode ? (t_u8) puser_scan_in->
+ bss_mode : (t_u8) pmadapter->scan_mode);
+
+ /* Set the number of probes to send, use Adapter setting if unset */
+ num_probes = (puser_scan_in->num_probes ? puser_scan_in->num_probes :
+ pmadapter->scan_probes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled (all zeros).
+ */
+ memcpy(pscan_cfg_out->specific_bssid,
+ puser_scan_in->specific_bssid,
+ sizeof(pscan_cfg_out->specific_bssid));
+
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(puser_scan_in->ssid_list))
+ && (*puser_scan_in->ssid_list[ssid_idx].ssid
+ || puser_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+
+ ssid_len =
+ wlan_strlen((t_s8 *) puser_scan_in->ssid_list[ssid_idx].ssid) +
+ 1;
+
+ pwildcard_ssid_tlv
+ = (MrvlIEtypes_WildCardSsIdParamSet_t *) ptlv_pos;
+ pwildcard_ssid_tlv->header.type
+ = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len
+ =
+ (t_u16) (ssid_len +
+ sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length =
+ puser_scan_in->ssid_list[ssid_idx].max_len;
+
+ memcpy(pwildcard_ssid_tlv->ssid,
+ puser_scan_in->ssid_list[ssid_idx].ssid, ssid_len);
+
+ ptlv_pos += (sizeof(pwildcard_ssid_tlv->header)
+ + pwildcard_ssid_tlv->header.len);
+
+ pwildcard_ssid_tlv->header.len
+ = wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n",
+ ssid_idx,
+ pwildcard_ssid_tlv->ssid,
+ pwildcard_ssid_tlv->max_ssid_length);
+
+ /* Empty wildcard ssid with a maxlen will match many or potentially
+ all SSIDs (maxlen == 32), therefore do not treat the scan as
+ filtered. */
+ if (!ssid_len && pwildcard_ssid_tlv->max_ssid_length) {
+ ssid_filter = MFALSE;
+ }
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not truncate
+ * scan results. That is not an issue with an SSID or BSSID
+ * filter applied to the scan results in the firmware.
+ */
+ if ((ssid_idx && ssid_filter)
+ || memcmp(pscan_cfg_out->specific_bssid, &zero_mac,
+ sizeof(zero_mac))) {
+ *pfiltered_scan = MTRUE;
+ }
+
+ } else {
+ pscan_cfg_out->bss_mode = (t_u8) pmadapter->scan_mode;
+ num_probes = pmadapter->scan_probes;
+ }
+
+ /*
+ * If a specific BSSID or SSID is used, the number of channels in the
+ * scan command will be increased to the absolute maximum.
+ */
+ if (*pfiltered_scan)
+ *pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ else
+ *pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ /* If the input config or adapter has the number of Probes set, add tlv */
+ if (num_probes) {
+
+ PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
+
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *) ptlv_pos;
+ pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len = sizeof(pnum_probes_tlv->num_probes);
+ pnum_probes_tlv->num_probes = wlan_cpu_to_le16((t_u16) num_probes);
+
+ ptlv_pos +=
+ sizeof(pnum_probes_tlv->header) + pnum_probes_tlv->header.len;
+
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(pnum_probes_tlv->header.len);
+ }
+
+ /* Append rates tlv */
+ memset(rates, 0, sizeof(rates));
+
+ rates_size = wlan_get_supported_rates(pmpriv, rates);
+
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) ptlv_pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(prates_tlv->rates, rates, rates_size);
+ ptlv_pos += sizeof(prates_tlv->header) + rates_size;
+
+ PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
+ && (pmpriv->adapter->config_bands & BAND_GN
+ || pmpriv->adapter->config_bands & BAND_AN)) {
+ pht_cap = (MrvlIETypes_HTCap_t *) ptlv_pos;
+ memset(pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_cap_info(pmadapter, pht_cap);
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
+ HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ /** Append vendor specific IE TLV */
+ wlan_cmd_append_vsie_tlv(pmpriv, MLAN_VSIE_MASK_SCAN, &ptlv_pos);
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this function (SSID, num_probes).
+ * Channel TLVs will be added past this for each scan command, preserving
+ * the TLVs that were previously added.
+ */
+ *ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *) ptlv_pos;
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
+
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+
+ for (chan_idx = 0;
+ chan_idx < WLAN_USER_SCAN_CHAN_MAX
+ && puser_scan_in->chan_list[chan_idx].chan_number; chan_idx++) {
+
+ channel = puser_scan_in->chan_list[chan_idx].chan_number;
+ (pscan_chan_list + chan_idx)->chan_number = channel;
+
+ radio_type = puser_scan_in->chan_list[chan_idx].radio_type;
+ (pscan_chan_list + chan_idx)->radio_type = radio_type;
+
+ scan_type = puser_scan_in->chan_list[chan_idx].scan_type;
+
+ /* Prevent active scanning on a radar controlled channel */
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (wlan_11h_radar_detect_required(pmpriv, channel)) {
+ scan_type = HostCmd_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (scan_type == HostCmd_SCAN_TYPE_PASSIVE) {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MTRUE;
+ } else {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MFALSE;
+ }
+
+ if (puser_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16) puser_scan_in->chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == HostCmd_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else if (*pfiltered_scan) {
+ scan_dur = pmadapter->specific_scan_time;
+ } else {
+ scan_dur = pmadapter->active_scan_time;
+ }
+ }
+
+ (pscan_chan_list + chan_idx)->min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ (pscan_chan_list + chan_idx)->max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chan_idx == 1)
+ && (puser_scan_in->chan_list[0].chan_number
+ == pmpriv->curr_bss_params.bss_descriptor.channel)) {
+ *pscan_current_only = MTRUE;
+ PRINTM(MINFO, "Scan: Scanning current channel only");
+ }
+
+ } else {
+ PRINTM(MINFO, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(pmpriv, puser_scan_in, pscan_chan_list,
+ *pfiltered_scan);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlv_buf_size Size of the TLV buffer
+ * @param req_tlv_type Request TLV's type
+ * @param pptlv Output parameter: Pointer to the request TLV if found
+ *
+ * @return n/a
+ */
+static t_void
+wlan_ret_802_11_scan_get_tlv_ptrs(IN pmlan_adapter pmadapter,
+ IN MrvlIEtypes_Data_t * ptlv,
+ IN t_u32 tlv_buf_size,
+ IN t_u32 req_tlv_type,
+ OUT MrvlIEtypes_Data_t ** pptlv)
+{
+ MrvlIEtypes_Data_t *pcurrent_tlv;
+ t_u32 tlv_buf_left;
+ t_u32 tlv_type;
+ t_u32 tlv_len;
+
+ ENTER();
+
+ pcurrent_tlv = ptlv;
+ tlv_buf_left = tlv_buf_size;
+ *pptlv = MNULL;
+
+ PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+
+ tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
+
+ if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
+ PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
+ break;
+ }
+
+ if (req_tlv_type == tlv_type) {
+ switch (tlv_type) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ PRINTM(MINFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ case TLV_TYPE_CHANNELBANDLIST:
+ PRINTM(MINFO, "SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ default:
+ PRINTM(MERROR, "SCAN_RESP: Unhandled TLV = %d\n", tlv_type);
+ /* Give up, this seems corrupted */
+ LEAVE();
+ return;
+ }
+ }
+
+ if (*pptlv) {
+ // HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4, tlv_len);
+ break;
+ }
+
+ tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
+ pcurrent_tlv = (MrvlIEtypes_Data_t *) (pcurrent_tlv->data + tlv_len);
+
+ } /* while */
+
+ LEAVE();
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table BSSDescriptor_t for that entry.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pbss_entry Output parameter: Pointer to the BSS Entry
+ * @param pbeacon_info Pointer to the Beacon information
+ * @param bytes_left Number of bytes left to parse
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_interpret_bss_desc_with_ie(IN pmlan_adapter pmadapter,
+ OUT BSSDescriptor_t * pbss_entry,
+ IN t_u8 ** pbeacon_info, IN t_u32 * bytes_left)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_FhParamSet_t *pfh_param_set;
+ IEEEtypes_DsParamSet_t *pds_param_set;
+ IEEEtypes_CfParamSet_t *pcf_param_set;
+ IEEEtypes_IbssParamSet_t *pibss_param_set;
+ IEEEtypes_CapInfo_t *pcap_info;
+ WLAN_802_11_FIXED_IEs fixed_ie;
+ t_u8 *pcurrent_ptr;
+ t_u8 *prate;
+ t_u8 element_len;
+ t_u16 total_ie_len;
+ t_u8 bytes_to_copy;
+ t_u8 rate_size;
+ t_u16 beacon_size;
+ t_u8 found_data_rate_ie;
+ t_u32 bytes_left_for_current_beacon;
+ IEEEtypes_ERPInfo_t *perp_info;
+
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+
+ IEEEtypes_CountryInfoSet_t *pcountry_info;
+
+ ENTER();
+
+ found_data_rate_ie = MFALSE;
+ rate_size = 0;
+ beacon_size = 0;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(&beacon_size, *pbeacon_info, sizeof(beacon_size));
+ beacon_size = wlan_le16_to_cpu(beacon_size);
+ *bytes_left -= sizeof(beacon_size);
+ *pbeacon_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+
+ *pbeacon_info += *bytes_left;
+ *bytes_left = 0;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+ pcurrent_ptr = *pbeacon_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeacon_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ bytes_left_for_current_beacon = beacon_size;
+
+ memcpy(pbss_entry->mac_address, pcurrent_ptr, MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pbss_entry->mac_address[0], pbss_entry->mac_address[1],
+ pbss_entry->mac_address[2], pbss_entry->mac_address[3],
+ pbss_entry->mac_address[4], pbss_entry->mac_address[5]);
+
+ pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
+ bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
+
+ if (bytes_left_for_current_beacon < 12) {
+ PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /*
+ * Next 4 fields are RSSI, time stamp, beacon interval,
+ * and capability information
+ */
+
+ /* RSSI is 1 byte long */
+ pbss_entry->rssi = (t_s32) (*pcurrent_ptr);
+ PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
+ pcurrent_ptr += 1;
+ bytes_left_for_current_beacon -= 1;
+
+ /*
+ * The RSSI is not part of the beacon/probe response. After we have
+ * advanced pcurrent_ptr past the RSSI field, save the remaining
+ * data for use at the application layer
+ */
+ pbss_entry->pbeacon_buf = pcurrent_ptr;
+ pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
+
+ /* Time stamp is 8 bytes long */
+ memcpy(fixed_ie.time_stamp, pcurrent_ptr, 8);
+ memcpy(pbss_entry->time_stamp, pcurrent_ptr, 8);
+ pcurrent_ptr += 8;
+ bytes_left_for_current_beacon -= 8;
+
+ /* Beacon interval is 2 bytes long */
+ memcpy(&fixed_ie.beacon_interval, pcurrent_ptr, 2);
+ pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Capability information is 2 bytes long */
+ memcpy(&fixed_ie.capabilities, pcurrent_ptr, 2);
+ PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
+ fixed_ie.capabilities);
+ fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
+ pcap_info = (IEEEtypes_CapInfo_t *) & fixed_ie.capabilities;
+ memcpy(&pbss_entry->cap_info, pcap_info, sizeof(IEEEtypes_CapInfo_t));
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Rest of the current buffer are IE's */
+ PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
+ bytes_left_for_current_beacon);
+
+ HEXDUMP("InterpretIE: IE info", (t_u8 *) pcurrent_ptr,
+ bytes_left_for_current_beacon);
+
+ if (pcap_info->privacy) {
+ PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
+ pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
+ } else {
+ pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ if (pcap_info->ibss == 1) {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
+ } else {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
+ }
+
+ if (pcap_info->spectrum_mgmt == 1) {
+ PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
+ "capability bit found\n");
+ pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
+ }
+
+ /* Process variable IE */
+ while (bytes_left_for_current_beacon >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+
+ if (bytes_left_for_current_beacon < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left_for_current_beacon = 0;
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+
+ switch (element_id) {
+
+ case SSID:
+ pbss_entry->ssid.ssid_len = element_len;
+ memcpy(pbss_entry->ssid.ssid, (pcurrent_ptr + 2), element_len);
+ PRINTM(MINFO, "InterpretIE: ssid: %-32s\n", pbss_entry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ memcpy(pbss_entry->data_rates, pcurrent_ptr + 2, element_len);
+ memcpy(pbss_entry->supported_rates, pcurrent_ptr + 2, element_len);
+ HEXDUMP("InterpretIE: SupportedRates:",
+ pbss_entry->supported_rates, element_len);
+ rate_size = element_len;
+ found_data_rate_ie = MTRUE;
+ break;
+
+ case FH_PARAM_SET:
+ pfh_param_set = (IEEEtypes_FhParamSet_t *) pcurrent_ptr;
+ pbss_entry->network_type_use = Wlan802_11FH;
+ memcpy(&pbss_entry->phy_param_set.fh_param_set, pfh_param_set,
+ sizeof(IEEEtypes_FhParamSet_t));
+ pbss_entry->phy_param_set.fh_param_set.dwell_time
+ =
+ wlan_le16_to_cpu(pbss_entry->phy_param_set.fh_param_set.
+ dwell_time);
+ break;
+
+ case DS_PARAM_SET:
+ pds_param_set = (IEEEtypes_DsParamSet_t *) pcurrent_ptr;
+
+ pbss_entry->network_type_use = Wlan802_11DS;
+ pbss_entry->channel = pds_param_set->current_chan;
+
+ memcpy(&pbss_entry->phy_param_set.ds_param_set, pds_param_set,
+ sizeof(IEEEtypes_DsParamSet_t));
+ break;
+
+ case CF_PARAM_SET:
+ pcf_param_set = (IEEEtypes_CfParamSet_t *) pcurrent_ptr;
+ memcpy(&pbss_entry->ss_param_set.cf_param_set, pcf_param_set,
+ sizeof(IEEEtypes_CfParamSet_t));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss_param_set = (IEEEtypes_IbssParamSet_t *) pcurrent_ptr;
+ pbss_entry->atim_window =
+ wlan_le16_to_cpu(pibss_param_set->atim_window);
+ memcpy(&pbss_entry->ss_param_set.ibss_param_set, pibss_param_set,
+ sizeof(IEEEtypes_IbssParamSet_t));
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountry_info = (IEEEtypes_CountryInfoSet_t *) pcurrent_ptr;
+
+ if (pcountry_info->len < sizeof(pcountry_info->country_code) ||
+ (unsigned) (pcountry_info->len + 2) >
+ sizeof(IEEEtypes_CountryInfoFullSet_t)) {
+ PRINTM(MERROR,
+ "InterpretIE: 11D- Err "
+ "country_info len =%d min=%d max=%d\n",
+ pcountry_info->len, sizeof(pcountry_info->country_code),
+ sizeof(IEEEtypes_CountryInfoFullSet_t));
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(&pbss_entry->country_info,
+ pcountry_info, pcountry_info->len + 2);
+ HEXDUMP("InterpretIE: 11D- country_info:",
+ (t_u8 *) pcountry_info, (t_u32) (pcountry_info->len + 2));
+ break;
+
+ case ERP_INFO:
+ perp_info = (IEEEtypes_ERPInfo_t *) pcurrent_ptr;
+ pbss_entry->erp_flags = perp_info->erp_flags;
+ break;
+
+ case POWER_CONSTRAINT:
+ case POWER_CAPABILITY:
+ case TPC_REPORT:
+ case CHANNEL_SWITCH_ANN:
+ case QUIET:
+ case IBSS_DFS:
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ wlan_11h_process_bss_elem(&pbss_entry->wlan_11h_bss_info,
+ pcurrent_ptr);
+ break;
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * Only process extended supported rate
+ * if data rate is already found.
+ * Data rate IE should come before
+ * extended supported rate IE
+ */
+ if (found_data_rate_ie) {
+ if ((element_len + rate_size) > WLAN_SUPPORTED_RATES) {
+ bytes_to_copy = (WLAN_SUPPORTED_RATES - rate_size);
+ } else {
+ bytes_to_copy = element_len;
+ }
+
+ prate = (t_u8 *) pbss_entry->data_rates;
+ prate += rate_size;
+ memcpy(prate, pcurrent_ptr + 2, bytes_to_copy);
+
+ prate = (t_u8 *) pbss_entry->supported_rates;
+ prate += rate_size;
+ memcpy(prate, pcurrent_ptr + 2, bytes_to_copy);
+ }
+ HEXDUMP("InterpretIE: ExtSupportedRates:",
+ pbss_entry->supported_rates, element_len + rate_size);
+ break;
+
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wpa_oui, sizeof(wpa_oui))) {
+ pbss_entry->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ pbss_entry->wpa_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WPA_IE",
+ (t_u8 *) pbss_entry->pwpa_ie,
+ ((*(pbss_entry->pwpa_ie)).vend_hdr.len +
+ sizeof(IEEEtypes_Header_t)));
+ } else
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui, sizeof(wmm_oui)))
+ {
+ if (total_ie_len == sizeof(IEEEtypes_WmmParameter_t)
+ || total_ie_len == sizeof(IEEEtypes_WmmInfo_t)) {
+
+ /*
+ * Only accept and copy the WMM IE if it matches
+ * the size expected for the WMM Info IE or the
+ * WMM Parameter IE.
+ */
+ memcpy((t_u8 *) & pbss_entry->wmm_ie, pcurrent_ptr,
+ total_ie_len);
+ HEXDUMP("InterpretIE: Resp WMM_IE",
+ (t_u8 *) & pbss_entry->wmm_ie, total_ie_len);
+ }
+ }
+ break;
+ case RSN_IE:
+ pbss_entry->prsn_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->rsn_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp RSN_IE", (t_u8 *) pbss_entry->prsn_ie,
+ (*(pbss_entry->prsn_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case WAPI_IE:
+ pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->wapi_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WAPI_IE", (t_u8 *) pbss_entry->pwapi_ie,
+ (*(pbss_entry->pwapi_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_CAPABILITY:
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *) pcurrent_ptr;
+ pbss_entry->ht_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE", (t_u8 *) pbss_entry->pht_cap,
+ (*(pbss_entry->pht_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_OPERATION:
+ pbss_entry->pht_info = (IEEEtypes_HTInfo_t *) pcurrent_ptr;
+ pbss_entry->ht_info_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTINFO_IE",
+ (t_u8 *) pbss_entry->pht_info,
+ (*(pbss_entry->pht_info)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case BSSCO_2040:
+ pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *) pcurrent_ptr;
+ pbss_entry->bss_co_2040_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
+ (t_u8 *) pbss_entry->pbss_co_2040,
+ (*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_CAPABILITY:
+ pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *) pcurrent_ptr;
+ pbss_entry->ext_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTCAP_IE",
+ (t_u8 *) pbss_entry->pext_cap,
+ (*(pbss_entry->pext_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case OVERLAPBSSSCANPARAM:
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) pcurrent_ptr;
+ pbss_entry->overlap_bss_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE",
+ (t_u8 *) pbss_entry->poverlap_bss_scan_param,
+ (*(pbss_entry->poverlap_bss_scan_param)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ }
+
+ pcurrent_ptr += element_len + 2;
+
+ /* Need to account for IE ID and IE Len */
+ bytes_left_for_current_beacon -= (element_len + 2);
+
+ } /* while (bytes_left_for_current_beacon > 2) */
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Store a beacon or probe response for a BSS returned in the scan
+ *
+ * Store a new scan response or an update for a previous scan response. New
+ * entries need to verify that they do not exceed the total amount of
+ * memory allocated for the table.
+
+ * Replacement entries need to take into consideration the amount of space
+ * currently allocated for the beacon/probe response and adjust the entry
+ * as needed.
+ *
+ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ * for an entry in case it is a beacon since a probe response for the
+ * network will by larger per the standard. This helps to reduce the
+ * amount of memory copying to fit a new probe response into an entry
+ * already occupied by a network's previously stored beacon.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param beacon_idx Index in the scan table to store this entry; may be
+ * replacing an older duplicate entry for this BSS
+ * @param num_of_ent Number of entries currently in the table
+ * @param pnew_beacon Pointer to the new beacon/probe response to save
+ *
+ * @return n/a
+ */
+static t_void
+wlan_ret_802_11_scan_store_beacon(IN mlan_private * pmpriv,
+ IN t_u32 beacon_idx,
+ IN t_u32 num_of_ent,
+ IN BSSDescriptor_t * pnew_beacon)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 *pbcn_store;
+ t_u32 new_bcn_size;
+ t_u32 old_bcn_size;
+ t_u32 bcn_space;
+ t_u32 adj_idx;
+
+ ENTER();
+
+ if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
+
+ new_bcn_size = pnew_beacon->beacon_buf_size;
+ old_bcn_size = pmadapter->pscan_table[beacon_idx].beacon_buf_size;
+ bcn_space = pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
+ pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
+
+ /* Set the max to be the same as current entry unless changed below */
+ pnew_beacon->beacon_buf_size_max = bcn_space;
+
+ if (new_bcn_size == old_bcn_size) {
+ /*
+ * Beacon is the same size as the previous entry.
+ * Replace the previous contents with the scan result
+ */
+ memcpy(pbcn_store,
+ pnew_beacon->pbeacon_buf, pnew_beacon->beacon_buf_size);
+
+ } else if (new_bcn_size <= bcn_space) {
+ /*
+ * New beacon size will fit in the amount of space
+ * we have previously allocated for it
+ */
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pbcn_store, pnew_beacon->pbeacon_buf, new_bcn_size);
+
+ /*
+ * If the old beacon size was less than the maximum
+ * we had alloted for the entry, and the new entry
+ * is even smaller, reset the max size to the old beacon
+ * entry and compress the storage space (leaving a new
+ * pad space of (old_bcn_size - new_bcn_size).
+ */
+ if (old_bcn_size < bcn_space && new_bcn_size <= old_bcn_size) {
+ /*
+ * Old Beacon size is smaller than the alloted storage size.
+ * Shrink the alloted storage space.
+ */
+ PRINTM(MINFO, "AppControl: Smaller Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (sizeof(pmadapter->bcn_buf) -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This cleans up any unused
+ * space the old larger beacon was using in the buffer
+ */
+ memmove(pbcn_store + old_bcn_size,
+ pbcn_store + bcn_space,
+ pmadapter->pbcn_buf_end - (pbcn_store + bcn_space));
+
+ /*
+ * Decrement the end pointer by the difference between
+ * the old larger size and the new smaller size since
+ * we are using less space due to the new beacon being
+ * smaller
+ */
+ pmadapter->pbcn_buf_end -= (bcn_space - old_bcn_size);
+
+ /* Set the maximum storage size to the old beacon size */
+ pnew_beacon->beacon_buf_size_max = old_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf >
+ pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf -=
+ (bcn_space - old_bcn_size);
+ if (pmadapter->pscan_table[adj_idx].pwpa_ie) {
+ pmadapter->pscan_table[adj_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].wpa_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].prsn_ie) {
+ pmadapter->pscan_table[adj_idx].prsn_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].rsn_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pwapi_ie) {
+ pmadapter->pscan_table[adj_idx].pwapi_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].wapi_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pht_cap) {
+ pmadapter->pscan_table[adj_idx].pht_cap =
+ (IEEEtypes_HTCap_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[adj_idx].pht_info) {
+ pmadapter->pscan_table[adj_idx].pht_info =
+ (IEEEtypes_HTInfo_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ ht_info_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pbss_co_2040) {
+ pmadapter->pscan_table[adj_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pext_cap) {
+ pmadapter->pscan_table[adj_idx].pext_cap =
+ (IEEEtypes_ExtCap_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].
+ poverlap_bss_scan_param) {
+ pmadapter->pscan_table[adj_idx].
+ poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ overlap_bss_offset);
+ }
+ }
+ }
+ }
+ } else if (pmadapter->pbcn_buf_end + (new_bcn_size - bcn_space)
+ < (pmadapter->bcn_buf + sizeof(pmadapter->bcn_buf))) {
+ /*
+ * Beacon is larger than space previously allocated (bcn_space)
+ * and there is enough space left in the beaconBuffer to store
+ * the additional data
+ */
+ PRINTM(MINFO, "AppControl: Larger Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (sizeof(pmadapter->bcn_buf) -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This moves the data for
+ * the beacons after this further in memory to
+ * make space for the new larger beacon we are
+ * about to copy in.
+ */
+ memmove(pbcn_store + new_bcn_size,
+ pbcn_store + bcn_space,
+ pmadapter->pbcn_buf_end - (pbcn_store + bcn_space));
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pbcn_store, pnew_beacon->pbeacon_buf, new_bcn_size);
+
+ /* Move the beacon end pointer by the amount of new beacon data we
+ are adding */
+ pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
+
+ /*
+ * This entry is bigger than the alloted max space
+ * previously reserved. Increase the max space to
+ * be equal to the new beacon size
+ */
+ pnew_beacon->beacon_buf_size_max = new_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf > pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf
+ += (new_bcn_size - bcn_space);
+ if (pmadapter->pscan_table[adj_idx].pwpa_ie) {
+ pmadapter->pscan_table[adj_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].wpa_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].prsn_ie) {
+ pmadapter->pscan_table[adj_idx].prsn_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].rsn_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pwapi_ie) {
+ pmadapter->pscan_table[adj_idx].pwapi_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].wapi_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pht_cap) {
+ pmadapter->pscan_table[adj_idx].pht_cap =
+ (IEEEtypes_HTCap_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[adj_idx].pht_info) {
+ pmadapter->pscan_table[adj_idx].pht_info =
+ (IEEEtypes_HTInfo_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].ht_info_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pbss_co_2040) {
+ pmadapter->pscan_table[adj_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].pext_cap) {
+ pmadapter->pscan_table[adj_idx].pext_cap =
+ (IEEEtypes_ExtCap_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[adj_idx].poverlap_bss_scan_param) {
+ pmadapter->pscan_table[adj_idx].
+ poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pmadapter->pscan_table[adj_idx].pbeacon_buf +
+ pmadapter->pscan_table[adj_idx].
+ overlap_bss_offset);
+ }
+ }
+ }
+ } else {
+ /*
+ * Beacon is larger than the previously allocated space, but
+ * there is not enough free space to store the additional data
+ */
+ PRINTM(MERROR,
+ "AppControl: Failed: Larger Duplicate Beacon (%d),"
+ " old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (sizeof(pmadapter->bcn_buf) -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure, keep old beacon intact */
+ pnew_beacon->beacon_buf_size = old_bcn_size;
+ if (pnew_beacon->pwpa_ie)
+ pnew_beacon->wpa_offset =
+ pmadapter->pscan_table[beacon_idx].wpa_offset;
+ if (pnew_beacon->prsn_ie)
+ pnew_beacon->rsn_offset =
+ pmadapter->pscan_table[beacon_idx].rsn_offset;
+ if (pnew_beacon->pwapi_ie)
+ pnew_beacon->wapi_offset =
+ pmadapter->pscan_table[beacon_idx].wapi_offset;
+ if (pnew_beacon->pht_cap)
+ pnew_beacon->ht_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ht_cap_offset;
+ if (pnew_beacon->pht_info)
+ pnew_beacon->ht_info_offset =
+ pmadapter->pscan_table[beacon_idx].ht_info_offset;
+ if (pnew_beacon->pbss_co_2040)
+ pnew_beacon->bss_co_2040_offset =
+ pmadapter->pscan_table[beacon_idx].bss_co_2040_offset;
+ if (pnew_beacon->pext_cap)
+ pnew_beacon->ext_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ext_cap_offset;
+ if (pnew_beacon->poverlap_bss_scan_param)
+ pnew_beacon->overlap_bss_offset =
+ pmadapter->pscan_table[beacon_idx].overlap_bss_offset;
+ }
+ /* Point the new entry to its permanent storage space */
+ pnew_beacon->pbeacon_buf = pbcn_store;
+ if (pnew_beacon->pwpa_ie) {
+ pnew_beacon->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->wpa_offset);
+ }
+ if (pnew_beacon->prsn_ie) {
+ pnew_beacon->prsn_ie = (IEEEtypes_Generic_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->rsn_offset);
+ }
+ if (pnew_beacon->pwapi_ie) {
+ pnew_beacon->pwapi_ie = (IEEEtypes_Generic_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->wapi_offset);
+ }
+ if (pnew_beacon->pht_cap) {
+ pnew_beacon->pht_cap = (IEEEtypes_HTCap_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ht_cap_offset);
+ }
+
+ if (pnew_beacon->pht_info) {
+ pnew_beacon->pht_info = (IEEEtypes_HTInfo_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ht_info_offset);
+ }
+ if (pnew_beacon->pbss_co_2040) {
+ pnew_beacon->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->bss_co_2040_offset);
+ }
+ if (pnew_beacon->pext_cap) {
+ pnew_beacon->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ext_cap_offset);
+ }
+ if (pnew_beacon->poverlap_bss_scan_param) {
+ pnew_beacon->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->overlap_bss_offset);
+ }
+
+ } else {
+ /*
+ * No existing beacon data exists for this entry, check to see
+ * if we can fit it in the remaining space
+ */
+ if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD < (pmadapter->bcn_buf +
+ sizeof(pmadapter->bcn_buf))) {
+
+ /*
+ * Copy the beacon buffer data from the local entry to the
+ * adapter dev struct buffer space used to store the raw
+ * beacon data for each entry in the scan table
+ */
+ memcpy(pmadapter->pbcn_buf_end, pnew_beacon->pbeacon_buf,
+ pnew_beacon->beacon_buf_size);
+
+ /* Update the beacon ptr to point to the table save area */
+ pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pnew_beacon->beacon_buf_size_max = (pnew_beacon->beacon_buf_size
+ + SCAN_BEACON_ENTRY_PAD);
+
+ if (pnew_beacon->pwpa_ie) {
+ pnew_beacon->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->wpa_offset);
+ }
+ if (pnew_beacon->prsn_ie) {
+ pnew_beacon->prsn_ie = (IEEEtypes_Generic_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->rsn_offset);
+ }
+ if (pnew_beacon->pwapi_ie) {
+ pnew_beacon->pwapi_ie = (IEEEtypes_Generic_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->wapi_offset);
+ }
+ if (pnew_beacon->pht_cap) {
+ pnew_beacon->pht_cap = (IEEEtypes_HTCap_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ht_cap_offset);
+ }
+
+ if (pnew_beacon->pht_info) {
+ pnew_beacon->pht_info = (IEEEtypes_HTInfo_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ht_info_offset);
+ }
+ if (pnew_beacon->pbss_co_2040) {
+ pnew_beacon->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pnew_beacon->pbeacon_buf +
+ pnew_beacon->bss_co_2040_offset);
+ }
+ if (pnew_beacon->pext_cap) {
+ pnew_beacon->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pnew_beacon->pbeacon_buf + pnew_beacon->ext_cap_offset);
+ }
+ if (pnew_beacon->poverlap_bss_scan_param) {
+ pnew_beacon->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pnew_beacon->pbeacon_buf +
+ pnew_beacon->overlap_bss_offset);
+ }
+
+ /* Increment the end pointer by the size reserved */
+ pmadapter->pbcn_buf_end += pnew_beacon->beacon_buf_size_max;
+
+ PRINTM(MINFO, "AppControl: Beacon[%02d] sz=%03d,"
+ " used = %04d, left = %04d\n",
+ beacon_idx,
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
+ (sizeof(pmadapter->bcn_buf) -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+ } else {
+ /*
+ * No space for new beacon
+ */
+ PRINTM(MINFO, "AppControl: No space beacon (%d): "
+ "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
+ beacon_idx,
+ pnew_beacon->mac_address[0], pnew_beacon->mac_address[1],
+ pnew_beacon->mac_address[2], pnew_beacon->mac_address[3],
+ pnew_beacon->mac_address[4], pnew_beacon->mac_address[5],
+ pnew_beacon->beacon_buf_size,
+ (sizeof(pmadapter->bcn_buf) -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure; clear storage records for this bcn */
+ pnew_beacon->pbeacon_buf = MNULL;
+ pnew_beacon->beacon_buf_size = 0;
+ pnew_beacon->beacon_buf_size_max = 0;
+ pnew_beacon->pwpa_ie = MNULL;
+ pnew_beacon->wpa_offset = 0;
+ pnew_beacon->prsn_ie = MNULL;
+ pnew_beacon->rsn_offset = 0;
+ pnew_beacon->pwapi_ie = MNULL;
+ pnew_beacon->wapi_offset = 0;
+ pnew_beacon->pht_cap = MNULL;
+ pnew_beacon->ht_cap_offset = 0;
+ pnew_beacon->pht_info = MNULL;
+ pnew_beacon->ht_info_offset = 0;
+ pnew_beacon->pbss_co_2040 = MNULL;
+ pnew_beacon->bss_co_2040_offset = 0;
+ pnew_beacon->pext_cap = MNULL;
+ pnew_beacon->ext_cap_offset = 0;
+ pnew_beacon->poverlap_bss_scan_param = MNULL;
+ pnew_beacon->overlap_bss_offset = 0;
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the BSSDescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return n/a
+ */
+static t_void
+wlan_scan_process_results(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 j;
+ t_u32 i;
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+
+ j = wlan_find_ssid_in_list(pmpriv,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, pmpriv->bss_mode);
+
+ if (j >= 0) {
+ pmadapter->callbacks.moal_spin_lock(pmpriv->curr_bcn_buf_lock);
+ pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.overlap_bss_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size_max = 0;
+
+ PRINTM(MINFO, "Found current ssid/bssid in list @ index #%d\n", j);
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&pmpriv->curr_bss_params.bss_descriptor,
+ &pmadapter->pscan_table[j],
+ sizeof(pmpriv->curr_bss_params.bss_descriptor));
+
+ wlan_save_curr_bcn(pmpriv);
+ pmadapter->callbacks.moal_spin_unlock(pmpriv->curr_bcn_buf_lock);
+ } else {
+ wlan_restore_curr_bcn(pmpriv);
+ }
+ }
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++)
+ PRINTM(MINFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+ "RSSI[%03d], SSID[%s]\n",
+ i,
+ pmadapter->pscan_table[i].mac_address[0],
+ pmadapter->pscan_table[i].mac_address[1],
+ pmadapter->pscan_table[i].mac_address[2],
+ pmadapter->pscan_table[i].mac_address[3],
+ pmadapter->pscan_table[i].mac_address[4],
+ pmadapter->pscan_table[i].mac_address[5],
+ (t_s32) pmadapter->pscan_table[i].rssi,
+ pmadapter->pscan_table[i].ssid.ssid);
+
+ /*
+ * Prepares domain info from scan table and downloads the
+ * domain info command to the FW.
+ */
+ wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
+
+ LEAVE();
+}
+
+/**
+ * @brief Convert radio type scan parameter to a band config used in join cmd
+ *
+ * @param radio_type Scan parameter indicating the radio used for a channel
+ * in a scan command.
+ *
+ * @return Band type conversion of scanBand used in join/assoc cmds
+ *
+ */
+static t_u8
+radio_type_to_band(t_u8 radio_type)
+{
+ t_u8 ret_band;
+
+ switch (radio_type) {
+ case HostCmd_SCAN_RADIO_TYPE_A:
+ ret_band = BAND_A;
+ break;
+ case HostCmd_SCAN_RADIO_TYPE_BG:
+ default:
+ ret_band = BAND_G;
+ break;
+ }
+
+ return ret_band;
+}
+
+/**
+ * @brief Delete a specific indexed entry from the scan table.
+ *
+ * Delete the scan table entry indexed by table_idx. Compact the remaining
+ * entries and adjust any buffering of beacon/probe response data
+ * if needed.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param table_idx Scan table entry index to delete from the table
+ *
+ * @return N/A
+ *
+ * @pre table_idx must be an index to a valid entry
+ */
+static t_void
+wlan_scan_delete_table_entry(IN mlan_private * pmpriv, IN t_s32 table_idx)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 del_idx;
+ t_u32 beacon_buf_adj;
+ t_u8 *pbeacon_buf;
+
+ ENTER();
+
+ /*
+ * Shift the saved beacon buffer data for the scan table back over the
+ * entry being removed. Update the end of buffer pointer. Save the
+ * deleted buffer allocation size for pointer adjustments for entries
+ * compacted after the deleted index.
+ */
+ beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+ table_idx, beacon_buf_adj);
+
+ /* Check if the table entry had storage allocated for its beacon */
+ if (beacon_buf_adj) {
+ pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
+
+ /*
+ * Remove the entry's buffer space, decrement the table end pointer
+ * by the amount we are removing
+ */
+ pmadapter->pbcn_buf_end -= beacon_buf_adj;
+
+ PRINTM(MINFO,
+ "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+ table_idx,
+ pbeacon_buf,
+ pbeacon_buf + beacon_buf_adj,
+ pmadapter->pbcn_buf_end - pbeacon_buf);
+
+ /*
+ * Compact data storage. Copy all data after the deleted entry's
+ * end address (pbeacon_buf + beacon_buf_adj) back to the original
+ * start address (pbeacon_buf).
+ *
+ * Scan table entries affected by the move will have their entry
+ * pointer adjusted below.
+ *
+ * Use memmove since the dest/src memory regions overlap.
+ */
+ memmove(pbeacon_buf,
+ pbeacon_buf + beacon_buf_adj,
+ pmadapter->pbcn_buf_end - pbeacon_buf);
+ }
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
+ table_idx, pmadapter->num_in_scan_table);
+
+ /* Shift all of the entries after the table_idx back by one, compacting the
+ table and removing the requested entry */
+ for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
+ del_idx++) {
+ /* Copy the next entry over this one */
+ memcpy(pmadapter->pscan_table + del_idx,
+ pmadapter->pscan_table + del_idx + 1, sizeof(BSSDescriptor_t));
+
+ /*
+ * Adjust this entry's pointer to its beacon buffer based on the
+ * removed/compacted entry from the deleted index. Don't decrement
+ * if the buffer pointer is MNULL (no data stored for this entry).
+ */
+ if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
+ pmadapter->pscan_table[del_idx].pbeacon_buf -= beacon_buf_adj;
+ if (pmadapter->pscan_table[del_idx].pwpa_ie) {
+ pmadapter->pscan_table[del_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wpa_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].prsn_ie) {
+ pmadapter->pscan_table[del_idx].prsn_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].rsn_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pwapi_ie) {
+ pmadapter->pscan_table[del_idx].pwapi_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wapi_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pht_cap) {
+ pmadapter->pscan_table[del_idx].pht_cap =
+ (IEEEtypes_HTCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pht_info) {
+ pmadapter->pscan_table[del_idx].pht_info =
+ (IEEEtypes_HTInfo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_info_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
+ pmadapter->pscan_table[del_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_cap) {
+ pmadapter->pscan_table[del_idx].pext_cap =
+ (IEEEtypes_ExtCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].poverlap_bss_scan_param) {
+ pmadapter->pscan_table[del_idx].poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) (pmadapter->
+ pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->
+ pscan_table[del_idx].
+ overlap_bss_offset);
+ }
+
+ }
+ }
+
+ /* The last entry is invalid now that it has been deleted or moved back */
+ memset(pmadapter->pscan_table + pmadapter->num_in_scan_table - 1,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ pmadapter->num_in_scan_table--;
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all occurrences of a given SSID from the scan table
+ *
+ * Iterate through the scan table and delete all entries that match a given
+ * SSID. Compact the remaining scan table entries.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdel_ssid Pointer to an SSID to be used in deleting all
+ * matching SSIDs from the scan table
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_delete_ssid_table_entry(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * pdel_ssid)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_s32 table_idx;
+
+ ENTER();
+
+ PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
+
+ /* If the requested SSID is found in the table, delete it. Then keep
+ searching the table for multiple entires for the SSID until no more are
+ found */
+ while ((table_idx = wlan_find_ssid_in_list(pmpriv,
+ pdel_ssid,
+ MNULL,
+ MLAN_BSS_MODE_AUTO)) >= 0) {
+ PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n", table_idx);
+ ret = MLAN_STATUS_SUCCESS;
+ wlan_scan_delete_table_entry(pmpriv, table_idx);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param puser_scan_in Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return MLAN_STATUS_SUCCESS or < 0 if error
+ */
+mlan_status
+wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
+ t_u32 buf_size;
+ ChanScanParamSet_t *pscan_chan_list;
+
+ t_u8 keep_previous_scan;
+ t_u8 filtered_scan;
+ t_u8 scan_current_chan_only;
+ t_u8 max_chan_per_scan;
+
+ ENTER();
+
+ ret = pcb->moal_malloc(sizeof(wlan_scan_cmd_config_tlv),
+ (t_u8 **) & pscan_cfg_out);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
+ ret = pcb->moal_malloc(buf_size, (t_u8 **) & pscan_chan_list);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
+ PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree((t_u8 *) pscan_cfg_out);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pscan_chan_list, 0x00, buf_size);
+ memset(pscan_cfg_out, 0x00, sizeof(wlan_scan_cmd_config_tlv));
+
+ keep_previous_scan = MFALSE;
+
+ wlan_scan_setup_scan_config(pmpriv,
+ puser_scan_in,
+ &pscan_cfg_out->config,
+ &pchan_list_out,
+ pscan_chan_list,
+ &max_chan_per_scan,
+ &filtered_scan, &scan_current_chan_only);
+
+ if (puser_scan_in) {
+ keep_previous_scan = puser_scan_in->keep_previous_scan;
+ }
+
+ if (keep_previous_scan == MFALSE) {
+ memset(pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ }
+
+ ret = wlan_scan_channel_list(pmpriv,
+ pioctl_buf,
+ max_chan_per_scan,
+ filtered_scan,
+ &pscan_cfg_out->config,
+ pchan_list_out, pscan_chan_list);
+
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (util_peek_list
+ (&pmadapter->scan_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) {
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(&pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MTRUE;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+ if (pscan_cfg_out)
+ pcb->moal_mfree((t_u8 *) pscan_cfg_out);
+
+ if (pscan_chan_list)
+ pcb->moal_mfree((t_u8 *) pscan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
+ wlan_scan_cmd_config *pscan_cfg;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *) pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan_cmd->bss_mode = pscan_cfg->bss_mode;
+ memcpy(pscan_cmd->bssid, pscan_cfg->specific_bssid,
+ sizeof(pscan_cmd->bssid));
+ memcpy(pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(pscan_cmd->bss_mode)
+ + sizeof(pscan_cmd->bssid)
+ + pscan_cfg->tlv_buf_len
+ + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-------------------------------------------------------------.
+ * | Header (4 * sizeof(t_u16)): Standard command response hdr |
+ * .-------------------------------------------------------------.
+ * | BufSize (t_u16) : sizeof the BSS Description data |
+ * .-------------------------------------------------------------.
+ * | NumOfSet (t_u8) : Number of BSS Descs returned |
+ * .-------------------------------------------------------------.
+ * | BSSDescription data (variable, size given in BufSize) |
+ * .-------------------------------------------------------------.
+ * | TLV data (variable, size calculated using Header->Size, |
+ * | BufSize and sizeof the fixed fields above) |
+ * .-------------------------------------------------------------.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ MrvlIEtypes_Data_t *ptlv;
+ MrvlIEtypes_TsfTimestamp_t *ptsf_tlv;
+ t_u8 *pbss_info;
+ t_u32 scan_resp_size;
+ t_u32 bytes_left;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u32 tlv_buf_size;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv;
+ ChanBandParamSet_t *pchan_band;
+ t_u8 band;
+ t_u8 is_bgscan_resp;
+
+ ENTER();
+ pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ if (is_bgscan_resp) {
+ pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+ } else {
+ pscan_rsp = &resp->params.scan_resp;
+ }
+
+ if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan_rsp->number_of_sets);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
+ PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
+
+ scan_resp_size = resp->size;
+
+ PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
+ pscan_rsp->number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
+
+ /*
+ * The size of the TLV buffer is equal to the entire command response
+ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bss_descript_size as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlv_buf_size = scan_resp_size - (bytes_left
+ + sizeof(pscan_rsp->bss_descript_size)
+ + sizeof(pscan_rsp->number_of_sets)
+ + S_DS_GEN);
+
+ ptlv =
+ (MrvlIEtypes_Data_t *) (pscan_rsp->bss_desc_and_tlv_buffer +
+ bytes_left);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_TSFTIMESTAMP,
+ (MrvlIEtypes_Data_t **) & ptsf_tlv);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_CHANNELBANDLIST,
+ (MrvlIEtypes_Data_t **) & pchan_band_tlv);
+
+ /*
+ * Process each scan response returned (pscan_rsp->number_of_sets). Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret = pcb->moal_malloc(sizeof(BSSDescriptor_t), (t_u8 **) & bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if ((wlan_interpret_bss_desc_with_ie(pmadapter,
+ bss_new_entry,
+ &pbss_info,
+ &bytes_left) ==
+ MLAN_STATUS_SUCCESS)
+ && CHECK_SSID_IS_VALID(bss_new_entry.ssid)) {
+
+ PRINTM(MINFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_new_entry->mac_address[0], bss_new_entry->mac_address[1],
+ bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
+ bss_new_entry->mac_address[4],
+ bss_new_entry->mac_address[5]);
+
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bss_idx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)
+ && (!memcmp(bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO, "SCAN_RESP: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST) {
+ bss_idx--;
+ } else {
+ num_in_table++;
+ }
+ }
+
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv,
+ bss_idx,
+ num_in_table, bss_new_entry);
+ /*
+ * If the TSF TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (ptsf_tlv) {
+ memcpy(&tsf_val, &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy(&bss_new_entry->network_tsf,
+ &tsf_val, sizeof(bss_new_entry->network_tsf));
+ }
+ band = BAND_G;
+ if (pchan_band_tlv) {
+ pchan_band = &pchan_band_tlv->chan_band_param[idx];
+ band =
+ radio_type_to_band(pchan_band->
+ radio_type & (MBIT(0) | MBIT(1)));
+ }
+
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) bss_new_entry->
+ bss_band,
+ (t_u16) bss_new_entry->
+ channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(&pmadapter->pscan_table[bss_idx],
+ bss_new_entry, sizeof(pmadapter->pscan_table[bss_idx]));
+
+ } else {
+
+ /* Error parsing/interpreting the scan response, skipped */
+ PRINTM(MERROR, "SCAN_RESP: "
+ "wlan_interpret_bss_desc_with_ie returned ERROR\n");
+ }
+ }
+
+ PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan_rsp->number_of_sets,
+ num_in_table - pmadapter->num_in_scan_table, num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+
+ if (!util_peek_list
+ (&pmadapter->scan_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_buf,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(&pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+
+ done:
+ if (bss_new_entry)
+ pcb->moal_mfree((t_u8 *) bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_query.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
+
+ bg_query->flush = 1;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_ssid_in_list(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1, j;
+ t_u8 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+ PRINTM(MINFO, "Num of Entries in Table = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Loop through the table until the maximum is reached or until a match
+ * is found based on the bssid field comparison
+ */
+ for (i = 0;
+ i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
+ i++) {
+ if (!wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid, ssid) &&
+ (!bssid
+ || !memcmp(pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH))) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ j = wlan_is_network_compatible(pmpriv, i, mode);
+
+ if (j >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ } else {
+ if (net == -1) {
+ net = j;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ /*
+ * Do not check compatibility if the mode requested is
+ * Auto/Unknown. Allows generic find to work without
+ * verifying against the Adapter security settings
+ */
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ if (net >= 0) {
+ if (!wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) pmadapter->
+ pscan_table[net].bss_band,
+ (t_u16) pmadapter->
+ pscan_table[net].channel)) {
+ net = -1;
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1;
+ t_u32 i;
+
+ ENTER();
+
+ if (!bssid) {
+ LEAVE();
+ return -1;
+ }
+
+ PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
+ if (!memcmp
+ (pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH)) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ net = wlan_is_network_compatible(pmpriv, i, mode);
+ break;
+ default:
+ net = i;
+ break;
+ }
+ }
+ }
+
+ if (net >= 0) {
+ if (!wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) pmadapter->
+ pscan_table[net].bss_band,
+ (t_u16) pmadapter->
+ pscan_table[net].channel)) {
+ net = -1;
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+t_s32
+wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief This function inserts scan command node to scan_pending_q.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @return n/a
+ */
+t_void
+wlan_queue_scan_cmd(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ util_enqueue_list_tail(&pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param preq_ssid_bssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ BSSDescriptor_t *preq_bss;
+ t_s32 i;
+
+ ENTER();
+
+ memset(preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ i = wlan_find_best_network_in_list(pmpriv);
+
+ if (i >= 0) {
+ preq_bss = &pmadapter->pscan_table[i];
+ memcpy(&preq_ssid_bssid->ssid, &preq_bss->ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy((t_u8 *) & preq_ssid_bssid->bssid,
+ (t_u8 *) & preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ /* Make sure we are in the right mode */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
+ pmpriv->bss_mode = preq_bss->bss_mode;
+ }
+
+ if (!preq_ssid_bssid->ssid.ssid_len) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Best network found = [%s], "
+ "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ preq_ssid_bssid->ssid.ssid,
+ preq_ssid_bssid->bssid[0], preq_ssid_bssid->bssid[1],
+ preq_ssid_bssid->bssid[2], preq_ssid_bssid->bssid[3],
+ preq_ssid_bssid->bssid[4], preq_ssid_bssid->bssid[5]);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param preq_ssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * preq_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_user_scan_cfg *pscan_cfg;
+
+ ENTER();
+
+ if (!preq_ssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
+
+ ret = pcb->moal_malloc(sizeof(wlan_user_scan_cfg), (t_u8 **) & pscan_cfg);
+
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
+
+ memcpy(pscan_cfg->ssid_list[0].ssid, preq_ssid->ssid, preq_ssid->ssid_len);
+ pscan_cfg->keep_previous_scan = MTRUE;
+
+ ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
+
+ if (pscan_cfg)
+ pcb->moal_mfree((t_u8 *) pscan_cfg);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function append the vendor specific IE TLV
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param vsie_mask VSIE bit mask
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int
+wlan_cmd_append_vsie_tlv(IN mlan_private * pmpriv,
+ IN t_u16 vsie_mask, OUT t_u8 ** ppbuffer)
+{
+ int id, ret_len = 0;
+ MrvlIETypes_VendorParamSet_t *pvs_param_set;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == 0) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == 0) {
+ LEAVE();
+ return 0;
+ }
+
+ /**
+ * Traverse through the saved vendor specific IE array and append
+ * the selected(scan/assoc/adhoc) IE as TLV to the command
+ */
+ for (id = 0; id < MLAN_MAX_VSIE_NUM; id++) {
+ if (pmpriv->vs_ie[id].mask & vsie_mask) {
+ pvs_param_set = (MrvlIETypes_VendorParamSet_t *) * ppbuffer;
+ pvs_param_set->header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ pvs_param_set->header.len =
+ (((t_u16) pmpriv->vs_ie[id].ie[1]) & 0x00FF) + 2;
+ memcpy(pvs_param_set->ie, pmpriv->vs_ie[id].ie,
+ pvs_param_set->header.len);
+ HEXDUMP("VENDOR_SPEC_IE", (t_u8 *) pvs_param_set,
+ sizeof(MrvlIEtypesHeader_t) + pvs_param_set->header.len);
+ *ppbuffer +=
+ pvs_param_set->header.len + sizeof(MrvlIEtypesHeader_t);
+ ret_len += pvs_param_set->header.len + sizeof(MrvlIEtypesHeader_t);
+ pvs_param_set->header.len =
+ wlan_cpu_to_le16(pvs_param_set->header.len);
+ }
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Save a beacon buffer of the current bss descriptor
+ * Save the current beacon buffer to restore in the following cases that
+ * makes the bcn_buf not to contain the current ssid's beacon buffer.
+ * - the current ssid was not found somehow in the last scan.
+ * - the current ssid was the last entry of the scan table and overloaded.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return n/a
+ */
+t_void
+wlan_save_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ /* save the beacon buffer if it is not saved or updated */
+ if ((pmpriv->pcurr_bcn_buf == MNULL) ||
+ (pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
+ (memcmp(pmpriv->pcurr_bcn_buf, pcurr_bss->pbeacon_buf,
+ pcurr_bss->beacon_buf_size))) {
+
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+
+ pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
+ ret = pcb->moal_malloc(pcurr_bss->beacon_buf_size,
+ &pmpriv->pcurr_bcn_buf);
+
+ if ((ret == MLAN_STATUS_SUCCESS) && pmpriv->pcurr_bcn_buf) {
+ memcpy(pmpriv->pcurr_bcn_buf, pcurr_bss->pbeacon_buf,
+ pcurr_bss->beacon_buf_size);
+ PRINTM(MINFO, "current beacon saved %d\n", pmpriv->curr_bcn_size);
+ }
+ }
+}
+
+/**
+ * @brief Restore a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return n/a
+ */
+t_void
+wlan_restore_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+
+ if (pmpriv->pcurr_bcn_buf &&
+ ((pmadapter->pbcn_buf_end + pmpriv->curr_bcn_size) <
+ (pmadapter->bcn_buf + sizeof(pmadapter->bcn_buf)))) {
+
+ pcb->moal_spin_lock(pmpriv->curr_bcn_buf_lock);
+
+ /* restore the current beacon buffer */
+ memcpy(pmadapter->pbcn_buf_end, pmpriv->pcurr_bcn_buf,
+ pmpriv->curr_bcn_size);
+ pcurr_bss->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
+ pmadapter->pbcn_buf_end += pmpriv->curr_bcn_size;
+
+ /* adjust the pointers in the current bss descriptor */
+ if (pcurr_bss->pwpa_ie) {
+ pcurr_bss->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->wpa_offset);
+ }
+
+ if (pcurr_bss->prsn_ie) {
+ pcurr_bss->prsn_ie = (IEEEtypes_Generic_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->rsn_offset);
+ }
+
+ if (pcurr_bss->pht_cap) {
+ pcurr_bss->pht_cap = (IEEEtypes_HTCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_cap_offset);
+ }
+
+ if (pcurr_bss->pht_info) {
+ pcurr_bss->pht_info = (IEEEtypes_HTInfo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_info_offset);
+ }
+
+ if (pcurr_bss->pbss_co_2040) {
+ pcurr_bss->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->bss_co_2040_offset);
+ }
+
+ if (pcurr_bss->pext_cap) {
+ pcurr_bss->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ext_cap_offset);
+ }
+
+ if (pcurr_bss->poverlap_bss_scan_param) {
+ pcurr_bss->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->overlap_bss_offset);
+ }
+
+ pcb->moal_spin_unlock(pmpriv->curr_bcn_buf_lock);
+
+ PRINTM(MINFO, "current beacon restored %d\n", pmpriv->curr_bcn_size);
+ } else {
+ PRINTM(MWARN, "curr_bcn_buf not saved or bcn_buf has no space\n");
+ }
+}
+
+/**
+ * @brief Free a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return n/a
+ */
+t_void
+wlan_free_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+}
diff --git a/wlan_src/mlan/mlan_sdio.c b/wlan_src/mlan/mlan_sdio.c
new file mode 100755
index 0000000..0de4d42
--- /dev/null
+++ b/wlan_src/mlan/mlan_sdio.c
@@ -0,0 +1,1420 @@
+/** @file mlan_sdio.c
+ *
+ * @brief This file contains SDIO specific code
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function initialize the SDIO port
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_init_ioport(mlan_adapter * pmadapter)
+{
+ t_u32 reg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ pmadapter->ioport = 0;
+
+ /* Read the IO port */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_0_REG, ®))
+ pmadapter->ioport |= (reg & 0xff);
+ else
+ return MLAN_STATUS_FAILURE;
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_1_REG, ®))
+ pmadapter->ioport |= ((reg & 0xff) << 8);
+ else
+ return MLAN_STATUS_FAILURE;
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_2_REG, ®))
+ pmadapter->ioport |= ((reg & 0xff) << 16);
+ else
+ return MLAN_STATUS_FAILURE;
+
+ PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n", pmadapter->ioport);
+
+#define SDIO_INT_MASK 0x3F
+ /* Set Host interrupt reset to read to clear */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG, ®)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG,
+ reg | SDIO_INT_MASK);
+ } else
+ return MLAN_STATUS_FAILURE;
+
+ /* Dnld/Upld ready set to auto reset */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG, ®)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG,
+ reg | AUTO_RE_ENABLE_INT);
+ } else
+ return MLAN_STATUS_FAILURE;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets available SDIO port for reading cmd/data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_rd_port(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u16 rd_bitmap = pmadapter->mp_rd_bitmap;
+
+ PRINTM(MDATA, "wlan_get_rd_port: mp_rd_bitmap=0x%04x\n", rd_bitmap);
+
+ if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
+ return MLAN_STATUS_FAILURE;
+
+ if (pmadapter->mp_rd_bitmap & CTRL_PORT_MASK) {
+ pmadapter->mp_rd_bitmap &= (t_u16) (~CTRL_PORT_MASK);
+ *pport = CTRL_PORT;
+ PRINTM(MDATA, "wlan_get_rd_port: port=%d mp_rd_bitmap=0x%04x\n", *pport,
+ pmadapter->mp_rd_bitmap);
+ } else {
+ if (pmadapter->mp_rd_bitmap & (1 << pmadapter->curr_rd_port)) {
+ pmadapter->mp_rd_bitmap &=
+ (t_u16) (~(1 << pmadapter->curr_rd_port));
+ *pport = pmadapter->curr_rd_port;
+
+ if (++pmadapter->curr_rd_port == MAX_PORT)
+ pmadapter->curr_rd_port = 1;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MDATA, "port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
+ *pport, rd_bitmap, pmadapter->mp_rd_bitmap);
+ }
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets available SDIO port for writing data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_wr_port_data(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u16 wr_bitmap = pmadapter->mp_wr_bitmap;
+
+ PRINTM(MDATA, "wlan_get_wr_port_data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
+
+ if (!(wr_bitmap & pmadapter->mp_data_port_mask))
+ return MLAN_STATUS_FAILURE;
+
+ if (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)) {
+ pmadapter->mp_wr_bitmap &= (t_u16) (~(1 << pmadapter->curr_wr_port));
+ *pport = pmadapter->curr_wr_port;
+ if (++pmadapter->curr_wr_port == pmadapter->mp_end_port)
+ pmadapter->curr_wr_port = 1;
+ } else {
+ pmadapter->data_sent = MTRUE;
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ PRINTM(MDATA, "port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
+ *pport, wr_bitmap, pmadapter->mp_wr_bitmap);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function polls the card status register.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param bits the bit mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_poll_card_status(mlan_adapter * pmadapter, t_u8 bits)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 tries;
+ t_u32 cs = 0;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_STATUS_REG, &cs) !=
+ MLAN_STATUS_SUCCESS)
+ break;
+ else if ((cs & bits) == bits)
+ return MLAN_STATUS_SUCCESS;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ PRINTM(MWARN, "wlan_sdio_poll_card_status failed, tries = %d\n", tries);
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function reads firmware status registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_read_fw_status(mlan_adapter * pmadapter, t_u16 * dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 fws0 = 0, fws1 = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG, &fws0))
+ return MLAN_STATUS_FAILURE;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS1_REG, &fws1))
+ return MLAN_STATUS_FAILURE;
+
+ *dat = (fws1 << 8) | fws0;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** @brief This function disables the host interrupts mask.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ t_u32 host_int_mask = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Read back the host_int_mask register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ &host_int_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~mask;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ host_int_mask)) {
+ PRINTM(MWARN, "Disable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts mask
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Simply write the mask to the register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG, mask)) {
+ PRINTM(MWARN, "Enable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads data from the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type A pointer to keep type as data or command
+ * @param nb A pointer to keep the data/cmd length returned in buffer
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param npayload the length of data/cmd buffer
+ * @param ioport the SDIO ioport
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_card_to_host(mlan_adapter * pmadapter,
+ t_u32 * type, t_u32 * nb, pmlan_buffer pmbuf,
+ t_u32 npayload, t_u32 ioport)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MWARN, "pmbuf NULL pointer received!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf, ioport, 0);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "card_to_host, read iomem failed: %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ *nb = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset));
+ if (*nb > npayload) {
+ PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb, npayload);
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ DBG_HEXDUMP(MDAT_D, "SDIO Blk Rd", pmbuf->pbuf,
+ MIN(npayload, MAX_DATA_DUMP_LEN));
+
+ *type = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset + 2));
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *firmware = pmfw->pfw_buf;
+ t_u32 firmwarelen = pmfw->fw_len;
+ t_u32 offset = 0;
+ t_u32 base0, base1;
+ t_void *tmpfwbuf = MNULL;
+ t_u32 tmpfwbufsz;
+ t_u8 *fwbuf;
+ mlan_buffer mbuf;
+ t_u16 len = 0;
+ t_u32 txlen = 0, tx_blocks = 0, tries = 0;
+ t_u32 i = 0;
+
+ ENTER();
+
+ if (!firmwarelen) {
+ PRINTM(MMSG, "No firmware image found! Terminating download\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "Downloading FW image (%d bytes)\n", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, HEADER_ALIGNMENT);
+ ret = pcb->moal_malloc(tmpfwbufsz, (t_u8 **) & tmpfwbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
+ PRINTM(MERROR,
+ "Unable to allocate buffer for firmware. Terminating download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(tmpfwbuf, 0, tmpfwbufsz);
+ /* Ensure 8-byte aligned firmware buffer */
+ fwbuf = (t_u8 *) ALIGN_ADDR(tmpfwbuf, HEADER_ALIGNMENT);
+
+ /* Perform firmware data transfer */
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+ ret =
+ wlan_sdio_poll_card_status(pmadapter,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW download with helper poll status timeout @ %d\n",
+ offset);
+ goto done;
+ }
+
+ /* More data? */
+ if (offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_F1_RD_BASE_0,
+ &base0)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MWARN,
+ "Dev BASE0 register read failed:"
+ " base0=0x%04X(%d). Terminating download\n", base0,
+ base0);
+ goto done;
+ }
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_F1_RD_BASE_1,
+ &base1)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MWARN,
+ "Dev BASE1 register read failed:"
+ " base1=0x%04X(%d). Terminating download\n", base1,
+ base1);
+ goto done;
+ }
+ len = ((base1 & 0xff) << 8) | (base0 & 0xff);
+
+ if (len)
+ break;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ if (!len)
+ break;
+ else if (len > WLAN_UPLD_SIZE) {
+ PRINTM(MFATAL, "FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & MBIT(0)) {
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(MFATAL,
+ "FW download failure @ %d, over max retry count\n",
+ offset);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR, "FW CRC error indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n", len, txlen);
+ len &= ~MBIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking for last block */
+ if (firmwarelen - offset < txlen) {
+ txlen = firmwarelen - offset;
+ }
+ PRINTM(MINFO, ".");
+
+ tx_blocks =
+ (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD -
+ 1) / MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ memmove(fwbuf, &firmware[offset], txlen);
+ }
+
+ /* Send data */
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *) fwbuf;
+ mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->ioport, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "FW download, write iomem (%d) failed @ %d\n", i,
+ offset);
+ if (pcb->
+ moal_write_reg(pmadapter->pmoal_handle, CONFIGURATION_REG,
+ 0x04) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ offset += txlen;
+ } while (MTRUE);
+
+ PRINTM(MINFO, "\nFW download over, size %d bytes\n", offset);
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmpfwbuf)
+ pcb->moal_mfree((t_u8 *) tmpfwbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interface is present
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS if the calling interface
+ * is the winner, otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_check_winner_status(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 winner_status;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+ winner_status = 0;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG,
+ &winner_status))
+ return MLAN_STATUS_FAILURE;
+
+ if (winner_status != 0)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_SUCCESS;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pollnum Maximum polling number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 firmwarestat;
+ t_u32 tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (MLAN_STATUS_SUCCESS !=
+ (ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat)))
+ continue;
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ } else {
+ wlan_mdelay(pmadapter, 100);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+mlan_status
+wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Download the firmware image via helper */
+ ret = wlan_prog_fw_w_helper(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function probes the driver
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_probe(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sdio_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ /*
+ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+ * from the bootloader. If we don't do this we get a interrupt
+ * as soon as we register the irq.
+ */
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INTSTATUS_REG, &sdio_ireg);
+
+ /* Disable host interrupt mask register for SDIO */
+ ret = wlan_disable_host_int(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS)
+ return MLAN_STATUS_FAILURE;
+
+ /* Get SDIO ioport */
+ ret = wlan_sdio_init_ioport(pmadapter);
+
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @return None
+ */
+t_void
+mlan_interrupt(t_void * adapter)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf;
+ t_u32 sdio_ireg = 0;
+
+ ENTER();
+
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = pmadapter->mp_regs;
+ mbuf.data_len = MAX_MP_REGS;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
+ REG_PORT | MLAN_SDIO_BYTE_MODE_MASK, 0)) {
+ PRINTM(MWARN, "moal_read_data_sync: read registers failed\n");
+ goto done;
+ }
+
+ DBG_HEXDUMP(MDAT_D, "SDIO MP Registers", pmadapter->mp_regs, MAX_MP_REGS);
+ sdio_ireg = pmadapter->mp_regs[HOST_INTSTATUS_REG];
+ if (sdio_ireg) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register
+ */
+ PRINTM(MINTR, "sdio_ireg = 0x%x\n", sdio_ireg);
+ pmadapter->sdio_ireg |= sdio_ireg;
+ }
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_disable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_enable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_enable_host_int_mask(pmadapter, HIM_ENABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function decodes the rx packet &
+ * calls corresponding handlers according to the packet type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param upld_typ Type of rx packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_decode_rx_packet(mlan_adapter * pmadapter, mlan_buffer * pmbuf,
+ t_u32 upld_typ)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *cmdBuf;
+ t_u32 event;
+
+ switch (upld_typ) {
+ case MLAN_TYPE_DATA:
+ PRINTM(MINFO, "--- Rx: Data packet ---\n");
+ pmbuf->data_len = (pmadapter->upld_len - INTF_HEADER_LEN);
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ wlan_handle_rx_packet(pmadapter, pmbuf);
+ break;
+
+ case MLAN_TYPE_CMD:
+ PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
+ DBG_HEXDUMP(MDAT_D, "Cmd RESP BUFFER", pmbuf->pbuf,
+ pmadapter->upld_len);
+ /* take care of curr_cmd = NULL case */
+ if (!pmadapter->curr_cmd) {
+ cmdBuf = pmadapter->upld_buf;
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ wlan_process_sleep_confirm_resp(pmadapter,
+ pmbuf->pbuf +
+ pmbuf->data_offset +
+ INTF_HEADER_LEN,
+ pmadapter->upld_len -
+ INTF_HEADER_LEN);
+ }
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ memcpy(cmdBuf, pmbuf->pbuf + pmbuf->data_offset + INTF_HEADER_LEN,
+ MIN(MRVDRV_SIZE_OF_CMD_BUFFER,
+ pmadapter->upld_len - INTF_HEADER_LEN));
+ pcb->moal_free_mlan_buffer(pmbuf);
+ } else {
+ pmadapter->cmd_resp_received = MTRUE;
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ pmbuf->data_len -= INTF_HEADER_LEN;
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+ }
+ break;
+
+ case MLAN_TYPE_EVENT:
+ PRINTM(MINFO, "--- Rx: Event ---\n");
+
+ event = *(t_u32 *) & pmbuf->pbuf[4];
+ pmadapter->event_cause = wlan_le32_to_cpu(event);
+ if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
+ ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) < MAX_EVENT_SIZE)) {
+ memcpy(pmadapter->event_body, pmbuf->pbuf + MLAN_EVENT_HEADER_LEN,
+ pmadapter->upld_len - MLAN_EVENT_HEADER_LEN);
+ }
+
+ /* event cause has been saved to adapter->event_cause */
+ pmadapter->event_received = MTRUE;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmadapter->pmlan_buffer_event = pmbuf;
+
+ /* remove SDIO header */
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmbuf->data_len -= INTF_HEADER_LEN;
+ break;
+
+ default:
+ PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
+ pcb->moal_free_mlan_buffer(pmbuf);
+ break;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/**
+ * @brief This function receives data from the card in aggregate mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param port Current port on which packet needs to be rxed
+ * @param rx_len Length of received packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter, mlan_buffer
+ * pmbuf, t_u8 port, t_u16 rx_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 f_do_rx_aggr = 0;
+ t_s32 f_do_rx_cur = 0;
+ t_s32 f_aggr_cur = 0;
+ mlan_buffer mbuf_aggr;
+ mlan_buffer *mbuf_deaggr;
+ t_u32 pind = 0;
+ t_u32 pkt_len, pkt_type = 0;
+ t_u8 *curr_ptr;
+
+ ENTER();
+
+ if (port == CTRL_PORT) {
+ /* Read the command Resp without aggr */
+ PRINTM(MINFO, "card_2_host_mp_aggr: No aggregation for cmd response\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (!pmadapter->mpa_rx.enabled) {
+ PRINTM(MINFO, "card_2_host_mp_aggr: rx aggregation disabled !\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (pmadapter->mp_rd_bitmap & (~((t_u16) CTRL_PORT_MASK))) {
+ /* Some more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_aggr = 1;
+ f_do_rx_cur = 1;
+ }
+ } else {
+ /* Rx aggr not in progress */
+ f_aggr_cur = 1;
+ }
+
+ } else {
+ /* No more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ f_do_rx_aggr = 1;
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_cur = 1;
+ }
+ } else {
+ f_do_rx_cur = 1;
+ }
+
+ }
+
+ if (f_aggr_cur) {
+ PRINTM(MINFO, "Current packet aggregation.\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
+
+ if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MINFO,
+ "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
+ /* No more pkts allowed in Aggr buf, rx it */
+ f_do_rx_aggr = 1;
+ }
+
+ }
+
+ if (f_do_rx_aggr) {
+ /* do aggr RX now */
+ PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
+ pmadapter->mpa_rx.pkt_cnt);
+
+ memset(&mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_rx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf_aggr,
+ (pmadapter->ioport | 0x1000 |
+ (pmadapter->mpa_rx.ports << 4)) +
+ pmadapter->mpa_rx.start_port, 0)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ curr_ptr = pmadapter->mpa_rx.buf;
+
+ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
+
+ /* get curr PKT len & type */
+ pkt_len = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[0]);
+ pkt_type = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[2]);
+
+ PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n", pind,
+ pkt_len, pkt_type);
+
+ /* copy pkt to deaggr buf */
+ mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind];
+ if ((pkt_type == MLAN_TYPE_DATA) &&
+ (pkt_len <= pmadapter->mpa_rx.len_arr[pind])) {
+ memcpy(mbuf_deaggr->pbuf, curr_ptr, pkt_len);
+ pmadapter->upld_len = pkt_len;
+ /* Process de-aggr packet */
+ wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type);
+ } else {
+ PRINTM(MERROR, "Wrong aggr packet: type=%d, len=%d, max_len=%d",
+ pkt_type, pkt_len, pmadapter->mpa_rx.len_arr[pind]);
+ pcb->moal_free_mlan_buffer(mbuf_deaggr);
+ }
+ curr_ptr += pmadapter->mpa_rx.len_arr[pind];
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ rx_curr_single:
+ if (f_do_rx_cur) {
+ PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port, rx_len);
+
+ if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type,
+ (t_u32 *) &
+ pmadapter->upld_len,
+ pmbuf, rx_len,
+ pmadapter->ioport +
+ port)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type);
+
+ }
+
+ done:
+ LEAVE();
+ return ret;
+
+}
+#endif
+/**
+ * @brief This function checks the interrupt status and handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_int_status(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 sdio_ireg = pmadapter->sdio_ireg;
+ mlan_buffer *pmbuf = MNULL;
+ t_u8 *tmp_buf = MNULL;
+ t_u8 port = CTRL_PORT;
+ t_u32 len_reg_l, len_reg_u;
+ t_u32 rx_blocks;
+ t_u16 rx_len;
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ t_u32 upld_typ = 0;
+#endif
+
+ ENTER();
+
+ if (!pmadapter->sdio_ireg)
+ goto done;
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ pmadapter->mp_wr_bitmap =
+ ((t_u16) pmadapter->mp_regs[WR_BITMAP_U]) << 8;
+ pmadapter->mp_wr_bitmap |= (t_u16) pmadapter->mp_regs[WR_BITMAP_L];
+ PRINTM(MINTR, "DNLD: wr_bitmap=0x%04x\n", pmadapter->mp_wr_bitmap);
+ if (pmadapter->data_sent &&
+ (pmadapter->mp_wr_bitmap & pmadapter->mp_data_port_mask)) {
+ PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
+ pmadapter->data_sent = MFALSE;
+ }
+ }
+
+ /* As firmware will not generate download ready interrupt if the port
+ updated is command port only, cmd_sent should be done for any SDIO
+ interrupt. */
+ if (pmadapter->cmd_sent == MTRUE) {
+ /* Check if firmware has attach buffer at command port and update just
+ that in wr_bit_map. */
+ pmadapter->mp_wr_bitmap |=
+ (t_u16) pmadapter->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+ if (pmadapter->mp_wr_bitmap & CTRL_PORT_MASK)
+ pmadapter->cmd_sent = MFALSE;
+
+ }
+
+ PRINTM(MINFO, "cmd_sent=%d data_sent=%d\n",
+ pmadapter->cmd_sent, pmadapter->data_sent);
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+ pmadapter->mp_rd_bitmap =
+ ((t_u16) pmadapter->mp_regs[RD_BITMAP_U]) << 8;
+ pmadapter->mp_rd_bitmap |= (t_u16) pmadapter->mp_regs[RD_BITMAP_L];
+ PRINTM(MINTR, "UPLD: rd_bitmap=0x%04x\n", pmadapter->mp_rd_bitmap);
+
+ while (MTRUE) {
+ ret = wlan_get_rd_port(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "no more rd_port available\n");
+ break;
+ }
+ len_reg_l = RD_LEN_P0_L + (port << 1);
+ len_reg_u = RD_LEN_P0_U + (port << 1);
+ rx_len = ((t_u16) pmadapter->mp_regs[len_reg_u]) << 8;
+ rx_len |= (t_u16) pmadapter->mp_regs[len_reg_l];
+ PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
+ rx_blocks =
+ (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) / MLAN_SDIO_BLOCK_SIZE;
+ if (rx_len <= INTF_HEADER_LEN ||
+ (rx_blocks * MLAN_SDIO_BLOCK_SIZE) > ALLOC_BUF_SIZE) {
+ PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_len = rx_blocks * MLAN_SDIO_BLOCK_SIZE;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_alloc_mlan_buffer(rx_len + HEADER_ALIGNMENT,
+ &pmbuf)) {
+ PRINTM(MWARN, "Failed to allocate 'mlan_buffer'\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ tmp_buf =
+ (t_u8 *) ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
+ HEADER_ALIGNMENT);
+ pmbuf->data_offset += tmp_buf - (pmbuf->pbuf + pmbuf->data_offset);
+ pmbuf->data_len = rx_len;
+ PRINTM(MINFO, "rx_len = %d\n", rx_len);
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf, port,
+ rx_len)) {
+#else
+ /* Transfer data from card */
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(pmadapter, &upld_typ,
+ (t_u32 *) & pmadapter->upld_len, pmbuf,
+ rx_len, pmadapter->ioport + port)) {
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ t_u32 cr = 0;
+
+ PRINTM(MERROR, "Card to host failed: int status=0x%x\n",
+ sdio_ireg);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ CONFIGURATION_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+
+ PRINTM(MINFO, "Config Reg val = %d\n", cr);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ CONFIGURATION_REG, (cr | 0x04)))
+ PRINTM(MERROR, "write CFG reg failed\n");
+
+ PRINTM(MINFO, "write success\n");
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ CONFIGURATION_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+
+ PRINTM(MINFO, "Config reg val =%x\n", cr);
+ ret = MLAN_STATUS_FAILURE;
+ pcb->moal_free_mlan_buffer(pmbuf);
+ goto done;
+ }
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ);
+#endif
+
+ }
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ pmadapter->sdio_ireg = 0;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
+ * @param tx_param A pointer to mlan_tx_param
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type, mlan_buffer * pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 buf_block_len;
+ t_u32 blksz;
+ t_u8 port = CTRL_PORT;
+ t_u32 i = 0;
+ t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
+
+ ENTER();
+
+ /* Allocate buffer and copy payload */
+ blksz = MLAN_SDIO_BLOCK_SIZE;
+ buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
+ *(t_u16 *) & payload[0] = wlan_cpu_to_le16(pmbuf->data_len);
+ *(t_u16 *) & payload[2] = wlan_cpu_to_le16(type);
+
+ /*
+ * This is SDIO specific header
+ * t_u16 length,
+ * t_u16 type (MLAN_TYPE_DATA = 0, MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
+ */
+ if (type == MLAN_TYPE_DATA) {
+ ret = wlan_get_wr_port_data(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "no wr_port available: %d\n", ret);
+ goto exit;
+ }
+ } else {
+ pmadapter->cmd_sent = MTRUE;
+ /* Type must be MLAN_TYPE_CMD */
+
+ if (pmbuf->data_len <= INTF_HEADER_LEN ||
+ pmbuf->data_len > WLAN_UPLD_SIZE)
+ PRINTM(MWARN,
+ "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
+ payload, pmbuf->data_len);
+ }
+
+ do {
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (tx_param)
+ ret =
+ wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
+ tx_param->next_pkt_len);
+ else
+ ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port, 0);
+#else
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->ioport + port, 0);
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ i++;
+ PRINTM(MERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+ ret);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, CONFIGURATION_REG,
+ 0x04)) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ if (type == MLAN_TYPE_CMD)
+ pmadapter->cmd_sent = MFALSE;
+ if (type == MLAN_TYPE_DATA)
+ pmadapter->data_sent = MFALSE;
+ goto exit;
+ }
+ } else {
+ if (type == MLAN_TYPE_DATA) {
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ pmadapter->data_sent = MTRUE;
+ else
+ pmadapter->data_sent = MFALSE;
+ }
+ DBG_HEXDUMP(MDAT_D, "SDIO Blk Wr", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/**
+ * @brief This function sends data to the card in SDIO aggregated mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mbuf A pointer to the SDIO data/cmd buffer
+ * @param port current port for aggregation
+ * @param next_pkt_len Length of next packet used for multiport aggregation
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter, mlan_buffer * mbuf,
+ t_u8 port, t_u32 next_pkt_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 f_send_aggr_buf = 0;
+ t_s32 f_send_cur_buf = 0;
+ t_s32 f_precopy_cur_buf = 0;
+ t_s32 f_postcopy_cur_buf = 0;
+ mlan_buffer mbuf_aggr;
+
+ ENTER();
+
+ PRINTM(MDAT_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
+ next_pkt_len, port);
+
+ if ((!pmadapter->mpa_tx.enabled) || (port == CTRL_PORT)) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: tx aggregation disabled !\n");
+
+ f_send_cur_buf = 1;
+ goto tx_curr_single;
+ }
+
+ if (next_pkt_len) {
+ /* More pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (!MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) &&
+ MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port))
+ || !MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ next_pkt_len)) {
+ f_send_aggr_buf = 1;
+ }
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) ||
+ !(pmadapter->
+ mp_wr_bitmap & (1 << pmadapter->curr_wr_port))) {
+ f_send_cur_buf = 1;
+ } else {
+ f_postcopy_cur_buf = 1;
+ }
+ }
+ } else {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len) &&
+ (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ f_precopy_cur_buf = 1;
+ else
+ f_send_cur_buf = 1;
+ }
+ } else {
+ /* Last pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* some packs in Aggr buf already */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_cur_buf = 1;
+ }
+ } else {
+ f_send_cur_buf = 1;
+ }
+ }
+
+ if (f_precopy_cur_buf) {
+ PRINTM(MDATA, "host_2_card_mp_aggr: Precopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+
+ if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MDAT_D,
+ "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
+ /* No more pkts allowed in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+ }
+ }
+
+ if (f_send_aggr_buf) {
+ PRINTM(MDATA, "host_2_card_mp_aggr: Send aggregation buffer."
+ "%d %d\n", pmadapter->mpa_tx.start_port,
+ pmadapter->mpa_tx.ports);
+
+ memset(&mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_tx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_tx.buf_len;
+ ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf_aggr,
+ (pmadapter->ioport | 0x1000 |
+ (pmadapter->mpa_tx.ports << 4)) +
+ pmadapter->mpa_tx.start_port, 0);
+
+ MP_TX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ tx_curr_single:
+ if (f_send_cur_buf) {
+ PRINTM(MDATA, "host_2_card_mp_aggr: Send current buffer %d\n", port);
+ ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, mbuf,
+ pmadapter->ioport + port, 0);
+ }
+
+ if (f_postcopy_cur_buf) {
+ PRINTM(MDATA, "host_2_card_mp_aggr: Postcopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief This function allocates buffer for the SDIO aggregation buffer
+ * related members of adapter structure
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mpa_tx_buf_size Tx buffer size to allocate
+ * @param mpa_rx_buf_size Rx buffer size to allocate
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size, t_u32 mpa_rx_buf_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ ret =
+ pcb->moal_malloc(mpa_tx_buf_size + HEADER_ALIGNMENT,
+ (t_u8 **) & pmadapter->mpa_tx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_tx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP TX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_tx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_tx.head_ptr, HEADER_ALIGNMENT);
+ pmadapter->mpa_tx.buf_size = mpa_tx_buf_size;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ ret =
+ pcb->moal_malloc(mpa_rx_buf_size + HEADER_ALIGNMENT,
+ (t_u8 **) & pmadapter->mpa_rx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP RX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_rx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_rx.head_ptr, HEADER_ALIGNMENT);
+ pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+ error:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ wlan_free_sdio_mpa_buffers(pmadapter);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees buffers for the SDIO aggregation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (pmadapter->mpa_tx.buf) {
+ pcb->moal_mfree((t_u8 *) pmadapter->mpa_tx.head_ptr);
+ pmadapter->mpa_tx.head_ptr = MNULL;
+ pmadapter->mpa_tx.buf = MNULL;
+ pmadapter->mpa_tx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (pmadapter->mpa_rx.buf) {
+ pcb->moal_mfree((t_u8 *) pmadapter->mpa_rx.head_ptr);
+ pmadapter->mpa_rx.head_ptr = MNULL;
+ pmadapter->mpa_rx.buf = MNULL;
+ pmadapter->mpa_rx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
diff --git a/wlan_src/mlan/mlan_sdio.h b/wlan_src/mlan/mlan_sdio.h
new file mode 100755
index 0000000..cf46277
--- /dev/null
+++ b/wlan_src/mlan/mlan_sdio.h
@@ -0,0 +1,323 @@
+/** @file mlan_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MLAN_SDIO_H
+#define _MLAN_SDIO_H
+
+/** Block mode */
+#define BLOCK_MODE 1
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+
+/** Control register for BUS interface */
+#define BUS_INTERFACE_CONTROL_REG 0x07
+
+/** Asynchronous interrupt mode */
+#define ASYNC_INT_MODE 0x20
+
+/** Port for registers */
+#define REG_PORT 0
+/** LSB of read bitmap */
+#define RD_BITMAP_L 0x04
+/** MSB of read bitmap */
+#define RD_BITMAP_U 0x05
+/** LSB of write bitmap */
+#define WR_BITMAP_L 0x06
+/** MSB of write bitmap */
+#define WR_BITMAP_U 0x07
+/** LSB of read length for port 0 */
+#define RD_LEN_P0_L 0x08
+/** MSB of read length for port 0 */
+#define RD_LEN_P0_U 0x09
+/** Ctrl port */
+#define CTRL_PORT 0
+/** Ctrl port mask */
+#define CTRL_PORT_MASK 0x0001
+/** Data port mask */
+#define DATA_PORT_MASK 0xfffe
+/** Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT MBIT(4)
+
+/* Host Control Registers */
+/** Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG 0x78
+/** Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG 0x79
+/** Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG 0x7A
+
+/** Host Control Registers : Configuration */
+#define CONFIGURATION_REG 0x00
+/** Host Control Registers : Host without Command 53 finish host*/
+#define HOST_TO_CARD_EVENT (0x1U << 3)
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/** Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG 0x02
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/** Enable Host interrupt mask */
+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/** Disable Host interrupt mask */
+#define HIM_DISABLE 0xff
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INTSTATUS_REG 0x03
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/** Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG 0x01
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG 0x28
+/** Host Control Registers : Upload CRC error */
+#define UP_LD_CRC_ERR (0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/* Card Control Registers */
+/** Card Control Registers : Read SQ base address A0 register */
+#define SQ_READ_BASE_ADDRESS_A0_REG 0x40
+/** Card Control Registers : Read SQ base address A1 register */
+#define SQ_READ_BASE_ADDRESS_A1_REG 0x41
+/** Card Control Registers : Read SQ base address A2 register */
+#define SQ_READ_BASE_ADDRESS_A2_REG 0x42
+/** Card Control Registers : Read SQ base address A3 register */
+#define SQ_READ_BASE_ADDRESS_A3_REG 0x43
+/** Card Control Registers : Read SQ base address B0 register */
+#define SQ_READ_BASE_ADDRESS_B0_REG 0x44
+/** Card Control Registers : Read SQ base address B1 register */
+#define SQ_READ_BASE_ADDRESS_B1_REG 0x45
+/** Card Control Registers : Read SQ base address B2 register */
+#define SQ_READ_BASE_ADDRESS_B2_REG 0x46
+/** Card Control Registers : Read SQ base address B3 register */
+#define SQ_READ_BASE_ADDRESS_B3_REG 0x47
+
+/** Card Control Registers : Card status register */
+#define CARD_STATUS_REG 0x30
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/** Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG 0x34
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/** Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG 0x38
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/** Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG 0x3c
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/** Card Control Registers : Debug 0 register */
+#define DEBUG_0_REG 0x70
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0 (0x1U)
+/** Card Control Registers : Debug 1 register */
+#define DEBUG_1_REG 0x71
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1 (0x1U)
+/** Card Control Registers : Debug 2 register */
+#define DEBUG_2_REG 0x72
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2 (0x1U)
+/** Card Control Registers : Debug 3 register */
+#define DEBUG_3_REG 0x73
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3 (0x1U)
+/** Card Control Registers : Card OCR 0 register */
+#define CARD_OCR_0_REG 0x68
+/** Card Control Registers : Card OCR 1 register */
+#define CARD_OCR_1_REG 0x69
+/** Card Control Registers : Card OCR 3 register */
+#define CARD_OCR_3_REG 0x6A
+/** Card Control Registers : Card config register */
+#define CARD_CONFIG_REG 0x6B
+/** Card Control Registers : Miscellaneous Configuration Register */
+#define CARD_MISC_CFG_REG 0x6C
+/** Card Control Registers : Card revision register */
+#define CARD_REVISION_REG 0x5c
+/** Card Control Registers : Command 53 finish G BUS */
+#define CMD53_FINISH_GBUS (0x1U << 1)
+/** Card Control Registers : SD negative edge */
+#define SD_NEG_EDGE (0x1U << 0)
+
+/* Special registers in function 0 of the SDxx card */
+/** Special register in function 0 of the SDxxx card : Scratch 0 */
+#define SCRATCH_0_REG 0x80fe
+/** Special register in function 0 of the SDxxx card : Scratch 1 */
+#define SCRATCH_1_REG 0x80ff
+/** Host F1 read base 0 */
+#define HOST_F1_RD_BASE_0 0x0040
+/** Host F1 read base 1 */
+#define HOST_F1_RD_BASE_1 0x0041
+/** Host F1 card ready */
+#define HOST_F1_CARD_RDY 0x0020
+
+/** Chip Id Register 0 */
+#define CARD_CHIP_ID_0_REG 0x801c
+/** Chip Id Register 1 */
+#define CARD_CHIP_ID_1_REG 0x801d
+/** Firmware status 0 register */
+#define CARD_FW_STATUS0_REG 0x60
+/** Firmware status 1 register */
+#define CARD_FW_STATUS1_REG 0x61
+/** Rx length register */
+#define CARD_RX_LEN_REG 0x62
+/** Rx unit register */
+#define CARD_RX_UNIT_REG 0x63
+
+/** Event header Len*/
+#define MLAN_EVENT_HEADER_LEN 8
+
+#define MAX_BYTE_MODE_SIZE 512
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+
+/** SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt>0)
+
+/** SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a,mbuf, len) ((a->mpa_tx.buf_len+len)<= a->mpa_tx.buf_size)
+
+/** Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, mbuf, port) do{ \
+ pmadapter->callbacks.moal_memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len],mbuf->pbuf+mbuf->data_offset,mbuf->data_len);\
+ a->mpa_tx.buf_len += mbuf->data_len; \
+ if(!a->mpa_tx.pkt_cnt){ \
+ a->mpa_tx.start_port = port; \
+ } \
+ if(a->mpa_tx.start_port<=port){ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
+ }else{ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - a->mp_end_port))); \
+ } \
+ a->mpa_tx.pkt_cnt++; \
+}while(0);
+
+/** SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_tx.pkt_cnt==a->mpa_tx.pkt_aggr_limit)
+
+/** SDIO Tx aggregation port limit ? */
+#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
+ a->mpa_tx.start_port) && (((MAX_PORT - \
+ a->mpa_tx.start_port) + a->curr_wr_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_tx.pkt_cnt = 0; \
+ a->mpa_tx.buf_len = 0; \
+ a->mpa_tx.ports = 0; \
+ a->mpa_tx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+
+/** SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_rx.pkt_cnt== a->mpa_rx.pkt_aggr_limit)
+
+/** SDIO Tx aggregation port limit ? */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
+ a->mpa_rx.start_port) && (((MAX_PORT - \
+ a->mpa_rx.start_port) + a->curr_rd_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt>0)
+
+/** SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a,rx_len) ((a->mpa_rx.buf_len+rx_len)<=a->mpa_rx.buf_size)
+
+/** Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, mbuf, port, rx_len) do{ \
+ a->mpa_rx.buf_len += rx_len; \
+ if(!a->mpa_rx.pkt_cnt){ \
+ a->mpa_rx.start_port = port; \
+ } \
+ if(a->mpa_rx.start_port<=port){ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
+ }else{ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
+ } \
+ a->mpa_rx.mbuf_arr[a->mpa_rx.pkt_cnt] = mbuf; \
+ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = rx_len; \
+ a->mpa_rx.pkt_cnt++; \
+}while(0);
+
+/** Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_rx.pkt_cnt = 0; \
+ a->mpa_rx.buf_len = 0; \
+ a->mpa_rx.ports = 0; \
+ a->mpa_rx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** Disable host interrupt */
+mlan_status wlan_disable_host_int(pmlan_adapter pmadapter);
+/** Enable host interrupt */
+mlan_status wlan_enable_host_int(pmlan_adapter pmadapter);
+/** Probe and initialization function */
+mlan_status wlan_sdio_probe(pmlan_adapter pmadapter);
+/** multi interface download check */
+mlan_status wlan_check_winner_status(mlan_adapter * pmadapter);
+/** Firmware status check */
+mlan_status wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum);
+/** Process Interrupt Status */
+mlan_status wlan_process_int_status(mlan_adapter * pmadapter);
+/** Transfer data to card */
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+mlan_status wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter,
+ mlan_buffer * mbuf, t_u8 port,
+ t_u32 next_pkt_len);
+#endif
+mlan_status wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type,
+ mlan_buffer * mbuf,
+ mlan_tx_param * tx_param);
+#endif /* _MLAN_SDIO_H */
diff --git a/wlan_src/mlan/mlan_shim.c b/wlan_src/mlan/mlan_shim.c
new file mode 100755
index 0000000..e4cf418
--- /dev/null
+++ b/wlan_src/mlan/mlan_shim.c
@@ -0,0 +1,721 @@
+/** @file mlan_shim.c
+ *
+ * @brief This file contains APIs to MOAL module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/**
+ * @mainpage MLAN Driver
+ *
+ * @section overview_sec Overview
+ *
+ * The MLAN is an OS independent WLAN driver for Marvell 802.11
+ * embedded chipset.
+ *
+ * @section copyright_sec Copyright
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** mlan function table */
+static mlan_operations ops[] = {
+ {
+ /* init cmd handler */
+ mlan_sta_init_cmd,
+ /* ioctl handler */
+ mlan_sta_ioctl,
+ /* cmd handler */
+ mlan_sta_prepare_cmd,
+ /* cmdresp handler */
+ mlan_process_sta_cmdresp,
+ /* rx handler */
+ mlan_process_sta_rx_packet,
+ /* Event handler */
+ mlan_process_sta_event,
+ /* txpd handler */
+ mlan_process_sta_txpd,
+ /* bss type */
+ MLAN_BSS_TYPE_STA,
+ },
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/**
+ * MLAN Adapter pointer
+ */
+mlan_adapter *g_pmadapter = MNULL;
+
+/********************************************************
+ Local Functions
+*******************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function registers MOAL to MLAN module.
+ *
+ * @param pmdevice A pointer to a mlan_device structure
+ * allocated in MOAL
+ * @param ppmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer as the context
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The registration succeeded.
+ * MLAN_STATUS_FAILURE
+ * The registration failed.
+ *
+ * mlan_status mlan_register (
+ * IN pmlan_device pmdevice,
+ * OUT t_void **ppmlan_adapter
+ * );
+ *
+ * Comments
+ * MOAL constructs mlan_device data structure to pass moal_handle and
+ * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to
+ * the ppmlan_adapter buffer provided by MOAL.
+ * Headers:
+ * declared in mlan_decl.h
+ * See Also
+ * mlan_unregister
+ */
+mlan_status
+mlan_register(IN pmlan_device pmdevice, OUT t_void ** ppmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = MNULL;
+ pmlan_callbacks pcb = MNULL;
+ t_u8 i = 0;
+ t_u32 j = 0;
+
+ ASSERT(pmdevice);
+ ASSERT(ppmlan_adapter);
+ ASSERT(pmdevice->callbacks.moal_malloc);
+ ASSERT(pmdevice->callbacks.moal_memset);
+ ASSERT(pmdevice->callbacks.moal_memmove);
+
+ /* Allocate memory for adapter structure */
+ if ((pmdevice->callbacks.moal_malloc(sizeof(mlan_adapter),
+ (t_u8 **) & pmadapter) !=
+ MLAN_STATUS_SUCCESS)
+ || !pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_register;
+ }
+ g_pmadapter = pmadapter;
+
+ pmdevice->callbacks.moal_memset(pmadapter, 0, sizeof(mlan_adapter));
+
+ pcb = &pmadapter->callbacks;
+
+ /* Save callback functions */
+ pmdevice->callbacks.moal_memmove(pcb,
+ &pmdevice->callbacks,
+ sizeof(mlan_callbacks));
+
+ /* Assertion for all callback functions */
+ ASSERT(pcb->moal_init_fw_complete);
+ ASSERT(pcb->moal_shutdown_fw_complete);
+ ASSERT(pcb->moal_send_packet_complete);
+ ASSERT(pcb->moal_recv_complete);
+ ASSERT(pcb->moal_recv_packet);
+ ASSERT(pcb->moal_recv_event);
+ ASSERT(pcb->moal_ioctl_complete);
+ ASSERT(pcb->moal_write_reg);
+ ASSERT(pcb->moal_read_reg);
+ ASSERT(pcb->moal_alloc_mlan_buffer);
+ ASSERT(pcb->moal_free_mlan_buffer);
+ ASSERT(pcb->moal_write_data_sync);
+ ASSERT(pcb->moal_read_data_sync);
+ ASSERT(pcb->moal_mfree);
+ ASSERT(pcb->moal_memcpy);
+ ASSERT(pcb->moal_memcmp);
+ ASSERT(pcb->moal_get_system_time);
+ ASSERT(pcb->moal_init_timer);
+ ASSERT(pcb->moal_free_timer);
+ ASSERT(pcb->moal_start_timer);
+ ASSERT(pcb->moal_stop_timer);
+ ASSERT(pcb->moal_init_lock);
+ ASSERT(pcb->moal_free_lock);
+ ASSERT(pcb->moal_spin_lock);
+ ASSERT(pcb->moal_spin_unlock);
+ ASSERT(pcb->moal_print);
+
+ ENTER();
+
+ /* Save pmoal_handle */
+ pmadapter->pmoal_handle = pmdevice->pmoal_handle;
+ /* card specific probing has been deferred until now .. */
+ if (MLAN_STATUS_SUCCESS != (ret = wlan_sdio_probe(pmadapter))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef MFG_CMD_SUPPORT
+ pmadapter->mfg_mode = pmdevice->mfg_mode;
+#endif
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmadapter->priv[i] = MNULL;
+ if (pmdevice->bss_attr[i].active == MTRUE) {
+ /* For valid bss_attr, allocate memory for private structure */
+ if ((pcb->moal_malloc(sizeof(mlan_private),
+ (t_u8 **) & pmadapter->priv[i]) !=
+ MLAN_STATUS_SUCCESS)
+ || !pmadapter->priv[i]) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ memset(pmadapter->priv[i], 0, sizeof(mlan_private));
+
+ pmadapter->priv[i]->adapter = pmadapter;
+
+ /* Save bss_type, frame_type & bss_priority */
+ pmadapter->priv[i]->bss_type =
+ (t_u8) pmdevice->bss_attr[i].bss_type;
+ pmadapter->priv[i]->frame_type =
+ (t_u8) pmdevice->bss_attr[i].frame_type;
+ pmadapter->priv[i]->bss_priority =
+ (t_u8) pmdevice->bss_attr[i].bss_priority;
+
+ /* Save bss_num */
+ pmadapter->priv[i]->bss_num = i;
+
+ /* init function table */
+ for (j = 0; j < (sizeof(ops) / sizeof(ops[0])); j++) {
+ if (ops[j].bss_type == pmadapter->priv[i]->bss_type) {
+ memcpy(&pmadapter->priv[i]->ops, &ops[j],
+ sizeof(mlan_operations));
+ }
+ }
+ }
+ }
+
+ /* Initialize locks */
+ if (pcb->moal_init_lock(&pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ if (pcb->moal_init_lock(&pmadapter->pmain_proc_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ if (pcb->moal_init_lock(&pmadapter->pmlan_cmd_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->
+ moal_init_timer(&pmadapter->pmlan_cmd_timer, wlan_cmd_timeout_func,
+ pmadapter)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ /* Return pointer of mlan_adapter to MOAL */
+ *ppmlan_adapter = pmadapter;
+
+ LEAVE();
+ goto exit_register;
+
+ error:
+ PRINTM(MINFO, "Leave mlan_register with error\n");
+ LEAVE();
+ /* Free resources */
+ if (pmadapter->pmlan_cmd_timer)
+ pcb->moal_free_timer(pmadapter->pmlan_cmd_timer);
+ if (pmadapter->pmlan_cmd_lock)
+ pcb->moal_free_lock(pmadapter->pmlan_cmd_lock);
+ if (pmadapter->pmain_proc_lock)
+ pcb->moal_free_lock(pmadapter->pmain_proc_lock);
+ if (pmadapter->pmlan_lock)
+ pcb->moal_free_lock(pmadapter->pmlan_lock);
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i])
+ pcb->moal_mfree((t_u8 *) pmadapter->priv[i]);
+ }
+ pcb->moal_mfree((t_u8 *) pmadapter);
+
+ exit_register:
+ return ret;
+}
+
+/**
+ * @brief This function unregisters MOAL from MLAN module.
+ *
+ * @param pmlan_adapter A pointer to a mlan_device structure
+ * allocated in MOAL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The deregistration succeeded.
+ * MLAN_STATUS_FAILURE
+ * The deregistration failed.
+ */
+mlan_status
+mlan_unregister(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ ASSERT(pmlan_adapter);
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ /* Free timers */
+ if (pmadapter->pmlan_cmd_timer)
+ pcb->moal_free_timer(pmadapter->pmlan_cmd_timer);
+
+ /* Free locks */
+ pcb->moal_free_lock(pmadapter->pmlan_cmd_lock);
+ pcb->moal_free_lock(pmadapter->pmain_proc_lock);
+ pcb->moal_free_lock(pmadapter->pmlan_lock);
+
+ /* Free private structures */
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ wlan_free_curr_bcn(pmadapter->priv[i]);
+ pcb->moal_free_lock(pmadapter->priv[i]->curr_bcn_buf_lock);
+ pcb->moal_mfree((t_u8 *) pmadapter->priv[i]);
+ }
+ }
+
+ LEAVE();
+ /* Free mlan_adapter */
+ pcb->moal_mfree((t_u8 *) pmadapter);
+
+ return ret;
+}
+
+/**
+ * @brief This function downloads the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware download succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware download failed.
+ */
+mlan_status
+mlan_dnld_fw(IN t_void * pmlan_adapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ t_u32 poll_num = 1;
+
+ ENTER();
+ ASSERT(pmlan_adapter);
+
+ /* Check if firmware is already running */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "WLAN FW already running! Skip FW download\n");
+ goto done;
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if other interface is downloading */
+ ret = wlan_check_winner_status(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MMSG,
+ "WLAN winner interface already running! Skip FW download\n");
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+ if (pmfw) {
+ /* Download helper/firmware */
+ ret = wlan_dnld_fw(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
+ LEAVE();
+ return ret;
+ }
+ }
+
+ poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW failed to be active in time!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ done:
+
+ /* re-enable host interrupt for mlan after fw dnld is successful */
+ wlan_enable_host_int(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware initialization is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware initialization failed.
+ */
+mlan_status
+mlan_init_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ ASSERT(pmlan_adapter);
+
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ /* Initialize firmware, may return PENDING */
+ ret = wlan_init_fw(pmadapter);
+ PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Shutdown firmware
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown call succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware shutdown call is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware shutdown call failed.
+ */
+mlan_status
+mlan_shutdown_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ mlan_private *priv = MNULL;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ ENTER();
+ ASSERT(pmlan_adapter);
+ /* mlan already shutdown */
+ if (pmadapter->hw_status == WlanHardwareStatusNotReady)
+ return MLAN_STATUS_SUCCESS;
+
+ pmadapter->hw_status = WlanHardwareStatusClosing;
+ /* wait for mlan_process to complete */
+ if (pmadapter->mlan_processing) {
+ PRINTM(MWARN, "mlan main processing is still running\n");
+ return ret;
+ }
+
+ /* shut down mlan */
+ PRINTM(MINFO, "Shutdown mlan...\n");
+
+ pcb = &pmadapter->callbacks;
+ /* Clean up Tx/Rx queues and delete BSS priority table */
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+
+ wlan_clean_txrx(priv);
+ wlan_wmm_cleanup_node(priv);
+ pcb->moal_free_lock(priv->rx_pkt_lock);
+ wlan_delete_bsspriotbl(priv);
+ pcb->moal_free_lock(priv->wmm.ra_list_spinlock);
+ }
+ }
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++)
+ util_free_list_head(&pmadapter->bssprio_tbl[i].bssprio_head,
+ pcb->moal_free_lock);
+
+ if (pcb->moal_spin_lock(pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+
+ if (pcb->moal_spin_unlock(pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ /* Notify completion */
+ ret = wlan_shutdown_fw_complete(pmadapter);
+
+ exit_shutdown_fw:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The main process
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_main_process(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ ASSERT(pmlan_adapter);
+
+ pcb = &pmadapter->callbacks;
+
+ pcb->moal_spin_lock(pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing) {
+ pcb->moal_spin_unlock(pmadapter->pmain_proc_lock);
+ goto exit_main_proc;
+ } else {
+ pmadapter->mlan_processing = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmain_proc_lock);
+ }
+ process_start:
+ do {
+ /* Is MLAN shutting down or not ready? */
+ if ((pmadapter->hw_status == WlanHardwareStatusClosing) ||
+ (pmadapter->hw_status == WlanHardwareStatusNotReady))
+ break;
+
+ /* Handle pending SDIO interrupts if any */
+ if (pmadapter->sdio_ireg) {
+ if (pmadapter->hs_activated == MTRUE)
+ wlan_process_hs_config(pmadapter);
+ wlan_process_int_status(pmadapter);
+ }
+
+ /* Need to wake up the card ? */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP) &&
+ (pmadapter->pm_wakeup_card_req &&
+ !pmadapter->pm_wakeup_fw_try) &&
+ (util_peek_list
+ (&pmadapter->cmd_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)
+ || !wlan_wmm_lists_empty(pmadapter))) {
+ pmadapter->pm_wakeup_fw_try = MTRUE;
+ wlan_pm_wakeup_card(pmadapter);
+ continue;
+ }
+ if (IS_CARD_RX_RCVD(pmadapter)) {
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ if (pmadapter->ps_state == PS_STATE_SLEEP)
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ } else {
+ /* We have tried to wakeup the card already */
+ if (pmadapter->pm_wakeup_fw_try)
+ break;
+ if (pmadapter->ps_state != PS_STATE_AWAKE ||
+ (pmadapter->tx_lock_flag == MTRUE))
+ break;
+
+ if (pmadapter->scan_processing || pmadapter->data_sent
+ || wlan_wmm_lists_empty(pmadapter)
+ ) {
+ if (pmadapter->cmd_sent || pmadapter->curr_cmd ||
+ (!util_peek_list(&pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ break;
+ }
+ }
+ }
+
+ /* Check for Cmd Resp */
+ if (pmadapter->cmd_resp_received) {
+ pmadapter->cmd_resp_received = MFALSE;
+ wlan_process_cmdresp(pmadapter);
+
+ /* call moal back when init_fw is done */
+ if (pmadapter->hw_status == WlanHardwareStatusInitdone) {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ wlan_init_fw_complete(pmadapter);
+ }
+ }
+
+ /* Check for event */
+ if (pmadapter->event_received) {
+ pmadapter->event_received = MFALSE;
+ wlan_process_event(pmadapter);
+ }
+
+ /* Check if we need to confirm Sleep Request received previously */
+ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) {
+
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ wlan_check_ps_cond(pmadapter);
+ }
+ }
+
+ /*
+ * The ps_state may have been changed during processing of
+ * Sleep Request event.
+ */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ || (pmadapter->tx_lock_flag == MTRUE)
+ )
+ continue;
+
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ if (wlan_exec_next_cmd(pmadapter) == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ /* TODO: need to check tid eligibility for transfer to avoid dead loop */
+ if (!pmadapter->scan_processing && !pmadapter->data_sent &&
+ !wlan_wmm_lists_empty(pmadapter)) {
+ wlan_wmm_process_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_TYPE_ANY),
+ MFALSE);
+ }
+ }
+
+ if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) {
+ if (wlan_send_null_packet
+ (wlan_get_priv(pmadapter, MLAN_BSS_TYPE_STA),
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
+ == MLAN_STATUS_SUCCESS) {
+ pmadapter->delay_null_pkt = MFALSE;
+ }
+ break;
+ }
+
+ } while (MTRUE);
+
+ pcb->moal_spin_lock(pmadapter->pmain_proc_lock);
+ if ((pmadapter->sdio_ireg) || IS_CARD_RX_RCVD(pmadapter)) {
+ pcb->moal_spin_unlock(pmadapter->pmain_proc_lock);
+ goto process_start;
+ }
+ pmadapter->mlan_processing = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmain_proc_lock);
+
+ exit_main_proc:
+ if (pmadapter->hw_status == WlanHardwareStatusClosing)
+ mlan_shutdown_fw(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Function to send packet
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ ASSERT(pmlan_adapter && pmbuf);
+
+ ASSERT(pmbuf->bss_num < MLAN_MAX_BSS_NUM);
+
+ {
+ /* Transmit the packet */
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+mlan_ioctl(IN t_void * adapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ pmlan_private pmpriv = MNULL;
+
+ ENTER();
+
+ if (pioctl_req == MNULL) {
+ PRINTM(MERROR, "MLAN IOCTL information buffer is NULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (pioctl_req->action == MLAN_ACT_CANCEL) {
+ wlan_cancel_pending_ioctl(pmadapter, pioctl_req);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+ pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ ret = pmpriv->ops.ioctl(adapter, pioctl_req);
+ exit:
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_sta_cmd.c b/wlan_src/mlan/mlan_sta_cmd.c
new file mode 100755
index 0000000..ce8d23d
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_cmd.c
@@ -0,0 +1,1839 @@
+/** @file mlan_sta_cmd.c
+ *
+ * @brief This file contains the handling of command.
+ * it prepares command and sends it to firmware when
+ * it is ready.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function prepares command of get_hw_spec.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_get_hw_spec(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * pcmd)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &pcmd->params.hw_spec;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+ memcpy(hw_spec->permanent_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of RSSI info.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_u16 cmd_action)
+{
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI_INFO) + S_DS_GEN);
+ pcmd->params.rssi_info.action = wlan_cpu_to_le16(cmd_action);
+ pcmd->params.rssi_info.ndata = wlan_cpu_to_le16(pmpriv->data_avg_factor);
+ pcmd->params.rssi_info.nbcn = wlan_cpu_to_le16(pmpriv->bcn_avg_factor);
+
+ /* Reset SNR/NF/RSSI values in private structure */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_MAC_CONTROL *pmac = &pcmd->params.mac_ctrl;
+ t_u16 action = *((t_u16 *) pdata_buf);
+
+ ENTER();
+
+ if (cmd_action != HostCmd_ACT_GEN_SET) {
+ PRINTM(MERROR, "wlan_cmd_mac_control(): support SET only.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+ pmac->action = wlan_cpu_to_le16(action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ t_u32 ul_temp;
+
+ ENTER();
+ PRINTM(MCMND, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(MAX_SNMP_BUF_SIZE);
+ cmd->size += MAX_SNMP_BUF_SIZE;
+ }
+
+ switch (cmd_oid) {
+ case FragThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) FragThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case RtsThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) RtsThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *(t_u16 *) (psnmp_mib->value) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+
+ case ShortRetryLim_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) ShortRetryLim_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = (*(t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11D_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11D_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11H_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case WwsMode_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) WwsMode_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ PRINTM(MCMND, "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, wlan_le16_to_cpu(psnmp_mib->buf_size),
+ wlan_le16_to_cpu(*(t_u16 *) psnmp_mib->value));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of get_log.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_get_log(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of radio_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_control = &cmd->params.radio;
+
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+ pradio_control->action = wlan_cpu_to_le16(cmd_action);
+ pradio_control->control = wlan_cpu_to_le16(pmadapter->radio_on);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_rate_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_TX_RATE_CFG *rate_cfg = &cmd->params.tx_rate_cfg;
+ MrvlRateScope_t *rate_scope;
+ MrvlRateDropPattern_t *rate_drop;
+ t_u16 *pbitmap_rates = (t_u16 *) pdata_buf;
+
+ t_u32 i;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+ rate_cfg->action = wlan_cpu_to_le16(cmd_action);
+ rate_cfg->cfg_index = 0;
+
+ rate_scope = (MrvlRateScope_t *) ((t_u8 *) rate_cfg +
+ sizeof(HostCmd_DS_TX_RATE_CFG));
+ rate_scope->type = wlan_cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+ rate_scope->length = wlan_cpu_to_le16(sizeof(MrvlRateScope_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (pbitmap_rates != MNULL) {
+ rate_scope->hr_dsss_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pbitmap_rates[2 + i]);
+ } else {
+ rate_scope->hr_dsss_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[2 + i]);
+ }
+
+ rate_drop = (MrvlRateDropPattern_t *) ((t_u8 *) rate_scope +
+ sizeof(MrvlRateScope_t));
+ rate_drop->type = wlan_cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
+ rate_drop->length = wlan_cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+ rate_drop->rate_drop_mode = 0;
+
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) +
+ sizeof(MrvlRateScope_t) +
+ sizeof(MrvlRateDropPattern_t));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_power_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &cmd->params.txp_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TXPWR_CFG));
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ ptxp = (HostCmd_DS_TXPWR_CFG *) pdata_buf;
+ if (ptxp->mode) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u32) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ memmove(ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t) + ppg_tlv->length);
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg +
+ sizeof
+ (HostCmd_DS_TXPWR_CFG));
+ cmd->size +=
+ wlan_cpu_to_le16(sizeof(MrvlTypes_Power_Group_t) +
+ ppg_tlv->length);
+ ppg_tlv->type = wlan_cpu_to_le16(ppg_tlv->type);
+ ppg_tlv->length = wlan_cpu_to_le16(ppg_tlv->length);
+ } else {
+ memmove(ptxp_cfg, pdata_buf, sizeof(HostCmd_DS_TXPWR_CFG));
+ }
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ ptxp_cfg->cfg_index = wlan_cpu_to_le16(ptxp_cfg->cfg_index);
+ ptxp_cfg->mode = wlan_cpu_to_le32(ptxp_cfg->mode);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of enhanced ps_mode.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_opt_ps_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_PS_MODE_ENH));
+ ((HostCmd_DS_802_11_PS_MODE_ENH *) (&cmd->params.psmode_enh))->action =
+ wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case EN_PS:
+ {
+ ps_param *pps_mode = &cmd->params.psmode_enh.params.opt_ps;
+ PRINTM(MCMND, "PS Command: Enter PS\n");
+
+ pps_mode->null_pkt_interval =
+ wlan_cpu_to_le16(pmadapter->null_pkt_interval);
+ pps_mode->multiple_dtims =
+ wlan_cpu_to_le16(pmadapter->multiple_dtim);
+ pps_mode->bcn_miss_timeout =
+ wlan_cpu_to_le16(pmadapter->bcn_miss_time_out);
+ pps_mode->local_listen_interval =
+ wlan_cpu_to_le16(pmadapter->local_listen_interval);
+ pps_mode->adhoc_wake_period =
+ wlan_cpu_to_le16(pmadapter->adhoc_awake_period);
+ pps_mode->delay_to_ps = wlan_cpu_to_le16(pmadapter->delay_to_ps);
+ pps_mode->mode = wlan_cpu_to_le16(pmadapter->enhanced_ps_mode);
+ break;
+ }
+ case DIS_PS:
+ PRINTM(MCMND, "PS Command: Exit PS\n");
+ break;
+ case EN_AUTO_DS:
+ {
+ t_u16 idletime = 0;
+ auto_ds_param *pps_mode = &cmd->params.psmode_enh.params.auto_ds;
+ if (pdata_buf) {
+ idletime = ((mlan_ds_auto_ds *) pdata_buf)->idletime;
+ }
+
+ PRINTM(MCMND, "PS Command: Enter Auto Deep Sleep\n");
+ pps_mode->deep_sleep_timeout = wlan_cpu_to_le16(idletime);
+ break;
+ }
+ case DIS_AUTO_DS:
+ PRINTM(MCMND, "PS Command: Exit Auto Deep Sleep\n");
+ break;
+ case SLEEP_CONFIRM:
+ {
+ sleep_confirm_param *pps_mode =
+ &cmd->params.psmode_enh.params.sleep_cfm;
+ PRINTM(MCMND, "PS Command: Sleep Confirm\n");
+
+ pps_mode->resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ break;
+ }
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN HostCmd_DS_802_11_HS_CFG_ENH * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+ t_u16 hs_activate = MFALSE;
+
+ ENTER();
+
+ if (pdata_buf == MNULL) {
+ /* New Activate command */
+ hs_activate = MTRUE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+ if (!hs_activate &&
+ (pdata_buf->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL)
+ && ((pmadapter->arp_filter_size > 0)
+ && (pmadapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
+ PRINTM(MCMND, "Attach %d bytes ArpFilter to HSCfg cmd\n",
+ pmadapter->arp_filter_size);
+ memcpy(((t_u8 *) phs_cfg) + sizeof(HostCmd_DS_802_11_HS_CFG_ENH),
+ pmadapter->arp_filter, pmadapter->arp_filter_size);
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16(pmadapter->arp_filter_size +
+ sizeof(HostCmd_DS_802_11_HS_CFG_ENH) +
+ S_DS_GEN);
+ } else
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (hs_activate) {
+ phs_cfg->action = HS_ACTIVATE;
+ phs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
+ } else {
+ phs_cfg->action = HS_CONFIGURE;
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->params.hs_config.conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->params.hs_config.gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->params.hs_config.gap;
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_address.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.mac_addr.action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy(cmd->params.mac_addr.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ // HEXDUMP("SET_CMD: MAC ADDRESS-", priv->CurrentAddr, 6);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_period.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &cmd->params.sleep_pd;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sleep_pd->sleep_pd = wlan_cpu_to_le16(*(t_u16 *) pdata_buf);
+ }
+ pcmd_sleep_pd->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_params.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *pcmd_sp = &cmd->params.sleep_param;
+ mlan_ds_sleep_params *psp = (mlan_ds_sleep_params *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PARAMS) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sp->reserved = (t_u16) psp->reserved;
+ pcmd_sp->error = (t_u16) psp->error;
+ pcmd_sp->offset = (t_u16) psp->offset;
+ pcmd_sp->stable_time = (t_u16) psp->stable_time;
+ pcmd_sp->cal_control = (t_u8) psp->cal_control;
+ pcmd_sp->external_sleep_clk = (t_u8) psp->ext_sleep_clk;
+
+ pcmd_sp->reserved = wlan_cpu_to_le16(pcmd_sp->reserved);
+ pcmd_sp->error = wlan_cpu_to_le16(pcmd_sp->error);
+ pcmd_sp->offset = wlan_cpu_to_le16(pcmd_sp->offset);
+ pcmd_sp->stable_time = wlan_cpu_to_le16(pcmd_sp->stable_time);
+ }
+ pcmd_sp->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_multicast_adr.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_multicast_list *pmcast_list = (mlan_multicast_list *) pdata_buf;
+ HostCmd_DS_MAC_MULTICAST_ADR *pmc_addr = &cmd->params.mc_addr;
+
+ ENTER();
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+ pmc_addr->action = wlan_cpu_to_le16(cmd_action);
+ pmc_addr->num_of_adrs =
+ wlan_cpu_to_le16((t_u16) pmcast_list->num_multicast_addr);
+ memcpy(pmc_addr->mac_list, pmcast_list->mac_list,
+ pmcast_list->num_multicast_addr * MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauthenticate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_DEAUTHENTICATE *pdeauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
+
+ /* Set AP MAC address */
+ memcpy(pdeauth->mac_addr, (t_u8 *) pdata_buf, MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MCMND, "Deauth: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pdeauth->mac_addr[0], pdeauth->mac_addr[1], pdeauth->mac_addr[2],
+ pdeauth->mac_addr[3], pdeauth->mac_addr[4], pdeauth->mac_addr[5]);
+
+/** Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+ pdeauth->reason_code = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_stop.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN);
+
+ if (wlan_11h_is_active(pmpriv))
+ wlan_11h_activate(pmpriv, MFALSE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Length of WEP 40 bit key */
+#define WEP_40_BIT_LEN 5
+/** Length of WEP 104 bit key */
+#define WEP_104_BIT_LEN 13
+
+/**
+ * @brief This function sets WEP key(s) to key_param_set TLV(s).
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param key_param_set A pointer to MrvlIEtype_KeyParamSet_t structure
+ * @param key_param_len A pointer to the length variable
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_set_keyparamset_wep(mlan_private * priv,
+ MrvlIEtype_KeyParamSet_t * key_param_set,
+ t_u16 * key_param_len)
+{
+ int cur_key_param_len = 0;
+ t_u8 i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Multi-key_param_set TLV is supported */
+ for (i = 0; i < MRVL_NUM_WEP_KEY; i++) {
+ if ((priv->wep_key[i].key_length == WEP_40_BIT_LEN) ||
+ (priv->wep_key[i].key_length == WEP_104_BIT_LEN)) {
+ key_param_set->type = wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+/** Key_param_set WEP fixed length */
+#define KEYPARAMSET_WEP_FIXED_LEN 8
+ key_param_set->length =
+ wlan_cpu_to_le16((t_u16)
+ (priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN));
+ key_param_set->key_type_id = wlan_cpu_to_le16(KEY_TYPE_ID_WEP);
+ key_param_set->key_info = wlan_cpu_to_le16
+ (KEY_INFO_WEP_ENABLED | KEY_INFO_WEP_UNICAST |
+ KEY_INFO_WEP_MCAST);
+ key_param_set->key_len =
+ (t_u16) wlan_cpu_to_le16(priv->wep_key[i].key_length);
+ /* Set WEP key index */
+ key_param_set->key[0] = i;
+ /* Set default Tx key flag */
+ if (i == (priv->wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
+ key_param_set->key[1] = 1;
+ else
+ key_param_set->key[1] = 0;
+ memmove(&key_param_set->key[2], priv->wep_key[i].key_material,
+ priv->wep_key[i].key_length);
+
+ cur_key_param_len = priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN + sizeof(MrvlIEtypesHeader_t);
+ *key_param_len += (t_u16) cur_key_param_len;
+ key_param_set =
+ (MrvlIEtype_KeyParamSet_t *) ((t_u8 *) key_param_set +
+ cur_key_param_len);
+ } else if (!priv->wep_key[i].key_length) {
+ continue;
+ } else {
+ PRINTM(MERROR, "key%d Length = %d is incorrect\n", (i + 1),
+ priv->wep_key[i].key_length);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of key_material.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material = &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *) pdata_buf;
+ t_u16 key_param_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN);
+ goto done;
+ }
+
+ if (!pkey) {
+ memset(&pkey_material->key_param_set, 0,
+ (MRVL_NUM_WEP_KEY * sizeof(MrvlIEtype_KeyParamSet_t)));
+ ret =
+ wlan_set_keyparamset_wep(pmpriv, &pkey_material->key_param_set,
+ &key_param_len);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ } else
+ memset(&pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ if (pkey->is_wapi_key) {
+ PRINTM(MINFO, "Set WAPI Key\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED));
+
+ pkey_material->key_param_set.key[0] = pkey->key_index;
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key[1] = 1;
+ else
+ pkey_material->key_param_set.key[1] = 0; /* set 0 when re-key */
+
+ if (0 != memcmp(pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* WAPI
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+ else { /* WAPI group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_MCAST);
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ }
+
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(&pkey_material->key_param_set.key[2], pkey->key_material,
+ pkey->key_len);
+ memcpy(&pkey_material->key_param_set.key[2 + pkey->key_len], pkey->pn,
+ PN_SIZE);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN) {
+ PRINTM(MCMND, "WPA_AES\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+ if (pkey->key_index & 0x40000000) /* AES pairwise key: unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+ else /* AES group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+ } else if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ PRINTM(MCMND, "WPA_TKIP\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+ if (pkey->key_index & 0x40000000) /* TKIP pairwise key: unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+ else /* TKIP group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+ }
+
+ if (pkey_material->key_param_set.key_type_id) {
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len =
+ wlan_cpu_to_le16((t_u16) pkey->key_len);
+ memcpy(pkey_material->key_param_set.key, pkey->key_material,
+ pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16((t_u16) pkey->key_len + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (t_u16) (pkey->key_len + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of supplicant pmk
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *ppassphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ HostCmd_DS_802_11_SUPPLICANT_PMK *pesupplicant_psk =
+ &cmd->params.esupplicant_psk;
+ t_u8 *ptlv_buffer = (t_u8 *) pesupplicant_psk->tlv_buffer;
+ mlan_ds_passphrase *psk = (mlan_ds_passphrase *) pdata_buf;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+ /*
+ * Parse the rest of the buf here
+ * 1) <ssid="valid ssid"> - This will get the passphrase, AKMP
+ * for specified ssid, if none specified then it will get all.
+ * Eg: iwpriv <mlanX> passphrase 0:ssid=marvell
+ * 2) <psk="psk">:<passphrase="passphare">:<bssid="00:50:43:ef:23:f3">
+ * <ssid="valid ssid"> - passphrase and psk cannot be provided to
+ * the same SSID, Takes one SSID at a time, If ssid= is present
+ * the it should contain a passphrase or psk. If no arguments are
+ * provided then AKMP=802.1x, and passphrase should be provided
+ * after association.
+ * End of each parameter should be followed by a ':'(except for the
+ * last parameter) as the delimiter. If ':' has to be used in
+ * an SSID then a '/' should be preceded to ':' as a escape.
+ * Eg:iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl AP:psk=abcdefgh:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl/: AP:psk=abcdefgd:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase "1:ssid=mrvlAP:psk=abcdefgd"
+ * 3) <ssid="valid ssid"> - This will clear the passphrase
+ * for specified ssid, if none specified then it will clear all.
+ * Eg: iwpriv <mlanX> passphrase 2:ssid=marvell
+ */
+
+ /* -1 is for t_u8 TlvBuffer[1] as this should not be included */
+ cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1;
+ if (psk->ssid.ssid_len) {
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) ptlv_buffer;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len = (t_u16) psk->ssid.ssid_len;
+ memcpy((char *) pssid_tlv->ssid, psk->ssid.ssid, psk->ssid.ssid_len);
+ ptlv_buffer += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+ }
+ if (memcmp((t_u8 *) & psk->bssid, zero_mac, sizeof(zero_mac))) {
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) ptlv_buffer;
+ pbssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BSSID);
+ pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pbssid_tlv->bssid, (t_u8 *) & psk->bssid, MLAN_MAC_ADDR_LENGTH);
+ ptlv_buffer += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pbssid_tlv->header.len = wlan_cpu_to_le16(pbssid_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PASSPHRASE) {
+ ppassphrase_tlv = (MrvlIEtypes_Passphrase_t *) ptlv_buffer;
+ ppassphrase_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PASSPHRASE);
+ ppassphrase_tlv->header.len =
+ (t_u16) psk->psk.passphrase.passphrase_len;
+ memcpy(ppassphrase_tlv->passphrase, psk->psk.passphrase.passphrase,
+ psk->psk.passphrase.passphrase_len);
+ ptlv_buffer +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppassphrase_tlv->header.len =
+ wlan_cpu_to_le16(ppassphrase_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PMK) {
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) ptlv_buffer;
+ ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK);
+ ppmk_tlv->header.len = MLAN_MAX_PMK_LENGTH;
+ memcpy(ppmk_tlv->pmk, psk->psk.pmk.pmk, MLAN_MAX_PMK_LENGTH);
+ ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len);
+ }
+ if ((cmd_action == HostCmd_ACT_GEN_SET) &&
+ ((pssid_tlv || pbssid_tlv) && (!ppmk_tlv && !ppassphrase_tlv))) {
+ PRINTM(MERROR,
+ "Invalid case,ssid/bssid present without pmk or passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK);
+ pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action);
+ pesupplicant_psk->cache_result = 0;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *sup_profile =
+ &cmd->params.esupplicant_profile;
+
+ ENTER();
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SUPPLICANT_PROFILE) +
+ S_DS_GEN - 1);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PROFILE);
+ sup_profile->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_channel.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_chan = &cmd->params.rf_channel;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
+ + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->adhoc_start_band & BAND_A)
+ || (pmpriv->adapter->adhoc_start_band & BAND_AN)
+ )
+ prf_chan->rf_type = HostCmd_SCAN_RADIO_TYPE_A;
+ SET_SECONDARYCHAN(prf_chan->rf_type, pmpriv->adapter->chan_offset);
+ prf_chan->rf_type = wlan_cpu_to_le16(prf_chan->rf_type);
+ prf_chan->current_channel = wlan_cpu_to_le16(*((t_u16 *) pdata_buf));
+ }
+ prf_chan->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_antenna.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pantenna->action = wlan_cpu_to_le16(HostCmd_ACT_SET_BOTH);
+ pantenna->antenna_mode = wlan_cpu_to_le16(*(t_u16 *) pdata_buf);
+ } else
+ pantenna->action = wlan_cpu_to_le16(HostCmd_ACT_GET_BOTH);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ibss_coalescing_status.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer or MNULL
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal = &(cmd->params.ibss_coalescing);
+ t_u16 enable = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_STATUS) + S_DS_GEN);
+ cmd->result = 0;
+ pibss_coal->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ if (pdata_buf != MNULL)
+ enable = *(t_u16 *) pdata_buf;
+ pibss_coal->enable = wlan_cpu_to_le16(enable);
+ break;
+
+ /* In other case.. Nothing to do */
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/**
+ * @brief This function sends general command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_mfg_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *) pdata_buf;
+
+ ENTER();
+
+ /* Copy the MFG command to command buffer */
+ memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
+ PRINTM(MCMND, "MFG command size = %d\n", pcmd_ptr->len);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ cmd->result = 0;
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/**
+ * @brief This function prepares LDO cfg command
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_ldo_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ t_u16 *pmsource = (t_u16 *) pdata_buf;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_LDO_CONFIG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_LDO_CFG) + S_DS_GEN);
+
+ cmd->params.ldo_cfg.action = wlan_cpu_to_le16(cmd_action);
+ cmd->params.ldo_cfg.pmsource = wlan_cpu_to_le16(*pmsource);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares system clock cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *cfg = &cmd->params.sys_clock_cfg;
+ mlan_ds_misc_sys_clock *clk_cfg = (mlan_ds_misc_sys_clock *) pdata_buf;
+ int i = 0;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG) + S_DS_GEN);
+
+ cfg->action = wlan_cpu_to_le16(cmd_action);
+ cfg->cur_sys_clk = wlan_cpu_to_le16(clk_cfg->cur_sys_clk);
+ cfg->sys_clk_type = wlan_cpu_to_le16(clk_cfg->sys_clk_type);
+ cfg->sys_clk_len = wlan_cpu_to_le16(clk_cfg->sys_clk_num) * sizeof(t_u16);
+ for (i = 0; i < clk_cfg->sys_clk_num; i++)
+ cfg->sys_clk[i] = wlan_cpu_to_le16(clk_cfg->sys_clk[i]);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reg_access.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_reg_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_reg_rw *reg_rw;
+
+ ENTER();
+
+ reg_rw = (mlan_ds_reg_rw *) pdata_buf;
+ switch (cmd->command) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *mac_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN);
+ mac_reg = (HostCmd_DS_MAC_REG_ACCESS *) & cmd->params.mac_reg;
+ mac_reg->action = wlan_cpu_to_le16(cmd_action);
+ mac_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ mac_reg->value = wlan_cpu_to_le32(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *bbp_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN);
+ bbp_reg = (HostCmd_DS_BBP_REG_ACCESS *) & cmd->params.bbp_reg;
+ bbp_reg->action = wlan_cpu_to_le16(cmd_action);
+ bbp_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ bbp_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *rf_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ rf_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ rf_reg->action = wlan_cpu_to_le16(cmd_action);
+ rf_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ rf_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ {
+ HostCmd_DS_PMIC_REG_ACCESS *pmic_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_PMIC_REG_ACCESS) + S_DS_GEN);
+ pmic_reg = (HostCmd_DS_PMIC_REG_ACCESS *) & cmd->params.pmic_reg;
+ pmic_reg->action = wlan_cpu_to_le16(cmd_action);
+ pmic_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ pmic_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *cau_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ cau_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ cau_reg->action = wlan_cpu_to_le16(cmd_action);
+ cau_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ cau_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *rd_eeprom = (mlan_ds_read_eeprom *) pdata_buf;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & cmd->params.eeprom;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) +
+ S_DS_GEN);
+ cmd_eeprom->action = wlan_cpu_to_le16(cmd_action);
+ cmd_eeprom->offset = wlan_cpu_to_le16(rd_eeprom->offset);
+ cmd_eeprom->byte_count = wlan_cpu_to_le16(rd_eeprom->byte_count);
+ cmd_eeprom->value = 0;
+ break;
+ }
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mem_access.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_mem_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_mem_rw *mem_rw = (mlan_ds_mem_rw *) pdata_buf;
+ HostCmd_DS_MEM_ACCESS *mem_access =
+ (HostCmd_DS_MEM_ACCESS *) & cmd->params.mem;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MEM_ACCESS) + S_DS_GEN);
+
+ mem_access->action = wlan_cpu_to_le16(cmd_action);
+ mem_access->addr = wlan_cpu_to_le32(mem_rw->addr);
+ mem_access->value = wlan_cpu_to_le32(mem_rw->value);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares inactivity timeout command
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_inactivity_timeout(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_ds_inactivity_to inac_to;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to = &cmd->params.inactivity_to;
+
+ ENTER();
+
+ inac_to = (mlan_ds_inactivity_to *) pdata_buf;
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_INACTIVITY_TIMEOUT_EXT) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_inac_to->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cmd_inac_to->timeout_unit =
+ wlan_cpu_to_le16((t_u16) inac_to->timeout_unit);
+ cmd_inac_to->unicast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->unicast_timeout);
+ cmd_inac_to->mcast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->mcast_timeout);
+ cmd_inac_to->ps_entry_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of bca_timeshare.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_bca_timeshare(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_bca_ts *pdata_bca_ts = (mlan_ds_bca_ts *) pdata_buf;
+ HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &cmd->params.bca_timeshare;
+
+ ENTER();
+
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_BCA_TIMESHARE)) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ memset(bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
+ bca_ts->action = wlan_cpu_to_le16(cmd_action);
+ bca_ts->traffic_type = wlan_cpu_to_le16(pdata_bca_ts->traffic_type);
+ } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+ bca_ts->action = wlan_cpu_to_le16(cmd_action);
+ bca_ts->traffic_type = wlan_cpu_to_le16(pdata_bca_ts->traffic_type);
+ bca_ts->timeshare_interval =
+ wlan_cpu_to_le32(pdata_bca_ts->timeshare_interval);
+ bca_ts->bt_time = wlan_cpu_to_le32(pdata_bca_ts->bt_time);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTl Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_cmd_mac_control(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_cmd_802_11_mac_address(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret =
+ wlan_cmd_mac_multicast_adr(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret =
+ wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_cmd_tx_power_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret =
+ wlan_cmd_802_11_opt_ps_mode(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (HostCmd_DS_802_11_HS_CFG_ENH *)
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_cmd_802_11_sleep_period(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_cmd_802_11_sleep_params(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_cmd_802_11_scan(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_cmd_802_11_bg_scan_query(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_cmd_802_11_associate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_cmd_802_11_deauthenticate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ ret = wlan_cmd_802_11_ad_hoc_start(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_cmd_802_11_ad_hoc_join(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_cmd_802_11_ad_hoc_stop(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_cmd_802_11_get_log(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_cmd_802_11_rssi_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret =
+ wlan_cmd_802_11_snmp_mib(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8) (*((t_u32 *) pdata_buf));
+ memcpy(&cmd_ptr->params, pdata_buf, sizeof(HostCmd_DS_VERSION_EXT));
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret =
+ wlan_cmd_802_11_rf_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status = WlanHardwareStatusReady;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret =
+ wlan_cmd_802_11_key_material(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret =
+ wlan_cmd_802_11_supplicant_pmk(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_cmd_11n_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ PRINTM(MCMND, "WMM: WMM_GET_STATUS cmd sent\n");
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_cmd_wmm_addts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_cmd_wmm_delts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_cmd_wmm_queue_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_cmd_wmm_queue_stats(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_cmd_wmm_ts_status(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret =
+ wlan_cmd_ibss_coalescing_status(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#ifdef MFG_CMD_SUPPORT
+ case HostCmd_CMD_MFG_COMMAND:
+ ret = wlan_cmd_mfg_cmd(pmpriv, cmd_ptr, pdata_buf);
+ break;
+#endif /* MFG_CMD_SUPPORT */
+ case HostCmd_CMD_802_11_LDO_CONFIG:
+ ret = wlan_cmd_ldo_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_cmd_sysclock_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = wlan_cmd_reg_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_cmd_mem_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_cmd_inactivity_timeout(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
+ ret =
+ wlan_cmd_802_11_bca_timeshare(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_sta flag for first station
+ *
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+mlan_status
+mlan_sta_init_cmd(IN t_void * priv, IN t_u8 first_sta)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 enable = MTRUE;
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (first_sta == MTRUE) {
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_INIT,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /*
+ * Read MAC address from HW
+ */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Reconfigure tx buf size */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->adapter->tx_buf_size);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* get tx rate */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->data_rate = 0;
+
+ /* get tx power */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* set ibss coalescing_status */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &enable);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+ amsdu_aggr_ctrl.enable = MLAN_ACT_ENABLE;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ (t_void *) & amsdu_aggr_ctrl);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* MAC Control must be the last command in init_fw */
+ /* set MAC Control */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** set last_init_cmd */
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_MAC_CONTROL;
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_sta_cmdresp.c b/wlan_src/mlan/mlan_sta_cmdresp.c
new file mode 100755
index 0000000..9873ff9
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_cmdresp.c
@@ -0,0 +1,1906 @@
+/** @file mlan_sta_cmdresp.c
+ *
+ * @brief This file contains the handling of command
+ * responses generated by firmware.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+void
+wlan_process_cmdresp_error(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n", resp->command,
+ resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &resp->params.psmode_enh;
+ PRINTM(MERROR,
+ "PS_MODE_ENH command failed: result=0x%x action=0x%X\n",
+ resp->result, wlan_le16_to_cpu(pm->action));
+ /*
+ * We do not re-try enter-ps command in ad-hoc mode.
+ */
+ if (wlan_le16_to_cpu(pm->action) == EN_PS &&
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ }
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ /* Cancel all pending scan command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(&pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(&pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ break;
+
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+
+ default:
+ break;
+ }
+ /*
+ * Handling errors here
+ */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of get_hw_spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &resp->params.hw_spec;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 i;
+
+ ENTER();
+
+ pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info);
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ pmadapter->fw_bands = (t_u8) GET_FW_DEFAULT_BANDS(pmadapter);
+ } else {
+ pmadapter->fw_bands = BAND_B;
+ }
+
+ pmadapter->config_bands = pmadapter->fw_bands;
+
+ if (pmadapter->fw_bands & BAND_A) {
+ if (pmadapter->fw_bands & BAND_GN) {
+ pmadapter->config_bands |= BAND_AN;
+ pmadapter->fw_bands |= BAND_AN;
+ }
+ if (pmadapter->fw_bands & BAND_AN) {
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else
+ pmadapter->adhoc_start_band = BAND_A;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+ } else if (pmadapter->fw_bands & BAND_GN) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else if (pmadapter->fw_bands & BAND_G) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ } else if (pmadapter->fw_bands & BAND_B) {
+ pmadapter->adhoc_start_band = BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ }
+
+ pmadapter->fw_release_number = hw_spec->fw_release_number;
+ pmadapter->number_of_antenna = hw_spec->number_of_antenna;
+
+ PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n",
+ wlan_le32_to_cpu(pmadapter->fw_release_number));
+ PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+ hw_spec->permanent_addr[0], hw_spec->permanent_addr[1],
+ hw_spec->permanent_addr[2], hw_spec->permanent_addr[3],
+ hw_spec->permanent_addr[4], hw_spec->permanent_addr[5]);
+ PRINTM(MINFO, "GET_HW_SPEC: hw_if_version=0x%X version=0x%X\n",
+ wlan_le16_to_cpu(hw_spec->hw_if_version),
+ wlan_le16_to_cpu(hw_spec->version));
+
+ if (pmpriv->curr_addr[0] == 0xff)
+ memmove(pmpriv->curr_addr, hw_spec->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code);
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (pmadapter->region_code == region_code_index[i])
+ break;
+ }
+
+ /* If it's unidentified region code, use the default (USA) */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ pmadapter->region_code = 0x10;
+ PRINTM(MWARN, "unidentified region code, use the default (USA)\n");
+ }
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->fw_bands)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->hw_dot_11n_dev_cap = wlan_le32_to_cpu(hw_spec->dot_11n_dev_cap);
+ pmadapter->usr_dot_11n_dev_cap = pmadapter->hw_dot_11n_dev_cap &
+ DEFAULT_11N_CAP_MASK;
+ pmadapter->usr_dev_mcs_support = pmadapter->hw_dev_mcs_support =
+ hw_spec->dev_mcs_support;
+ wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap);
+ wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support);
+ pmadapter->mp_end_port = wlan_le16_to_cpu(hw_spec->mp_end_port);
+
+ for (i = 1; i <= (unsigned) (MAX_PORT - pmadapter->mp_end_port); i++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of RSSI info
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_RSP *prssi_info_rsp =
+ &resp->params.rssi_info_rsp;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+
+ pmpriv->data_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_last);
+ pmpriv->data_nf_last = wlan_le16_to_cpu(prssi_info_rsp->data_nf_last);
+
+ pmpriv->data_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_avg);
+ pmpriv->data_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->data_nf_avg);
+
+ pmpriv->bcn_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_last);
+ pmpriv->bcn_nf_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_last);
+
+ pmpriv->bcn_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_avg);
+ pmpriv->bcn_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_avg);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_buf != MNULL) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+
+ memset(pget_info, 0, sizeof(mlan_ds_get_info));
+
+ pget_info->param.signal.selector = ALL_RSSI_INFO_MASK;
+
+ /* RSSI */
+ pget_info->param.signal.bcn_rssi_last = pmpriv->bcn_rssi_last;
+ pget_info->param.signal.bcn_rssi_avg = pmpriv->bcn_rssi_avg;
+ pget_info->param.signal.data_rssi_last = pmpriv->data_rssi_last;
+ pget_info->param.signal.data_rssi_avg = pmpriv->data_rssi_avg;
+
+ /* SNR */
+ pget_info->param.signal.bcn_snr_last =
+ CAL_SNR(pmpriv->bcn_rssi_last, pmpriv->bcn_nf_last);
+ pget_info->param.signal.bcn_snr_avg =
+ CAL_SNR(pmpriv->bcn_rssi_avg, pmpriv->bcn_nf_avg);
+ pget_info->param.signal.data_snr_last =
+ CAL_SNR(pmpriv->data_rssi_last, pmpriv->data_nf_last);
+ pget_info->param.signal.data_snr_avg =
+ CAL_SNR(pmpriv->data_rssi_avg, pmpriv->data_nf_avg);
+
+ /* NF */
+ pget_info->param.signal.bcn_nf_last = pmpriv->bcn_nf_last;
+ pget_info->param.signal.bcn_nf_avg = pmpriv->bcn_nf_avg;
+ pget_info->param.signal.data_nf_last = pmpriv->data_nf_last;
+ pget_info->param.signal.data_nf_avg = pmpriv->data_nf_avg;
+
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psmib = &resp->params.smib;
+ t_u16 oid = wlan_le16_to_cpu(psmib->oid);
+ t_u16 query_type = wlan_le16_to_cpu(psmib->query_type);
+ t_u32 ul_temp;
+ mlan_ds_snmp_mib *mib = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf)
+ mib = (mlan_ds_snmp_mib *) pioctl_buf->pbuf;
+
+ PRINTM(MINFO, "SNMP_RESP: value of the oid = 0x%x, query_type=0x%x\n", oid,
+ query_type);
+ PRINTM(MINFO, "SNMP_RESP: Buf size = 0x%x\n",
+ wlan_le16_to_cpu(psmib->buf_size));
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ switch (oid) {
+ case FragThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: FragThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.frag_threshold = ul_temp;
+ break;
+
+ case RtsThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.rts_threshold = ul_temp;
+ break;
+
+ case ShortRetryLim_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ if (mib)
+ mib->param.retry_count = ul_temp;
+ break;
+ case WwsMode_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: WWSCfg =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *) pioctl_buf->pbuf)->param.wws_cfg =
+ ul_temp;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (pioctl_buf) {
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_snmp_mib);
+ }
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_log
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_get_log(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_GET_LOG *pget_log =
+ (HostCmd_DS_802_11_GET_LOG *) & resp->params.get_log;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ pget_info->param.stats.mcast_tx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_tx_frame);
+ pget_info->param.stats.failed = wlan_le32_to_cpu(pget_log->failed);
+ pget_info->param.stats.retry = wlan_le32_to_cpu(pget_log->retry);
+ pget_info->param.stats.multi_retry =
+ wlan_le32_to_cpu(pget_log->multiretry);
+ pget_info->param.stats.frame_dup =
+ wlan_le32_to_cpu(pget_log->frame_dup);
+ pget_info->param.stats.rts_success =
+ wlan_le32_to_cpu(pget_log->rts_success);
+ pget_info->param.stats.rts_failure =
+ wlan_le32_to_cpu(pget_log->rts_failure);
+ pget_info->param.stats.ack_failure =
+ wlan_le32_to_cpu(pget_log->ack_failure);
+ pget_info->param.stats.rx_frag = wlan_le32_to_cpu(pget_log->rx_frag);
+ pget_info->param.stats.mcast_rx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_rx_frame);
+ pget_info->param.stats.fcs_error =
+ wlan_le32_to_cpu(pget_log->fcs_error);
+ pget_info->param.stats.tx_frame = wlan_le32_to_cpu(pget_log->tx_frame);
+ pget_info->param.stats.wep_icv_error[0] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[0]);
+ pget_info->param.stats.wep_icv_error[1] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[1]);
+ pget_info->param.stats.wep_icv_error[2] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[2]);
+ pget_info->param.stats.wep_icv_error[3] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[3]);
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of radio_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_ctrl =
+ (HostCmd_DS_802_11_RADIO_CONTROL *) & resp->params.radio;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+ pmadapter->radio_on = wlan_le16_to_cpu(pradio_ctrl->control);
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio_cfg->param.radio_on_off = (t_u32) pmadapter->radio_on;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_rate_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *ds_rate = MNULL;
+ HostCmd_DS_TX_RATE_CFG *prate_cfg = &resp->params.tx_rate_cfg;
+ MrvlRateScope_t *prate_scope;
+ MrvlIEtypesHeader_t *head = MNULL;
+ t_u16 tlv, tlv_buf_len;
+ t_u8 *tlv_buf;
+ t_u32 i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ tlv_buf = (t_u8 *) ((t_u8 *) prate_cfg) + sizeof(HostCmd_DS_TX_RATE_CFG);
+ tlv_buf_len = *(t_u16 *) (tlv_buf + sizeof(t_u16));
+ tlv_buf_len = wlan_le16_to_cpu(tlv_buf_len);
+
+ while (tlv_buf && tlv_buf_len > 0) {
+ tlv = (*tlv_buf);
+ tlv = tlv | (*(tlv_buf + 1) << 8);
+
+ switch (tlv) {
+ case TLV_TYPE_RATE_SCOPE:
+ prate_scope = (MrvlRateScope_t *) tlv_buf;
+ pmpriv->bitmap_rates[0] =
+ wlan_le16_to_cpu(prate_scope->hr_dsss_rate_bitmap);
+ pmpriv->bitmap_rates[1] =
+ wlan_le16_to_cpu(prate_scope->ofdm_rate_bitmap);
+ for (i = 0;
+ i < sizeof(prate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ pmpriv->bitmap_rates[2 + i] =
+ wlan_le16_to_cpu(prate_scope->ht_mcs_rate_bitmap[i]);
+ break;
+ /* Add RATE_DROP tlv here */
+ }
+
+ head = (MrvlIEtypesHeader_t *) tlv_buf;
+ head->len = wlan_le16_to_cpu(head->len);
+ tlv_buf += head->len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -= head->len;
+ }
+
+ pmpriv->is_data_rate_auto = wlan_is_rate_auto(pmpriv);
+
+ if (pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = 0;
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+
+ }
+
+ if (pioctl_buf) {
+ ds_rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (wlan_le16_to_cpu(prate_cfg->action) == HostCmd_ACT_GEN_GET) {
+ if (pmpriv->is_data_rate_auto)
+ ds_rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ ds_rate->param.rate_cfg.rate =
+ wlan_get_rate_index(pmadapter, pmpriv->bitmap_rates,
+ sizeof(pmpriv->bitmap_rates));
+ if (ds_rate->param.rate_cfg.rate >= MLAN_RATE_BITMAP_OFDM0 &&
+ ds_rate->param.rate_cfg.rate <= MLAN_RATE_BITMAP_OFDM7)
+ ds_rate->param.rate_cfg.rate -=
+ (MLAN_RATE_BITMAP_OFDM0 - MLAN_RATE_INDEX_OFDM0);
+ if (ds_rate->param.rate_cfg.rate >= MLAN_RATE_BITMAP_MCS0 &&
+ ds_rate->param.rate_cfg.rate <= MLAN_RATE_BITMAP_MCS127)
+ ds_rate->param.rate_cfg.rate -=
+ (MLAN_RATE_BITMAP_MCS0 - MLAN_RATE_INDEX_MCS0);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power level and rate index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdata_buf Pointer to the data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_power_level(pmlan_private pmpriv, void *pdata_buf)
+{
+ int length = -1, max_power = -1, min_power = -1;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+
+ ENTER();
+
+ if (pdata_buf) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ length = ppg_tlv->length;
+ if (length > 0) {
+ max_power = pg->power_max;
+ min_power = pg->power_min;
+ length -= sizeof(Power_Group_t);
+ }
+ while (length) {
+ pg++;
+ if (max_power < pg->power_max) {
+ max_power = pg->power_max;
+ }
+ if (min_power > pg->power_min) {
+ min_power = pg->power_min;
+ }
+ length -= sizeof(Power_Group_t);
+ }
+ if (ppg_tlv->length > 0) {
+ pmpriv->min_tx_power_level = (t_u8) min_power;
+ pmpriv->max_tx_power_level = (t_u8) max_power;
+ }
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_power_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &resp->params.txp_cfg;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ t_u16 action = wlan_le16_to_cpu(ptxp_cfg->action);
+ mlan_ds_power_cfg *power = MNULL;
+ t_u32 data[5];
+
+ ENTER();
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ ppg_tlv->length = wlan_le16_to_cpu(ppg_tlv->length);
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_get_power_level(pmpriv, ptxp_cfg);
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ break;
+ }
+ case HostCmd_ACT_GEN_SET:
+ if (wlan_le32_to_cpu(ptxp_cfg->mode)) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ if (pg->power_max == pg->power_min)
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ }
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: unknown command action %d\n", action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level, pmpriv->max_tx_power_level,
+ pmpriv->min_tx_power_level);
+
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_power_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level = pmpriv->tx_power_level;
+ if (wlan_le32_to_cpu(ptxp_cfg->mode))
+ power->param.power_cfg.is_power_auto = 0;
+ else
+ power->param.power_cfg.is_power_auto = 1;
+ } else {
+ power->param.power_ext.len = 0;
+ while (ppg_tlv->length) {
+ data[0] = pg->first_rate_code;
+ data[1] = pg->last_rate_code;
+ if (pg->modulation_class == MOD_CLASS_OFDM) {
+ data[0] += MLAN_RATE_INDEX_OFDM0;
+ data[1] += MLAN_RATE_INDEX_OFDM0;
+ } else if (pg->modulation_class == MOD_CLASS_HT) {
+ data[0] += MLAN_RATE_INDEX_MCS0;
+ data[1] += MLAN_RATE_INDEX_MCS0;
+ if (pg->ht_bandwidth == HT_BW_40) {
+ data[0] |= TX_RATE_HT_BW40_BIT;
+ data[1] |= TX_RATE_HT_BW40_BIT;
+ }
+ }
+ data[2] = pg->power_min;
+ data[3] = pg->power_max;
+ data[4] = pg->power_step;
+ memcpy((t_u8 *) & power->param.power_ext.
+ power_data[power->param.power_ext.len],
+ (t_u8 *) data, sizeof(data));
+ power->param.power_ext.len += 5;
+ pg++;
+ ppg_tlv->length -= sizeof(Power_Group_t);
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_power_cfg_ext) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ps_mode_enh
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_opt_ps_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_PS_MODE_ENH *pps_mode = &resp->params.psmode_enh;
+
+ ENTER();
+
+ PRINTM(MINFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, pps_mode->action);
+ pps_mode->action = wlan_le16_to_cpu(pps_mode->action);
+
+ switch (pps_mode->action) {
+ case EN_PS:
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ PRINTM(MDATA, "Settting ps_state to AWAKE\n");
+ if (pmadapter->sleep_period.period) {
+ PRINTM(MDATA, "Setting uapsd/pps mode to TRUE\n");
+ }
+ break;
+ case DIS_PS:
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ PRINTM(MDATA, "Setting ps_state to AWAKE\n");
+ if (pmadapter->sleep_period.period) {
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->tx_lock_flag = MFALSE;
+ }
+ break;
+ case EN_AUTO_DS:
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ PRINTM(MDATA, "Enabled auto deep sleep\n");
+ pmpriv->adapter->is_deep_sleep = MTRUE;
+ break;
+ case DIS_AUTO_DS:
+ pmpriv->adapter->is_deep_sleep = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ PRINTM(MDATA, "Disabled auto deep sleep\n");
+ break;
+ case SLEEP_CONFIRM:
+ PRINTM(MDATA,
+ "Received Sleep confirm response, setting ps_state to SLEEP\n");
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: unknown PS_MODE action 0x%x\n",
+ pps_mode->action);
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_period
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &resp->params.sleep_pd;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 sleep_pd = 0;
+
+ ENTER();
+
+ sleep_pd = wlan_le16_to_cpu(pcmd_sleep_pd->sleep_pd);
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ pm_cfg->param.sleep_period = (t_u32) sleep_pd;
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_period)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+ pmpriv->adapter->sleep_period.period = sleep_pd;
+ if (sleep_pd == SLEEP_PERIOD_RESERVED_FF)
+ pmpriv->gen_null_pkg = MFALSE;
+ else
+ pmpriv->gen_null_pkg = MTRUE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_params
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *presp_sp = &resp->params.sleep_param;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ mlan_ds_sleep_params *psp = MNULL;
+ sleep_params_t *psleep_params = &pmpriv->adapter->sleep_params;
+
+ ENTER();
+
+ psleep_params->sp_reserved = wlan_le16_to_cpu(presp_sp->reserved);
+ psleep_params->sp_error = wlan_le16_to_cpu(presp_sp->error);
+ psleep_params->sp_offset = wlan_le16_to_cpu(presp_sp->offset);
+ psleep_params->sp_stable_time = wlan_le16_to_cpu(presp_sp->stable_time);
+ psleep_params->sp_cal_control = presp_sp->cal_control;
+ psleep_params->sp_ext_sleep_clk = presp_sp->external_sleep_clk;
+
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ psp = (mlan_ds_sleep_params *) & pm_cfg->param.sleep_params;
+
+ psp->error = (t_u32) psleep_params->sp_error;
+ psp->offset = (t_u32) psleep_params->sp_offset;
+ psp->stable_time = (t_u32) psleep_params->sp_stable_time;
+ psp->cal_control = (t_u32) psleep_params->sp_cal_control;
+ psp->ext_sleep_clk = (t_u32) psleep_params->sp_ext_sleep_clk;
+ psp->reserved = (t_u32) psleep_params->sp_reserved;
+
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_params)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_MAC_ADDRESS *pmac_addr = &resp->params.mac_addr;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ memcpy(pmpriv->curr_addr, pmac_addr->mac_addr, MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MINFO, "set mac address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_addr[0], pmpriv->curr_addr[1], pmpriv->curr_addr[2],
+ pmpriv->curr_addr[3], pmpriv->curr_addr[4], pmpriv->curr_addr[5]);
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ memcpy(&bss->param.mac_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ pioctl_buf->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of multicast_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ if (pioctl_buf) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx rate query
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_tx_rate_query(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *rate = MNULL;
+ ENTER();
+
+ pmpriv->tx_rate = resp->params.tx_rate.tx_rate;
+ pmpriv->tx_htinfo = resp->params.tx_rate.ht_info;
+ if (!pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate =
+ wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+
+ if (pioctl_buf) {
+ rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG) {
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
+ if (pmpriv->tx_htinfo & MBIT(0))
+ rate->param.rate_cfg.rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1
+ for OFDM rate index */
+ rate->param.rate_cfg.rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ } else {
+ rate->param.rate_cfg.rate =
+ wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+ } else if (rate->sub_command == MLAN_OID_GET_DATA_RATE) {
+ if (pmpriv->tx_htinfo & MBIT(0))
+ rate->param.data_rate.tx_data_rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1 for
+ OFDM rate index */
+ rate->param.data_rate.tx_data_rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ if (pmpriv->rxpd_htinfo & MBIT(0))
+ rate->param.data_rate.rx_data_rate =
+ pmpriv->rxpd_rate + MLAN_RATE_INDEX_MCS0;
+ else
+ /* For rate index in RxPD, there is a hole in rate table
+ between HR/DSSS and OFDM rates, so minus 1 for OFDM rate
+ index */
+ rate->param.data_rate.rx_data_rate =
+ (pmpriv->rxpd_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->rxpd_rate -
+ 1 : pmpriv->rxpd_rate;
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of deauthenticate
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+
+ pmadapter->dbg.num_cmd_deauth++;
+ if (!memcmp(resp->params.deauth.mac_addr,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(resp->params.deauth.mac_addr))) {
+ wlan_reset_connect_state(pmpriv);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_stop
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+
+ wlan_reset_connect_state(pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of key_material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey = &resp->params.key_material;
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pkey->action) == HostCmd_ACT_GEN_SET) {
+ if ((wlan_le16_to_cpu(pkey->key_param_set.key_info) &
+ KEY_INFO_TKIP_MCAST)) {
+ PRINTM(MINFO, "key: GTK is set\n");
+ pmpriv->wpa_is_gtk_set = MTRUE;
+
+ }
+ }
+
+ memset(pmpriv->aes_key.key_param_set.key, 0,
+ sizeof(pkey->key_param_set.key));
+ pmpriv->aes_key.key_param_set.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->aes_key.key_param_set.key, pkey->key_param_set.key,
+ pmpriv->aes_key.key_param_set.key_len);
+
+ HEXDUMP("CMD_RESP (Key_Material)", pmpriv->aes_key.key_param_set.key,
+ pmpriv->aes_key.key_param_set.key_len);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant pmk response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PMK *supplicant_pmk_resp =
+ &resp->params.esupplicant_psk;
+ mlan_ds_sec_cfg *sec = MNULL;
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *passphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ t_u8 *tlv_buf = (t_u8 *) supplicant_pmk_resp->tlv_buffer;
+ t_u16 action = wlan_le16_to_cpu(supplicant_pmk_resp->action);
+ int tlv_buf_len = 0;
+ t_u16 tlv;
+
+ ENTER();
+ tlv_buf_len = resp->size - (sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) +
+ S_DS_GEN - 1);
+ if (pioctl_buf) {
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ while (tlv_buf_len > 0) {
+ tlv = (*tlv_buf) | (*(tlv_buf + 1) << 8);
+ if ((tlv != TLV_TYPE_SSID) && (tlv != TLV_TYPE_BSSID) &&
+ (tlv != TLV_TYPE_PASSPHRASE)
+ && (tlv != TLV_TYPE_PMK))
+ break;
+ switch (tlv) {
+ case TLV_TYPE_SSID:
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) tlv_buf;
+ pssid_tlv->header.len =
+ wlan_le16_to_cpu(pssid_tlv->header.len);
+ memcpy(sec->param.passphrase.ssid.ssid, pssid_tlv->ssid,
+ pssid_tlv->header.len);
+ sec->param.passphrase.ssid.ssid_len = pssid_tlv->header.len;
+ tlv_buf +=
+ pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_BSSID:
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) tlv_buf;
+ pbssid_tlv->header.len =
+ wlan_le16_to_cpu(pbssid_tlv->header.len);
+ memcpy(&sec->param.passphrase.bssid, pbssid_tlv->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ tlv_buf +=
+ pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PASSPHRASE:
+ passphrase_tlv = (MrvlIEtypes_Passphrase_t *) tlv_buf;
+ passphrase_tlv->header.len =
+ wlan_le16_to_cpu(passphrase_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ sec->param.passphrase.psk.passphrase.passphrase_len =
+ passphrase_tlv->header.len;
+ memcpy(sec->param.passphrase.psk.passphrase.passphrase,
+ passphrase_tlv->passphrase,
+ passphrase_tlv->header.len);
+ tlv_buf +=
+ passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PMK:
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) tlv_buf;
+ ppmk_tlv->header.len =
+ wlan_le16_to_cpu(ppmk_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ memcpy(sec->param.passphrase.psk.pmk.pmk, ppmk_tlv->pmk,
+ ppmk_tlv->header.len);
+ tlv_buf +=
+ ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+
+ }
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *psup_profile =
+ &resp->params.esupplicant_profile;
+ MrvlIEtypesHeader_t *head;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 *tlv;
+ int len;
+
+ ENTER();
+
+ len = resp->size - S_DS_GEN - sizeof(t_u16);
+ tlv = psup_profile->tlv_buf;
+ if (pioctl_buf) {
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ while (len > 0) {
+ head = (MrvlIEtypesHeader_t *) tlv;
+ head->type = wlan_le16_to_cpu(head->type);
+ head->len = wlan_le16_to_cpu(head->len);
+ switch (head->type) {
+ case TLV_TYPE_ENCRYPTION_PROTO:
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *) head;
+ sec->param.esupp_mode.rsn_mode =
+ wlan_le16_to_cpu(encr_proto_tlv->rsn_mode);
+ PRINTM(MCMND, "rsn_mode=0x%x\n",
+ sec->param.esupp_mode.rsn_mode);
+ break;
+ case TLV_TYPE_CIPHER:
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *) head;
+ sec->param.esupp_mode.act_paircipher = pcipher_tlv->pair_cipher;
+ sec->param.esupp_mode.act_groupcipher =
+ pcipher_tlv->group_cipher;
+ PRINTM(MCMND, "paircipher=0x%x, groupcipher=0x%x\n",
+ sec->param.esupp_mode.act_paircipher,
+ sec->param.esupp_mode.act_groupcipher);
+ break;
+ }
+ len -= (head->len - sizeof(MrvlIEtypesHeader_t));
+ tlv = tlv + (head->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_channel = &resp->params.rf_channel;
+ t_u16 new_channel = wlan_le16_to_cpu(prf_channel->current_channel);
+ mlan_ds_bss *bss = MNULL;
+ ENTER();
+ if (pmpriv->curr_bss_params.bss_descriptor.channel != new_channel) {
+ PRINTM(MCMND, "Channel Switch: %d to %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel, new_channel);
+ /* Update the channel again */
+ pmpriv->curr_bss_params.bss_descriptor.channel = new_channel;
+ }
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ bss->param.bss_chan.channel = new_channel;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_antenna
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna;
+ t_u16 ant_mode = wlan_le16_to_cpu(pantenna->antenna_mode);
+ mlan_ds_radio_cfg *radio = MNULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
+ wlan_le16_to_cpu(pantenna->action), ant_mode);
+
+ if (pioctl_buf) {
+ radio = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio->param.antenna = ant_mode;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the version_ext resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_ver_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_VERSION_EXT *ver_ext = &resp->params.verext;
+ mlan_ds_get_info *info;
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ info->param.ver_ext.version_str_sel = ver_ext->version_str_sel;
+ memcpy(info->param.ver_ext.version_str, ver_ext->version_str,
+ sizeof(char) * 128);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the ibss_coalescing_status resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal_resp =
+ &(resp->params.ibss_coalescing);
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pibss_coal_resp->action) == HostCmd_ACT_GEN_SET) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "New BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pibss_coal_resp->bssid[0], pibss_coal_resp->bssid[1],
+ pibss_coal_resp->bssid[2], pibss_coal_resp->bssid[3],
+ pibss_coal_resp->bssid[4], pibss_coal_resp->bssid[5]);
+
+ /* If rsp has MNULL BSSID, Just return..... No Action */
+ if (!memcmp(pibss_coal_resp->bssid, zero_mac, MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG, "New BSSID is MNULL\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* If BSSID is diff, modify current BSS parameters */
+ if (memcmp(pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH)) {
+ /* BSSID */
+ memcpy(pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ /* Beacon Interval and ATIM window */
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period
+ = wlan_le16_to_cpu(pibss_coal_resp->beacon_interval);
+ pmpriv->curr_bss_params.bss_descriptor.atim_window
+ = wlan_le16_to_cpu(pibss_coal_resp->atim_window);
+
+ /* ERP Information */
+ pmpriv->curr_bss_params.bss_descriptor.erp_flags
+ = (t_u8) wlan_le16_to_cpu(pibss_coal_resp->use_g_rate_protect);
+
+ pmpriv->adhoc_state = ADHOC_COALESCED;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/**
+ * @brief This function handles the command response of mfg_cmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mfg_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc;
+
+ ENTER();
+
+ PRINTM(MINFO, "MFG command response size = %d\n", resp->size);
+ resp->size = MIN(resp->size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.mfgcmd.len = resp->size;
+ memcpy(misc->param.mfgcmd.cmd, (void *) resp, resp->size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/**
+ * @brief This function handles the command response of ldo_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_ldo_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *mis_ccfg = MNULL;
+ HostCmd_DS_802_11_LDO_CFG *pldo_cfg = &resp->params.ldo_cfg;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ mis_ccfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ mis_ccfg->param.ldo_cfg = wlan_le16_to_cpu(pldo_cfg->pmsource);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sysclock
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *mis_ccfg = MNULL;
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *clk_cfg = &resp->params.sys_clock_cfg;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ mis_ccfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ mis_ccfg->param.sys_clock.cur_sys_clk =
+ wlan_le16_to_cpu(clk_cfg->cur_sys_clk);
+ mis_ccfg->param.sys_clock.sys_clk_type =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_type);
+ mis_ccfg->param.sys_clock.sys_clk_num =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_len) / sizeof(t_u16);
+ for (i = 0; i < mis_ccfg->param.sys_clock.sys_clk_num; i++)
+ mis_ccfg->param.sys_clock.sys_clk[i] =
+ wlan_le16_to_cpu(clk_cfg->sys_clk[i]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of reg_access
+ *
+ * @param type The type of reg access (MAC, BBP or RF)
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_reg_access(t_u16 type,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_reg_rw *reg_rw = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ reg_rw = ®_mem->param.reg_rw;
+ switch (type) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *reg;
+ reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.mac_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = wlan_le32_to_cpu(reg->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *reg;
+ reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbp_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ {
+ HostCmd_DS_PMIC_REG_ACCESS *reg;
+ reg = (HostCmd_DS_PMIC_REG_ACCESS *) & resp->params.pmic_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *eeprom = ®_mem->param.rd_eeprom;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & resp->params.eeprom;
+ cmd_eeprom->byte_count =
+ wlan_le16_to_cpu(cmd_eeprom->byte_count);
+ PRINTM(MINFO, "EEPROM read len=%x\n", cmd_eeprom->byte_count);
+ if (eeprom->byte_count < cmd_eeprom->byte_count) {
+ eeprom->byte_count = 0;
+ PRINTM(MINFO, "EEPROM read return length is too big\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ eeprom->offset = wlan_le16_to_cpu(cmd_eeprom->offset);
+ eeprom->byte_count = cmd_eeprom->byte_count;
+ if (eeprom->byte_count > 0) {
+ memcpy(&eeprom->value, &cmd_eeprom->value,
+ eeprom->byte_count);
+ HEXDUMP("EEPROM", (char *) &eeprom->value,
+ eeprom->byte_count);
+ }
+ break;
+ }
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mem_access
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_mem_access(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_mem_rw *mem_rw = MNULL;
+ HostCmd_DS_MEM_ACCESS *mem = (HostCmd_DS_MEM_ACCESS *) & resp->params.mem;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ mem_rw = ®_mem->param.mem_rw;
+
+ mem_rw->addr = wlan_le32_to_cpu(mem->addr);
+ mem_rw->value = wlan_le32_to_cpu(mem->value);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of inactivity timeout
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_inactivity_timeout(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_ds_inactivity_to *inac_to = MNULL;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to =
+ (HostCmd_DS_INACTIVITY_TIMEOUT_EXT *) & resp->params.inactivity_to;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ inac_to->timeout_unit = wlan_le16_to_cpu(cmd_inac_to->timeout_unit);
+ inac_to->unicast_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->unicast_timeout);
+ inac_to->mcast_timeout = wlan_le16_to_cpu(cmd_inac_to->mcast_timeout);
+ inac_to->ps_entry_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of bca_timeshare
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_802_11_bca_timeshare(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &resp->params.bca_timeshare;
+ mlan_ds_bca_cfg *bca_cfg = MNULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "TrafficType=0x%x TimeShareInterva=0x%x BTTime=0x%x\n",
+ wlan_le16_to_cpu(bca_ts->traffic_type),
+ wlan_le32_to_cpu(bca_ts->timeshare_interval),
+ wlan_le32_to_cpu(bca_ts->bt_time));
+ if (pioctl_buf) {
+ bca_cfg = (mlan_ds_bca_cfg *) pioctl_buf->pbuf;
+ bca_cfg->param.bca_ts.traffic_type =
+ wlan_le16_to_cpu(bca_ts->traffic_type);
+ bca_cfg->param.bca_ts.timeshare_interval =
+ wlan_le32_to_cpu(bca_ts->timeshare_interval);
+ bca_cfg->param.bca_ts.bt_time = wlan_le32_to_cpu(bca_ts->bt_time);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles the station command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_process_sta_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *) pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int ctr;
+ /* If the command is not successful, cleanup and return failure */
+ if ((resp->result != HostCmd_RESULT_OK)
+ ) {
+ wlan_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_ret_mac_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_ret_802_11_mac_address(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = wlan_ret_mac_multicast_adr(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
+ PRINTM(MINFO, "CMD_RESP: BG_SCAN result is ready!\n");
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_ret_tx_power_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_802_11_opt_ps_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_ret_802_11_sleep_period(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_ret_802_11_sleep_params(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_ret_802_11_associate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_ret_802_11_deauthenticate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_ret_802_11_ad_hoc(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_ret_802_11_ad_hoc_stop(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_ret_get_log(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_ret_802_11_rssi_info(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_ret_802_11_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = wlan_ret_802_11_rf_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_ret_802_11_key_material(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_ret_802_11_supplicant_pmk(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_ret_802_11_supplicant_profile(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size = (t_u16) wlan_le16_to_cpu(resp->params.
+ tx_buf.buff_size);
+ pmadapter->mp_end_port = wlan_le16_to_cpu(resp->params.
+ tx_buf.mp_end_port);
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (ctr = 1; ctr <= MAX_PORT - pmadapter->mp_end_port; ctr++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - ctr));
+ }
+
+ pmadapter->curr_wr_port = 1;
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port),
+ pmadapter->mp_data_port_mask);
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ ret = wlan_ret_wmm_get_status(pmpriv, resp);
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_ret_wmm_addts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_ret_wmm_delts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_ret_wmm_queue_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_ret_wmm_queue_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_ret_wmm_ts_status(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = wlan_ret_ibss_coalescing_status(pmpriv, resp);
+ break;
+#ifdef MFG_CMD_SUPPORT
+ case HostCmd_CMD_MFG_COMMAND:
+ ret = wlan_ret_mfg_cmd(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_ret_11n_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_LDO_CONFIG:
+ ret = wlan_ret_ldo_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_ret_sysclock_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = wlan_ret_reg_access(cmdresp_no, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_ret_mem_access(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_ret_inactivity_timeout(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
+ ret = wlan_ret_802_11_bca_timeshare(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_sta_event.c b/wlan_src/mlan/mlan_sta_event.c
new file mode 100755
index 0000000..1c67ad5
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_event.c
@@ -0,0 +1,453 @@
+/** @file mlan_sta_event.c
+ *
+ * @brief This file contains MLAN event handling.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles disconnect event, reports disconnect
+ * to upper layer, cleans tx/rx packets,
+ * resets link state etc.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_reset_connect_state(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable;
+
+ ENTER();
+
+ if (priv->media_connected != MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MINFO, "Handles disconnect event.\n");
+
+ priv->media_connected = MFALSE;
+
+ /* Free Tx and Rx packets, report disconnect to upper layer */
+ wlan_clean_txrx(priv);
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_htinfo = 0;
+
+ PRINTM(MINFO, "Current SSID=%s, SSID Length=%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ PRINTM(MINFO, "Previous SSID=%s, SSID Length=%u\n",
+ priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ priv->wpa_ie_len = 0;
+
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+
+ /* Enable auto data rate */
+ priv->is_data_rate_auto = MTRUE;
+ priv->data_rate = 0;
+
+ if (priv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->adhoc_is_link_sensed = MFALSE;
+ priv->adhoc_auto_sel = MTRUE;
+ }
+
+ /*
+ * Memorize the previous SSID and BSSID so
+ * it could be used for re-assoc
+ */
+
+ memcpy(&priv->prev_ssid,
+ &priv->curr_bss_params.bss_descriptor.ssid,
+ sizeof(mlan_802_11_ssid));
+
+ memcpy(priv->prev_bssid,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Need to erase the current SSID and BSSID info */
+ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
+
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+
+ if ((wlan_11d_get_state(priv) == ENABLE_11D) &&
+ (pmadapter->state_11d.user_enable_11d == DISABLE_11D)) {
+
+ pmadapter->state_11d.enable_11d = DISABLE_11D;
+ enable = DISABLE_11D;
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &enable);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to enable 11D\n");
+ }
+ if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd &&
+ (pmadapter->cmd_timer_is_set == MFALSE)) {
+ LEAVE();
+ return;
+ }
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles link lost, deauth and
+ * disassoc events.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @return N/A
+ */
+static void
+wlan_handle_disconnect_event(pmlan_private priv)
+{
+ ENTER();
+ if (priv->media_connected == MTRUE) {
+ wlan_reset_connect_state(priv);
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the OBSS scan parameters to the application
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_2040_coex_event(pmlan_private pmpriv)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+ t_u8 ele_len;
+
+ ENTER();
+
+ if (pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param &&
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.element_id == OVERLAPBSSSCANPARAM) {
+ ele_len =
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.len;
+ pevent->bss_num = pmpriv->bss_num;
+ pevent->event_id = MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM;
+ /* Copy OBSS scan parameters */
+ memcpy((t_u8 *) pevent->event_buf,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ poverlap_bss_scan_param->obss_scan_param, ele_len);
+ pevent->event_len = ele_len;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM, pevent);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_process_sta_event(IN t_void * priv)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ switch (eventcause) {
+ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+ PRINTM(MERROR,
+ "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
+ break;
+ case EVENT_LINK_SENSED:
+ PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
+ pmpriv->adhoc_is_link_sensed = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL);
+ break;
+
+ case EVENT_DEAUTHENTICATED:
+ PRINTM(MEVENT, "EVENT: Deauthenticated\n");
+ pmadapter->dbg.num_event_deauth++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_DISASSOCIATED:
+ PRINTM(MEVENT, "EVENT: Disassociated\n");
+ pmadapter->dbg.num_event_disassoc++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_LINK_LOST:
+ PRINTM(MEVENT, "EVENT: Link lost\n");
+ pmadapter->dbg.num_event_link_lost++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM(MEVENT, "_");
+
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ wlan_check_ps_cond(pmadapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE \n");
+ PRINTM(MEVENT, "|");
+ pmadapter->tx_lock_flag = MFALSE;
+ if (pmadapter->sleep_period.period) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ if (!pmadapter->data_sent && pmpriv->gen_null_pkg) {
+ wlan_send_null_packet(pmpriv,
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET);
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+
+ break;
+
+ case EVENT_DEEP_SLEEP_AWAKE:
+ wlan_pm_reset_card(pmadapter);
+ PRINTM(MEVENT, "EVENT: DS_AWAKE\n");
+ if (pmadapter->is_deep_sleep == MTRUE) {
+ pmadapter->is_deep_sleep = MFALSE;
+ }
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DS_AWAKE, MNULL);
+ break;
+
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ 0, 0, MNULL, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_UNICAST:
+ PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_MULTICAST:
+ PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
+ break;
+ case EVENT_MIB_CHANGED:
+ case EVENT_INIT_DONE:
+ break;
+
+ case EVENT_ADHOC_BCN_LOST:
+ PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL);
+ break;
+ case EVENT_BG_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
+ /* Clear the previous scan result */
+ memset(pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+ case EVENT_STOP_TX:
+ PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
+ wlan_11h_tx_disable(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_STOP_TX, MNULL);
+ break;
+ case EVENT_START_TX:
+ PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
+ wlan_11h_tx_enable(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_START_TX, MNULL);
+ break;
+ case EVENT_CHANNEL_SWITCH:
+ PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
+ /* To be handled for 'chanswann' private command */
+ break;
+ case EVENT_MEAS_REPORT_RDY:
+ PRINTM(MINFO, "EVENT: Measurement Report Ready (%#x)\n", eventcause);
+ /* To be handled for 'measreq' private command */
+ break;
+ case EVENT_WMM_STATUS_CHANGE:
+ PRINTM(MEVENT, "EVENT: WMM status changed\n");
+ ret = (mlan_status) wlan_cmd_wmm_status_change(pmpriv);
+ break;
+
+ case EVENT_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL);
+ break;
+ case EVENT_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
+ break;
+ case EVENT_MAX_FAIL:
+ PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
+ break;
+ case EVENT_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
+ break;
+ case EVENT_DATA_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
+ break;
+ case EVENT_DATA_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
+ break;
+ case EVENT_DATA_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_DATA_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
+ break;
+ case EVENT_LINK_QUALITY:
+ PRINTM(MEVENT, "EVENT: Link Quality\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
+ break;
+ case EVENT_PRE_BEACON_LOST:
+ PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
+ break;
+ case EVENT_IBSS_COALESCED:
+ PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+ case EVENT_PORT_RELEASE:
+ PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIEMOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ wlan_11n_ba_stream_timeout(pmpriv,
+ (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
+ event_body);
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pmpriv->adapter->tx_buf_size =
+ MIN(pmpriv->adapter->max_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmpriv->adapter->tx_buf_size);
+ break;
+
+ case EVENT_WEP_ICV_ERR:
+ PRINTM(MEVENT, "EVENT: WEP ICV error\n");
+ pevent->bss_num = pmpriv->bss_num;
+ pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
+ pevent->event_len = sizeof(Event_WEP_ICV_ERR);
+ memcpy((t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
+ break;
+
+ case EVENT_BW_CHANGE:
+ PRINTM(MEVENT, "EVENT: BW Change\n");
+ pevent->bss_num = pmpriv->bss_num;
+ pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
+ pevent->event_len = sizeof(t_u8);
+ /* Copy event body from the event buffer */
+ memcpy((t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
+ break;
+
+ default:
+ PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_sta_ioctl.c b/wlan_src/mlan/mlan_sta_ioctl.c
new file mode 100755
index 0000000..749055f
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_ioctl.c
@@ -0,0 +1,4838 @@
+/** @file mlan_sta_ioctl.c
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief enable adhoc aes key
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+void
+wlan_enable_aes_key(pmlan_private pmpriv)
+{
+ mlan_ds_encrypt_key encrypt_key;
+ if (pmpriv->aes_key.key_param_set.key_len != WPA_AES_KEY_LEN)
+ return;
+ memset(&encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
+ encrypt_key.key_len = WPA_AES_KEY_LEN;
+ encrypt_key.key_index = 0x40000000;
+ memcpy(encrypt_key.key_material, pmpriv->aes_key.key_param_set.key,
+ encrypt_key.key_len);
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, MNULL,
+ &encrypt_key);
+ encrypt_key.key_index &= ~0x40000000;
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED, MNULL, &encrypt_key);
+ return;
+}
+
+/**
+ * @brief Get signal information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_signal(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_signal)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_signal);
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Signal info can be obtained only if connected */
+ if (pmpriv->media_connected == MFALSE) {
+ PRINTM(MINFO, "Can not get signal in disconnected state\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_bss_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ BSSDescriptor_t *pbss_desc;
+ t_s32 tbl_idx = 0;
+
+ ENTER();
+
+ /* Get current BSS info */
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ /* BSS mode */
+ info->param.bss_info.bss_mode = pmpriv->bss_mode;
+
+ /* SSID */
+ memcpy(&info->param.bss_info.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* BSSID */
+ memcpy(&info->param.bss_info.bssid, &pbss_desc->mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Channel */
+ info->param.bss_info.bss_chan = pbss_desc->channel;
+
+ /* Region code */
+ info->param.bss_info.region_code = pmadapter->region_code;
+
+ /* Scan table index if connected */
+ info->param.bss_info.scan_table_idx = 0;
+ if (pmpriv->media_connected == MTRUE) {
+ tbl_idx =
+ wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
+ pbss_desc->mac_address, pmpriv->bss_mode);
+ if (tbl_idx >= 0)
+ info->param.bss_info.scan_table_idx = tbl_idx;
+ }
+
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* Tx power information */
+ info->param.bss_info.max_power_level = pmpriv->max_tx_power_level;
+ info->param.bss_info.min_power_level = pmpriv->min_tx_power_level;
+
+ /* AdHoc state */
+ info->param.bss_info.adhoc_state = pmpriv->adhoc_state;
+
+ /* Last beacon NF */
+ info->param.bss_info.bcn_nf_last = pmpriv->bcn_nf_last;
+
+ /* wep status */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ info->param.bss_info.wep_status = MTRUE;
+ else
+ info->param.bss_info.wep_status = MFALSE;
+
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.bss_info.is_deep_sleep = pmadapter->is_deep_sleep;
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get extended version information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_ver_ext(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET,
+ 0,
+ (t_void *) pioctl_req,
+ &info->param.ver_ext.version_str_sel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get information handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ switch (pget_info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ status = wlan_get_info_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ status = wlan_get_info_signal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_FW_INFO:
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ memcpy(&pget_info->param.fw_info.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ break;
+ case MLAN_OID_GET_BSS_INFO:
+ status = wlan_get_info_bss_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DEBUG_INFO:
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_VER_EXT:
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get SNMP MIB handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_snmp_mib_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u16 cmd_oid = 0;
+ mlan_ds_snmp_mib *mib = MNULL;
+ t_u32 value = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ mib = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ switch (mib->sub_command) {
+ case MLAN_OID_SNMP_MIB_RTS_THRESHOLD:
+ value = mib->param.rts_threshold;
+ cmd_oid = RtsThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_FRAG_THRESHOLD:
+ value = mib->param.frag_threshold;
+ cmd_oid = FragThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_RETRY_COUNT:
+ value = mib->param.retry_count;
+ cmd_oid = ShortRetryLim_i;
+ break;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action, cmd_oid, (t_void *) pioctl_req, &value);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl_radio_ctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->radio_on == radio_cfg->param.radio_on_off) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ pmadapter->radio_on = (t_u16) radio_cfg->param.radio_on_off;
+ }
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RADIO_CONTROL,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Infra/Ad-hoc band configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl_band_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ t_u8 infra_band = 0;
+ t_u8 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ infra_band = (t_u8) radio_cfg->param.band_cfg.config_bands;
+ adhoc_band = (t_u8) radio_cfg->param.band_cfg.adhoc_start_band;
+ adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
+
+ /* SET Infra band */
+ if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_set_regiontable
+ (pmpriv, (t_u8) pmadapter->region_code, infra_band)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_set_universal_table(pmpriv, infra_band)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->config_bands = infra_band;
+
+ /* SET Ad-hoc Band */
+ if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (adhoc_band)
+ pmadapter->adhoc_start_band = adhoc_band;
+ pmpriv->adhoc_auto_sel = MFALSE;
+ /*
+ * If no adhoc_channel is supplied verify if the existing adhoc channel
+ * compiles with new adhoc_band
+ */
+ if (!adhoc_channel) {
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ pmpriv->adhoc_channel)) {
+ /* Pass back the default channel */
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ if ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ ) {
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ }
+ } else { /* Retrurn error if adhoc_band and
+ adhoc_channel combination is invalid */
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ (t_u16) adhoc_channel)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->adhoc_channel = (t_u8) adhoc_channel;
+ }
+ if ((adhoc_band & BAND_GN)
+ || (adhoc_band & BAND_AN)
+ ) {
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else {
+ pmadapter->adhoc_11n_enabled = MFALSE;
+ }
+ } else {
+ radio_cfg->param.band_cfg.config_bands = pmadapter->config_bands; /* Infra
+ Bands
+ */
+ radio_cfg->param.band_cfg.adhoc_start_band = pmadapter->adhoc_start_band; /* Adhoc
+ Band
+ */
+ radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel; /* Adhoc
+ Channel
+ */
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get antenna configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl_ant_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u16 antenna_mode;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* User input validation */
+ if ((radio_cfg->param.antenna < RF_ANTENNA_1 ||
+ radio_cfg->param.antenna >=
+ (unsigned) (RF_ANTENNA_1 + pmadapter->number_of_antenna)) &&
+ (radio_cfg->param.antenna != RF_ANTENNA_AUTO ||
+ pmadapter->number_of_antenna <= 1)) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Cast it to t_u16, antenna mode for command HostCmd_CMD_802_11_RF_ANTENNA
+ requires 2 bytes */
+ antenna_mode = (t_u16) radio_cfg->param.antenna;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_ANTENNA,
+ cmd_action,
+ 0, (t_void *) pioctl_req, (t_void *) & antenna_mode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Radio command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_radio_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_radio_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ switch (radio_cfg->sub_command) {
+ case MLAN_OID_RADIO_CTRL:
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BAND_CFG:
+ status = wlan_radio_ioctl_band_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_ANT_CFG:
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ memcpy(&bss->param.mac_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+
+ memcpy(pmpriv->curr_addr, &bss->param.mac_addr, MLAN_MAC_ADDR_LENGTH);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set multicast list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_set_multicast_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 old_pkt_filter;
+
+ ENTER();
+
+ old_pkt_filter = pmpriv->curr_pkt_filter;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) {
+ PRINTM(MINFO, "Enable Promiscuous mode\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ /* Multicast */
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ if (bss->param.multicast_list.mode == MLAN_MULTICAST_MODE) {
+ PRINTM(MINFO, "Enabling All Multicast!\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ if (bss->param.multicast_list.num_multicast_addr) {
+ PRINTM(MINFO, "Set multicast list=%d\n",
+ bss->param.multicast_list.num_multicast_addr);
+ /* Set multicast addresses to firmware */
+ if (old_pkt_filter == pmpriv->curr_pkt_filter) {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *) pioctl_req,
+ &bss->param.multicast_list);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &bss->param.multicast_list);
+ }
+ }
+ }
+ }
+ PRINTM(MINFO, "old_pkt_filter=0x%lx, curr_pkt_filter=0x%lx\n",
+ old_pkt_filter, pmpriv->curr_pkt_filter);
+ if (old_pkt_filter != pmpriv->curr_pkt_filter) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_get_channel_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp;
+ t_u32 i, j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((wlan_11d_get_state(pmpriv) == ENABLE_11D &&
+ pmpriv->media_connected == MTRUE) &&
+ ((pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ||
+ (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ pmpriv->adhoc_state != ADHOC_STARTED))
+ ) {
+ t_u8 chan_no;
+ t_u8 band;
+
+ parsed_region_chan_11d_t *parsed_region_chan = MNULL;
+ parsed_region_chan_11d_t region_chan;
+
+ BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+
+ /* If country IE is present in the associated AP then return the
+ channel list from country IE else return it from the learning table */
+
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ ®ion_chan) == MLAN_STATUS_SUCCESS) {
+
+ parsed_region_chan = ®ion_chan;
+ } else {
+ parsed_region_chan = &pmadapter->parsed_region_chan;
+ }
+
+ band = parsed_region_chan->band;
+ PRINTM(MINFO, "band=%d no_of_chan=%d\n", band,
+ parsed_region_chan->no_of_chan);
+
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (i < parsed_region_chan->no_of_chan); i++) {
+ chan_no = parsed_region_chan->chan_pwr[i].chan;
+ PRINTM(MINFO, "chan_no=%d\n", chan_no);
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].channel =
+ (t_u32) chan_no;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) wlan_11d_chan_2_freq(pmadapter, chan_no, band);
+ bss->param.chanlist.num_of_chan++;
+ }
+ } else {
+ for (j = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (j <
+ sizeof(pmadapter->region_channel) /
+ sizeof(pmadapter->region_channel[0])); j++) {
+ cfp = pmadapter->region_channel[j].pcfp;
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && pmadapter->region_channel[j].valid
+ && cfp && (i < pmadapter->region_channel[j].num_cfp); i++) {
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].
+ channel = (t_u32) cfp->channel;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) cfp->freq;
+ bss->param.chanlist.num_of_chan++;
+ cfp++;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "num of channel=%d\n", bss->param.chanlist.num_of_chan);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
+ pmpriv->curr_bss_params.band,
+ (t_u16) pmpriv->curr_bss_params.
+ bss_descriptor.channel);
+ if (cfp) {
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+ } else
+ ret = MLAN_STATUS_FAILURE;
+ pioctl_req->data_read_written =
+ sizeof(chan_freq) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+ }
+ if (!bss->param.bss_chan.channel && !bss->param.bss_chan.freq) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmadapter->adhoc_start_band & BAND_AN)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ else if (pmadapter->adhoc_start_band & BAND_A)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ if (bss->param.bss_chan.channel) {
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, 0,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, BAND_A,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ } else {
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, 0,
+ bss->param.bss_chan.freq);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, BAND_A,
+ bss->param.bss_chan.freq);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ }
+ if (!cfp || !cfp->channel) {
+ PRINTM(MERROR, "Invalid channel/freq\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+
+ }
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ pmpriv->adhoc_auto_sel = MFALSE;
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_mode(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_mode = pmpriv->bss_mode;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ goto exit;
+ }
+
+ if ((pmpriv->bss_mode == bss->param.bss_mode) ||
+ (bss->param.bss_mode == MLAN_BSS_MODE_AUTO)) {
+ PRINTM(MINFO, "Already set to required mode! No change!\n");
+ pmpriv->bss_mode = bss->param.bss_mode;
+ goto exit;
+ }
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ }
+
+ ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
+
+ pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
+ pmpriv->bss_mode = bss->param.bss_mode;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_start(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ t_s32 i = -1;
+
+ ENTER();
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Infra mode */
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ if (ret)
+ goto start_ssid_done;
+
+ /* Search for the requested SSID in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_INFRA);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ MLAN_BSS_MODE_INFRA);
+ }
+
+ if (i >= 0) {
+ PRINTM(MINFO, "SSID found in scan list ... associating...\n");
+
+ /* Clear any past association response stored for application
+ retrieval */
+ pmpriv->assoc_rsp_size = 0;
+ ret = wlan_associate(pmpriv, pioctl_req,
+ &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ ret = MLAN_STATUS_FAILURE;
+ goto start_ssid_done;
+ }
+ } else {
+ /* Adhoc mode */
+ /* If the requested SSID matches current SSID, return */
+ if (bss->param.ssid_bssid.ssid.ssid_len &&
+ (!wlan_ssid_cmp
+ (pmadapter, &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ &bss->param.ssid_bssid.ssid))) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto start_ssid_done;
+ }
+
+ /* Exit Adhoc mode first */
+ PRINTM(MINFO, "Sending Adhoc Stop\n");
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ if (ret)
+ goto start_ssid_done;
+
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+
+ /* Search for the requested network in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_IBSS);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ MLAN_BSS_MODE_IBSS);
+ }
+
+ if (i >= 0) {
+ PRINTM(MINFO, "Network found in scan list ... joining ...\n");
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ ret =
+ wlan_adhoc_join(pmpriv, pioctl_req, &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ PRINTM(MINFO, "Network not found in the list, "
+ "creating adhoc with ssid = %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ ret =
+ wlan_adhoc_start(pmpriv, pioctl_req,
+ &bss->param.ssid_bssid.ssid);
+ if (ret)
+ goto start_ssid_done;
+ }
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ start_ssid_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_stop(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.bssid);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IBSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_ibss_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->media_connected == MFALSE) {
+ bss->param.bss_chan.channel = pmpriv->adhoc_channel;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ pmpriv->adhoc_channel = (t_u8) bss->param.bss_chan.channel;
+ pmpriv->adhoc_auto_sel = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_CHANNEL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &bss->param.bss_chan.channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_beacon_interval(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bcn_interval = pmpriv->beacon_period;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.bcn_interval =
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period;
+ } else
+ pmpriv->beacon_period = (t_u16) bss->param.bcn_interval;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_atim_window(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.atim_window = pmpriv->atim_window;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.atim_window =
+ pmpriv->curr_bss_params.bss_descriptor.atim_window;
+ } else
+ pmpriv->atim_window = (t_u16) bss->param.atim_window;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_find_bss(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (memcmp(&bss->param.ssid_bssid.bssid, zero_mac, sizeof(zero_mac))) {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ memcpy(mac, &bss->param.ssid_bssid.bssid, sizeof(mac));
+ PRINTM(MERROR, "Can not find bssid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(&bss->param.ssid_bssid.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ } else if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid, MNULL,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ PRINTM(MERROR, "Can not find ssid %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy((t_u8 *) & bss->param.ssid_bssid.bssid,
+ (t_u8 *) & pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief BSS command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_bss)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_bss);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_START:
+ status = wlan_bss_ioctl_start(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_STOP:
+ status = wlan_bss_ioctl_stop(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MODE:
+ status = wlan_bss_ioctl_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL:
+ status = wlan_bss_ioctl_channel(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL_LIST:
+ status = wlan_bss_ioctl_get_channel_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MAC_ADDR:
+ status = wlan_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MULTICAST_LIST:
+ status = wlan_bss_ioctl_set_multicast_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_FIND_BSS:
+ status = wlan_bss_ioctl_find_bss(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_BCN_INTERVAL:
+ status = wlan_bss_ioctl_beacon_interval(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_ATIM_WINDOW:
+ status = wlan_bss_ioctl_atim_window(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_CHANNEL:
+ status = wlan_bss_ioctl_ibss_channel(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get supported rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_supported_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ wlan_get_active_data_rates(pmpriv, rate->param.rates);
+ pioctl_req->data_read_written =
+ MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto;
+ pioctl_req->data_read_written =
+ sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+
+ if (pmpriv->media_connected != MTRUE) {
+ switch (pmadapter->config_bands) {
+ case BAND_B:
+ /* Return the lowest supported rate for B band */
+ rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ /* Return the lowest supported rate for G band */
+ rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ /* Return the lowest supported rate for BG band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ case BAND_A | BAND_AN:
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
+ break;
+ case BAND_GN:
+ /* Return the lowest supported rate for N band */
+ rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
+ break;
+ default:
+ PRINTM(MMSG, "Invalid Band 0x%x\n", pmadapter->config_bands);
+ break;
+ }
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_set_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *ds_rate = MNULL;
+ WLAN_802_11_RATES rates;
+ t_u8 *rate = MNULL;
+ int rate_index = 0;
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ t_u32 i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ memset(rates, 0, sizeof(rates));
+ wlan_get_active_data_rates(pmpriv, rates);
+ rate = rates;
+ for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
+ PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i],
+ ds_rate->param.rate_cfg.rate);
+ if ((rate[i] & 0x7f) == (ds_rate->param.rate_cfg.rate & 0x7f))
+ break;
+ }
+ if (!rate[i] || (i == WLAN_SUPPORTED_RATES)) {
+ PRINTM(MERROR, "The fixed data rate 0x%X is out "
+ "of range\n", ds_rate->param.rate_cfg.rate);
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+
+ rate_index =
+ wlan_data_rate_to_index(pmadapter, ds_rate->param.rate_cfg.rate);
+
+ /* Only allow b/g rates to be set */
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3)
+ bitmap_rates[0] = 1 << rate_index;
+ else {
+ rate_index -= 1; /* There is a 0x00 in the table */
+ if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ }
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_rate_index(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_set_rate_index(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int rate_index;
+ t_u32 i;
+ mlan_ds_rate *ds_rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate_index = ds_rate->param.rate_cfg.rate;
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < NELEMENTS(bitmap_rates) - 3; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ PRINTM(MINFO, "Rate index is %d\n", rate_index);
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Bitmap of HR/DSSS rates */
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3)
+ bitmap_rates[0] = 1 << rate_index;
+ /* Bitmap of OFDM rates */
+ if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ /* Bitmap of HT-MCSs allowed for initial rate */
+ if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
+ rate_index <= MLAN_RATE_INDEX_MCS32)
+ bitmap_rates[((rate_index - MLAN_RATE_INDEX_MCS0) / 16) + 2] =
+ 1 << ((rate_index - MLAN_RATE_INDEX_MCS0) % 16);
+ }
+
+ PRINTM(MINFO, "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
+ "IsRateAuto=%d, DataRate=%d\n",
+ bitmap_rates[9], bitmap_rates[8],
+ bitmap_rates[7], bitmap_rates[6],
+ bitmap_rates[5], bitmap_rates[4],
+ bitmap_rates[3], bitmap_rates[2],
+ bitmap_rates[1], bitmap_rates[0],
+ pmpriv->is_data_rate_auto, pmpriv->data_rate);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, (t_void *) bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_value(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_value(pmadapter, pioctl_req);
+ } else {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_index(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_index(pmadapter, pioctl_req);
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_data_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_rate)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_rate);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ switch (rate->sub_command) {
+ case MLAN_OID_RATE_CFG:
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DATA_RATE:
+ status = wlan_rate_ioctl_get_data_rate(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SUPPORTED_RATES:
+ status = wlan_rate_ioctl_get_supported_rate(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_get_power(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_set_power(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ t_u16 dbm = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ if (!power->param.power_cfg.is_power_auto) {
+ dbm = (t_u16) power->param.power_cfg.power_level;
+ if ((dbm < pmpriv->min_tx_power_level) ||
+ (dbm > pmpriv->max_tx_power_level)) {
+ PRINTM(MERROR,
+ "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ dbm, pmpriv->min_tx_power_level, pmpriv->max_tx_power_level);
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ ret = pcb->moal_malloc(MRVDRV_SIZE_OF_CMD_BUFFER, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MMSG, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ if (!power->param.power_cfg.is_power_auto) {
+ txp_cfg->mode = 1;
+ pg_tlv =
+ (MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = 4 * sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ /* Power group for modulation class HR/DSSS */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x03;
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class OFDM */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x07;
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class HTBW20 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_20;
+ pg++;
+ /* Power group for modulation class HTBW40 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_40;
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ if (buf)
+ pcb->moal_mfree(buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get modulation class from rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate_index Rate index
+ *
+ * @return 0 fail, otherwise return modulation class
+ */
+static int
+wlan_get_modulation_class(pmlan_adapter pmadapter, int rate_index)
+{
+ ENTER();
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
+ return MOD_CLASS_HR_DSSS;
+ } else if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7) {
+ return MOD_CLASS_OFDM;
+ } else if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
+ rate_index <= MLAN_RATE_INDEX_MCS127) {
+ return MOD_CLASS_HT;
+ }
+ PRINTM(MERROR, "Invalid rate index = %d supplied!\n", rate_index);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set extended power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_set_power_ext(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_power_cfg *power = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ int mod_class;
+ t_u32 data[4];
+ t_u8 ht_bw;
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ ret = pcb->moal_malloc(MRVDRV_SIZE_OF_CMD_BUFFER, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ memcpy((t_u8 *) & data, (t_u8 *) power->param.power_ext.power_data,
+ sizeof(data));
+ switch (power->param.power_ext.len) {
+ case 1:
+ if (data[0] == 0xFF)
+ txp_cfg->mode = 0;
+ else
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ case 2:
+ case 4:
+ ht_bw = (data[0] & TX_RATE_HT_BW40_BIT) ? HT_BW_40 : HT_BW_20;
+ data[0] &= ~TX_RATE_HT_BW40_BIT;
+ if (!(mod_class = wlan_get_modulation_class(pmadapter, data[0]))) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ht_bw && mod_class != MOD_CLASS_HT) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ txp_cfg->mode = 1;
+ pg_tlv =
+ (MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ pg->modulation_class = (t_u8) mod_class;
+ pg->first_rate_code = (t_u8) data[0];
+ pg->last_rate_code = (t_u8) data[0];
+ if (mod_class == MOD_CLASS_OFDM) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ } else if (mod_class == MOD_CLASS_HT) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->ht_bandwidth = ht_bw;
+ }
+ pg->power_min = (t_s8) data[1];
+ pg->power_max = (t_s8) data[1];
+ if (power->param.power_ext.len == 4) {
+ pg->power_max = (t_s8) data[2];
+ pg->power_step = (t_s8) data[3];
+ }
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (buf)
+ pcb->moal_mfree(buf);
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ if (buf)
+ pcb->moal_mfree(buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_power_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_power_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ switch (power->sub_command) {
+ case MLAN_OID_POWER_CFG:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter, pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_POWER_CFG_EXT:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter, pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set power save configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ps_mode Power save mode
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_ps_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u16 ps_mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ t_u16 sub_cmd;
+
+ ENTER();
+
+ sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ? EN_PS : DIS_PS;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, sub_cmd,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param phs_cfg A pointer to HOST_SLEEP_CFG structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_hs_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req,
+ IN HostCmd_DS_802_11_HS_CFG_ENH * phs_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, phs_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Inactivity timeout extend
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_inactivity_timeout(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_INACTIVITY_TIMEOUT_EXT,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & pmcfg->param.inactivity_to);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable Auto Deep Sleep
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_auto_deep_sleep(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = (pmlan_private) pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.auto_ds ==
+ DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ mode = EN_AUTO_DS;
+ } else {
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "AutoAUTO_DEEP_SLEEP Deep Sleep: off\n");
+ mode = DIS_AUTO_DS;
+ }
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.idletime;
+
+ /* note: the command could be queued and executed later if there is
+ command in progress. */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ mode, 0, (t_void *) pioctl_req, &auto_ds);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_sleep_pd(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+ cmd_action, 0, (t_void *) pioctl_req,
+ &pm_cfg->param.sleep_period);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_ps_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ } else {
+ if (pm_cfg->param.ps_cfg.ps_null_interval)
+ pmadapter->null_pkt_interval =
+ (t_u16) pm_cfg->param.ps_cfg.ps_null_interval;
+ else
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ if (pm_cfg->param.ps_cfg.multiple_dtim_interval)
+ pmadapter->multiple_dtim =
+ (t_u16) pm_cfg->param.ps_cfg.multiple_dtim_interval;
+ else
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ if (pm_cfg->param.ps_cfg.listen_interval)
+ pmadapter->local_listen_interval =
+ (t_u16) pm_cfg->param.ps_cfg.listen_interval;
+ else
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ if (pm_cfg->param.ps_cfg.adhoc_awake_period)
+ pmadapter->adhoc_awake_period =
+ (t_u16) pm_cfg->param.ps_cfg.adhoc_awake_period;
+ else
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ if (pm_cfg->param.ps_cfg.bcn_miss_timeout)
+ pmadapter->bcn_miss_time_out =
+ (t_u16) pm_cfg->param.ps_cfg.bcn_miss_timeout;
+ else
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ if (pm_cfg->param.ps_cfg.delay_to_ps != DELAY_TO_PS_UNCHANGED)
+ pmadapter->delay_to_ps = (t_u16) pm_cfg->param.ps_cfg.delay_to_ps;
+ else
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ if (pm_cfg->param.ps_cfg.ps_mode)
+ pmadapter->enhanced_ps_mode = (t_u16) pm_cfg->param.ps_cfg.ps_mode;
+ else
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get/Set the sleep parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_sleep_params(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ &pm_cfg->param.sleep_params);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power save command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ switch (pm->sub_command) {
+ case MLAN_OID_PM_CFG_IEEE_PS:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pm->param.ps_mode)
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ status =
+ wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->ps_mode == Wlan802_11PowerModePSP)
+ pm->param.ps_mode = 1;
+ else
+ pm->param.ps_mode = 0;
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_HS_CFG:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ pmadapter->hs_cfg.params.hs_config.conditions =
+ pm->param.hs_cfg.conditions;
+ pmadapter->hs_cfg.params.hs_config.gpio = pm->param.hs_cfg.gpio;
+ pmadapter->hs_cfg.params.hs_config.gap = pm->param.hs_cfg.gap;
+ if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
+ status =
+ wlan_pm_ioctl_hs_cfg(pmadapter, pioctl_req,
+ &pmadapter->hs_cfg);
+ }
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->is_hs_configured) {
+ pm->param.hs_cfg.conditions =
+ pmadapter->hs_cfg.params.hs_config.conditions;
+ pm->param.hs_cfg.gpio = pmadapter->hs_cfg.params.hs_config.gpio;
+ pm->param.hs_cfg.gap = pmadapter->hs_cfg.params.hs_config.gap;
+ }
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_INACTIVITY_TO:
+ status = wlan_pm_ioctl_inactivity_timeout(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_DEEP_SLEEP:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "Station already in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ } else if (!pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_OFF) {
+ PRINTM(MMSG,
+ "Station already not in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_set_auto_deep_sleep(pmadapter, pioctl_req);
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->is_deep_sleep)
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_PS_CFG:
+ status = wlan_set_get_ps_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PD:
+ status = wlan_set_get_sleep_pd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PARAMS:
+ status = wlan_set_get_sleep_params(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WMM status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_enable(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+ ENTER();
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.wmm_enable = (t_u32) pmpriv->wmm_required;
+ else
+ pmpriv->wmm_required = (t_u8) wmm->param.wmm_enable;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WMM QoS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_qos(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
+ else
+ pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
+
+ pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get tid multi-port eligibility table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_tid_elig_tbl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *wmm = MNULL;
+ t_u32 i;
+
+ ENTER();
+
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ for (i = 0; i < MAX_NUM_TID; i++)
+ wmm->param.tid_tbl[i] = pmadapter->tx_eligibility[i];
+ } else {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (wmm->param.tid_tbl[i] >= pmadapter->mp_end_port)
+ ret = MLAN_STATUS_FAILURE;
+ }
+ if (ret == MLAN_STATUS_SUCCESS) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (wmm->param.tid_tbl[i])
+ pmadapter->tx_eligibility[i] = (t_u8) wmm->param.tid_tbl[i];
+ }
+ }
+ }
+
+ pioctl_req->data_read_written =
+ sizeof(wmm->param.tid_tbl) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for add a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_addts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.addts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for delete a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_delts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.delts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get a specified AC Queue's parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_config(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief To get and start/stop queue stats on a WMM AC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_stats(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_stats);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM AC queues
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+ mlan_ds_wmm_queue_status *pqstatus = MNULL;
+ WmmAcStatus_t *pac_status = MNULL;
+ mlan_wmm_ac_e ac_idx;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ pqstatus = (mlan_ds_wmm_queue_status *) & cfg->param.q_status;
+
+ for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
+ pac_status = &pmpriv->wmm.ac_status[ac_idx];
+
+ /* Firmware status */
+ pqstatus->ac_status[ac_idx].flow_required = pac_status->flow_required;
+ pqstatus->ac_status[ac_idx].flow_created = pac_status->flow_created;
+ pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
+
+ /* ACM bit reflected in firmware status (redundant) */
+ pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM Traffic Streams
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_ts_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.ts_status);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WMM configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wmm_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ switch (wmm->sub_command) {
+ case MLAN_OID_WMM_CFG_ENABLE:
+ status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QOS:
+ status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_TID_ELIG_TBL:
+ status = wlan_wmm_ioctl_tid_elig_tbl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_ADDTS:
+ status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_DELTS:
+ status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
+ status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATS:
+ status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATUS:
+ status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_TS_STATUS:
+ status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_set_wpa_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wpa_ie)) {
+ PRINTM(MERROR, "failed to copy WPA IE, too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
+ priv->wpa_ie_len = (t_u8) ie_len;
+ PRINTM(MCMND, "Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "Wpa_ie", priv->wpa_ie, priv->wpa_ie_len);
+ if (priv->wpa_ie[0] == WPA_IE) {
+ priv->sec_info.wpa_enabled = MTRUE;
+ } else if (priv->wpa_ie[0] == RSN_IE) {
+ priv->sec_info.wpa2_enabled = MTRUE;
+ } else {
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+ } else {
+ memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ PRINTM(MINFO, "Reset Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_set_wapi_ie(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wapi_ie)) {
+ PRINTM(MINFO, "failed to copy WAPI IE, too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
+ priv->wapi_ie_len = ie_len;
+ PRINTM(MCMND, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie, priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = ie_len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_wapi_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE)
+ wlan_set_wapi_ie(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wapi_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get authentication mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_auth_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
+ else {
+ pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
+ if (pmpriv->sec_info.authentication_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get encryption mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_encrypt_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.encrypt_mode = pmpriv->sec_info.encryption_mode;
+ else {
+ pmpriv->sec_info.encryption_mode = sec->param.encrypt_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPA status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_wpa_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wpa_ie_len)
+ sec->param.wpa_enabled = MTRUE;
+ else
+ sec->param.wpa_enabled = MFALSE;
+ } else {
+ if (sec->param.wpa_enabled == MFALSE)
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WEP keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wep_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ mrvl_wep_key_t *pwep_key = MNULL;
+ int index;
+
+ ENTER();
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+ pwep_key = &pmpriv->wep_key[pmpriv->wep_key_curr_index];
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (sec->param.encrypt_key.is_current_wep_key == MTRUE)
+ index = pmpriv->wep_key_curr_index;
+ else
+ index = sec->param.encrypt_key.key_index;
+ if (sec->param.encrypt_key.key_disable == MTRUE) {
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled &&
+ pmpriv->media_connected == MTRUE &&
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ PRINTM(MERROR, "Can not disable key in IBSS connected state\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ } else if (!sec->param.encrypt_key.key_len) {
+ if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled &&
+ pmpriv->media_connected == MTRUE &&
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ PRINTM(MERROR, "Can not enable key in IBSS connected state\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ /* Copy the required key as the current key */
+ pwep_key = &pmpriv->wep_key[index];
+ if (!pwep_key->key_length) {
+ PRINTM(MERROR, "Key not set,so cannot enable it\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pmpriv->wep_key_curr_index = (t_u16) index;
+ pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
+ } else {
+ pwep_key = &pmpriv->wep_key[index];
+ /* Cleanup */
+ memset(pwep_key, 0, sizeof(mrvl_wep_key_t));
+ /* Copy the key in the driver */
+ memcpy(pwep_key->key_material, sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ pwep_key->key_index = index;
+ pwep_key->key_length = sec->param.encrypt_key.key_len;
+ if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled) {
+ /*
+ * The status is set as Key Absent
+ * so as to make sure we display the
+ * keys when iwlist mlanX key is used
+ */
+ pmpriv->sec_info.wep_status = Wlan802_11WEPKeyAbsent;
+ }
+ pmpriv->wep_key_curr_index = (t_u16) index;
+ }
+ if (pwep_key->key_length) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret)
+ goto exit;
+ }
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wpa_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 remove_key = MFALSE;
+ HostCmd_DS_802_11_KEY_MATERIAL *pibss_key;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ /* Current driver only supports key length of up to 32 bytes */
+ if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
+ PRINTM(MERROR, " Error in key length \n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ /*
+ * IBSS/WPA-None uses only one key (Group) for both receiving and
+ * sending unicast and multicast packets.
+ */
+ /* Send the key as PTK to firmware */
+ sec->param.encrypt_key.key_index = 0x40000000;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ MNULL, &sec->param.encrypt_key);
+ if (ret)
+ goto exit;
+
+ pibss_key = &pmpriv->aes_key;
+ memset(pibss_key, 0, sizeof(HostCmd_DS_802_11_KEY_MATERIAL));
+ /* Copy the key in the driver */
+ memcpy(pibss_key->key_param_set.key,
+ sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ memcpy(&pibss_key->key_param_set.key_len,
+ &sec->param.encrypt_key.key_len,
+ sizeof(pibss_key->key_param_set.key_len));
+ pibss_key->key_param_set.key_type_id = KEY_TYPE_ID_TKIP;
+ pibss_key->key_param_set.key_info = KEY_INFO_TKIP_ENABLED;
+
+ /* Send the key as GTK to firmware */
+ sec->param.encrypt_key.key_index = ~0x40000000;
+ }
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN) {
+ t_u8 zero_key_material[WPA_AES_KEY_LEN];
+
+ memset(zero_key_material, 0, sizeof(zero_key_material));
+ if (memcmp(sec->param.encrypt_key.key_material, zero_key_material,
+ WPA_AES_KEY_LEN)) {
+ PRINTM(MINFO, "Adhoc AES Enabled.\n");
+ pmpriv->adhoc_aes_enabled = MTRUE;
+ remove_key = MFALSE;
+ } else {
+ PRINTM(MINFO, "Adhoc AES Disabled.\n");
+ pmpriv->adhoc_aes_enabled = MFALSE;
+ remove_key = MTRUE;
+ }
+ }
+
+ if (!sec->param.encrypt_key.key_index)
+ sec->param.encrypt_key.key_index = 0x40000000;
+
+ if (remove_key == MTRUE) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ !(KEY_INFO_ENABLED),
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get security keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_get_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ int index;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+
+ if (pmpriv->adhoc_aes_enabled == MTRUE &&
+ (pmpriv->aes_key.key_param_set.key_len == WPA_AES_KEY_LEN)) {
+ HEXDUMP("Get WPA Key", pmpriv->aes_key.key_param_set.key,
+ WPA_AES_KEY_LEN);
+ memcpy(sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, WPA_AES_KEY_LEN);
+ LEAVE();
+ return ret;
+
+ }
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+
+ if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ || (pmpriv->sec_info.wep_status == Wlan802_11WEPKeyAbsent)
+ || pmpriv->sec_info.ewpa_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled) {
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+
+ if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
+ if ((pmpriv->wep_key[pmpriv->wep_key_curr_index].key_length) &&
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)) {
+ index = pmpriv->wep_key_curr_index;
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material,
+ pmpriv->wep_key[index].key_length);
+ sec->param.encrypt_key.key_len = pmpriv->wep_key[index].key_length;
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ memcpy(sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key,
+ pmpriv->aes_key.key_param_set.key_len);
+ sec->param.encrypt_key.key_len =
+ pmpriv->aes_key.key_param_set.key_len;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ } else {
+ index = sec->param.encrypt_key.key_index;
+ if (pmpriv->wep_key[index].key_length) {
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material,
+ pmpriv->wep_key[index].key_length);
+ sec->param.encrypt_key.key_len = pmpriv->wep_key[index].key_length;
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set security key(s)
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_encrypt_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.encrypt_key.is_wapi_key)
+ status = wlan_sec_ioctl_set_wapi_key(pmadapter, pioctl_req);
+ else if (sec->param.encrypt_key.key_len > MAX_WEP_KEY_SIZE)
+ status = wlan_sec_ioctl_set_wpa_key(pmadapter, pioctl_req);
+ else
+ status = wlan_sec_ioctl_set_wep_key(pmadapter, pioctl_req);
+ } else {
+ status = wlan_sec_ioctl_get_key(pmadapter, pioctl_req);
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA passphrase for esupplicant
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_passphrase(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u16 cmd_action = 0;
+ BSSDescriptor_t *pbss_desc;
+ int i = 0;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
+ if (sec->param.passphrase.ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & sec->param.passphrase.
+ bssid, MLAN_BSS_MODE_AUTO);
+ if (i > 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(&sec->param.passphrase.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ memset(&sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MCMND, "PSK_QUERY: found ssid=%s\n",
+ sec->param.passphrase.ssid.ssid);
+ }
+ } else
+ memset(&sec->param.passphrase.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PMK,
+ cmd_action,
+ 0, (t_void *) pioctl_req, &sec->param.passphrase);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get esupplicant status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_ewpa_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
+ } else {
+ pmpriv->sec_info.ewpa_enabled = (t_u8) sec->param.ewpa_enabled;
+ PRINTM(MCMND, "Set: ewpa_enabled = %d\n",
+ (int) pmpriv->sec_info.ewpa_enabled);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupplicant mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_esupp_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ HostCmd_ACT_GEN_GET_CURRENT,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Security configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_sec_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_sec_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ switch (sec->sub_command) {
+ case MLAN_OID_SEC_CFG_AUTH_MODE:
+ status = wlan_sec_ioctl_auth_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_MODE:
+ status = wlan_sec_ioctl_encrypt_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WPA_ENABLED:
+ status = wlan_sec_ioctl_wpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WAPI_ENABLED:
+ status = wlan_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_KEY:
+ status = wlan_sec_ioctl_encrypt_key(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PASSPHRASE:
+ status = wlan_sec_ioctl_passphrase(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_EWPA_ENABLED:
+ status = wlan_sec_ioctl_ewpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ESUPP_MODE:
+ status = wlan_sec_ioctl_esupp_mode(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Append/Reset IE buffer.
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command. This function is the main body
+ * for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ * Data is appended to an existing buffer and then wrapped in a passthrough
+ * TLV in the command API to the firmware. The firmware treats the data
+ * as a transparent passthrough to the transmitted management frame.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to iwreq structure
+ * @param ie_len Length of the IE or IE block passed in ie_data_ptr
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_VendorHeader_t *pvendor_ie;
+ const t_u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ ENTER();
+
+ /* If the passed length is zero, reset the buffer */
+ if (!ie_len) {
+ priv->gen_ie_buf_len = 0;
+ priv->wps.session_enable = MFALSE;
+ } else if (!ie_data_ptr) {
+ /* MNULL check */
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+ if (((pvendor_ie->element_id == WPA_IE)
+ && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
+ || (pvendor_ie->element_id == RSN_IE)
+ ) {
+
+ /* IE is a WPA/WPA2 IE so call set_wpa function */
+ ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+ priv->wps.session_enable = MFALSE;
+ } else if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_set_wapi_ie(priv, ie_data_ptr, ie_len);
+ } else {
+ /*
+ * Verify that the passed length is not larger than the available
+ * space remaining in the buffer
+ */
+ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+
+ /* Test to see if it is a WPS IE, if so, enable wps session
+ flag */
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ if ((pvendor_ie->element_id == WPS_IE)
+ && (!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
+ priv->wps.session_enable = MTRUE;
+ PRINTM(MINFO, "WPS Session Enabled.\n");
+ }
+
+ /* Append the passed data to the end of the genIeBuffer */
+ memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
+ ie_len);
+ /* Increment the stored buffer length by the size passed */
+ priv->gen_ie_buf_len += ie_len;
+ } else {
+ /* Passed data does not fit in the remaining buffer space */
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+
+ /* Return MLAN_STATUS_SUCCESS, or MLAN_STATUS_FAILURE for error case */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get IE buffer from driver
+ *
+ * Used to pass an opaque block of data, expected to be IEEE IEs,
+ * back to the application. Currently the data block passed
+ * back to the application is the saved association response retrieved
+ * from the firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to the IE or IE block
+ * @param ie_len_ptr In/Out parameter pointer for the buffer length passed
+ * in ie_data_ptr and the resulting data length copied
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr,
+ t_u16 * ie_len_ptr)
+{
+ IEEEtypes_AssocRsp_t *passoc_rsp;
+ t_u16 copy_size;
+
+ ENTER();
+
+ if ((priv->media_connected == MFALSE) || (priv->assoc_rsp_size == 0)) {
+ *ie_len_ptr = 0;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ passoc_rsp = (IEEEtypes_AssocRsp_t *) priv->assoc_rsp_buf;
+
+ /*
+ * Set the amount to copy back to the application as the minimum of the
+ * available IE data or the buffer provided by the application
+ */
+ copy_size = (t_u16) (priv->assoc_rsp_size - sizeof(passoc_rsp->capability)
+ - sizeof(passoc_rsp->status_code) -
+ sizeof(passoc_rsp->a_id));
+ copy_size = MIN(copy_size, *ie_len_ptr);
+
+ /* Copy the IEEE TLVs in the assoc response back to the application */
+ memcpy(ie_data_ptr, (t_u8 *) passoc_rsp->ie_buffer, copy_size);
+ /* Returned copy length */
+ *ie_len_ptr = copy_size;
+ /* No error on return */
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_wws_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u32 enable = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ enable = misc_cfg->param.wws_cfg;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action,
+ WwsMode_i, (t_void *) pioctl_req, &enable);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get 11D status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "11D: 11dcfg SET=%d\n", pcfg_11d->param.enable_11d);
+
+ /* Compare with current settings */
+ if (pmadapter->state_11d.user_enable_11d != pcfg_11d->param.enable_11d) {
+ ret =
+ wlan_11d_enable(pmpriv, pioctl_req,
+ (state_11d_t) pcfg_11d->param.enable_11d);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ PRINTM(MINFO, "11D: same as current setting, do nothing\n");
+ }
+ } else {
+ pcfg_11d->param.enable_11d =
+ (t_u32) pmadapter->state_11d.user_enable_11d;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ PRINTM(MINFO, "11D: 11dcfg GET=%d\n", pcfg_11d->param.enable_11d);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 11D configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ status = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ switch (pcfg_11d->sub_command) {
+ case MLAN_OID_11D_CFG_ENABLE:
+ status = wlan_11d_cfg_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ exit:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief WPS configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wps_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_wps_cfg *pwps = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wps_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wps_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) pioctl_req->pbuf;
+ switch (pwps->sub_command) {
+ case MLAN_OID_WPS_CFG_SESSION:
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pwps->param.wps_session == MLAN_WPS_CFG_SESSION_START ||
+ pwps->param.wps_session == MLAN_WPS_CFG_SESSION_END)
+ pmpriv->wps.session_enable = (t_u8) pwps->param.wps_session;
+ else
+ pmpriv->wps.session_enable = MLAN_WPS_CFG_SESSION_END;
+ } else {
+ pwps->param.wps_session = (t_u32) pmpriv->wps.session_enable;
+ pioctl_req->data_read_written = sizeof(t_u32);
+ PRINTM(MINFO, "wpscfg GET=%d\n", pwps->param.wps_session);
+ }
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Read/write adapter register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_reg_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0, cmd_no;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ switch (reg_mem->param.reg_rw.type) {
+ case MLAN_REG_MAC:
+ cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+ break;
+ case MLAN_REG_BBP:
+ cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+ break;
+ case MLAN_REG_RF:
+ cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+ break;
+ case MLAN_REG_PMIC:
+ cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
+ break;
+ case MLAN_REG_CAU:
+ cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action,
+ 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.reg_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_read_eeprom(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_EEPROM_ACCESS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.rd_eeprom);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/write memory of device
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_mem_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MEM_ACCESS,
+ cmd_action, 0,
+ (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.mem_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief register memory access handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_reg_mem *reg_mem = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_reg_mem)) {
+ PRINTM(MWARN, "MLAN REG_MEM IOCTL length is too short\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_reg_mem);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ switch (reg_mem->sub_command) {
+ case MLAN_OID_REG_RW:
+ status = wlan_reg_mem_ioctl_reg_rw(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_EEPROM_RD:
+ status = wlan_reg_mem_ioctl_read_eeprom(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MEM_RW:
+ status = wlan_reg_mem_ioctl_mem_rw(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get BCA time share parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bca_cfg_ioctl_bca_ts(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_bca_cfg *bca_cfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bca_cfg = (mlan_ds_bca_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & bca_cfg->param.bca_ts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief BCA configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bca_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bca_cfg *bca_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_bca_cfg)) {
+ PRINTM(MWARN, "MLAN_IOCTL_BCA_CFG IOCTL length is too short\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_bca_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ bca_cfg = (mlan_ds_bca_cfg *) pioctl_req->pbuf;
+ switch (bca_cfg->sub_command) {
+ case MLAN_OID_BCA_TS:
+ status = wlan_bca_cfg_ioctl_bca_ts(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_gen_ie(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->param.gen_ie.type) {
+ case MLAN_IE_TYPE_GEN_IE:
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.gen_ie.len = pmpriv->wpa_ie_len;
+ memcpy(misc->param.gen_ie.ie_data, pmpriv->wpa_ie,
+ misc->param.gen_ie.len);
+ } else {
+ wlan_set_gen_ie_helper(pmpriv, misc->param.gen_ie.ie_data,
+ (t_u16) misc->param.gen_ie.len);
+ }
+ break;
+ case MLAN_IE_TYPE_ARP_FILTER:
+ memset(pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ if (misc->param.gen_ie.len > ARP_FILTER_MAX_BUF_SIZE) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MERROR, "Invalid ARP Filter Size\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ memcpy(pmadapter->arp_filter, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ pmadapter->arp_filter_size = misc->param.gen_ie.len;
+ HEXDUMP("ArpFilter", pmadapter->arp_filter,
+ pmadapter->arp_filter_size);
+ }
+ break;
+ default:
+ PRINTM(MERROR, "Invalid IE type\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_ds_misc_gen_ie) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_region(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+ int i;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.region_code = pmadapter->region_code;
+ } else {
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (misc->param.region_code == region_code_index[i]) {
+ pmadapter->region_code = (t_u16) misc->param.region_code;
+ break;
+ }
+ }
+ /* It's unidentified region code */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ PRINTM(MERROR, "Region Code not identified\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->config_bands)) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Perform warm reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+static mlan_status
+wlan_misc_ioctl_warm_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ HostCmd_DS_VERSION_EXT dummy;
+ t_s32 i = 0;
+ t_u8 first_sta = MTRUE;
+
+ ENTER();
+
+ /** Init all the head nodes and free all the locks here */
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmadapter->priv[i]) {
+ wlan_wmm_cleanup_node(pmpriv);
+ pcb->moal_free_lock(pmpriv->rx_pkt_lock);
+ pcb->moal_free_lock(pmpriv->wmm.ra_list_spinlock);
+ }
+ }
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ /* Initialize private structures */
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmadapter->priv[i])
+ wlan_init_priv(pmpriv);
+ }
+
+ pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ /* Restart the firmware */
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+
+ /* Issue commands to initialize firmware */
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ pmadapter->priv[i]->ops.init_cmd(pmadapter->priv[i], first_sta);
+ first_sta = MFALSE;
+ }
+ }
+
+ /* Issue dummy Get command to complete the ioctl */
+ memset(&dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, (t_void *) & dummy);
+
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Reconfigure SDIO multiport aggregation parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_sdio_mpa_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_ds_misc_sdio_mpa_ctrl *mpa_ctrl = MNULL;
+
+ ENTER();
+
+ mpa_ctrl = &misc->param.mpa_ctrl;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MMSG, "SDIO MP-A CTRL: not allowed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_enable > 1) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_enable > 1) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_buf_size || mpa_ctrl->rx_buf_size) {
+
+ wlan_free_sdio_mpa_buffers(pmadapter);
+
+ if (mpa_ctrl->tx_buf_size > 0)
+ pmadapter->mpa_tx.buf_size = mpa_ctrl->tx_buf_size;
+
+ if (mpa_ctrl->rx_buf_size > 0)
+ pmadapter->mpa_rx.buf_size = mpa_ctrl->rx_buf_size;
+
+ if (wlan_alloc_sdio_mpa_buffers(pmadapter,
+ pmadapter->mpa_tx.buf_size,
+ pmadapter->mpa_rx.buf_size) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ if (mpa_ctrl->tx_max_ports > 0)
+ pmadapter->mpa_tx.pkt_aggr_limit = mpa_ctrl->tx_max_ports;
+ if (mpa_ctrl->rx_max_ports > 0)
+ pmadapter->mpa_rx.pkt_aggr_limit = mpa_ctrl->rx_max_ports;
+
+ pmadapter->mpa_tx.enabled = mpa_ctrl->tx_enable;
+ pmadapter->mpa_rx.enabled = mpa_ctrl->rx_enable;
+
+ } else {
+ mpa_ctrl->tx_enable = pmadapter->mpa_tx.enabled;
+ mpa_ctrl->rx_enable = pmadapter->mpa_rx.enabled;
+ mpa_ctrl->tx_buf_size = pmadapter->mpa_tx.buf_size;
+ mpa_ctrl->rx_buf_size = pmadapter->mpa_rx.buf_size;
+ mpa_ctrl->tx_max_ports = pmadapter->mpa_tx.pkt_aggr_limit;
+ mpa_ctrl->rx_max_ports = pmadapter->mpa_rx.pkt_aggr_limit;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+#ifdef MFG_CMD_SUPPORT
+/**
+ * @brief send mfg cmd
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_mfg_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MFG_COMMAND,
+ 0,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.mfgcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/**
+ * @brief Set/Get LDO configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_ldo(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_LDO_CONFIG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.ldo_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system clock configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_sysclock(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.sys_clock);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/** Flag for VSIE */
+#define VSIE_FLAG 1
+
+/** Max total length of vendor specific IEs for scan/assoc/ad-hoc */
+#define MAX_TOTAL_VSIE_LEN 512
+
+/**
+ * @brief Get/Add/Remove the vendor specific IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_vendor_spec_ie(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 id, index, max_len;
+ t_u16 mask_bak;
+ t_u8 bit, len_bak;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ id = misc->param.vsie.id;
+ switch (pioctl_req->action) {
+ case MLAN_ACT_GET:
+ misc->param.vsie.mask = (t_u32) pmpriv->vs_ie[id].mask;
+ memcpy(misc->param.vsie.ie, pmpriv->vs_ie[id].ie,
+ sizeof(misc->param.vsie.ie));
+ break;
+ case MLAN_ACT_SET:
+ mask_bak = pmpriv->vs_ie[id].mask;
+ pmpriv->vs_ie[id].mask = (t_u16) misc->param.vsie.mask;
+ if (!pmpriv->vs_ie[id].mask) {
+ memset(&pmpriv->vs_ie[id], 0, sizeof(vendor_spec_cfg_ie));
+ } else {
+ /* Check if the total length of VS IEs is over limitation */
+ len_bak = pmpriv->vs_ie[id].ie[1];
+ pmpriv->vs_ie[id].ie[1] = misc->param.vsie.ie[1];
+ for (bit = MLAN_VSIE_MASK_SCAN; bit <= MLAN_VSIE_MASK_ADHOC;
+ bit <<= 1) {
+ max_len = 0;
+ for (index = 0; index < MLAN_MAX_VSIE_NUM; index++) {
+ if (pmpriv->vs_ie[index].mask & bit)
+ max_len += (pmpriv->vs_ie[index].ie[1] + 2);
+ }
+ if (max_len > MAX_TOTAL_VSIE_LEN) {
+ PRINTM(MERROR,
+ "Total length of VS IEs for %s (%d) is over limitation (%d)\n",
+ (bit == MLAN_VSIE_MASK_SCAN) ? "scan" : (bit ==
+ MLAN_VSIE_MASK_ASSOC)
+ ? "assoc" : "ad-hoc", max_len, MAX_TOTAL_VSIE_LEN);
+ pmpriv->vs_ie[id].mask = mask_bak;
+ pmpriv->vs_ie[id].ie[1] = len_bak;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (!ret) {
+ pmpriv->vs_ie[id].flag = VSIE_FLAG;
+ memcpy(pmpriv->vs_ie[id].ie, misc->param.vsie.ie,
+ sizeof(misc->param.vsie.ie));
+ pmpriv->vs_ie[id].ie[0] = VS_IE;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Miscellaneous configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->sub_command) {
+ case MLAN_OID_MISC_GEN_IE:
+ status = wlan_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_REGION:
+ status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WARM_RESET:
+ status = wlan_misc_ioctl_warm_reset(pmadapter, pioctl_req);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case MLAN_OID_MISC_SDIO_MPA_CTRL:
+ status = wlan_misc_ioctl_sdio_mpa_ctrl(pmadapter, pioctl_req);
+ break;
+#endif
+#ifdef MFG_CMD_SUPPORT
+ case MLAN_OID_MISC_MFG_CMD:
+ status = wlan_misc_ioctl_mfg_cmd(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_HOST_CMD:
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_LDO:
+ status = wlan_misc_ioctl_ldo(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SYS_CLOCK:
+ status = wlan_misc_ioctl_sysclock(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WWS:
+ status = wlan_misc_ioctl_wws_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_VS_IE:
+ status = wlan_misc_ioctl_vendor_spec_ie(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_INIT_SHUTDOWN:
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ break;
+
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get scan configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param action Set/Get
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_scan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 action)
+{
+ mlan_ds_scan *scan = MNULL;
+
+ ENTER();
+
+ scan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (action == MLAN_ACT_GET) {
+ scan->param.scan_cfg.scan_type = (t_u32) pmadapter->scan_type + 1;
+ scan->param.scan_cfg.scan_mode = pmadapter->scan_mode;
+ scan->param.scan_cfg.scan_probe = (t_u32) pmadapter->scan_probes;
+ scan->param.scan_cfg.scan_time.specific_scan_time =
+ (t_u32) pmadapter->specific_scan_time;
+ scan->param.scan_cfg.scan_time.active_scan_time =
+ (t_u32) pmadapter->active_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time =
+ (t_u32) pmadapter->passive_scan_time;
+ } else {
+ if (scan->param.scan_cfg.scan_type)
+ pmadapter->scan_type = (t_u8) scan->param.scan_cfg.scan_type - 1;
+ if (scan->param.scan_cfg.scan_mode)
+ pmadapter->scan_mode = scan->param.scan_cfg.scan_mode;
+ if (scan->param.scan_cfg.scan_probe)
+ pmadapter->scan_probes = (t_u16) scan->param.scan_cfg.scan_probe;
+ if (scan->param.scan_cfg.scan_time.specific_scan_time)
+ pmadapter->specific_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.specific_scan_time;
+ if (scan->param.scan_cfg.scan_time.active_scan_time)
+ pmadapter->active_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.active_scan_time;
+ if (scan->param.scan_cfg.scan_time.passive_scan_time)
+ pmadapter->passive_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.passive_scan_time;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get scan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_scan_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *pscan;
+
+ ENTER();
+
+ pscan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MCMND, "Scan already in process...\n");
+ LEAVE();
+ return status;
+ }
+ /* Set scan */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ switch (pscan->sub_command) {
+ case MLAN_OID_SCAN_NORMAL:
+ status = wlan_scan_networks(pmpriv, pioctl_req, MNULL);
+ break;
+ case MLAN_OID_SCAN_SPECIFIC_SSID:
+ status = wlan_scan_specific_ssid(pmpriv, pioctl_req,
+ &pscan->param.scan_req.scan_ssid);
+ break;
+ case MLAN_OID_SCAN_USER_CONFIG:
+ status = wlan_scan_networks(pmpriv, pioctl_req,
+ (wlan_user_scan_cfg *) pscan->param.
+ user_scan.scan_cfg_buf);
+ break;
+ case MLAN_OID_SCAN_CONFIG:
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_SET);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CONFIG)) {
+ PRINTM(MINFO, "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ }
+ /* Get scan */
+ else {
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG) {
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_GET);
+ } else if (pscan->sub_command == MLAN_OID_SCAN_SPECIFIC_SSID) {
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ } else {
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief MLAN station ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+mlan_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ status = wlan_scan_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_BSS:
+ status = wlan_bss_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ status = wlan_radio_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ status = wlan_snmp_mib_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ status = wlan_get_info_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ status = wlan_sec_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ status = wlan_rate_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_POWER_CFG:
+ status = wlan_power_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ status = wlan_pm_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WMM_CFG:
+ status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WPS_CFG:
+ status = wlan_wps_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ status = wlan_11d_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_REG_MEM:
+ status = wlan_reg_mem_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_BCA_CFG:
+ status = wlan_bca_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/wlan_src/mlan/mlan_sta_rx.c b/wlan_src/mlan/mlan_sta_rx.c
new file mode 100755
index 0000000..3994998
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_rx.c
@@ -0,0 +1,250 @@
+/** @file mlan_sta_rx.c
+ *
+ * @brief This file contains the handling of RX in MLAN
+ * module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Ethernet II header */
+typedef struct
+{
+ /** Ethernet II header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header length */
+ t_u16 ethertype;
+
+} EthII_Hdr_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_num];
+ RxPacketHdr_t *prx_pkt;
+ RxPD *prx_pd;
+ int hdr_chop;
+ EthII_Hdr_t *peth_hdr;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ ENTER();
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ DBG_HEXDUMP(MDAT_D, "Rx", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+
+/** Rx packet type debugging */
+#define RX_PKT_TYPE_DEBUG 0xEF
+/** Small debug type */
+#define DBG_TYPE_SMALL 2
+/** Size of debugging structure */
+#define SIZE_OF_DBG_STRUCT 4
+ if (prx_pd->rx_pkt_type == RX_PKT_TYPE_DEBUG) {
+ t_u8 dbgType;
+ dbgType = *(t_u8 *) & prx_pkt->eth803_hdr;
+ if (dbgType == DBG_TYPE_SMALL) {
+ PRINTM(MFW_D, "\n");
+ DBG_HEXDUMP(MFW_D, "FWDBG",
+ (t_s8 *) ((t_u8 *) & prx_pkt->eth803_hdr +
+ SIZE_OF_DBG_STRUCT), prx_pd->rx_pkt_length);
+ PRINTM(MFW_D, "FWDBG::\n");
+ }
+ goto done;
+ }
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ HEXDUMP("RX Data: Dest", prx_pkt->eth803_hdr.dest_addr,
+ sizeof(prx_pkt->eth803_hdr.dest_addr));
+ HEXDUMP("RX Data: Src", prx_pkt->eth803_hdr.src_addr,
+ sizeof(prx_pkt->eth803_hdr.src_addr));
+
+ if (!memcmp(&prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype).
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ peth_hdr = (EthII_Hdr_t *)
+ ((t_u8 *) & prx_pkt->eth803_hdr
+ + sizeof(prx_pkt->eth803_hdr) + sizeof(prx_pkt->rfc1042_hdr)
+ - sizeof(prx_pkt->eth803_hdr.dest_addr)
+ - sizeof(prx_pkt->eth803_hdr.src_addr)
+ - sizeof(prx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(peth_hdr->src_addr, prx_pkt->eth803_hdr.src_addr,
+ sizeof(peth_hdr->src_addr));
+ memcpy(peth_hdr->dest_addr, prx_pkt->eth803_hdr.dest_addr,
+ sizeof(peth_hdr->dest_addr));
+
+ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+ that was removed. */
+ hdr_chop = (t_u8 *) peth_hdr - (t_u8 *) prx_pd;
+ } else {
+ HEXDUMP("RX Data: LLC/SNAP",
+ (t_u8 *) & prx_pkt->rfc1042_hdr, sizeof(prx_pkt->rfc1042_hdr));
+
+ /* Chop off the RxPD */
+ hdr_chop = (t_u8 *) & prx_pkt->eth803_hdr - (t_u8 *) prx_pd;
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ either the reconstructed EthII frame or the 802.2/llc/snap frame */
+ pmbuf->data_len -= hdr_chop;
+ pmbuf->data_offset += hdr_chop;
+ pmbuf->pparent = MNULL;
+
+ priv->rxpd_rate = prx_pd->rx_rate;
+
+ priv->rxpd_htinfo = prx_pd->ht_info;
+
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "RX Error: moal_recv_packet" " returns failure\n");
+ }
+
+ pmadapter->callbacks.moal_get_system_time(&pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%lu : Data => kernel\n", pmbuf->out_ts_sec,
+ pmbuf->out_ts_usec);
+
+ if (ret != MLAN_STATUS_PENDING) {
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ 0, ret);
+ }
+
+ done:
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_process_sta_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_num];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ ret = MLAN_STATUS_FAILURE;
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ pmbuf, 0, ret);
+
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+ if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ pmbuf->data_len = prx_pd->rx_pkt_length;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ wlan_11n_deaggregate_pkt(priv, pmbuf);
+ goto done;
+ }
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if (!IS_11N_ENABLED(priv) ||
+ memcmp(priv->curr_addr, prx_pkt->eth803_hdr.dest_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+
+ if (queuing_ra_based(priv)) {
+ memcpy(ta, prx_pkt->eth803_hdr.src_addr, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memcpy(ta,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf)) ||
+ (prx_pd->rx_pkt_type == PKT_TYPE_BAR)
+ ) {
+ if ((ret =
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ pmbuf, 0, ret)))
+ PRINTM(MERROR, "RX Error: moal_recv_complete returns" " failure\n");
+ }
+
+ done:
+
+ LEAVE();
+ return (ret);
+}
diff --git a/wlan_src/mlan/mlan_sta_tx.c b/wlan_src/mlan/mlan_sta_tx.c
new file mode 100755
index 0000000..f153230
--- /dev/null
+++ b/wlan_src/mlan/mlan_sta_tx.c
@@ -0,0 +1,245 @@
+/** @file mlan_sta_tx.c
+ *
+ * @brief This file contains the handling of data packet
+ * transmission in MLAN module.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function fill the pxpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *
+mlan_process_sta_txpd(IN t_void * priv, IN pmlan_buffer pmbuf)
+{
+ mlan_private *pmpriv = (mlan_private *) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ TxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "Tx Error: bad packet length: %d\n", pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ if (pmbuf->data_offset < (sizeof(TxPD) + INTF_HEADER_LEN +
+ HEADER_ALIGNMENT)) {
+ PRINTM(MERROR, "not enough space for TxPD: %d\n", pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr =
+ pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) - INTF_HEADER_LEN;
+ head_ptr = (t_u8 *) ((t_u32) head_ptr & ~((t_u32) (HEADER_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
+ memset(plocal_tx_pd, 0, sizeof(TxPD));
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = pmpriv->bss_num;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8) pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control
+ = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ pmadapter->tx_lock_flag = MTRUE;
+ plocal_tx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset =
+ (t_u16) ((t_u32) pmbuf->pbuf + pmbuf->data_offset -
+ (t_u32) plocal_tx_pd);
+
+ if (!plocal_tx_pd->tx_control) {
+ /* TxCtrl set by user or default */
+ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
+ }
+
+ endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = head_ptr - pmbuf->pbuf;
+ pmbuf->data_len -= pmbuf->data_offset;
+
+ done:
+ return head_ptr;
+}
+
+/**
+ * @brief This function tells firmware to send a NULL data packet.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param flags Trasmit Pkt Flags
+ *
+ * @return N/A
+ */
+mlan_status
+wlan_send_null_packet(pmlan_private priv, t_u8 flags)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ TxPD *ptx_pd;
+/* sizeof(TxPD) + Interface specific header */
+#define NULL_PACKET_HDR 64
+ t_u32 data_len = NULL_PACKET_HDR + HEADER_ALIGNMENT;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 *ptr;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ if (pmadapter->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->data_sent == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmbuf = wlan_alloc_mlan_buffer(&pmadapter->callbacks, data_len);
+ if (!pmbuf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmbuf->pbuf, 0, data_len);
+ pmbuf->bss_num = priv->bss_num;
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ ptr = (t_u8 *) ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
+ HEADER_ALIGNMENT);
+ pmbuf->data_offset = ptr - pmbuf->pbuf;
+ pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN;
+ ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN);
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+ ptx_pd->flags = flags;
+ ptx_pd->priority = WMM_HIGHEST_PRIORITY;
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+
+ endian_convert_TxPD(ptx_pd);
+
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL);
+
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->data_sent = MTRUE;
+ /* Fall through FAILURE handling */
+ case MLAN_STATUS_FAILURE:
+ wlan_free_mlan_buffer(&pmadapter->callbacks, pmbuf);
+ PRINTM(MERROR, "TX Error: wlan_send_null_packet failed! ret=%d\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ goto done;
+ case MLAN_STATUS_SUCCESS:
+ wlan_free_mlan_buffer(&pmadapter->callbacks, pmbuf);
+ PRINTM(MDATA, "TX: wlan_send_null_packet succeeded!\n");
+ pmadapter->tx_lock_flag = MTRUE;
+ break;
+ case MLAN_STATUS_PENDING:
+ break;
+ default:
+ break;
+ }
+
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MDATA, "%lu.%lu : Null data => FW\n", sec, usec);
+ DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if we need to send last packet indication.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_check_last_packet_indication(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 ret = MFALSE;
+ t_u8 prop_ps = MTRUE;
+
+ ENTER();
+
+ if (!pmadapter->sleep_period.period) {
+ LEAVE();
+ return ret;
+ }
+ if (wlan_wmm_lists_empty(pmadapter)) {
+ if ((
+ /* TODO */
+ (priv->curr_bss_params.wmm_uapsd_enabled == MTRUE) &&
+ priv->wmm_qosinfo) || prop_ps)
+
+ ret = MTRUE;
+ }
+ if (ret && !pmadapter->cmd_sent && !pmadapter->curr_cmd
+ && !IS_COMMAND_PENDING(pmadapter)) {
+ pmadapter->delay_null_pkt = MFALSE;
+ ret = MTRUE;
+ } else {
+ ret = MFALSE;
+ pmadapter->delay_null_pkt = MTRUE;
+ }
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_txrx.c b/wlan_src/mlan/mlan_txrx.c
new file mode 100755
index 0000000..d5b0026
--- /dev/null
+++ b/wlan_src/mlan/mlan_txrx.c
@@ -0,0 +1,243 @@
+/**
+ * @file mlan_txrx.c
+ *
+ * @brief This file contains the handling of TX/RX in MLAN
+ *
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ * All Rights Reserved
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ t_u32 bss_num = 0;
+ RxPD *prx_pd;
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Get the BSS number from RxPD, get corresponding priv */
+ bss_num = prx_pd->bss_num & (MLAN_MAX_BSS_NUM - 1);
+ priv = pmadapter->priv[bss_num];
+ if (!priv) {
+ bss_num = 0;
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
+ }
+ pmbuf->bss_num = bss_num;
+ ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function queues the packet received from
+ * kernel/upper layer and wake up the main thread to handle it.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer includes TX packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_tx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ HEXDUMP("TX Data", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, 100));
+
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to device
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ * @param tx_param A pointer to mlan_tx_param structure
+ *
+ * @return mlan_status
+ */
+mlan_status
+wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 *head_ptr = MNULL;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf);
+ if (!head_ptr) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param);
+ done:
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MDATA, "MLAN_STATUS_RESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: moal_write_data_async failed: 0x%X\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
+ pmadapter->callbacks.moal_get_system_time(&sec, &usec);
+ PRINTM(MDATA, "%lu.%lu : Data => FW\n", sec, usec);
+
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
+ MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet send completion handling
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_write_data_complete(IN pmlan_adapter pmadapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ ASSERT(pmadapter && pmbuf);
+
+ pcb = &pmadapter->callbacks;
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_DATA) {
+ PRINTM(MDATA, "wlan_write_data_complete: DATA\n");
+
+ if (!pmbuf->pdesc) {
+ /* pmbuf was allocated by MLAN */
+ wlan_free_mlan_buffer(&pmadapter->callbacks, pmbuf);
+ } else {
+ /* pmbuf was allocated by MOAL */
+ pcb->moal_send_packet_complete(pmadapter->pmoal_handle,
+ pmbuf, status);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_private pmp;
+ pmlan_callbacks pcb;
+ pmlan_buffer pmbuf_parent;
+
+ ENTER();
+ ASSERT(pmlan_adapter && pmbuf);
+
+ pcb = &pmadapter->callbacks;
+
+ ASSERT(pmbuf->bss_num < MLAN_MAX_BSS_NUM);
+
+ pmp = pmadapter->priv[pmbuf->bss_num];
+
+ if (pmbuf->pparent) {
+ pmbuf_parent = pmbuf->pparent;
+
+ pmadapter->callbacks.moal_spin_lock(pmp->rx_pkt_lock);
+ --pmbuf_parent->use_count;
+ if (!pmbuf_parent->use_count) {
+ pmadapter->callbacks.moal_spin_unlock(pmp->rx_pkt_lock);
+ pcb->moal_recv_complete(pmadapter->pmoal_handle,
+ pmbuf_parent, pmadapter->ioport, status);
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmp->rx_pkt_lock);
+ }
+
+ pcb->moal_mfree((t_u8 *) pmbuf);
+ } else {
+ pcb->moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->ioport, status);
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/wlan_src/mlan/mlan_util.h b/wlan_src/mlan/mlan_util.h
new file mode 100755
index 0000000..704093c
--- /dev/null
+++ b/wlan_src/mlan/mlan_util.h
@@ -0,0 +1,235 @@
+/** @file mlan_util.h
+ *
+ * @brief This file contains wrappers for linked-list,
+ * spinlock and timer defines.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_UTIL_H_
+#define _MLAN_UTIL_H_
+
+/** Circular doubly linked list */
+typedef struct _mlan_linked_list
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+} mlan_linked_list, *pmlan_linked_list;
+
+/** List head */
+typedef struct _mlan_list_head
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+ /** Pointer to lock */
+ t_void *plock;
+} mlan_list_head, *pmlan_list_head;
+
+/**
+ * @brief This function initializes a list without locking
+ *
+ * @param phead List head
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list(pmlan_linked_list phead)
+{
+ /* Both next and prev point to self */
+ phead->pprev = phead->pnext = (pmlan_linked_list) phead;
+}
+
+/**
+ * @brief This function initializes a list
+ *
+ * @param phead List head
+ * @param lock_required A flag for spinlock requirement
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list_head(pmlan_list_head phead,
+ t_u8 lock_required,
+ mlan_status(*moal_init_lock) (t_void ** pplock))
+{
+ /* Both next and prev point to self */
+ util_init_list((pmlan_linked_list) phead);
+ if (lock_required)
+ moal_init_lock(&phead->plock);
+ else
+ phead->plock = 0;
+}
+
+/**
+ * @brief This function frees a list
+ *
+ * @param phead List head
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_free_list_head(pmlan_list_head phead,
+ mlan_status(*moal_free_lock) (t_void * plock))
+{
+ phead->pprev = phead->pnext = 0;
+ if (phead->plock)
+ moal_free_lock(phead->plock);
+}
+
+/**
+ * @brief This function peeks into a list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_peek_list(pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * plock))
+{
+ pmlan_linked_list pnode = 0;
+
+ if (moal_spin_lock)
+ moal_spin_lock(phead->plock);
+ if (phead->pnext != (pmlan_linked_list) phead) {
+ pnode = phead->pnext;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(phead->plock);
+ return pnode;
+}
+
+/**
+ * @brief This function queues a node at the list tail
+ *
+ * @param phead List head
+ * @param pnode List node to queue
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_tail(pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * plock))
+{
+ pmlan_linked_list pold_last;
+
+ if (moal_spin_lock)
+ moal_spin_lock(phead->plock);
+ pold_last = phead->pprev;
+ pnode->pprev = pold_last;
+ pnode->pnext = (pmlan_linked_list) phead;
+
+ phead->pprev = pold_last->pnext = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(phead->plock);
+}
+
+/**
+ * @brief This function adds a node at the list head
+ *
+ * @param phead List head
+ * @param pnode List node to add
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_head(pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * plock))
+{
+ pmlan_linked_list pold_first;
+
+ if (moal_spin_lock)
+ moal_spin_lock(phead->plock);
+ pold_first = phead->pnext;
+ pnode->pprev = (pmlan_linked_list) phead;
+ pnode->pnext = pold_first;
+
+ phead->pnext = pold_first->pprev = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(phead->plock);
+}
+
+/**
+ * @brief This function removes a node from the list
+ *
+ * @param phead List head
+ * @param pnode List node to remove
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_unlink_list(pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * plock))
+{
+ pmlan_linked_list pmy_prev;
+ pmlan_linked_list pmy_next;
+
+ if (moal_spin_lock)
+ moal_spin_lock(phead->plock);
+ pmy_prev = pnode->pprev;
+ pmy_next = pnode->pnext;
+ pmy_next->pprev = pmy_prev;
+ pmy_prev->pnext = pmy_next;
+
+ pnode->pnext = pnode->pprev = 0;
+ if (moal_spin_unlock)
+ moal_spin_unlock(phead->plock);
+}
+
+/**
+ * @brief This function dequeues a node from the list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_dequeue_list(pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * plock))
+{
+ pmlan_linked_list pnode;
+
+ if (moal_spin_lock)
+ moal_spin_lock(phead->plock);
+ pnode = phead->pnext;
+ if (pnode != (pmlan_linked_list) phead) {
+ util_unlink_list(phead, pnode, 0, 0);
+ } else {
+ pnode = 0;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(phead->plock);
+ return pnode;
+}
+
+#endif /* !_MLAN_UTIL_H_ */
diff --git a/wlan_src/mlan/mlan_wmm.c b/wlan_src/mlan/mlan_wmm.c
new file mode 100755
index 0000000..6b6dfe9
--- /dev/null
+++ b/wlan_src/mlan/mlan_wmm.c
@@ -0,0 +1,1888 @@
+/** @file mlan_wmm.c
+ *
+ * @brief This file contains functions for WMM.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/********************************************************
+Change log:
+ 10/24/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX 512
+
+/*
+ * Upper and Lower threshold for packet queuing in the driver
+
+ * - When the number of packets queued reaches the upper limit,
+ * the driver will stop the net queue in the app/kernel space.
+
+ * - When the number of packets drops beneath the lower limit after
+ * having reached the upper limit, the driver will restart the net
+ * queue.
+ */
+
+/** Lower threshold for packet queuing in the driver.
+ * When the number of packets drops beneath the lower limit after having
+ * reached the upper limit, the driver will restart the net queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
+
+/** Upper threshold for packet queuing in the driver.
+ * When the number of packets queued reaches the upper limit, the driver
+ * will stop the net queue in the app/kernel space.
+ */
+#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** WMM information IE */
+static const t_u8 wmm_info_ie[] = { WMM_IE, 0x07,
+ 0x00, 0x50, 0xf2, 0x02,
+ 0x00, 0x01, 0x00
+};
+
+/**
+ * AC Priorities go from AC_BK to AC_VO. The ACI enumeration for AC_BK (1)
+ * is higher than the enumeration for AC_BE (0); hence the needed
+ * mapping conversion for wmm AC to priority Queue Index
+ */
+static const t_u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VO
+};
+
+/**
+ * This table will be used to store the tid values based on ACs.
+ * It is initialized to default values per TID.
+ */
+t_u8 tos_to_tid[] = {
+ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+ 0x01, /* 0 1 0 AC_BK */
+ 0x02, /* 0 0 0 AC_BK */
+ 0x00, /* 0 0 1 AC_BE */
+ 0x03, /* 0 1 1 AC_BE */
+ 0x04, /* 1 0 0 AC_VI */
+ 0x05, /* 1 0 1 AC_VI */
+ 0x06, /* 1 1 0 AC_VO */
+ 0x07 /* 1 1 1 AC_VO */
+};
+
+/**
+ * This table will provide the tid value for given ac. This table does not change
+ * and will be used to copy back the deafult values to tos_to_tid in case of
+ * disconnect.
+ */
+t_u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/**
+ * @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ * @param pac_param Pointer to the AC parameters to display
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)
+{
+ const char *ac_str[] = { "BK", "BE", "VI", "VO" };
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+ ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
+ pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
+ pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
+ pac_param->ecw.ecw_max, wlan_le16_to_cpu(pac_param->tx_op_limit));
+
+ LEAVE();
+}
+
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
+#else
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param)
+#endif
+
+/**
+ * @brief Allocate route address
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ra Pointer to the route address
+ *
+ * @return ra_list
+ */
+raListTbl *
+wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ if (pmadapter->callbacks.
+ moal_malloc(sizeof(raListTbl), (t_u8 **) & ra_list)) {
+ PRINTM(MERROR, "Fail to allocate ra_list\n");
+ goto done;
+ }
+ util_init_list((pmlan_linked_list) ra_list);
+ util_init_list_head(&ra_list->buf_head, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ memcpy(ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ ra_list->total_pkts_size = 0;
+
+ PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
+ done:
+ LEAVE();
+ return ra_list;
+}
+
+/**
+ * @brief This function cleans Tx/Rx queues
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+t_void
+wlan_clean_txrx(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ wlan_wmm_cleanup_queues(priv);
+ wlan_11n_cleanup_reorder_tbl(priv);
+ wlan_11n_deleteall_txbastream_tbl(priv);
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ MP_TX_AGGR_BUF_RESET(priv->adapter);
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ MP_RX_AGGR_BUF_RESET(priv->adapter);
+#endif
+ wlan_wmm_delete_all_ralist(priv);
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+
+ memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+
+ LEAVE();
+}
+
+/**
+ * @brief Allocate and add a RA list for all TIDs with the given RA
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra Address of the receiver STA (AP in case of infra)
+ *
+ * @return N/A
+ */
+void
+wlan_ralist_add(mlan_private * priv, t_u8 * ra)
+{
+ int i;
+ raListTbl *ra_list;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
+ PRINTM(MINFO, "Creating RA List %p\n", ra_list);
+ if (!ra_list)
+ break;
+ if (queuing_ra_based(priv))
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
+ else
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ PRINTM(MDATA, "ralist %p: is_11n_enabled=%d\n", ra_list,
+ ra_list->is_11n_enabled);
+ util_enqueue_list_tail(&priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Set the WMM queue priorities to their default values
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_default_queue_priorities(pmlan_private priv)
+{
+ ENTER();
+
+ /* Default queue priorities: VO->VI->BE->BK */
+ priv->wmm.queue_priority[0] = WMM_AC_VO;
+ priv->wmm.queue_priority[1] = WMM_AC_VI;
+ priv->wmm.queue_priority[2] = WMM_AC_BE;
+ priv->wmm.queue_priority[3] = WMM_AC_BK;
+
+ LEAVE();
+}
+
+/**
+ * @brief Map ACs to TID
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param queue_priority Queue_priority structure
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_queue_priorities_tid(pmlan_private priv, t_u8 queue_priority[])
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < 4; ++i) {
+ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize WMM priority queues
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param pwmm_ie Pointer to the IEEEtypes_WmmParameter_t data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * pwmm_ie)
+{
+ t_u16 cw_min, avg_back_off, tmp[4];
+ t_u32 i, j, num_ac;
+ t_u8 ac_idx;
+
+ ENTER();
+
+ if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, just set the defaults and return */
+ wlan_wmm_default_queue_priorities(priv);
+ LEAVE();
+ return;
+ }
+
+ HEXDUMP("WMM: setup_queue_priorities: param IE",
+ (t_u8 *) pwmm_ie, sizeof(IEEEtypes_WmmParameter_t));
+
+ PRINTM(MINFO, "WMM Parameter IE: version=%d, "
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
+ pwmm_ie->reserved);
+
+ for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
+ cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
+ avg_back_off =
+ (cw_min >> 1) + pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
+
+ ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac].aci_aifsn.aci];
+ priv->wmm.queue_priority[ac_idx] = ac_idx;
+ tmp[ac_idx] = avg_back_off;
+
+ PRINTM(MINFO, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
+ cw_min, avg_back_off);
+ PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
+ }
+
+ HEXDUMP("WMM: avg_back_off", (t_u8 *) tmp, sizeof(tmp));
+ HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+
+ /* Bubble sort */
+ for (i = 0; i < num_ac; i++) {
+ for (j = 1; j < num_ac - i; j++) {
+ if (tmp[j - 1] > tmp[j]) {
+ SWAP_U16(tmp[j - 1], tmp[j]);
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ } else if (tmp[j - 1] == tmp[j]) {
+ if (priv->wmm.queue_priority[j - 1]
+ < priv->wmm.queue_priority[j]) {
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ }
+ }
+ }
+ }
+
+ wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+
+ HEXDUMP("WMM: avg_back_off, sort", (t_u8 *) tmp, sizeof(tmp));
+ HEXDUMP("WMM: queue_priority, sort", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+ LEAVE();
+}
+
+/**
+ * @brief Evaluate whether or not an AC is to be downgraded
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param eval_ac AC to evaluate for downgrading
+ *
+ * @return WMM AC The eval_ac traffic is to be sent on.
+ */
+static mlan_wmm_ac_e
+wlan_wmm_eval_downgrade_ac(pmlan_private priv, mlan_wmm_ac_e eval_ac)
+{
+ int down_ac;
+ mlan_wmm_ac_e ret_ac;
+ WmmAcStatus_t *pac_status;
+
+ ENTER();
+
+ pac_status = &priv->wmm.ac_status[eval_ac];
+
+ if (pac_status->disabled == MFALSE) {
+ LEAVE();
+ /* Okay to use this AC, its enabled */
+ return eval_ac;
+ }
+
+ /* Setup a default return value of the lowest priority */
+ ret_ac = WMM_AC_BK;
+
+ /*
+ * Find the highest AC that is enabled and does not require admission
+ * control. The spec disallows downgrading to an AC, which is enabled
+ * due to a completed admission control. Unadmitted traffic is not
+ * to be sent on an AC with admitted traffic.
+ */
+ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+ pac_status = &priv->wmm.ac_status[down_ac];
+
+ if ((pac_status->disabled == MFALSE)
+ && (pac_status->flow_required == MFALSE))
+ /* AC is enabled and does not require admission control */
+ ret_ac = (mlan_wmm_ac_e) down_ac;
+ }
+
+ LEAVE();
+ return ret_ac;
+}
+
+/**
+ * @brief Downgrade WMM priority queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_ac_downgrade(pmlan_private priv)
+{
+ int ac_val;
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+ if (priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, default priorities */
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val] = (mlan_wmm_ac_e) ac_val;
+ }
+ }
+ } else {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val]
+ = wlan_wmm_eval_downgrade_ac(priv, (mlan_wmm_ac_e) ac_val);
+ PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n",
+ ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param tos IP TOS field
+ *
+ * @return WMM AC Queue mapping of the IP TOS field
+ */
+static mlan_wmm_ac_e
+wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter, t_u32 tos)
+{
+ /* Map of TOS UP values to WMM AC */
+ const mlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+ };
+
+ ENTER();
+
+ if (tos >= NELEMENTS(tos_to_ac)) {
+ LEAVE();
+ return WMM_AC_BE;
+ }
+
+ LEAVE();
+ return tos_to_ac[tos];
+}
+
+/**
+ * @brief Evaluate a given TID and downgrade it to a lower TID if the
+ * WMM Parameter IE received from the AP indicates that the AP
+ * is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care internally
+ *
+ * @param priv Pointer to the mlan_private data struct
+ * @param tid tid to evaluate for downgrading
+ *
+ * @return Same tid as input if downgrading not required or
+ * the tid the traffic for the given tid should be downgraded to
+ */
+static t_u8 INLINE
+wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
+{
+ mlan_wmm_ac_e ac_down;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ ac_down =
+ priv->wmm.
+ ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter, tid)];
+
+ LEAVE();
+ /*
+ * Send the index to tid array, picking from the array will be
+ * taken care by dequeuing function
+ */
+ return ac_to_tid[ac_down][tid % 2];
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ * @param pmadapter Pointer to the mlan_adapter data structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_init(pmlan_adapter pmadapter)
+{
+ int i, j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+ memset(&priv->wmm, 0x00, sizeof(priv->wmm));
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].amsdu = tos_to_tid[i];
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid[i];
+
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ util_init_list_head(&priv->wmm.tid_tbl_ptr[i].ra_list, MTRUE,
+ priv->adapter->callbacks.moal_init_lock);
+ }
+
+ priv->aggr_prio_tbl[6].amsdu = priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ priv->add_ba_param.tx_win_size = MLAN_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_AMPDU_DEF_RXWINSIZE;
+ priv->adapter->callbacks.moal_init_lock(&priv->wmm.
+ ra_list_spinlock);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Setup the queue priorities and downgrade any queues as required
+ * by the WMM info. Setups default values if WMM is not active
+ * for this association.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queues(pmlan_private priv)
+{
+ ENTER();
+ wlan_wmm_setup_queue_priorities(priv, MNULL);
+ wlan_wmm_setup_ac_downgrade(priv);
+ LEAVE();
+}
+
+/**
+ * @brief Send a command to firmware to retrieve the current WMM status
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_wmm_status_change(pmlan_private priv)
+{
+ return wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, MNULL);
+}
+
+/**
+ * @brief Check if RA list is empty or not
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ra_list_hhead RA list header
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+static INLINE t_u8
+wlan_wmm_is_ra_list_empty(pmlan_adapter pmadapter,
+ mlan_list_head * ra_list_hhead)
+{
+ raListTbl *ra_list;
+
+ ra_list = (raListTbl *) ra_list_hhead->pnext;
+
+ while (ra_list != (raListTbl *) ra_list_hhead) {
+ if (util_peek_list(&ra_list->buf_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ ra_list = (raListTbl *) ra_list->pnext;
+ }
+
+ return MTRUE;
+}
+
+/**
+ * @brief Check if wmm TX queue is empty
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+int
+wlan_wmm_lists_empty(pmlan_adapter pmadapter)
+{
+ int i, j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (!wlan_wmm_is_ra_list_empty(pmadapter,
+ &priv->wmm.tid_tbl_ptr[i].
+ ra_list)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ }
+ }
+
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief Delete packets in RA node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv, raListTbl * ra_list)
+{
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+ while ((pmbuf = (pmlan_buffer) util_peek_list(&ra_list->buf_head,
+ MNULL, MNULL))) {
+ util_unlink_list(&ra_list->buf_head, (pmlan_linked_list) pmbuf, MNULL,
+ MNULL);
+
+ pmadapter->callbacks.moal_send_packet_complete(pmadapter->pmoal_handle,
+ pmbuf,
+ MLAN_STATUS_FAILURE);
+ }
+ util_free_list_head(&ra_list->buf_head,
+ pmadapter->callbacks.moal_free_lock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist(pmlan_private priv, mlan_list_head * ra_list_head)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ ra_list = (raListTbl *) util_peek_list(ra_list_head, MNULL, MNULL);
+
+ while (ra_list && ra_list != (raListTbl *) ra_list_head) {
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Clean up the wmm queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_cleanup_queues(pmlan_private priv)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ wlan_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].ra_list);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Clean up initilized queues
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_cleanup_node(pmlan_private priv)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM_TID; ++i)
+ util_free_list_head(&priv->wmm.tid_tbl_ptr[i].ra_list,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head(&priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head(&priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+}
+
+/**
+ * @brief Delete all route address from RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_delete_all_ralist(pmlan_private priv)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
+ while ((ra_list =
+ (raListTbl *) util_peek_list(&priv->wmm.tid_tbl_ptr[i].ra_list,
+ MNULL, MNULL))) {
+ util_unlink_list(&priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree((t_u8 *) ra_list);
+ }
+
+ util_init_list((pmlan_linked_list)
+ & priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Get ralist node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list or MNULL
+ */
+raListTbl *
+wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+ ENTER();
+ ra_list = (raListTbl *) util_peek_list(&priv->wmm.tid_tbl_ptr[tid].ra_list,
+ MNULL, MNULL);
+ while (ra_list && (ra_list != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[tid].ra_list)) {
+ if (!memcmp(ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return ra_list;
+ }
+ ra_list = ra_list->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Get queue RA pointer
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list
+ */
+raListTbl *
+wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ if (ra_list) {
+ LEAVE();
+ return ra_list;
+ }
+ wlan_ralist_add(priv, ra_addr);
+
+ LEAVE();
+ return wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+}
+
+int
+wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int ptrindex)
+{
+ raListTbl *rlist;
+
+ rlist = (raListTbl *) util_peek_list(&priv->wmm.
+ tid_tbl_ptr[ptrindex].ra_list, MNULL,
+ MNULL);
+
+ while (rlist && (rlist != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
+ if (rlist == ra_list)
+ return MTRUE;
+
+ rlist = rlist->pnext;
+ }
+
+ return MFALSE;
+}
+
+/**
+ * @brief Add packet to WMM queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_num];
+ t_u32 tid;
+ raListTbl *ra_list;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
+
+ ENTER();
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ pmbuf->flags = 0;
+
+ tid = pmbuf->priority;
+ tid_down = wlan_wmm_downgrade_tid(priv, tid);
+
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ /* In case of infra as we have already created the list during association
+ we just don't have to call get_queue_raptr, we will have only 1 raptr
+ for a tid in case of infra */
+ if (!queuing_ra_based(priv)) {
+ ra_list =
+ (raListTbl *) util_peek_list(&priv->wmm.tid_tbl_ptr[tid_down].
+ ra_list, MNULL, MNULL);
+ } else {
+ memcpy(ra, pmbuf->pbuf + pmbuf->data_offset, MLAN_MAC_ADDR_LENGTH);
+ ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
+ }
+
+ if (!ra_list) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MDAT_D, "Adding pkt to ra_list %p %p\n", ra_list, pmbuf);
+ util_enqueue_list_tail(&ra_list->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ ra_list->total_pkts_size += pmbuf->data_len;
+// PRINTM(MERROR, "[+%d->%u] ", pmbuf->data_len, ra_list->total_pkts_size);
+
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ pmadapter->callbacks.moal_get_system_time(&pmbuf->in_ts_sec,
+ &pmbuf->in_ts_usec);
+
+ LEAVE();
+}
+
+/**
+ * @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ * The GET_WMM_STATUS command returns multiple TLVs for:
+ * - Each AC Queue status
+ * - Current WMM Parameter IE
+ *
+ * This function parses the TLVs and then calls further functions
+ * to process any changes in the queue prioritize or state.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param resp Pointer to the command response buffer including TLVs
+ * TLVs for each queue and the WMM Parameter IE.
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_get_status(pmlan_private priv, const HostCmd_DS_COMMAND * resp)
+{
+ t_u8 *pcurrent = (t_u8 *) & resp->params.get_wmm_status;
+ t_u32 resp_len = resp->size;
+ int valid = MTRUE;
+
+ MrvlIEtypes_Data_t *pTlvHdr;
+ MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
+ IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
+ WmmAcStatus_t *pac_status;
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
+ HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
+
+ while ((resp_len >= sizeof(pTlvHdr->header)) && valid) {
+ pTlvHdr = (MrvlIEtypes_Data_t *) pcurrent;
+ pTlvHdr->header.len = wlan_le16_to_cpu(pTlvHdr->header.len);
+
+ switch (wlan_le16_to_cpu(pTlvHdr->header.type)) {
+ case TLV_TYPE_WMMQSTATUS:
+ pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
+ PRINTM(MINFO, "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+ pTlvWmmQStatus->queue_index,
+ pTlvWmmQStatus->flow_required, pTlvWmmQStatus->disabled);
+
+ pac_status = &priv->wmm.ac_status[pTlvWmmQStatus->queue_index];
+ pac_status->disabled = pTlvWmmQStatus->disabled;
+ pac_status->flow_required = pTlvWmmQStatus->flow_required;
+ pac_status->flow_created = pTlvWmmQStatus->flow_created;
+ break;
+
+ case WMM_IE:
+ /*
+ * Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+
+ HEXDUMP("WMM: WMM TLV:", (t_u8 *) pTlvHdr, pTlvHdr->header.len + 4);
+
+ pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pcurrent + 2);
+ pWmmParamIe->vend_hdr.len = (t_u8) pTlvHdr->header.len;
+ pWmmParamIe->vend_hdr.element_id = WMM_IE;
+
+ PRINTM(MINFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+ pWmmParamIe->qos_info.para_set_count);
+
+ memcpy((t_u8 *) & priv->curr_bss_params.bss_descriptor.wmm_ie,
+ pWmmParamIe, pWmmParamIe->vend_hdr.len + 2);
+
+ break;
+
+ default:
+ valid = MFALSE;
+ break;
+ }
+
+ pcurrent += (pTlvHdr->header.len + sizeof(pTlvHdr->header));
+ resp_len -= (pTlvHdr->header.len + sizeof(pTlvHdr->header));
+ }
+
+ wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
+ wlan_wmm_setup_ac_downgrade(priv);
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, MNULL);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Call back from the command module to allow insertion of a WMM TLV
+ *
+ * If the BSS we are associating to supports WMM, add the required WMM
+ * Information IE to the association request command buffer in the form
+ * of a Marvell extended IEEE IE.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ppAssocBuf Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended WMM TLV
+ * @param pWmmIE Pointer to the WMM IE for the BSS we are joining
+ * @param pHTCap Pointer to the HT IE for the BSS we are joining
+ *
+ * @return Length of data appended to the association tlv buffer
+ */
+t_u32
+wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap)
+{
+ MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
+ t_u32 ret_len = 0;
+
+ ENTER();
+
+ /* Null checks */
+ if (!ppAssocBuf) {
+ LEAVE();
+ return 0;
+ }
+ if (!(*ppAssocBuf)) {
+ LEAVE();
+ return 0;
+ }
+
+ if (!pWmmIE) {
+ LEAVE();
+ return 0;
+ }
+
+ PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
+ pWmmIE->vend_hdr.element_id);
+
+ if ((priv->wmm_required
+ || (pHTCap && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY)
+ && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN))
+ )
+ && pWmmIE->vend_hdr.element_id == WMM_IE) {
+ pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
+ pwmm_tlv->header.type = (t_u16) wmm_info_ie[0];
+ pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
+ pwmm_tlv->header.len = (t_u16) wmm_info_ie[1];
+ memcpy(pwmm_tlv->wmm_ie, &wmm_info_ie[2], pwmm_tlv->header.len);
+ if (pWmmIE->qos_info.qos_uapsd)
+ memcpy((t_u8 *) (pwmm_tlv->wmm_ie + pwmm_tlv->header.len
+ - sizeof(priv->wmm_qosinfo)),
+ &priv->wmm_qosinfo, sizeof(priv->wmm_qosinfo));
+
+ ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
+ pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
+
+ HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *) pwmm_tlv, ret_len);
+ *ppAssocBuf += ret_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Compute the time delay in the driver queues for a given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param pmbuf Pointer to the mlan_buffer which has been previously timestamped
+ *
+ * @return Time delay of the packet in 2ms units after having limit applied
+ */
+t_u8
+wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf)
+{
+ t_u8 retVal = 0;
+ t_u32 out_ts_sec, out_ts_usec, queue_delay;
+
+ ENTER();
+
+ priv->adapter->callbacks.moal_get_system_time(&out_ts_sec, &out_ts_usec);
+
+ queue_delay = (out_ts_sec - pmbuf->in_ts_sec) * 1000;
+ queue_delay += (out_ts_usec - pmbuf->in_ts_usec) / 1000;
+
+ /*
+ * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+ *
+ * Pass max value if queue_delay is beyond the uint8 range
+ */
+ retVal = (t_u8) (MIN(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+ PRINTM(MDATA, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
+ queue_delay, retVal);
+
+ LEAVE();
+ return retVal;
+}
+
+/**
+ * @brief This function gets the highest priority list pointer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param priv A pointer to mlan_private
+ * @param tid A pointer to return tid
+ *
+ * @return raListTbl
+ */
+static raListTbl *
+wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
+ pmlan_private * priv, int *tid)
+{
+ pmlan_private priv_tmp;
+ raListTbl *ptr, *head;
+ mlan_bssprio_node *bssprio_node, *bssprio_head;
+ tid_tbl_t *tid_ptr;
+ int i, j;
+
+ ENTER();
+
+ PRINTM(MDAT_D, "POP\n");
+ for (j = MLAN_MAX_BSS_NUM - 1; j >= 0; --j) {
+ if (!(util_peek_list(&pmadapter->bssprio_tbl[j].bssprio_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)))
+ continue;
+
+ if (pmadapter->bssprio_tbl[j].bssprio_cur == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head)
+ bssprio_head = bssprio_node =
+ pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
+ else
+ bssprio_head = bssprio_node = pmadapter->bssprio_tbl[j].bssprio_cur;
+
+ do {
+ priv_tmp = bssprio_node->priv;
+
+ for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
+
+ tid_ptr = &(priv_tmp)->wmm.tid_tbl_ptr[tos_to_tid[i]];
+ if (!util_peek_list(&tid_ptr->ra_list,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock))
+ continue;
+
+ /*
+ * Always choose the next ra we transmitted
+ * last time, this way we pick the ra's in
+ * round robin fashion.
+ */
+ if (tid_ptr->ra_list_curr->pnext !=
+ (raListTbl *) & tid_ptr->ra_list)
+ head = ptr = tid_ptr->ra_list_curr->pnext;
+ else
+ head = ptr = tid_ptr->ra_list_curr;
+
+ do {
+ if (util_peek_list(&ptr->buf_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ *priv = priv_tmp;
+ *tid = tos_to_tid[i];
+ LEAVE();
+ return ptr;
+ }
+
+ if ((ptr = ptr->pnext) == (raListTbl *) & tid_ptr->ra_list)
+ ptr = ptr->pnext;
+ } while (ptr != head);
+ }
+
+ if ((bssprio_node = bssprio_node->pnext) == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head)
+ bssprio_node = bssprio_node->pnext;
+ } while (bssprio_node != bssprio_head);
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function gets the number of packets in the Tx queue
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param maxBufSize Maximum buffer size
+ *
+ * @return Packet count
+ */
+static int
+wlan_num_pkts_in_txq(mlan_private * priv, raListTbl * ptr, int maxBufSize)
+{
+ int count = 0, total_size = 0;
+ pmlan_buffer pmbuf;
+
+ ENTER();
+
+ for (pmbuf = (pmlan_buffer) ptr->buf_head.pnext;
+ pmbuf != (pmlan_buffer) (&ptr->buf_head); pmbuf = pmbuf->pnext) {
+
+ total_size += pmbuf->data_len;
+ if (total_size < maxBufSize)
+ ++count;
+ else
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function sends a single packet
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_single_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf;
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(&ptr->buf_head,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ PRINTM(MDATA, "Dequeuing the packet %p %p\n", ptr, pmbuf);
+
+ ptr->total_pkts_size -= pmbuf->data_len;
+ pmbuf_next =
+ (pmlan_buffer) util_peek_list(&ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ status = wlan_process_tx(priv, pmbuf, &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /** Queue the packet back at the head */
+ PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n", ptr, pmbuf);
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ util_enqueue_list_head(&ptr->buf_head,
+ (pmlan_linked_list) pmbuf,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ ptr->total_pkts_size += pmbuf->data_len;
+ pmbuf->flags = MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ } else {
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ PRINTM(MDATA, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function checks if this mlan_buffer is already processed.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_ptr_processed(mlan_private * priv, raListTbl * ptr)
+{
+ pmlan_buffer pmbuf;
+
+ if ((pmbuf = (pmlan_buffer) util_peek_list(&ptr->buf_head, MNULL, MNULL))
+ && (pmbuf->flags == MLAN_BUF_FLAG_REQUEUED_PKT))
+ return MTRUE;
+
+ return MFALSE;
+}
+
+/**
+ * @brief This function sends a single packet
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_processed_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(&ptr->buf_head,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ pmbuf_next =
+ (pmlan_buffer) util_peek_list(&ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MDATA, "MLAN_STATUS_RESOURCE is returned\n");
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ util_enqueue_list_head(&ptr->buf_head,
+ (pmlan_linked_list) pmbuf,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+
+ pmbuf->flags = MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: moal_write_data failed: 0x%X\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ }
+}
+
+/**
+ * @brief This function dequeues a packet
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS;
+ */
+static int
+wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
+{
+ raListTbl *ptr;
+ pmlan_private priv = MNULL;
+ int ptrindex = 0;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ int tid = 0;
+ t_u8 avail_ports = 0;
+ int i;
+
+ ENTER();
+
+ if (!(ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ tid = wlan_get_tid(priv->adapter, ptr);
+ for (i = 1; i < pmadapter->mp_end_port; i++) {
+ if ((pmadapter->mp_wr_bitmap >> i) & 1)
+ avail_ports++;
+ }
+
+ PRINTM(MDATA,
+ "mp_wr_bitmap=0x%04x avail_ports=%d tid=%d tx_eligibility[%d]=%d\n",
+ pmadapter->mp_wr_bitmap, avail_ports, tid, tid,
+ pmadapter->tx_eligibility[tid]);
+
+ if (avail_ports < pmadapter->tx_eligibility[tid]) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmadapter->callbacks.moal_spin_lock(priv->wmm.ra_list_spinlock);
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Note:- Spinlock are unlocked in wlan_send_processed_packet ,
+ wlan_send_single_packet or wlan_11n_aggregate_pkt. The spinlock would
+ be required for some parts of both of function. But, the the bulk of
+ these function will execute w/o spinlock. Unlocking the spinlock
+ inside these function will help us avoid taking the spinlock again,
+ check to see if the ptr is still valid and then proceed. This is done
+ purely to increase execution time. */
+
+ /* Note:- Also, anybody adding code which does not get into
+ wlan_send_processed_packet, wlan_send_single_packet, or
+ wlan_11n_aggregate_pkt should make sure ra_list_spinlock is freed.
+ Otherwise there would be a lock up. */
+
+ if (wlan_is_ptr_processed(priv, ptr)) {
+ wlan_send_processed_packet(priv, ptr, ptrindex);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ if (!ptr->is_11n_enabled || wlan_is_bastream_setup(priv, ptr)
+ || ((priv->sec_info.ewpa_enabled == MFALSE) &&
+ ((priv->sec_info.wpa_enabled
+ || priv->sec_info.wpa2_enabled) &&
+ priv->wpa_is_gtk_set == MFALSE))
+ ) {
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ } else {
+ if (wlan_is_ampdu_allowed(priv, ptr)) {
+ if (wlan_is_bastream_avail(priv)) {
+ tid = wlan_get_tid(priv->adapter, ptr);
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_addba(priv, tid, ptr->ra);
+ } else if (wlan_find_stream_to_delete(priv, ptr, &tid, ra)) {
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra,
+ wlan_get_tid(priv->adapter, ptr),
+ BA_STREAM_SETUP_INPROGRESS);
+
+ wlan_send_delba(priv, tid, ra, 1);
+ }
+ }
+/** Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+ if (wlan_is_amsdu_allowed(priv, ptr) &&
+ (wlan_num_pkts_in_txq(priv, ptr,
+ pmadapter->tx_buf_size) >= MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
+ } else {
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_process_tx(pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ do {
+ /* Check if busy */
+ if (pmadapter->data_sent || pmadapter->tx_lock_flag)
+ break;
+
+ if (wlan_dequeue_tx_packet(pmadapter))
+ break;
+ } while (MTRUE);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares the command of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *) pdata_buf;
+ HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token)
+ + sizeof(pcmd_addts->timeout_ms)
+ + sizeof(pcmd_addts->command_result)
+ + sizeof(pcmd_addts->ieee_status_code)
+ + paddts->tspec_data_len + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
+ pcmd_addts->dialog_token = paddts->dialog_tok;
+ memcpy(pcmd_addts->tspec_data, paddts->tspec_data, paddts->tspec_data_len);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_addts *paddts = MNULL;
+ const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ paddts = (mlan_ds_wmm_addts *) & pwmm->param.addts;
+ paddts->result = presp_addts->command_result;
+ paddts->dialog_tok = presp_addts->dialog_token;
+ paddts->status_code = (t_u32) presp_addts->ieee_status_code;
+
+ if (presp_addts->command_result == MLAN_CMD_RESULT_SUCCESS) {
+ /* The tspecData field is potentially variable in size due to extra
+ IEs that may have been in the ADDTS response action frame.
+ Calculate the data length from the firmware command response. */
+ paddts->tspec_data_len = (t_u8) (resp->size
+ -
+ sizeof(presp_addts->command_result)
+ - sizeof(presp_addts->timeout_ms)
+ - sizeof(presp_addts->dialog_token)
+ -
+ sizeof(presp_addts->
+ ieee_status_code)
+ - S_DS_GEN);
+
+ /* Copy the TSPEC data include any extra IEs after the TSPEC */
+ memcpy(paddts->tspec_data, presp_addts->tspec_data,
+ paddts->tspec_data_len);
+ } else {
+ paddts->tspec_data_len = 0;
+ }
+ PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+ paddts->result, paddts->status_code, paddts->tspec_data_len);
+
+ HEXDUMP("TSPEC: ADDTS data",
+ paddts->tspec_data, paddts->tspec_data_len);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *) pdata_buf;
+ HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token)
+ + sizeof(pcmd_delts->command_result)
+ + sizeof(pcmd_delts->ieee_reason_code)
+ + pdelts->tspec_data_len + S_DS_GEN);
+ cmd->result = 0;
+ pcmd_delts->ieee_reason_code = (t_u8) pdelts->status_code;
+ memcpy(pcmd_delts->tspec_data, pdelts->tspec_data, pdelts->tspec_data_len);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.delts.result = presp_delts->command_result;
+ PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
+ presp_delts->command_result);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_qcfg->action)
+ + sizeof(pcmd_qcfg->access_category)
+ + sizeof(pcmd_qcfg->msdu_lifetime_expiry)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qcfg->action = pqcfg->action;
+ pcmd_qcfg->access_category = pqcfg->access_category;
+ pcmd_qcfg->msdu_lifetime_expiry =
+ wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg = &resp->params.queue_config;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.q_cfg.action = presp_qcfg->action;
+ pwmm->param.q_cfg.access_category = presp_qcfg->access_category;
+ pwmm->param.q_cfg.msdu_lifetime_expiry =
+ wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qstats->action = pqstats->action;
+ pcmd_qstats->access_category = pqstats->access_category;
+ pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
+ pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
+ pcmd_qstats->avg_queue_delay = wlan_cpu_to_le32(pqstats->avg_queue_delay);
+ pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
+ pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
+ pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pcmd_qstats->delay_histogram[id] =
+ wlan_cpu_to_le16(pqstats->delay_histogram[id]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_queue_stats *pqstats = MNULL;
+ const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats = &resp->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ pqstats->action = presp_qstats->action;
+ pqstats->access_category = presp_qstats->access_category;
+ pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
+ pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
+ pqstats->avg_queue_delay =
+ wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
+ pqstats->avg_tx_delay = wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
+ pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
+ pqstats->policed_time = wlan_le16_to_cpu(presp_qstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pqstats->delay_histogram[id] =
+ wlan_le16_to_cpu(presp_qstats->delay_histogram[id]);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *) pdata_buf;
+ HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ memcpy((t_void *) pcmd_ts_status, (t_void *) pts_status,
+ sizeof(HostCmd_DS_WMM_TS_STATUS));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ presp_ts_status->medium_time =
+ wlan_le16_to_cpu(presp_ts_status->medium_time);
+ memcpy((t_void *) & pwmm->param.ts_status, (t_void *) presp_ts_status,
+ sizeof(mlan_ds_wmm_ts_status));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mlan/mlan_wmm.h b/wlan_src/mlan/mlan_wmm.h
new file mode 100755
index 0000000..055d7e0
--- /dev/null
+++ b/wlan_src/mlan/mlan_wmm.h
@@ -0,0 +1,161 @@
+/** @file mlan_wmm.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+/****************************************************
+Change log:
+ 10/24/2008: initial version
+****************************************************/
+
+#ifndef _MLAN_WMM_H_
+#define _MLAN_WMM_H_
+
+/**
+ * @brief This function gets the TID
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ptr A pointer to RA list table
+ *
+ * @return TID
+ */
+static INLINE int
+wlan_get_tid(pmlan_adapter pmadapter, raListTbl * ptr)
+{
+ pmlan_buffer mbuf;
+
+ ENTER();
+
+ mbuf = (pmlan_buffer) util_peek_list(&ptr->buf_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ LEAVE();
+ return mbuf->priority;
+}
+
+/**
+ * @brief This function gets the length of a list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param head A pointer to mlan_list_head
+ *
+ * @return Length of list
+ */
+static INLINE int
+wlan_wmm_list_len(pmlan_adapter pmadapter, pmlan_list_head head)
+{
+ pmlan_linked_list pos;
+ int count = 0;
+
+ ENTER();
+
+ pos = head->pnext;
+
+ while (pos != (pmlan_linked_list) head) {
+ ++count;
+ pos = pos->pnext;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/** Allocate RA list node */
+raListTbl *wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra);
+/** Add buffer to WMM Tx queue */
+void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Delete all RA lists */
+void wlan_wmm_delete_all_ralist(pmlan_private priv);
+/** Add to RA list */
+void wlan_ralist_add(mlan_private * priv, t_u8 * ra);
+
+/** Clean up WMM node */
+void wlan_wmm_cleanup_node(pmlan_private priv);
+/** WMM status change command handler */
+int wlan_cmd_wmm_status_change(pmlan_private priv);
+/** Check if WMM lists are empty */
+int wlan_wmm_lists_empty(pmlan_adapter pmadapter);
+/** Clean up WMM queues */
+t_void wlan_wmm_cleanup_queues(pmlan_private priv);
+/** Process WMM transmission */
+t_void wlan_wmm_process_tx(pmlan_adapter pmadapter);
+/** Test to see if the ralist ptr is valid */
+int wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int tid);
+
+/** Compute driver packet delay */
+t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf);
+/** Initialize WMM */
+t_void wlan_wmm_init(pmlan_adapter pmadapter);
+/** Setup WMM queues */
+extern void wlan_wmm_setup_queues(pmlan_private priv);
+/* Setup default queues */
+void wlan_wmm_default_queue_priorities(pmlan_private priv);
+
+/** Process WMM association request */
+extern t_u32 wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap);
+
+/** setup wmm queue priorities */
+void wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * wmm_ie);
+/** Downgrade WMM priority queue */
+void wlan_wmm_setup_ac_downgrade(pmlan_private priv);
+/*
+ * Functions used in the cmd handling routine
+ */
+/** WMM ADDTS request command handler */
+extern mlan_status wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM DELTS request command handler */
+extern mlan_status wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_CONFIG command handler */
+extern mlan_status wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_STATS command handler */
+extern mlan_status wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM TS_STATUS command handler */
+extern mlan_status wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/*
+ * Functions used in the cmdresp handling routine
+ */
+/** WMM get status command response handler */
+extern mlan_status wlan_ret_wmm_get_status(pmlan_private priv,
+ const HostCmd_DS_COMMAND * resp);
+/** WMM ADDTS request command response handler */
+extern mlan_status wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM DELTS request command response handler */
+extern mlan_status wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_CONFIG command response handler */
+extern mlan_status wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_STATS command response handler */
+extern mlan_status wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM TS_STATUS command response handler */
+extern mlan_status wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+
+#endif /* !_MLAN_WMM_H_ */
diff --git a/wlan_src/mlinux/moal_debug.c b/wlan_src/mlinux/moal_debug.c
new file mode 100755
index 0000000..41d2849
--- /dev/null
+++ b/wlan_src/mlinux/moal_debug.c
@@ -0,0 +1,393 @@
+/** @file moal_debug.c
+ *
+ * @brief This file contains functions for debug proc file.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/03/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+/** MLAN debug info */
+static mlan_debug_info info;
+
+/** Get info item size */
+#define item_size(n) (sizeof(info.n))
+/** Get info item address */
+#define item_addr(n) ((t_u32) &(info.n))
+
+/** Get moal_private member size */
+#define item_priv_size(n) (sizeof ((moal_private *)0)->n)
+/** Get moal_private member address */
+#define item_priv_addr(n) ((t_u32) &((moal_private *)0)->n)
+
+/** Get moal_handle member size */
+#define item_handle_size(n) (sizeof ((moal_handle *)0)->n)
+/** Get moal_handle member address */
+#define item_handle_addr(n) ((t_u32) &((moal_handle *)0)->n)
+
+/** Debug data */
+struct debug_data
+{
+ /** Name */
+ char name[32];
+ /** Size */
+ t_u32 size;
+ /** Address */
+ t_u32 addr;
+};
+
+/** Private debug data */
+struct debug_data_priv
+{
+ /** moal_private handle */
+ moal_private *priv;
+ /** Debug items */
+ struct debug_data *items;
+ /** numbre of item */
+ int num_of_items;
+};
+
+static struct debug_data items[] = {
+ {"int_counter", item_size(int_counter), item_addr(int_counter)},
+ {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
+ item_addr(packets_out[WMM_AC_VO])},
+ {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
+ item_addr(packets_out[WMM_AC_VI])},
+ {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
+ item_addr(packets_out[WMM_AC_BE])},
+ {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
+ item_addr(packets_out[WMM_AC_BK])},
+ {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)},
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)},
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode)},
+ {"ps_state", item_size(ps_state), item_addr(ps_state)},
+ {"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep)},
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req)},
+ {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)},
+ {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)},
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated)},
+ {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)},
+ {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)},
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)},
+ {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)},
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)},
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)},
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)},
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id)},
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index)},
+ {"last_event", item_size(last_event), item_addr(last_event)},
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index)},
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure)},
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure)},
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure)},
+ {"num_evt_deauth", item_size(num_event_deauth),
+ item_addr(num_event_deauth)},
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc)},
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost)},
+ {"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth)},
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success)},
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure)},
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)},
+ {"data_sent", item_size(data_sent), item_addr(data_sent)},
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)},
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)},
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)},
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)},
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received)},
+ {"event_received", item_size(event_received), item_addr(event_received)},
+
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending)},
+ {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)},
+ {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)},
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count)},
+ {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)},
+};
+
+/** Private debug data */
+static struct debug_data_priv items_priv;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function
+ *
+ * @param page Pointer to buffer
+ * @param s Read data starting position
+ * @param off Offset
+ * @param cnt Counter
+ * @param eof End of file flag
+ * @param data Output data
+ *
+ * @return Number of output data
+ */
+static int
+woal_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
+{
+ int val = 0;
+ int i;
+ char *p = page;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+
+ if (MODULE_GET == 0)
+ return MLAN_STATUS_FAILURE;
+
+ /* Get debug information */
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
+ if (d[i].size == 1)
+ val = *((t_u8 *) d[i].addr);
+ else if (d[i].size == 2)
+ val = *((t_u16 *) d[i].addr);
+ else if (d[i].size == 4)
+ val = *((t_u32 *) d[i].addr);
+ else {
+ int j;
+ p += sprintf(p, "%s=", d[i].name);
+ for (j = 0; j < d[i].size; j += 2) {
+ val = *(t_u16 *) (d[i].addr + j);
+ p += sprintf(p, "0x%x ", val);
+ }
+ p += sprintf(p, "\n");
+ continue;
+ }
+ if (strstr(d[i].name, "id"))
+ p += sprintf(p, "%s=0x%x\n", d[i].name, val);
+ else
+ p += sprintf(p, "%s=%d\n", d[i].name, val);
+ }
+ if (info.tx_tbl_num) {
+ p += sprintf(p, "Tx BA stream table:\n");
+ for (i = 0; i < info.tx_tbl_num; i++) {
+ p += sprintf(p, "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (int) info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
+ info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
+ info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
+ info.tx_tbl[i].ra[5]);
+ }
+ }
+ if (info.rx_tbl_num) {
+ p += sprintf(p, "Rx reorder table:\n");
+ for (i = 0; i < info.rx_tbl_num; i++) {
+ int j;
+
+ p += sprintf(p,
+ "tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, "
+ "win_size = %d, buffer: ", (int) info.rx_tbl[i].tid,
+ info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
+ info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
+ info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
+ (int) info.rx_tbl[i].start_win,
+ (int) info.rx_tbl[i].win_size);
+ for (j = 0; j < info.rx_tbl[i].win_size; j++) {
+ if (info.rx_tbl[i].buffer[j] == MTRUE)
+ p += sprintf(p, "1 ");
+ else
+ p += sprintf(p, "0 ");
+ }
+ p += sprintf(p, "\n");
+ }
+ }
+ exit:
+ MODULE_PUT;
+ return p - page;
+}
+
+/**
+ * @brief Proc write function
+ *
+ * @param f File pointer
+ * @param buf Pointer to data buffer
+ * @param cnt Data number to write
+ * @param data Data to write
+ *
+ * @return Number of data
+ */
+static int
+woal_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+
+ if (MODULE_GET == 0)
+ return MLAN_STATUS_FAILURE;
+
+ pdata = (char *) kmalloc(cnt, GFP_ATOMIC);
+ if (pdata == NULL) {
+ MODULE_PUT;
+ return 0;
+ }
+
+ if (copy_from_user(pdata, buf, cnt)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ kfree(pdata);
+ MODULE_PUT;
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = woal_string_to_number(p2);
+ if (d[i].size == 1)
+ *((t_u8 *) d[i].addr) = (t_u8) r;
+ else if (d[i].size == 2)
+ *((t_u16 *) d[i].addr) = (t_u16) r;
+ else if (d[i].size == 4)
+ *((t_u32 *) d[i].addr) = (t_u32) r;
+ break;
+ } while (MTRUE);
+ }
+ kfree(pdata);
+
+ /* Set debug information */
+ if (woal_set_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
+ MODULE_PUT;
+ return 0;
+ }
+
+ MODULE_PUT;
+ return cnt;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Create debug proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return None
+ */
+void
+woal_debug_entry(moal_private * priv)
+{
+ struct proc_dir_entry *r;
+
+ ENTER();
+
+ if (priv->proc_entry == NULL)
+ return;
+
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ LEAVE();
+ return;
+ }
+ /* Setup MOAL debug info */
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ items_priv.priv = priv;
+ items_priv.items = items;
+ items_priv.num_of_items = sizeof(items) / sizeof(items[0]);
+ items[items_priv.num_of_items - 1].addr += (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 2].addr += (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 3].addr += (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 4].addr += (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 5].addr += (t_u32) (priv->phandle);
+ }
+ /* Create proc entry */
+ r = create_proc_entry("debug", 0644, priv->proc_entry);
+ if (r == NULL) {
+ LEAVE();
+ return;
+ }
+ /* Populate proc entry handlers */
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ r->data = &items_priv;
+ r->read_proc = woal_debug_read;
+ r->write_proc = woal_debug_write;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ r->owner = THIS_MODULE;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return None
+ */
+void
+woal_debug_remove(moal_private * priv)
+{
+ ENTER();
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ /* Reset MOAL debug info */
+ items[items_priv.num_of_items - 1].addr -= (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 2].addr -= (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 3].addr -= (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 4].addr -= (t_u32) (priv->phandle);
+ items[items_priv.num_of_items - 5].addr -= (t_u32) (priv->phandle);
+ }
+ /* Remove proc entry */
+ remove_proc_entry("debug", priv->proc_entry);
+
+ LEAVE();
+}
+#endif
diff --git a/wlan_src/mlinux/moal_ioctl.c b/wlan_src/mlinux/moal_ioctl.c
new file mode 100755
index 0000000..46c176e
--- /dev/null
+++ b/wlan_src/mlinux/moal_ioctl.c
@@ -0,0 +1,733 @@
+/** @file moal_ioctl.c
+ *
+ * @brief This file contains ioctl function to MLAN
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Copy multicast table
+ *
+ * @param mlist A pointer to mlan_multicast_list structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return Number of mulitcast address
+ */
+static inline int
+woal_copy_mcast_addr(mlan_multicast_list * mlist, struct net_device *dev)
+{
+ int i = 0;
+ struct dev_mc_list *mcptr = dev->mc_list;
+
+ for (i = 0; i < dev->mc_count; i++) {
+ memcpy(&mlist->mac_list[i], mcptr->dmi_addr, ETH_ALEN);
+ mcptr = mcptr->next;
+ }
+ return i;
+}
+
+/**
+ * @brief Fill in wait queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait A pointer to wait_queue structure
+ * @param wait_option Wait option
+ *
+ * @return None
+ */
+static inline void
+woal_fill_wait_queue(moal_private * priv, wait_queue * wait, t_u8 wait_option)
+{
+ ENTER();
+ wait->start_time = jiffies;
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ priv->ioctl_wait_q_woken = MFALSE;
+ wait->wait = &priv->ioctl_wait_q;
+ wait->condition = &priv->ioctl_wait_q_woken;
+ break;
+ case MOAL_CMD_WAIT:
+ priv->cmd_wait_q_woken = MFALSE;
+ wait->wait = &priv->cmd_wait_q;
+ wait->condition = &priv->cmd_wait_q_woken;
+ break;
+ case MOAL_PROC_WAIT:
+ priv->proc_wait_q_woken = MFALSE;
+ wait->wait = &priv->proc_wait_q;
+ wait->condition = &priv->proc_wait_q_woken;
+ break;
+ case MOAL_WSTATS_WAIT:
+ priv->w_stats_wait_q_woken = MFALSE;
+ wait->wait = &priv->w_stats_wait_q;
+ wait->condition = &priv->w_stats_wait_q_woken;
+ break;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Wait mlan ioctl complete
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req structure
+ * @param wait_option Wait option
+ *
+ * @return None
+ */
+static inline void
+woal_wait_ioctl_complete(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option)
+{
+ BOOLEAN cancel_flag = MFALSE;
+ ENTER();
+
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ wait_event_interruptible(priv->ioctl_wait_q, priv->ioctl_wait_q_woken);
+ if (priv->ioctl_wait_q_woken == MFALSE)
+ cancel_flag = MTRUE;
+ break;
+ case MOAL_CMD_WAIT:
+ wait_event_interruptible(priv->cmd_wait_q, priv->cmd_wait_q_woken);
+ if (priv->cmd_wait_q_woken == MFALSE)
+ cancel_flag = MTRUE;
+ break;
+ case MOAL_PROC_WAIT:
+ wait_event_interruptible(priv->proc_wait_q, priv->proc_wait_q_woken);
+ if (priv->proc_wait_q_woken == MFALSE)
+ cancel_flag = MTRUE;
+ break;
+ case MOAL_WSTATS_WAIT:
+ wait_event_interruptible(priv->w_stats_wait_q,
+ priv->w_stats_wait_q_woken);
+ if (priv->w_stats_wait_q_woken == MFALSE)
+ cancel_flag = MTRUE;
+ break;
+ }
+ if (cancel_flag == MTRUE) {
+ req->action = MLAN_ACT_CANCEL;
+ mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ PRINTM(MCMND,
+ "IOCTL cancel: id=0x%lx, sub_id=0x%lx wait_option=%d, action=%d\n",
+ req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action);
+ }
+ LEAVE();
+ return;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Send open request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_request_open(moal_private * priv)
+{
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Send close request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_request_close(moal_private * priv)
+{
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Send ioctl request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option)
+{
+ wait_queue *wait;
+ mlan_status status;
+
+ ENTER();
+ if (priv->phandle->surprise_removed == MTRUE) {
+ PRINTM(MERROR, "IOCTL is not allowed while surprise_removed = TRUE\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ wait = (wait_queue *) req->reserved_1;
+ req->bss_num = priv->bss_num;
+ if (wait_option)
+ woal_fill_wait_queue(priv, wait, wait_option);
+ else
+ req->reserved_1 = 0;
+
+ /* Call MLAN ioctl handle */
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ PRINTM(MCMND,
+ "IOCTL pending: id=0x%lx, sub_id=0x%lx wait_option=%d, action=%d\n",
+ req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action);
+ atomic_inc(&priv->phandle->ioctl_pending);
+ /* Status pending, wake up main process */
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* Wait for completion */
+ if (wait_option) {
+ woal_wait_ioctl_complete(priv, req, wait_option);
+ status = wait->status;
+ }
+ break;
+ case MLAN_STATUS_SUCCESS:
+ case MLAN_STATUS_FAILURE:
+ case MLAN_STATUS_RESOURCE:
+ default:
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send set MAC address request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_set_mac_address(moal_private * priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
+ memcpy(&bss->param.mac_addr, priv->current_addr,
+ sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ } else {
+ PRINTM(MERROR, "set mac address failed! status=%d, error_code=0x%lx\n",
+ status, req->status_code);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send multicast list request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return None
+ */
+void
+woal_request_set_multicast_list(moal_private * priv, struct net_device *dev)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ PRINTM(MERROR, "%s:Fail to alloc ioctl req buffer\n", __FUNCTION__);
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (dev->flags & IFF_PROMISC) {
+ bss->param.multicast_list.mode = MLAN_PROMISC_MODE;
+ } else if (dev->flags & IFF_ALLMULTI ||
+ dev->mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) {
+ bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE;
+ } else {
+ bss->param.multicast_list.mode = MLAN_MULTICAST_MODE;
+ if (dev->mc_count)
+ bss->param.multicast_list.num_multicast_addr =
+ woal_copy_mcast_addr(&bss->param.multicast_list, dev);
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_NO_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send deauth command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param mac MAC address to deauthenticate
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ if (mac)
+ memcpy((t_u8 *) & bss->param.bssid, mac, sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+#ifdef REASSOCIATION
+ priv->reassoc_required = MFALSE;
+#endif /* REASSOCIATION */
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send bss_start command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A point to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Stop the O.S. TX queue if needed */
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_START;
+ if (ssid_bssid)
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get BSS info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param bss_info A pointer to mlan_bss_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_BSS_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (bss_info) {
+ memcpy(bss_info, &info->param.bss_info, sizeof(mlan_bss_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef PROC_DEBUG
+/**
+ * @brief Get debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (debug_info) {
+ memcpy(debug_info, &info->param.debug_info,
+ sizeof(mlan_debug_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!debug_info) {
+ ret = -EINVAL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ memcpy(&info->param.debug_info, debug_info, sizeof(mlan_debug_info));
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+#endif /* PROC_DEBUG */
+
+/**
+ * @brief ioctl function get BSS type
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_bss_type(struct net_device * dev, struct ifreq * req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int bss_type;
+
+ ENTER();
+
+ bss_type = (int) priv->bss_type;
+ if (copy_to_user(req->ifr_data, &bss_type, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param hscfg A pointer to mlan_ds_hs_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_hs_params(moal_private * priv, t_u8 wait_option,
+ mlan_ds_hs_cfg * hscfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (hscfg) {
+ memcpy(hscfg, &pmcfg->param.hs_cfg, sizeof(mlan_ds_hs_cfg));
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING,
+ * or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_hs_cfg_cancel(moal_private * priv, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Get current Host Sleep configuration */
+ woal_get_hs_params(priv, wait_option, &pmcfg->param.hs_cfg);
+
+ pmcfg->param.hs_cfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ pmcfg->param.hs_cfg.is_invoke_hostcmd = MTRUE;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wapi enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WAPI_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wapi_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
diff --git a/wlan_src/mlinux/moal_main.c b/wlan_src/mlinux/moal_main.c
new file mode 100755
index 0000000..1eee3e1
--- /dev/null
+++ b/wlan_src/mlinux/moal_main.c
@@ -0,0 +1,1620 @@
+/** @file moal_main.c
+ *
+ * @brief This file contains the major functions in WLAN
+ * driver.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Driver version */
+const char driver_version[] =
+ "SD8787-%s-M2614" MLAN_RELEASE_VERSION "-GPL" "-(" "FP" FPNUM ")"
+#ifdef DEBUG_LEVEL2
+ "-dbg"
+#endif
+ " ";
+
+/** Firmware name */
+char *fw_name = NULL;
+
+#ifdef MFG_CMD_SUPPORT
+/** Mfg mode */
+int mfg_mode = 0;
+#endif
+
+/** woal_callbacks */
+static mlan_callbacks woal_callbacks = {
+ .moal_init_fw_complete = moal_init_fw_complete,
+ .moal_shutdown_fw_complete = moal_shutdown_fw_complete,
+ .moal_send_packet_complete = moal_send_packet_complete,
+ .moal_recv_complete = moal_recv_complete,
+ .moal_recv_packet = moal_recv_packet,
+ .moal_recv_event = moal_recv_event,
+ .moal_ioctl_complete = moal_ioctl_complete,
+ .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
+ .moal_free_mlan_buffer = moal_free_mlan_buffer,
+ .moal_write_reg = moal_write_reg,
+ .moal_read_reg = moal_read_reg,
+ .moal_write_data_sync = moal_write_data_sync,
+ .moal_read_data_sync = moal_read_data_sync,
+ .moal_malloc = moal_malloc,
+ .moal_mfree = moal_mfree,
+ .moal_memset = moal_memset,
+ .moal_memcpy = moal_memcpy,
+ .moal_memmove = moal_memmove,
+ .moal_memcmp = moal_memcmp,
+ .moal_get_system_time = moal_get_system_time,
+ .moal_init_timer = moal_init_timer,
+ .moal_free_timer = moal_free_timer,
+ .moal_start_timer = moal_start_timer,
+ .moal_stop_timer = moal_stop_timer,
+ .moal_init_lock = moal_init_lock,
+ .moal_free_lock = moal_free_lock,
+ .moal_spin_lock = moal_spin_lock,
+ .moal_spin_unlock = moal_spin_unlock,
+ .moal_print = moal_print,
+};
+
+/** BSS attributes */
+static mlan_bss_attr woal_bss_sta[] = {
+ {MLAN_BSS_TYPE_STA, MLAN_DATA_FRAME_TYPE_ETH_II, MTRUE, 0},
+};
+
+int drv_mode = DRV_MODE_STA;
+
+/** Supported drv_mode table */
+static moal_drv_mode drv_mode_tbl[] = {
+ {
+ /* drv_mode */
+ .drv_mode = DRV_MODE_STA,
+ /* intf number */
+ .intf_num = sizeof(woal_bss_sta) / sizeof(woal_bss_sta[0]),
+ /* bss_attr */
+ .bss_attr = woal_bss_sta,
+ /* fw name */
+ .fw_name = DEFAULT_FW_NAME,
+ }
+ ,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/** Semaphore for add/remove card */
+struct semaphore AddRemoveCardSem;
+/**
+ * The global variable of a pointer to moal_handle
+ * structure variable
+ */
+moal_handle *m_handle = NULL;
+
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff & ~MEVENT)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif /* DEBUG_LEVEL2 */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+t_u32 ifdbg = 0;
+#endif /* DEBUG_LEVEL1 */
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function initializes software
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_init_sw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int i;
+ mlan_device device;
+ t_void *pmlan;
+
+ ENTER();
+
+ /* find moal_drv_mode entry from drv_mode_tbl */
+ handle->drv_mode = NULL;
+ for (i = 0; i < (sizeof(drv_mode_tbl) / sizeof(drv_mode_tbl[0])); i++) {
+ if (drv_mode_tbl[i].drv_mode == drv_mode) {
+ handle->drv_mode = &drv_mode_tbl[i];
+ break;
+ }
+ }
+
+ if (!handle->drv_mode) {
+ PRINTM(MERROR, "Invalid drv_mode=%d\n", drv_mode);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize moal_handle structure */
+ handle->hardware_status = HardwareStatusInitializing;
+ /* PnP and power profile */
+ handle->surprise_removed = MFALSE;
+ init_waitqueue_head(&handle->init_wait_q);
+
+#ifdef REASSOCIATION
+ MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
+
+#if (WIRELESS_EXT >= 18)
+ handle->reassoc_on = MFALSE;
+#else
+ handle->reassoc_on = MTRUE;
+#endif
+
+ /* Initialize the timer for the reassociation */
+ woal_initialize_timer(&handle->reassoc_timer,
+ woal_reassoc_timer_func, handle);
+ handle->is_reassoc_timer_set = MFALSE;
+#endif /* REASSOCIATION */
+ /* Register to MLAN */
+ memset(&device, 0, sizeof(mlan_device));
+ device.pmoal_handle = handle;
+
+#ifdef MFG_CMD_SUPPORT
+ device.mfg_mode = (t_u32) mfg_mode;
+#endif
+ for (i = 0; i < handle->drv_mode->intf_num; i++) {
+ device.bss_attr[i].bss_type = handle->drv_mode->bss_attr[i].bss_type;
+ device.bss_attr[i].frame_type =
+ handle->drv_mode->bss_attr[i].frame_type;
+ device.bss_attr[i].active = handle->drv_mode->bss_attr[i].active;
+ device.bss_attr[i].bss_priority =
+ handle->drv_mode->bss_attr[i].bss_priority;
+ }
+ memcpy(&device.callbacks, &woal_callbacks, sizeof(mlan_callbacks));
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
+ handle->pmlan_adapter = pmlan;
+ else
+ ret = MLAN_STATUS_FAILURE;
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of moal_handle
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void
+woal_free_moal_handle(moal_handle * handle)
+{
+ ENTER();
+ if (!handle) {
+ PRINTM(MERROR, "The handle is NULL.\n");
+ LEAVE();
+ return;
+ }
+
+ if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
+ sock_release((handle->nl_sk)->sk_socket);
+ handle->nl_sk = NULL;
+ }
+
+ if (handle->pmlan_adapter)
+ mlan_unregister(handle->pmlan_adapter);
+ PRINTM(MINFO, "Free Adapter\n");
+ if (handle->malloc_count || handle->lock_count) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_count=%lu lock_count=%lu\n",
+ handle->malloc_count, handle->lock_count);
+ }
+ /* Free the moal handle itself */
+ kfree(handle);
+ m_handle = NULL;
+ LEAVE();
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_init_fw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int err;
+ mlan_fw_image fw;
+
+ ENTER();
+
+ memset(&fw, 0, sizeof(mlan_fw_image));
+
+ if ((err =
+ request_firmware(&handle->firmware, handle->drv_mode->fw_name,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MFATAL, "request_firmware() failed, error code = %#x\n", err);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ fw.pfw_buf = (t_u8 *) handle->firmware->data;
+ fw.fw_len = handle->firmware->size;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ PRINTM(MMSG, "WLAN FW is active\n");
+
+ handle->hardware_status = HardwareStatusFwReady;
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ handle->init_wait_q_woken = MFALSE;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_init_fw(handle->pmlan_adapter);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ } else if (ret == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReady;
+ goto done;
+ }
+ /* Wait for mlan_init to complete */
+ wait_event_interruptible(handle->init_wait_q, handle->init_wait_q_woken);
+ if (handle->hardware_status != HardwareStatusReady) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ if (handle->firmware)
+ release_firmware(handle->firmware);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will fill in the mlan_buffer
+ *
+ * @param pmbuf A pointer to mlan_buffer
+ * @param skb A pointer to struct sk_buff
+ *
+ * @return N/A
+ */
+static void
+woal_fill_mlan_buffer(mlan_buffer * pmbuf, struct sk_buff *skb)
+{
+ struct ethhdr *eth = NULL;
+ struct timeval tstamp;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ struct iphdr *iph;
+#endif
+ t_u8 tid = 0;
+
+ ENTER();
+
+ eth = (struct ethhdr *) skb->data;
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ iph = ip_hdr(skb);
+ tid = IPTOS_PREC(iph->tos);
+#else
+ tid = IPTOS_PREC(skb->nh.iph->tos);
+#endif
+ PRINTM(MDATA, "packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
+ eth->h_proto, tid, skb->priority);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto);
+ default:
+ break;
+ }
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+ skb->priority = tid = (tid >> IPTOS_OFFSET);
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ do_gettimeofday(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ skb->tstamp = timeval_to_ktime(tstamp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+ skb_set_timestamp(skb, &tstamp);
+#else
+ memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
+#endif
+ pmbuf->pdesc = skb;
+ pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
+ pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
+ pmbuf->data_len = skb->len;
+ pmbuf->priority = skb->priority;
+ pmbuf->in_ts_sec = (t_u32) tstamp.tv_sec;
+ pmbuf->in_ts_usec = (t_u32) tstamp.tv_usec;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function opens the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_open(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u8 carrier_on = MFALSE;
+
+ ENTER();
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if ((priv->bss_type == MLAN_BSS_TYPE_STA) &&
+ (priv->media_connected || priv->is_adhoc_link_sensed))
+ carrier_on = MTRUE;
+ if (carrier_on == MTRUE) {
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+ } else
+ netif_carrier_off(priv->netdev);
+ woal_request_open(priv);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0
+ */
+static int
+woal_close(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ woal_request_close(priv);
+ MODULE_PUT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles packet transmission
+ *
+ * @param skb A pointer to sk_buff structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_buffer *pmbuf = NULL;
+ mlan_status status;
+ struct sk_buff *new_skb = NULL;
+
+ ENTER();
+
+ PRINTM(MDATA, "%lu BSS(%d): Data <= kernel\n", jiffies, priv->bss_num);
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ kfree(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n",
+ skb->len, ETH_FRAME_LEN);
+ kfree(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (skb_headroom(skb) < (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer))) {
+ PRINTM(MWARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb =
+ skb_realloc_headroom(skb,
+ MLAN_MIN_DATA_HEADER_LEN +
+ sizeof(mlan_buffer));
+ if (unlikely(!new_skb)) {
+ PRINTM(MERROR, "Tx: Cannot allocate skb\n");
+ kfree(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ kfree_skb(skb);
+ skb = new_skb;
+ PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
+ }
+ pmbuf = (mlan_buffer *) skb->head;
+ pmbuf->bss_num = priv->bss_num;
+ woal_fill_mlan_buffer(pmbuf, skb);
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING) {
+ netif_stop_queue(priv->netdev);
+ dev->trans_start = jiffies;
+ }
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ woal_free_mlan_buffer(pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ woal_free_mlan_buffer(pmbuf);
+ break;
+ }
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function sets the MAC address to firmware.
+ *
+ * @param dev A pointer to mlan_private structure
+ * @param addr MAC address to set
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct sockaddr *phw_addr = (struct sockaddr *) addr;
+
+ ENTER();
+
+ memset(priv->current_addr, 0, ETH_ALEN);
+ /* dev->dev_addr is 6 bytes */
+ HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ HEXDUMP("addr:", (t_u8 *) phw_addr->sa_data, ETH_ALEN);
+ memcpy(priv->current_addr, phw_addr->sa_data, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static void
+woal_set_multicast_list(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ woal_request_set_multicast_list(priv, dev);
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the timeout of packet
+ * transmission
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static void
+woal_tx_timeout(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ PRINTM(MERROR, "%lu : Tx timeout, bss_num=%d\n", jiffies, priv->bss_num);
+ dev->trans_start = jiffies;
+ priv->num_tx_timeout++;
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to net_device_stats structure
+ */
+static struct net_device_stats *
+woal_get_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ return &priv->stats;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/** Network device handlers */
+static const struct net_device_ops woal_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+ .ndo_set_multicast_list = woal_set_multicast_list,
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for station mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_init_sta_dev(struct net_device *dev, moal_private * priv)
+{
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer);
+#ifdef WIRELESS_EXT
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers = (struct iw_handler_def *) &woal_handler_def;
+#endif
+/** Netif dynamic alloc */
+#define NETIF_F_DYNALLOC 16
+ dev->features |= NETIF_F_DYNALLOC;
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ /* Initialize private structure */
+ init_waitqueue_head(&priv->ioctl_wait_q);
+ init_waitqueue_head(&priv->cmd_wait_q);
+ init_waitqueue_head(&priv->proc_wait_q);
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ priv->current_key_index = 0;
+ priv->rate_index = AUTO_RATE;
+ priv->media_connected = MFALSE;
+ priv->is_adhoc_link_sensed = MFALSE;
+ memset(&priv->current_addr, 0, sizeof(priv->current_addr));
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ woal_request_get_fw_info(priv);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_num BSS number (0-7)
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *
+woal_add_interface(moal_handle * handle, t_u8 bss_num, t_u8 bss_type)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+
+ ENTER();
+
+ /* Allocate an Ethernet device */
+ if (!(dev = alloc_etherdev(sizeof(moal_private)))) {
+ PRINTM(MFATAL, "Init virtual ethernet device failed!\n");
+ goto error;
+ }
+ /* Allocate device name */
+ if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "mlan%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate device name!\n");
+ goto error;
+ }
+ priv = (moal_private *) netdev_priv(dev);
+ /* Save the priv to handle */
+ bss_num &= BSS_NUM_MASK;
+ handle->priv[bss_num] = priv;
+
+ /* Use the same handle structure */
+ priv->phandle = handle;
+ priv->netdev = dev;
+ priv->bss_num = bss_num;
+ priv->bss_type = bss_type;
+ MOAL_INIT_SEMAPHORE(&priv->async_sem);
+ priv->scan_pending_on_block = MFALSE;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ SET_MODULE_OWNER(dev);
+#endif
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ woal_init_sta_dev(dev, priv);
+
+ /* Register network device */
+ if (register_netdev(dev)) {
+ PRINTM(MERROR, "Cannot register virtual network device!\n");
+ goto error;
+ }
+
+ PRINTM(MINFO, "%s: Marvell 802.11 Adapter\n", dev->name);
+#ifdef CONFIG_PROC_FS
+ woal_create_proc_entry(priv);
+#ifdef PROC_DEBUG
+ woal_debug_entry(priv);
+#endif /* PROC_DEBUG */
+#endif /* CONFIG_PROC_FS */
+ LEAVE();
+ return priv;
+ error:
+ if (dev)
+ free_netdev(dev);
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes an interface.
+ *
+ * @param handle A pointer to the moal_handle structure
+ * @param bss_num BSS number
+ *
+ * @return N/A
+ */
+void
+woal_remove_interface(moal_handle * handle, t_u8 bss_num)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = handle->priv[bss_num];
+ union iwreq_data wrqu;
+
+ ENTER();
+ if (!priv)
+ goto error;
+ dev = priv->netdev;
+
+ if (priv->media_connected == MTRUE) {
+ priv->media_connected = MFALSE;
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+ }
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+ /* Remove proc debug */
+ woal_debug_remove(priv);
+#endif /* PROC_DEBUG */
+ woal_proc_remove(priv);
+#endif /* CONFIG_PROC_FS */
+ /* Last reference is our one */
+ PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+
+ PRINTM(MINFO, "netdev_finish_unregister: %s%s\n", dev->name,
+ (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+
+ /* Clear the priv in handle */
+ priv->phandle->priv[priv->bss_num] = NULL;
+ priv->phandle = NULL;
+ priv->netdev = NULL;
+ free_netdev(dev);
+ error:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send FW shutdown command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_shutdown_fw(moal_private * priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
+ misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function initializes the private structure
+ * and set default value to the member of moal_private.
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_init_priv(moal_private * priv)
+{
+ ENTER();
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ priv->current_key_index = 0;
+ priv->rate_index = AUTO_RATE;
+ priv->media_connected = MFALSE;
+ priv->is_adhoc_link_sensed = MFALSE;
+ memset(&priv->current_addr, 0, sizeof(priv->current_addr));
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ woal_request_get_fw_info(priv);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function return the point to structure moal_private
+ *
+ * @param handle Pointer to structure moal_handle
+ * @param bss_num BSS number
+ *
+ * @return moal_private pointer or NULL
+ */
+moal_private *
+woal_bss_num_to_priv(moal_handle * handle, t_u8 bss_num)
+{
+ ENTER();
+ if (!handle || (bss_num >= MLAN_MAX_BSS_NUM)) {
+ LEAVE();
+ return NULL;
+ }
+ LEAVE();
+ return handle->priv[bss_num];
+}
+
+/**
+ * @brief This function alloc mlan_buffer.
+ *
+ * @param size buffer size to allocate
+ *
+ * @return mlan_buffer pointer or NULL
+ */
+pmlan_buffer
+woal_alloc_mlan_buffer(int size)
+{
+ mlan_buffer *pmbuf = NULL;
+ struct sk_buff *skb;
+
+ ENTER();
+ if (!(pmbuf = kzalloc(sizeof(mlan_buffer), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc mlan buffer", __FUNCTION__);
+ return NULL;
+ }
+ if (!(skb = dev_alloc_skb(size))) {
+ kfree(pmbuf);
+ return NULL;
+ }
+ pmbuf->pdesc = (t_void *) skb;
+ pmbuf->pbuf = (t_u8 *) skb->tail;
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function alloc mlan_ioctl_req.
+ *
+ * @param size buffer size to allocate
+ *
+ * @return mlan_ioctl_req pointer or NULL
+ */
+pmlan_ioctl_req
+woal_alloc_mlan_ioctl_req(int size)
+{
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (!
+ (req =
+ (mlan_ioctl_req *)
+ kzalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
+ sizeof(wait_queue)), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc ioctl buffer", __FUNCTION__);
+ LEAVE();
+ return NULL;
+ }
+ req->pbuf = (t_u8 *) req + sizeof(mlan_ioctl_req);
+ req->buf_len = (t_u32) size;
+ req->reserved_1 =
+ ALIGN_ADDR((t_u8 *) req + sizeof(mlan_ioctl_req) + size, sizeof(int));
+
+ LEAVE();
+ return req;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ *
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+void
+woal_free_mlan_buffer(pmlan_buffer pmbuf)
+{
+ ENTER();
+ if (!pmbuf)
+ return;
+ if (pmbuf->pdesc)
+ dev_kfree_skb_any((struct sk_buff *) pmbuf->pdesc);
+ kfree(pmbuf);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param payload A pointer to payload buffer
+ * @param len Length of the payload
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_broadcast_event(moal_private * priv, t_u8 * payload, t_u32 len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ moal_handle *handle = priv->phandle;
+ struct sock *sk = handle->nl_sk;
+
+ ENTER();
+ if (len > NL_MAX_PAYLOAD) {
+ PRINTM(MERROR, "event size is too big!!! len=%d\n", (int) len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (sk) {
+ /* Allocate skb */
+ if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Could not allocate skb for netlink.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ nlh = (struct nlmsghdr *) skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(len);
+
+ /* From kernel */
+ nlh->nlmsg_pid = 0;
+ nlh->nlmsg_flags = 0;
+
+ /* Data */
+ skb_put(skb, nlh->nlmsg_len);
+ memcpy(NLMSG_DATA(nlh), payload, len);
+
+ /* From Kernel */
+ NETLINK_CB(skb).pid = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ /* Multicast message */
+ NETLINK_CB(skb).dst_pid = 0;
+#endif
+
+ /* Multicast group number */
+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
+
+ /* Send message */
+ netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_KERNEL);
+
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "Could not send event through NETLINK. Link down.\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief This function handles re-association. it is triggered
+ * by re-assoc timer.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_reassociation_thread(void *data)
+{
+ moal_thread *pmoal_thread = data;
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_thread->handle;
+ wait_queue_t wait;
+ int i;
+ BOOLEAN reassoc_timer_req;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_status status;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ woal_activate_thread(pmoal_thread);
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&pmoal_thread->wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&pmoal_thread->wait_q, &wait);
+
+ /* Cancel re-association timer */
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+
+ if (handle->surprise_removed)
+ break;
+ if (kthread_should_stop())
+ break;
+
+ if (handle->hardware_status != HardwareStatusReady) {
+ PRINTM(MINFO, "Reassoc: Hardware status is not correct\n");
+ continue;
+ }
+ PRINTM(MINFO, "Reassoc: Thread waking up...\n");
+ reassoc_timer_req = MFALSE;
+
+ for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) {
+ if (priv->reassoc_required == MFALSE)
+ continue;
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_CMD_WAIT, &bss_info)) {
+ PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+ if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
+ priv->media_connected != MFALSE) {
+ PRINTM(MINFO, "Reassoc: ad-hoc mode or media connected\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+
+ /* The semaphore is used to avoid reassociation thread and
+ wlan_set_scan/wlan_set_essid interrupting each other.
+ Reassociation should be disabled completely by application if
+ wlan_set_user_scan_ioctl/wlan_set_wap is used. */
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR,
+ "Acquire semaphore error, reassociation thread\n");
+ reassoc_timer_req = MTRUE;
+ break;
+ }
+ PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
+ priv->prev_ssid_bssid.ssid.ssid);
+ PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
+
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memcpy(&req_ssid, &priv->prev_ssid_bssid.ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_CMD_WAIT, &req_ssid)) {
+ PRINTM(MERROR, "Reassoc: Fail to do specific scan\n");
+ reassoc_timer_req = MTRUE;
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ if (handle->surprise_removed) {
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+ status =
+ woal_set_ewpa_mode(priv, MOAL_CMD_WAIT, &priv->prev_ssid_bssid);
+ /* Search AP by BSSID first */
+ PRINTM(MINFO, "Reassoc: Search AP by BSSID first\n");
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.bssid, &priv->prev_ssid_bssid.bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ status = woal_find_best_network(priv, MOAL_CMD_WAIT, &ssid_bssid);
+ if (MLAN_STATUS_SUCCESS != status) {
+ PRINTM(MINFO, "Reassoc: AP not found in scan list\n");
+ PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
+ /* Search AP by SSID */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.ssid, &priv->prev_ssid_bssid.ssid,
+ sizeof(mlan_802_11_ssid));
+ status =
+ woal_find_best_network(priv, MOAL_CMD_WAIT, &ssid_bssid);
+ }
+ if (status == MLAN_STATUS_SUCCESS) {
+ /* set the wep key */
+ if (bss_info.wep_status)
+ woal_enable_wep_key(priv, MOAL_IOCTL_WAIT);
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ status = woal_bss_start(priv, MOAL_CMD_WAIT, &ssid_bssid);
+ }
+ if (priv->media_connected == MFALSE)
+ reassoc_timer_req = MTRUE;
+ else {
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ reassoc_timer_req = MFALSE;
+
+ if (priv->rate_index != AUTO_RATE) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+
+ req->action = MLAN_ACT_SET;
+
+ rate->param.rate_cfg.rate = priv->rate_index;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_CMD_WAIT)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (req)
+ kfree(req);
+ }
+ }
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ }
+ if (handle->surprise_removed)
+ break;
+ if (reassoc_timer_req == MTRUE) {
+ PRINTM(MINFO,
+ "Reassoc: No AP found or assoc failed. Restarting re-assoc Timer.\n");
+ handle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&handle->reassoc_timer, MOAL_TIMER_10S);
+ }
+ }
+ woal_deactivate_thread(pmoal_thread);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function triggers re-association by waking up
+ * re-assoc thread.
+ *
+ * @param context A pointer to context
+ * @return n/a
+ */
+void
+woal_reassoc_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *) context;
+
+ ENTER();
+
+ PRINTM(MINFO, "reassoc_timer fired.\n");
+ handle->is_reassoc_timer_set = MFALSE;
+
+ PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ LEAVE();
+ return;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief This workqueue function handles main_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void
+woal_main_work_queue(struct work_struct * work)
+{
+ moal_handle *handle = container_of(work, moal_handle, main_work);
+
+ ENTER();
+
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function cancel all works in the queue
+ * and destroy the main workqueue.
+ *
+ * @param handle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void
+woal_terminate_workqueue(moal_handle * handle)
+{
+ ENTER();
+
+ flush_workqueue(handle->workqueue);
+ destroy_workqueue(handle->workqueue);
+ handle->workqueue = NULL;
+
+ LEAVE();
+}
+
+void
+woal_interrupt(moal_handle * handle)
+{
+ ENTER();
+
+ PRINTM(MINTR, "*\n");
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ /* call mlan_interrupt to read int status */
+ mlan_interrupt(handle->pmlan_adapter);
+ queue_work(handle->workqueue, &handle->main_work);
+ LEAVE();
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the mlan_private and initialize the device.
+ *
+ * @param card A pointer to card
+ *
+ * @return A pointer to moal_handle structure
+ */
+moal_handle *
+woal_add_card(void *card)
+{
+ moal_handle *handle = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int i;
+
+ ENTER();
+
+ if (down_interruptible(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ /* Allocate buffer for moal_handle */
+ if (!(handle = kmalloc(sizeof(moal_handle), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
+ goto err_handle;
+ }
+
+ /* Init moal_handle */
+ memset(handle, 0, sizeof(moal_handle));
+ handle->card = card;
+ m_handle = handle;
+ ((struct sdio_mmc_card *) card)->handle = handle;
+
+ /* Init SW */
+ if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto err_kmalloc;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ handle->nl_sk =
+ netlink_kernel_create(NETLINK_MARVELL, NL_MULTICAST_GROUP, NULL,
+ THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ handle->nl_sk =
+ netlink_kernel_create(NETLINK_MARVELL, NL_MULTICAST_GROUP, NULL, NULL,
+ THIS_MODULE);
+#else
+ handle->nl_sk =
+ netlink_kernel_create(&init_net, NETLINK_MARVELL, NL_MULTICAST_GROUP,
+ NULL, NULL, THIS_MODULE);
+#endif
+#endif
+ if (handle->nl_sk == NULL) {
+ PRINTM(MERROR,
+ "Could not initialize netlink event passing mechanism!\n");
+ goto err_kmalloc;
+ }
+
+ /** Create workqueue */
+ handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
+ if (!handle->workqueue)
+ goto err_kmalloc;
+
+ MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Starting re-association thread...\n");
+ handle->reassoc_thread.handle = handle;
+ woal_create_thread(woal_reassociation_thread, &handle->reassoc_thread,
+ "woal_reassoc_service");
+
+ while (!handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+ /* Register the device. Fill up the private data structure with relevant
+ information from the card and request for the required IRQ. */
+ if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+
+ /* Init FW and HW */
+ if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto err_init_fw;
+ }
+#ifdef CONFIG_PROC_FS
+ /* Initialize proc fs */
+ woal_proc_init(handle);
+#endif /* CONFIG_PROC_FS */
+ /* Add interfaces */
+ for (i = 0; i < handle->drv_mode->intf_num; i++) {
+ if (!woal_add_interface
+ (handle, handle->priv_num,
+ handle->drv_mode->bss_attr[i].bss_type)) {
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ handle->priv_num++;
+ }
+ if (status != MLAN_STATUS_SUCCESS)
+ goto err_add_intf;
+ up(&AddRemoveCardSem);
+ LEAVE();
+ return handle;
+ err_add_intf:
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ err_init_fw:
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ err_registerdev:
+ handle->surprise_removed = MTRUE;
+ woal_terminate_workqueue(handle);
+#ifdef REASSOCIATION
+ if (handle->reassoc_thread.pid) {
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+ }
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+ err_kmalloc:
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ PRINTM(MINFO, "shutdown mlan\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ }
+ woal_free_moal_handle(handle);
+ m_handle = NULL;
+ ((struct sdio_mmc_card *) card)->handle = NULL;
+ err_handle:
+ up(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes the card.
+ *
+ * @param card A pointer to card
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_remove_card(void *card)
+{
+ moal_handle *handle = NULL;
+ moal_private *priv = NULL;
+ mlan_status status;
+ int i;
+
+ ENTER();
+ if (down_interruptible(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ handle = m_handle;
+ if (!handle)
+ goto exit_remove;
+ handle->surprise_removed = MTRUE;
+
+ /* Stop data */
+ for (i = 0; i < handle->priv_num; i++) {
+ if ((priv = handle->priv[i])) {
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+ }
+
+ /* Shutdown firmware */
+ PRINTM(MCMND, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MCMND, "mlan_shutdown_fw done!\n");
+ if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ woal_terminate_workqueue(handle);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Free reassoc_timer\n");
+ if (handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ /* Free adapter structure */
+ PRINTM(MINFO, "Free Adapter\n");
+ woal_free_moal_handle(handle);
+
+ m_handle = NULL;
+ exit_remove:
+ up(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes module.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+woal_init_module(void)
+{
+ int ret = (int) MLAN_STATUS_SUCCESS;
+ int i = 0;
+
+ ENTER();
+
+ /* Replace default fw image name for specific drv_mode */
+ if (fw_name) {
+ for (i = 0; i < (sizeof(drv_mode_tbl) / sizeof(drv_mode_tbl[0])); i++) {
+ if (drv_mode_tbl[i].drv_mode == drv_mode) {
+ drv_mode_tbl[i].fw_name = fw_name;
+ break;
+ }
+ }
+ }
+
+ /* Init mutex */
+ init_MUTEX(&AddRemoveCardSem);
+
+ /* Register with bus */
+ ret = (int) woal_bus_register();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans module
+ *
+ * @return N/A
+ */
+static void
+woal_cleanup_module(void)
+{
+ moal_handle *handle = m_handle;
+ int i;
+ ENTER();
+ if (down_interruptible(&AddRemoveCardSem))
+ goto exit_sem_err;
+ if (!handle)
+ goto exit;
+
+ for (i = 0; i < handle->priv_num; i++) {
+ if ((handle->priv[i]->bss_type == MLAN_BSS_TYPE_STA) &&
+ (handle->priv[i]->media_connected == MTRUE)) {
+ woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
+ }
+ }
+
+#ifdef MFG_CMD_SUPPORT
+ if (!mfg_mode)
+#endif
+ woal_shutdown_fw(woal_get_priv(handle, MLAN_BSS_TYPE_ANY),
+ MOAL_CMD_WAIT);
+
+ exit:
+ up(&AddRemoveCardSem);
+ exit_sem_err:
+ /* Unregister from bus */
+ woal_bus_unregister();
+ LEAVE();
+}
+
+module_init(woal_init_module);
+module_exit(woal_cleanup_module);
+
+module_param(fw_name, charp, 0);
+MODULE_PARM_DESC(fw_name, "Firmware name");
+#ifdef MFG_CMD_SUPPORT
+module_param(mfg_mode, int, 0);
+MODULE_PARM_DESC(mfg_mode,
+ "0: Download normal firmware; 1: Download MFG firmware");
+#endif /* MFG_CMD_SUPPORT */
+#ifdef DEBUG_LEVEL1
+module_param(drvdbg, ulong, 0);
+MODULE_PARM_DESC(drvdbg, "Driver debug");
+#endif /* DEBUG_LEVEL1 */
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/wlan_src/mlinux/moal_main.h b/wlan_src/mlinux/moal_main.h
new file mode 100755
index 0000000..c4d0547
--- /dev/null
+++ b/wlan_src/mlinux/moal_main.h
@@ -0,0 +1,843 @@
+/** @file moal_main.h
+ *
+ * @brief This file contains wlan driver specific defines etc.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _MOAL_MAIN_H
+#define _MOAL_MAIN_H
+
+/* warnfix for FS redefination if any? */
+#ifdef FS
+#undef FS
+#endif
+
+/* Linux header files */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+
+/* ASM files */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Net header files */
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/firmware.h>
+
+/* Wireless header */
+#include <net/iw_handler.h>
+#include "mlan.h"
+#include "moal_shim.h"
+#include "moal_wext.h"
+#include "moal_priv.h"
+
+/** Define BOOLEAN */
+typedef t_u8 BOOLEAN;
+
+/** Driver version */
+extern const char driver_version[];
+
+/** Private structure for MOAL */
+typedef struct _moal_private moal_private;
+/** Handle data structure for MOAL */
+typedef struct _moal_handle moal_handle;
+
+/** Hardware status codes */
+typedef enum _MOAL_HARDWARE_STATUS
+{
+ HardwareStatusReady,
+ HardwareStatusInitializing,
+ HardwareStatusFwReady,
+ HardwareStatusReset,
+ HardwareStatusClosing,
+ HardwareStatusNotReady
+} MOAL_HARDWARE_STATUS;
+
+/** moal_wait_option */
+enum
+{
+ MOAL_NO_WAIT,
+ MOAL_IOCTL_WAIT,
+ MOAL_CMD_WAIT,
+ MOAL_PROC_WAIT,
+ MOAL_WSTATS_WAIT
+};
+
+/** HostCmd_Header */
+typedef struct _HostCmd_Header
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+} HostCmd_Header;
+
+#ifndef MIN
+/** Find minimum */
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * OS timer specific
+ */
+
+/** Timer structure */
+typedef struct _moal_drv_timer
+{
+ /** Timer list */
+ struct timer_list tl;
+ /** Timer function */
+ void (*timer_function) (void *context);
+ /** Timer function context */
+ void *function_context;
+ /** Time period */
+ t_u32 time_period;
+ /** Is timer periodic ? */
+ t_u32 timer_is_periodic;
+ /** Is timer cancelled ? */
+ t_u32 timer_is_canceled;
+} moal_drv_timer, *pmoal_drv_timer;
+
+/**
+ * @brief Timer handler
+ *
+ * @param fcontext Timer context
+ *
+ * @return N/A
+ */
+static inline void
+woal_timer_handler(unsigned long fcontext)
+{
+ pmoal_drv_timer timer = (pmoal_drv_timer) fcontext;
+
+ timer->timer_function(timer->function_context);
+
+ if (timer->timer_is_periodic == MTRUE) {
+ mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
+ }
+}
+
+/**
+ * @brief Initialize timer
+ *
+ * @param timer Timer structure
+ * @param TimerFunction Timer function
+ * @param FunctionContext Timer function context
+ *
+ * @return N/A
+ */
+static inline void
+woal_initialize_timer(pmoal_drv_timer timer,
+ void (*TimerFunction) (void *context),
+ void *FunctionContext)
+{
+ /* First, setup the timer to trigger the wlan_timer_handler proxy */
+ init_timer(&timer->tl);
+ timer->tl.function = woal_timer_handler;
+ timer->tl.data = (t_u32) timer;
+
+ /* Then tell the proxy which function to call and what to pass it */
+ timer->timer_function = TimerFunction;
+ timer->function_context = FunctionContext;
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ timer->timer_is_periodic = MFALSE;
+}
+
+/**
+ * @brief Modify timer
+ *
+ * @param timer Timer structure
+ * @param MillisecondPeriod Time period in millisecond
+ *
+ * @return N/A
+ */
+static inline void
+woal_mod_timer(pmoal_drv_timer timer, t_u32 MillisecondPeriod)
+{
+ timer->time_period = MillisecondPeriod;
+ mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
+ timer->timer_is_canceled = MFALSE;
+}
+
+/**
+ * @brief Cancel timer
+ *
+ * @param timer Timer structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_cancel_timer(moal_drv_timer * timer)
+{
+ del_timer(&timer->tl);
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+}
+
+#ifdef REASSOCIATION
+/*
+ * OS Thread Specific
+ */
+
+#include <linux/kthread.h>
+
+/** Kernel thread structure */
+typedef struct _moal_thread
+{
+ /** Task control structrue */
+ struct task_struct *task;
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t wait_q;
+ /** PID */
+ pid_t pid;
+ /** Pointer to moal_handle */
+ void *handle;
+} moal_thread;
+
+/**
+ * @brief Activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_activate_thread(moal_thread * thr)
+{
+ /** Record the thread pid */
+ thr->pid = current->pid;
+
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->wait_q);
+}
+
+/**
+ * @brief De-activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_deactivate_thread(moal_thread * thr)
+{
+ /* Reset the pid */
+ thr->pid = 0;
+}
+
+/**
+ * @brief Create and run the thread
+ *
+ * @param threadfunc Thread function
+ * @param thr Thread structure
+ * @param name Thread name
+ * @return N/A
+ */
+static inline void
+woal_create_thread(int (*threadfunc) (void *), moal_thread * thr, char *name)
+{
+ /* Create and run the thread */
+ thr->task = kthread_run(threadfunc, thr, "%s", name);
+}
+#endif /* REASSOCIATION */
+
+/* The following macros are neccessary to retain compatibility
+ * around the workqueue chenges happened in kernels >= 2.6.20:
+ * - INIT_WORK changed to take 2 arguments and let the work function
+ * get its own data through the container_of macro
+ * - delayed works have been split from normal works to save some
+ * memory usage in struct work_struct
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK INIT_WORK
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK INIT_DELAYED_WORK
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m.work)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+
+/**
+ * @brief Schedule timeout
+ *
+ * @param millisec Timeout duration in milli second
+ *
+ * @return N/A
+ */
+static inline void
+woal_sched_timeout(t_u32 millisec)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout((millisec * HZ) / 1000);
+}
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/** Get module */
+#define MODULE_GET try_module_get(THIS_MODULE)
+/** Put module */
+#define MODULE_PUT module_put(THIS_MODULE)
+
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) init_MUTEX(x)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) init_MUTEX_LOCKED(x)
+/** Acquire semaphore and with blocking */
+#define MOAL_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
+/** Acquire semaphore without blocking */
+#define MOAL_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
+/** Release semaphore */
+#define MOAL_REL_SEMAPHORE(x) up(x)
+
+/** Default watchdog timeout */
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
+
+/** 10 seconds */
+#define MOAL_TIMER_10S 10000
+/** 5 seconds */
+#define MOAL_TIMER_5S 5000
+/** 1 second */
+#define MOAL_TIMER_1S 1000
+
+/** BSS number bit mask */
+#define BSS_NUM_MASK 7
+
+/** Netlink protocol number */
+#define NETLINK_MARVELL (MAX_LINKS - 1)
+/** Netlink maximum payload size */
+#define NL_MAX_PAYLOAD 1024
+/** Netlink multicast group number */
+#define NL_MULTICAST_GROUP 1
+
+/** MAX PENDING Tx data */
+#define MAX_TX_PENDING 60
+
+/** wait_queue structure */
+typedef struct _wait_queue
+{
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t *wait;
+ /** Pointer to wait condition */
+ t_u16 *condition;
+ /** Start time */
+ t_u32 start_time;
+ /** Status from MLAN */
+ mlan_status status;
+} wait_queue, *pwait_queue;
+
+/** Driver mode STA */
+#define DRV_MODE_STA 0x1
+/** Driver mode UAP */
+#define DRV_MODE_UAP 0x2
+/** Driver mode STA+UAP */
+#define DRV_MODE_UAP_STA 0x3
+
+typedef struct _moal_drv_mode
+{
+ /** driver mode */
+ t_u16 drv_mode;
+ /** total number of interfaces */
+ t_u16 intf_num;
+ /** attribute of bss */
+ mlan_bss_attr *bss_attr;
+ /** name of firmware image */
+ char *fw_name;
+} moal_drv_mode;
+
+/** Private structure for MOAL */
+struct _moal_private
+{
+ /** Handle structure */
+ moal_handle *phandle;
+ /** Tx timeout count */
+ t_u32 num_tx_timeout;
+ /** BSS number */
+ t_u8 bss_num;
+ /** BSS type */
+ t_u8 bss_type;
+ /** MAC address information */
+ t_u8 current_addr[ETH_ALEN];
+ /** Media connection status */
+ BOOLEAN media_connected;
+ /** Net device pointer */
+ struct net_device *netdev;
+ /** Net device statistics structure */
+ struct net_device_stats stats;
+
+ /** IOCTL wait queue token */
+ t_u16 ioctl_wait_q_woken;
+ /** ioctl wait queue */
+ wait_queue_head_t ioctl_wait_q __ATTRIB_ALIGN__;
+ /** Cmd wait queue token */
+ t_u16 cmd_wait_q_woken;
+ /** IOCTL wait queue */
+ wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__;
+#ifdef CONFIG_PROC_FS
+ /** Proc entry */
+ struct proc_dir_entry *proc_entry;
+ /** Proc entry name */
+ t_s8 proc_entry_name[IFNAMSIZ];
+ /** Proc wait queue token */
+ t_u16 proc_wait_q_woken;
+ /** IOCTL wait queue */
+ wait_queue_head_t proc_wait_q __ATTRIB_ALIGN__;
+#endif /* CONFIG_PROC_FS */
+ /** Nickname */
+ t_u8 nick_name[16];
+ /** AdHoc link sensed flag */
+ BOOLEAN is_adhoc_link_sensed;
+ /** IW statistics */
+ struct iw_statistics w_stats;
+ /** w_stats wait queue token */
+ t_u16 w_stats_wait_q_woken;
+ /** w_stats wait queue */
+ wait_queue_head_t w_stats_wait_q __ATTRIB_ALIGN__;
+ /** Current WEP key index */
+ t_u16 current_key_index;
+#ifdef REASSOCIATION
+ mlan_ssid_bssid prev_ssid_bssid;
+ /** Re-association required */
+ BOOLEAN reassoc_required;
+#endif /* REASSOCIATION */
+ /** Rate index */
+ t_u16 rate_index;
+ /** Async scan semaphore */
+ struct semaphore async_sem;
+ /** Scan pending on blocked flag */
+ t_u8 scan_pending_on_block;
+};
+
+/** Handle data structure for MOAL */
+struct _moal_handle
+{
+ /** MLAN adapter structure */
+ t_void *pmlan_adapter;
+ /** Private pointer */
+ moal_private *priv[MLAN_MAX_BSS_NUM];
+ /** Priv number */
+ t_u8 priv_num;
+ /** Bss attr */
+ moal_drv_mode *drv_mode;
+#ifdef CONFIG_PROC_FS
+ /** Proc top level directory entry */
+ struct proc_dir_entry *proc_mwlan;
+#endif
+ /** Firmware */
+ const struct firmware *firmware;
+ /** Hotplug device */
+ struct device *hotplug_device;
+ /** STATUS variables */
+ MOAL_HARDWARE_STATUS hardware_status;
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ BOOLEAN surprise_removed;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Init wait queue token */
+ t_u16 init_wait_q_woken;
+ /** Init wait queue */
+ wait_queue_head_t init_wait_q __ATTRIB_ALIGN__;
+ /** Card pointer */
+ t_void *card;
+ /** Rx pending in MLAN */
+ atomic_t rx_pending;
+ /** Tx packet pending count in mlan */
+ atomic_t tx_pending;
+ /** IOCTL pending count in mlan */
+ atomic_t ioctl_pending;
+ /** Malloc count */
+ t_u32 malloc_count;
+ /** lock count */
+ t_u32 lock_count;
+#ifdef REASSOCIATION
+ /** Re-association thread */
+ moal_thread reassoc_thread;
+ /** Re-association timer set flag */
+ BOOLEAN is_reassoc_timer_set;
+ /** Re-association timer */
+ moal_drv_timer reassoc_timer __ATTRIB_ALIGN__;
+ /** */
+ struct semaphore reassoc_sem;
+ /** Flag of re-association on/off */
+ BOOLEAN reassoc_on;
+#endif /* REASSOCIATION */
+ /** Driver workqueue */
+ struct workqueue_struct *workqueue;
+ /** main work */
+ struct work_struct main_work;
+ /** Netlink kernel socket */
+ struct sock *nl_sk;
+};
+
+/** Debug Macro definition*/
+#ifdef DEBUG_LEVEL1
+extern t_u32 drvdbg;
+extern t_u32 ifdbg;
+
+/** Debug message control bit definition for ifdbg */
+#define MIF_D MBIT(0)
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) do {if (drvdbg & MINFO) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MWARN(msg...) do {if (drvdbg & MWARN) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MENTRY(msg...) do {if (drvdbg & MENTRY) printk(KERN_DEBUG msg);} while(0)
+#else
+#define PRINTM_MINFO(msg...) do {} while (0)
+#define PRINTM_MWARN(msg...) do {} while (0)
+#define PRINTM_MENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) do {if (drvdbg & MFW_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MCMD_D(msg...) do {if (drvdbg & MCMD_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDAT_D(msg...) do {if (drvdbg & MDAT_D) printk(KERN_DEBUG msg);} while(0)
+
+#define PRINTM_MINTR(msg...) do {if (drvdbg & MINTR) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MEVENT(msg...) do {if (drvdbg & MEVENT) printk(msg);} while(0)
+#define PRINTM_MCMND(msg...) do {if (drvdbg & MCMND) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDATA(msg...) do {if (drvdbg & MDATA) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MERROR(msg...) do {if (drvdbg & MERROR) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MFATAL(msg...) do {if (drvdbg & MFATAL) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MMSG(msg...) do {if (drvdbg & MMSG) printk(KERN_ALERT msg);} while(0)
+
+#define PRINTM_MIF_D(msg...) do {if (ifdbg & MIF_D) printk(KERN_DEBUG msg);} while(0)
+
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+#else
+
+#define PRINTM(level,msg...) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Wait until a condition becomes true */
+#define ASSERT(cond) \
+do { \
+ if (!(cond)) \
+ PRINTM(MINFO, "ASSERT: %s:%i\n", __FUNCTION__); \
+} while(0)
+
+/** Log entry point for debugging */
+#define ENTER() PRINTM(MENTRY, "Enter: %s\n", \
+ __FUNCTION__)
+/** Log exit point for debugging */
+#define LEAVE() PRINTM(MENTRY, "Leave: %s\n", \
+ __FUNCTION__)
+
+#ifdef DEBUG_LEVEL1
+#define DBG_DUMP_BUF_LEN 64
+#define MAX_DUMP_PER_LINE 16
+
+static inline void
+hexdump(char *prompt, t_u8 * buf, int len)
+{
+ int i;
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+ char *ptr = dbgdumpbuf;
+
+ printk(KERN_DEBUG "%s:\n", prompt);
+ for (i = 1; i <= len; i++) {
+ ptr += sprintf(ptr, "%02x ", *buf);
+ buf++;
+ if (i % MAX_DUMP_PER_LINE == 0) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ ptr = dbgdumpbuf;
+ }
+ }
+ if (len % MAX_DUMP_PER_LINE) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ }
+}
+
+#define DBG_HEXDUMP_MCMD_D(x,y,z) do {if (drvdbg & MCMD_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MDAT_D(x,y,z) do {if (drvdbg & MDAT_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MIF_D(x,y,z) do {if (ifdbg & MIF_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MFW_D(x,y,z) do {if (drvdbg & MFW_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
+
+#else
+/** Do nothing since debugging is not turned on */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+#endif
+
+#ifdef DEBUG_LEVEL2
+#define HEXDUMP(x,y,z) do {if (drvdbg & MINFO) hexdump(x,y,z);} while(0)
+#else
+/** Do nothing since debugging is not turned on */
+#define HEXDUMP(x,y,z) do {} while (0)
+#endif
+
+#ifdef BIG_ENDIAN
+/** Convert from 16 bit little endian format to CPU format */
+#define woal_le16_to_cpu(x) le16_to_cpu(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define woal_le32_to_cpu(x) le32_to_cpu(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define woal_le64_to_cpu(x) le64_to_cpu(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define woal_cpu_to_le16(x) cpu_to_le16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define woal_cpu_to_le32(x) cpu_to_le32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define woal_cpu_to_le64(x) cpu_to_le64(x)
+#else
+/** Do nothing */
+#define woal_le16_to_cpu(x) x
+/** Do nothing */
+#define woal_le32_to_cpu(x) x
+/** Do nothing */
+#define woal_le64_to_cpu(x) x
+/** Do nothing */
+#define woal_cpu_to_le16(x) x
+/** Do nothing */
+#define woal_cpu_to_le32(x) x
+/** Do nothing */
+#define woal_cpu_to_le64(x) x
+#endif
+
+/**
+ * @brief This function returns first available priv
+ * based on the bss_type
+ *
+ * @param handle A pointer to moal_handle
+ * @param bss_type BSS type or MLAN_BSS_TYPE_ANY
+ *
+ * @return Pointer to moal_private
+ */
+static inline moal_private *
+woal_get_priv(moal_handle * handle, mlan_bss_type bss_type)
+{
+ int i;
+
+ for (i = 0; i < handle->priv_num; i++) {
+ if (handle->priv[i]) {
+ if (bss_type == MLAN_BSS_TYPE_ANY ||
+ handle->priv[i]->bss_type == bss_type)
+ break;
+ }
+ }
+ return ((i < handle->priv_num) ? handle->priv[i] : NULL);
+}
+
+/** Allocate buffer */
+pmlan_buffer woal_alloc_mlan_buffer(int size);
+/** Allocate IOCTL request buffer */
+pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size);
+/** Free buffer */
+void woal_free_mlan_buffer(pmlan_buffer pmbuf);
+/** Get private structure of a BSS by index */
+moal_private *woal_bss_num_to_priv(moal_handle * handle, t_u8 bss_num);
+/* Functions in interface module */
+/** Add card */
+moal_handle *woal_add_card(void *card);
+/** Remove card */
+mlan_status woal_remove_card(void *card);
+/** broadcast event */
+mlan_status woal_broadcast_event(moal_private * priv, t_u8 * payload,
+ t_u32 len);
+
+/** Interrupt handler */
+void woal_interrupt(moal_handle * handle);
+
+/** Get driver version */
+void woal_get_version(moal_handle * handle, char *version, int maxlen);
+/** Request open */
+mlan_status woal_request_open(moal_private * priv);
+/** Request close */
+mlan_status woal_request_close(moal_private * priv);
+/** Request MAC address setting */
+mlan_status woal_request_set_mac_address(moal_private * priv);
+/** Request multicast list setting */
+void woal_request_set_multicast_list(moal_private * priv,
+ struct net_device *dev);
+/** Request IOCTL action */
+mlan_status woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option);
+#ifdef PROC_DEBUG
+/** Get debug information */
+mlan_status woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+/** Set debug information */
+mlan_status woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+#endif
+/** Disconnect */
+mlan_status woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac);
+/** associate */
+mlan_status woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Get Host Sleep parameters */
+mlan_status woal_get_hs_params(moal_private * priv, t_u8 wait_option,
+ mlan_ds_hs_cfg * hscfg);
+/** Cancel Host Sleep configuration */
+mlan_status woal_hs_cfg_cancel(moal_private * priv, t_u8 wait_option);
+
+/** set deep sleep */
+int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option,
+ BOOLEAN bdeep_sleep, t_u16 idletime);
+void woal_send_iwevcustom_event(moal_private * priv, t_s8 * str);
+void woal_send_mic_error_event(moal_private * priv, t_u32 event);
+void woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req);
+/** Request firmware information */
+void woal_request_get_fw_info(moal_private * priv);
+/** Get mode */
+t_u32 woal_get_mode(moal_private * priv, t_u8 wait_option);
+/** Get signal information */
+mlan_status woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal);
+/** Get statistics information */
+mlan_status woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats);
+/** Get data rates */
+mlan_status woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates);
+/** Get channel list */
+mlan_status woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chanlist);
+/** Get BSS information */
+mlan_status woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info);
+/** Get scan table */
+mlan_status woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scanresp);
+/** Set authentication mode */
+mlan_status woal_set_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 auth_mode);
+/** Get authentication mode */
+mlan_status woal_get_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * auth_mode);
+/** Set encryption mode */
+mlan_status woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 encrypt_mode);
+/** Get encryption mode */
+mlan_status woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode);
+/** Enable wep key */
+mlan_status woal_enable_wep_key(moal_private * priv, t_u8 wait_option);
+/** Set WPA enable */
+mlan_status woal_set_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+/** Get WPA state */
+mlan_status woal_get_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 * enable);
+/** Find best network to connect */
+mlan_status woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Request a network scan */
+mlan_status woal_request_scan(moal_private * priv, t_u8 wait_option,
+ mlan_802_11_ssid * req_ssid);
+/** Set E-Supplicant mode */
+mlan_status woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Set Ad-Hoc channel */
+mlan_status woal_change_adhoc_chan(moal_private * priv, int channel);
+/** Set radio on/off */
+int woal_set_radio(moal_private * priv, t_u8 option);
+
+mlan_status woal_set_wapi_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Initialize priv */
+void woal_init_priv(moal_private * priv);
+mlan_status woal_get_bss_type(struct net_device *dev, struct ifreq *req);
+
+#ifdef CONFIG_PROC_FS
+/** Initialize proc fs */
+void woal_proc_init(moal_handle * handle);
+/** Clean up proc fs */
+void woal_proc_exit(moal_handle * handle);
+/** Create proc entry */
+void woal_create_proc_entry(moal_private * priv);
+/** Remove proc entry */
+void woal_proc_remove(moal_private * priv);
+/** string to number */
+int woal_string_to_number(char *s);
+#endif
+
+#ifdef PROC_DEBUG
+/** Create debug proc fs */
+void woal_debug_entry(moal_private * priv);
+/** Remove debug proc fs */
+void woal_debug_remove(moal_private * priv);
+#endif /* PROC_DEBUG */
+
+#ifdef REASSOCIATION
+int woal_reassociation_thread(void *data);
+void woal_reassoc_timer_func(void *context);
+#endif /* REASSOCIATION */
+
+t_void woal_main_work_queue(struct work_struct *work);
+
+#endif /* _MOAL_MAIN_H */
diff --git a/wlan_src/mlinux/moal_priv.c b/wlan_src/mlinux/moal_priv.c
new file mode 100755
index 0000000..5cadd81
--- /dev/null
+++ b/wlan_src/mlinux/moal_priv.c
@@ -0,0 +1,6998 @@
+/** @file moal_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/30/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A,
+ BAND_AN, BAND_A | BAND_AN,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Handle get BSS resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param bss Pointer to mlan_ds_bss structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss)
+{
+ t_u32 mode = 0;
+
+ ENTER();
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_MODE:
+ if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA)
+ mode = IW_MODE_INFRA;
+ else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS)
+ mode = IW_MODE_ADHOC;
+ else
+ mode = IW_MODE_AUTO;
+ priv->w_stats.status = mode;
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to destination buffer
+ * @param pos The position for copy
+ * @param src A pointer to source buffer
+ * @param len Length of the source buffer
+ *
+ * @return Number of rates copied
+ */
+static inline int
+woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= MLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+ return pos;
+}
+
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_driver_version(moal_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *) req;
+ int len;
+ char buf[MLAN_MAX_VER_STR_LEN];
+ ENTER();
+
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+
+ len = strlen(buf);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ wrq->u.data.length = len;
+ }
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get extended driver version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ireq A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_driver_verext(moal_private * priv, struct ifreq *ireq)
+{
+ struct iwreq *wrq = (struct iwreq *) ireq;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ if (!wrq->u.data.flags) {
+ info->param.ver_ext.version_str_sel =
+ *((int *) (wrq->u.name + SUBCMD_OFFSET));
+ } else {
+ if (copy_from_user
+ (&info->param.ver_ext.version_str_sel, wrq->u.data.pointer,
+ sizeof(info->param.ver_ext.version_str_sel))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ } else {
+ if (info->param.ver_ext.version_str_sel < 0) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, info->param.ver_ext.version_str,
+ strlen(info->param.ver_ext.version_str))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ wrq->u.data.length = strlen(info->param.ver_ext.version_str);
+ }
+
+ PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
+ info->param.ver_ext.version_str);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ * @param bdeep_sleep TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ * @param idletime Idle time for optimized PS API
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep,
+ t_u16 idletime)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_SET;
+ if (bdeep_sleep == MTRUE) {
+ PRINTM(MCMND, "Deep Sleep: sleep\n");
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ if (idletime) {
+ pm->param.auto_deep_sleep.idletime = idletime;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MCMND, "%lu : Deep Sleep: wakeup\n", jiffies);
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Performs warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_warm_reset(moal_private * priv)
+{
+ int ret = 0;
+ int intf_num;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Disable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_stop_queue(handle->priv[intf_num]->netdev);
+ netif_device_detach(handle->priv[intf_num]->netdev);
+ }
+
+ /* Exit deep sleep */
+ woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_PROC_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ if (MLAN_STATUS_SUCCESS != woal_hs_cfg_cancel(priv, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect from network */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ if (handle->priv[intf_num]->media_connected == MTRUE) {
+ woal_disconnect(handle->priv[intf_num], MOAL_IOCTL_WAIT, NULL);
+ }
+ }
+
+ /* Initialize private structures */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++)
+ woal_init_priv(handle->priv[intf_num]);
+
+#ifdef REASSOCIATION
+ /* Reset the reassoc timer and status */
+ handle->reassoc_on = MFALSE;
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+#endif
+
+ /* Restart the firmware */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_WARM_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ kfree(req);
+ goto done;
+ }
+ kfree(req);
+ }
+
+ /* Enable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_device_attach(handle->priv[intf_num]->netdev);
+ netif_start_queue(handle->priv[intf_num]->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_signal(moal_private * priv, struct iwreq *wrq)
+{
+/** Input data size */
+#define IN_DATA_SIZE 2
+/** Output data size */
+#define OUT_DATA_SIZE 12
+ int ret = 0;
+ int in_data[IN_DATA_SIZE];
+ int out_data[OUT_DATA_SIZE];
+ mlan_ds_get_signal signal;
+ int data_length = 0;
+
+ ENTER();
+
+ memset(in_data, 0, sizeof(in_data));
+ memset(out_data, 0, sizeof(out_data));
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (in_data, wrq->u.data.pointer,
+ sizeof(int) * MIN(wrq->u.data.length, sizeof(in_data)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ switch (wrq->u.data.length) {
+ case 0: /* No checking, get everything */
+ break;
+ case 2: /* Check subtype range */
+ if (in_data[1] < 1 || in_data[1] > 4) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Fall through */
+ case 1: /* Check type range */
+ if (in_data[0] < 1 || in_data[0] > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int) signal.bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int) signal.bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n", (int) signal.data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n", (int) signal.data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n", (int) signal.bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n", (int) signal.bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n", (int) signal.data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n", (int) signal.data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n", (int) signal.bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n", (int) signal.bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n", (int) signal.data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n", (int) signal.data_nf_avg);
+
+ /* Check type */
+ switch (in_data[0]) {
+ case 0: /* Send everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* RSSI */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_rssi_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* SNR */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_snr_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_snr_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_snr_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* NF */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_nf_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_nf_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_nf_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, out_data,
+ wrq->u.data.length * sizeof(out_data[0]))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param deep_sleep Pointer to return deep_sleep setting
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_deep_sleep(moal_private * priv, t_u32 * deep_sleep)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *deep_sleep = pm->param.auto_deep_sleep.auto_ds;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set DeepSleep mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wreq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deep_sleep_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u32 deep_sleep = DEEP_SLEEP_OFF;
+ static t_u16 idletime = DEEP_SLEEP_ILDE_TIME;
+ t_u32 data[2];
+
+ ENTER();
+
+ if (wrq->u.data.length == 1 || wrq->u.data.length == 2) {
+ if (copy_from_user
+ (&data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ deep_sleep = data[0];
+ if (deep_sleep == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+ } else if (deep_sleep == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (wrq->u.data.length == 2)
+ idletime = data[1];
+ woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, idletime);
+ } else {
+ PRINTM(MERROR, "Unknown option = %lu\n", deep_sleep);
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments %d\n", wrq->u.data.length);
+ LEAVE();
+ return -EINVAL;
+ } else { /* Display Deep Sleep settings */
+ PRINTM(MINFO, "Get Deep Sleep Mode\n");
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, &deep_sleep)) {
+ LEAVE();
+ return -EFAULT;
+ }
+ }
+
+ /* Copy the Deep Sleep setting to user */
+ if (copy_to_user(wrq->u.data.pointer, &deep_sleep, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get Usr 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_htcap_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length > 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (((req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg))) == NULL)) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 1) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.htcap_cfg = data;
+ PRINTM(MINFO, "SET: htusrcap:0x%x\n", data);
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = cfg_11n->param.htcap_cfg;
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data);
+
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable amsdu_aggr_ctrl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_amsdu_aggr_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.length != 0) && (wrq->u.data.length != 1)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 1) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
+ data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_tx_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.length != 0) && (wrq->u.data.length != 1)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 1) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.httxcap = data;
+ PRINTM(MINFO, "SET: httxcap:%d\n", data);
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap:%d\n", data);
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable TX Aggregation
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_prio_tbl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID * 2], i, j;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.pointer == NULL)) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ wrq->u.data.length = MAX_NUM_TID * 2;
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
+ data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 16) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA Reject paramters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_reject(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID], ret = 0, i;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ PRINTM(MERROR, "%s\n", __FUNCTION__);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ PRINTM(MERROR, "Addba reject moal\n");
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ wrq->u.data.length = MAX_NUM_TID;
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ data[i] = cfg_11n->param.addba_reject[i];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 8) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ cfg_11n->param.addba_reject[i] = data[i];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA paramters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_para_updt(moal_private * priv, struct iwreq *wrq)
+{
+ int data[3], ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Add BA parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = cfg_11n->param.addba_param.timeout;
+ data[1] = cfg_11n->param.addba_param.txwinsize;
+ data[2] = cfg_11n->param.addba_param.rxwinsize;
+ PRINTM(MINFO, "GET: timeout:%d txwinsize:%d rxwinsize:%d\n", data[0],
+ data[1], data[2]);
+
+ wrq->u.data.length = 3;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 3) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.timeout = data[0];
+ cfg_11n->param.addba_param.txwinsize = data[1];
+ cfg_11n->param.addba_param.rxwinsize = data[2];
+ PRINTM(MINFO, "SET: timeout:%d txwinsize:%d rxwinsize:%d\n", data[0],
+ data[1], data[2]);
+
+ /* Update Add BA parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit buffer size
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_txbuf_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int buf_size;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Tx buffer size from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user(&buf_size, wrq->u.data.pointer, sizeof(buf_size))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "SET: Tx buffer size %d\n", buf_size);
+ /* Update Tx buffer size in MLAN */
+ req->action = MLAN_ACT_SET;
+ cfg_11n->param.tx_buf_size = buf_size;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf_size = cfg_11n->param.tx_buf_size;
+ if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_cfg(moal_private * priv, struct iwreq *wrq, BOOLEAN invoke_hostcmd)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ds_hs_cfg hscfg;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if (data_length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ req->action = MLAN_ACT_SET;
+ if (data_length >= 1 && data_length <= 3) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* Do a GET first if all arguments are not available */
+ if (data_length >= 1 && data_length < 3) {
+ woal_get_hs_params(priv, MOAL_IOCTL_WAIT, &hscfg);
+ }
+
+ switch (data_length) {
+ case 3: /* Conditions, GPIO, GAP provided */
+ pmcfg->param.hs_cfg.conditions = data[0];
+ pmcfg->param.hs_cfg.gpio = data[1];
+ pmcfg->param.hs_cfg.gap = data[2];
+ break;
+ case 2: /* Conditions, GPIO provided */
+ pmcfg->param.hs_cfg.conditions = data[0];
+ pmcfg->param.hs_cfg.gpio = data[1];
+ pmcfg->param.hs_cfg.gap = hscfg.gap;
+ break;
+ case 1: /* Conditions provided */
+ pmcfg->param.hs_cfg.conditions = data[0];
+ pmcfg->param.hs_cfg.gpio = hscfg.gpio;
+ pmcfg->param.hs_cfg.gap = hscfg.gap;
+ break;
+ case 0:
+ break;
+ default:
+ break;
+ }
+
+ pmcfg->param.hs_cfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ data[0] = pmcfg->param.hs_cfg.conditions;
+ data[1] = pmcfg->param.hs_cfg.gpio;
+ data[2] = pmcfg->param.hs_cfg.gap;
+ wrq->u.data.length = 3;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_setpara(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length >= 1 && data_length <= 3) {
+ ret = woal_hs_cfg(priv, wrq, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout extend
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_inactivity_timeout_ext(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ pmlan_ds_inactivity_to inac_to = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if ((data_length != 0) && (data_length != 3) && (data_length != 4)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->action = MLAN_ACT_GET;
+ if (data_length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ inac_to->timeout_unit = data[0];
+ inac_to->unicast_timeout = data[1];
+ inac_to->mcast_timeout = data[2];
+ inac_to->ps_entry_timeout = data[3];
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy back current values regardless of GET/SET */
+ data[0] = inac_to->timeout_unit;
+ data[1] = inac_to->unicast_timeout;
+ data[2] = inac_to->mcast_timeout;
+ data[3] = inac_to->ps_entry_timeout;
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = 4;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_ecl_sys_clock(moal_private * priv, struct iwreq *wrq)
+{
+ int data[64];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int data_length = wrq->u.data.length;
+ int i = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length)
+ req->action = MLAN_ACT_GET;
+ else if (data_length <= MLAN_MAX_CLK_NUM) {
+ req->action = MLAN_ACT_SET;
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ /* Get configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Current system clock */
+ data[0] = (int) cfg->param.sys_clock.cur_sys_clk;
+ wrq->u.data.length = 1;
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Configurable clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+ wrq->u.data.length += data_length;
+
+ /* Get supported clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Supported clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+
+ wrq->u.data.length += data_length;
+
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /* Set configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ cfg->param.sys_clock.sys_clk_num = MIN(MLAN_MAX_CLK_NUM, data_length);
+ for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++) {
+ cfg->param.sys_clock.sys_clk[i] = (t_u16) data[i];
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_band_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, i;
+ int data[3];
+ int user_data_len = wrq->u.data.length;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+
+ if (user_data_len > 3) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channnel values from
+ MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = radio_cfg->param.band_cfg.config_bands; /* Infra Band */
+ data[1] = radio_cfg->param.band_cfg.adhoc_start_band; /* Adhoc Band */
+ data[2] = radio_cfg->param.band_cfg.adhoc_channel; /* Adhoc
+ Channel */
+
+ wrq->u.data.length = 3;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+
+ /* To support only <b/bg/bgn/n> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len == 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BCA timeshare
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_bca_time_share(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data[3];
+ int user_data_len = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bca_cfg *bca_cfg = NULL;
+
+ ENTER();
+
+ if (user_data_len != 1 && user_data_len != 3) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if ((data[0] > TRAFFIC_TYPE_MEDIUMHIGH) && (data[0] != TRAFFIC_TYPE_RESET)) {
+ PRINTM(MERROR, "Invalid traffic_type\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len == 3) {
+ /* Valid Range for timeshare_interval: < 20 ... 60_000 > ms */
+ if (data[1] < MIN_TIMESHARE_INTERVAL ||
+ data[1] > MAX_TIMESHARE_INTERVAL) {
+ PRINTM(MERROR,
+ "Invalid timeshare_interval Range: < 20 ... 60000 > ms\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ data[1] -= (data[1] % 10); /* If value is not multiple of 10 then
+ take the floor value */
+
+ /* If value is not multiple of 10 then take the floor value */
+ data[2] -= (data[2] % 10);
+ /* Valid Range for timeshare_interval: < 0 ... bt_time > */
+ if (data[2] < 0 || data[2] > data[1]) {
+ PRINTM(MERROR,
+ "Invalid bt_time Range: < 0 ... timeshare_interval > ms\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bca_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ bca_cfg = (mlan_ds_bca_cfg *) req->pbuf;
+ bca_cfg->sub_command = MLAN_OID_BCA_TS;
+ req->req_id = MLAN_IOCTL_BCA_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (user_data_len > 0)
+ bca_cfg->param.bca_ts.traffic_type = data[0];
+ if (user_data_len == 3) {
+ req->action = MLAN_ACT_SET;
+ bca_cfg->param.bca_ts.timeshare_interval = data[1];
+ bca_cfg->param.bca_ts.bt_time = data[2];
+ }
+
+ PRINTM(MINFO, "traffic_type=0x%x", data[0]);
+ if (user_data_len == 3)
+ PRINTM(MINFO, " timeshare_interval=0x%x bt_time=0x%x\n", data[1],
+ data[2]);
+
+ /* Set/Get BCA time share values from MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ if (user_data_len < 3) {
+ data[0] = bca_cfg->param.bca_ts.traffic_type;
+ data[1] = bca_cfg->param.bca_ts.timeshare_interval;
+ data[2] = bca_cfg->param.bca_ts.bt_time;
+
+ wrq->u.data.length = 3;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write adapter registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_reg_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 3) {
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ reg->param.reg_rw.type = (t_u32) data[0];
+ reg->param.reg_rw.offset = (t_u32) data[1];
+ if (data_length == 3)
+ reg->param.reg_rw.value = (t_u32) data[2];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, ®->param.reg_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_read_eeprom(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_EEPROM_RD;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg->param.rd_eeprom.offset = (t_u16) data[0];
+ reg->param.rd_eeprom.byte_count = (t_u16) data[1];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = reg->param.rd_eeprom.byte_count;
+ if (copy_to_user
+ (wrq->u.data.pointer, reg->param.rd_eeprom.value,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write device memory value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mem_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ t_u32 data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *) req->pbuf;
+ reg_mem->sub_command = MLAN_OID_MEM_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 1) {
+ PRINTM(MINFO, "MEM_RW: GET\n");
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 2) {
+ PRINTM(MINFO, "MEM_RW: SET\n");
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg_mem->param.mem_rw.addr = (t_u32) data[0];
+ if (data_length == 2)
+ reg_mem->param.mem_rw.value = (t_u32) data[1];
+
+ PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n",
+ (int) reg_mem->param.mem_rw.addr, (int) reg_mem->param.mem_rw.value);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, ®_mem->param.mem_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get LOG
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_log(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_get_stats stats;
+ char *buf = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, " GET STATS\n");
+ if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_ATOMIC))) {
+ PRINTM(MERROR, "kmalloc failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf, "\n"
+ "mcasttxframe %lu\n"
+ "failed %lu\n"
+ "retry %lu\n"
+ "multiretry %lu\n"
+ "framedup %lu\n"
+ "rtssuccess %lu\n"
+ "rtsfailure %lu\n"
+ "ackfailure %lu\n"
+ "rxfrag %lu\n"
+ "mcastrxframe %lu\n"
+ "fcserror %lu\n"
+ "txframe %lu\n"
+ "wepicverrcnt-1 %lu\n"
+ "wepicverrcnt-2 %lu\n"
+ "wepicverrcnt-3 %lu\n"
+ "wepicverrcnt-4 %lu\n",
+ stats.mcast_tx_frame,
+ stats.failed,
+ stats.retry,
+ stats.multi_retry,
+ stats.frame_dup,
+ stats.rts_success,
+ stats.rts_failure,
+ stats.ack_failure,
+ stats.rx_frag,
+ stats.mcast_rx_frame,
+ stats.fcs_error,
+ stats.tx_frame,
+ stats.wep_icv_error[0],
+ stats.wep_icv_error[1],
+ stats.wep_icv_error[2], stats.wep_icv_error[3]);
+ wrq->u.data.length = strlen(buf) + 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deauth(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sockaddr saddr;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ /* Deauth mentioned BSSID */
+ if (copy_from_user(&saddr, wrq->u.data.pointer, sizeof(saddr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) saddr.sa_data))
+ ret = -EFAULT;
+ } else {
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL))
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_tx_power_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[5], user_data_len;
+ int ret = 0;
+ mlan_bss_info bss_info;
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ memset(data, 0, sizeof(data));
+ user_data_len = wrq->u.data.length;
+
+ if (user_data_len) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ switch (user_data_len) {
+ case 1:
+ if (data[0] != 0xFF)
+ ret = -EINVAL;
+ break;
+ case 2:
+ case 4:
+ if (data[0] == 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ if (data[1] < bss_info.min_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[1], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (user_data_len == 4) {
+ if (data[1] > data[2]) {
+ PRINTM(MERROR, "Min power should be less than maximum!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] < 0) {
+ PRINTM(MERROR, "Step should not less than 0!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[2] > bss_info.max_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] > data[2] - data[1]) {
+ PRINTM(MERROR,
+ "Step should not greater than power difference!\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ if (!user_data_len)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ pcfg->param.power_ext.len = user_data_len;
+ memcpy((t_u8 *) & pcfg->param.power_ext.power_data, (t_u8 *) data,
+ sizeof(data));
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & pcfg->param.power_ext.power_data,
+ sizeof(int) * pcfg->param.power_ext.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = pcfg->param.power_ext.len;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx/Rx data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txrx_rate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & rate->param.data_rate,
+ sizeof(int) * 2)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Turn on/off the sdio clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sdio_clock_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data = 2;
+ /* Initialize the clock state as on */
+ static int clock_state = 1;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ wrq->u.data.length = sizeof(clock_state) / sizeof(int);
+ if (copy_to_user(wrq->u.data.pointer, &clock_state, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ goto done;
+ }
+ switch (data) {
+ case CMD_DISABLED:
+ PRINTM(MINFO, "SDIO clock is turned off\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
+ clock_state = data;
+ break;
+ case CMD_ENABLED:
+ PRINTM(MINFO, "SDIO clock is turned on\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
+ clock_state = data;
+ break;
+ default:
+ ret = -EINVAL;
+ PRINTM(MINFO, "sdioclock: wrong parameter\n");
+ break;
+ }
+ done:
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_beacon_interval(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int bcn = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bcn < MLAN_MIN_BEACON_INTERVAL) ||
+ (bcn > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.bcn_interval = bcn;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.bcn_interval,
+ sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_atim_window(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int atim = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&atim, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((atim < 0) || (atim > MLAN_MAX_ATIM_WINDOW)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_ATIM_WINDOW;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.atim_window = atim;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.atim_window, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_txrate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ int rateindex = 0;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ if (copy_from_user(&rateindex, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ if (rateindex == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((rateindex != MLAN_RATE_INDEX_MCS32) &&
+ ((rateindex < 0) || (rateindex > MLAN_RATE_INDEX_MCS7))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = rateindex;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (wrq->u.data.length)
+ priv->rate_index = rateindex;
+ }
+ if (!wrq->u.data.length) {
+ if (rate->param.rate_cfg.is_rate_auto)
+ rateindex = AUTO_RATE;
+ else
+ rateindex = rate->param.rate_cfg.rate;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int))) {
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_regioncode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int region = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(®ion, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &cfg->param.region_code, sizeof(int)))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_radio(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_bss_info bss_info;
+ int option = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (wrq->u.data.length) {
+ /* Set radio */
+ if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8) option))
+ ret = -EFAULT;
+ } else {
+ /* Get radio status */
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &bss_info.radio_on,
+ sizeof(bss_info.radio_on))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Get/Set the bit mask of driver debug message control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to wrq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_drv_dbg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+
+ ENTER();
+
+ if (!wrq->u.data.length) {
+ data[0] = drvdbg;
+ data[1] = ifdbg;
+ /* Return the current driver debug bit masks */
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ wrq->u.data.length = 2;
+ } else if (wrq->u.data.length < 3) {
+ /* Get the driver debug bit masks */
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ drvdbg = data[0];
+ if (wrq->u.data.length == 2)
+ ifdbg = data[1];
+ } else {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ goto drvdbgexit;
+ }
+
+ printk(KERN_ALERT "drvdbg = 0x%08lx\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+ printk(KERN_ALERT "MINFO (%08lx) %s\n", MINFO,
+ (drvdbg & MINFO) ? "X" : "");
+ printk(KERN_ALERT "MWARN (%08lx) %s\n", MWARN,
+ (drvdbg & MWARN) ? "X" : "");
+ printk(KERN_ALERT "MENTRY (%08lx) %s\n", MENTRY,
+ (drvdbg & MENTRY) ? "X" : "");
+#endif
+ printk(KERN_ALERT "MFW_D (%08lx) %s\n", MFW_D,
+ (drvdbg & MFW_D) ? "X" : "");
+ printk(KERN_ALERT "MCMD_D (%08lx) %s\n", MCMD_D,
+ (drvdbg & MCMD_D) ? "X" : "");
+ printk(KERN_ALERT "MDAT_D (%08lx) %s\n", MDAT_D,
+ (drvdbg & MDAT_D) ? "X" : "");
+ printk(KERN_ALERT "MINTR (%08lx) %s\n", MINTR,
+ (drvdbg & MINTR) ? "X" : "");
+ printk(KERN_ALERT "MEVENT (%08lx) %s\n", MEVENT,
+ (drvdbg & MEVENT) ? "X" : "");
+ printk(KERN_ALERT "MCMND (%08lx) %s\n", MCMND,
+ (drvdbg & MCMND) ? "X" : "");
+ printk(KERN_ALERT "MDATA (%08lx) %s\n", MDATA,
+ (drvdbg & MDATA) ? "X" : "");
+ printk(KERN_ALERT "MERROR (%08lx) %s\n", MERROR,
+ (drvdbg & MERROR) ? "X" : "");
+ printk(KERN_ALERT "MFATAL (%08lx) %s\n", MFATAL,
+ (drvdbg & MFATAL) ? "X" : "");
+ printk(KERN_ALERT "MMSG (%08lx) %s\n", MMSG, (drvdbg & MMSG) ? "X" : "");
+ printk(KERN_ALERT "ifdbg = 0x%08lx\n", ifdbg);
+ printk(KERN_ALERT "MIF_D (%08lx) %s\n", MIF_D, (ifdbg & MIF_D) ? "X" : "");
+
+ drvdbgexit:
+ LEAVE();
+ return ret;
+}
+#endif /* DEBUG_LEVEL1 */
+
+/**
+ * @brief Set/Get Tx/Rx antenna
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_tx_rx_ant(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ radio->param.antenna = data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = radio->param.antenna;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_qos_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8) data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = (int) cfg->param.qos_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get LDO configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ldo_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_LDO;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != LDO_INTERNAL && data != LDO_EXTERNAL) {
+ PRINTM(MERROR, "Invalid parameter, LDO config not changed\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.ldo_cfg = (t_u16) data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = (int) cfg->param.ldo_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wws_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *wws = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wws = (mlan_ds_misc_cfg *) req->pbuf;
+ wws->sub_command = MLAN_OID_MISC_WWS;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != CMD_DISABLED && data != CMD_ENABLED) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ wws->param.wws_cfg = data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = wws->param.wws_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_pd(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+ (data == 0)
+ || (data == SLEEP_PERIOD_RESERVED_FF)
+ ) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = data;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = pm_cfg->param.sleep_period;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configuer sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_ds_sleep_params *psleep_params = NULL;
+ int data[6] = { 0 }, i;
+#ifdef DEBUG_LEVEL1
+ char err_str[][35] = { {"sleep clock error in ppm"},
+ {"wakeup offset in usec"},
+ {"clock stabilization time in usec"},
+ {"value of reserved for debug"}
+ };
+#endif
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ psleep_params = (pmlan_ds_sleep_params) & pm->param.sleep_params;
+
+ if (wrq->u.data.length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 6) {
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) *
+ wrq->u.data.length)) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
+ return -EINVAL;
+ }
+#define MIN_VAL 0x0000
+#define MAX_VAL 0xFFFF
+ for (i = 0; i < 6; i++) {
+ if ((i == 3) || (i == 4)) {
+ /* These two cases are handled below the loop */
+ continue;
+ }
+ if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
+ PRINTM(MERROR, "Invalid %s (0-65535)!\n", err_str[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (data[3] < 0 || data[3] > 2) {
+ PRINTM(MERROR, "Invalid control periodic calibration (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[4] < 0 || data[4] > 2) {
+ PRINTM(MERROR, "Invalid control of external sleep clock (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ psleep_params->error = data[0];
+ psleep_params->offset = data[1];
+ psleep_params->stable_time = data[2];
+ psleep_params->cal_control = data[3];
+ psleep_params->ext_sleep_clk = data[4];
+ psleep_params->reserved = data[5];
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = psleep_params->error;
+ data[1] = psleep_params->offset;
+ data[2] = psleep_params->stable_time;
+ data[3] = psleep_params->cal_control;
+ data[4] = psleep_params->ext_sleep_clk;
+ data[5] = psleep_params->reserved;
+ wrq->u.data.length = 6;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) *
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief Set/Get reassociation settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_reassoc(moal_private * priv, struct iwreq *wrq)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int data = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data == 0) {
+ handle->reassoc_on = MFALSE;
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ } else
+ handle->reassoc_on = MTRUE;
+ } else {
+ data = (int) handle->reassoc_on;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief implement WMM enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wmm_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *wmm = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
+
+ if (wrq->u.data.length) {
+ /* Set WMM configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ wmm->param.wmm_enable = MFALSE;
+ else
+ wmm->param.wmm_enable = MTRUE;
+ } else {
+ /* Get WMM status */
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &wmm->param.wmm_enable,
+ sizeof(wmm->param.wmm_enable))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11d_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
+ if (wrq->u.data.length) {
+ /* Set 11D configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data == CMD_DISABLED)
+ pcfg_11d->param.enable_11d = MFALSE;
+ else
+ pcfg_11d->param.enable_11d = MTRUE;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &pcfg_11d->param.enable_11d,
+ sizeof(pcfg_11d->param.enable_11d))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wps_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ char buf[8];
+ struct iwreq *wreq = (struct iwreq *) wrq;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, wreq->u.data.pointer,
+ MIN(sizeof(buf) - 1, wreq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (buf[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert ascii string to Hex integer
+ *
+ * @param d A pointer to integer buf
+ * @param s A pointer to ascii string
+ * @param dlen The length o fascii string
+ *
+ * @return Number of integer
+ */
+static int
+woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen)
+{
+ int i;
+ t_u8 n;
+
+ ENTER();
+
+ memset(d, 0x00, dlen);
+
+ for (i = 0; i < dlen * 2; i++) {
+ if ((s[i] >= 48) && (s[i] <= 57))
+ n = s[i] - 48;
+ else if ((s[i] >= 65) && (s[i] <= 70))
+ n = s[i] - 55;
+ else if ((s[i] >= 97) && (s[i] <= 102))
+ n = s[i] - 87;
+ else
+ break;
+ if (!(i % 2))
+ n = n * 16;
+ d[i / 2] += n;
+ }
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Return hex value of a give character
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted chanrater if chr is a valid hex, else 0
+ */
+static int
+woal_hexval(char chr)
+{
+ ENTER();
+
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Return hex value of a given ascii string
+ *
+ * @param a String to be converted to ascii
+ *
+ * @return The converted chanrater if a is a valid hex, else 0
+ */
+static int
+woal_atox(char *a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (isxdigit(*a))
+ i = i * 16 + woal_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Extension of strsep lib command. This function will also take care
+ * escape character
+ *
+ * @param s A pointer to array of chars to process
+ * @param delim The delimiter character to end the string
+ * @param esc The escape character to ignore for delimiter
+ *
+ * @return Pointer to the seperated string if delim found, else NULL
+ */
+static char *
+woal_strsep(char **s, char delim, char esc)
+{
+ char *se = *s, *sb;
+
+ ENTER();
+
+ if (!(*s) || (*se == '\0')) {
+ LEAVE();
+ return NULL;
+ }
+
+ for (sb = *s; *sb != '\0'; ++sb) {
+ if (*sb == esc && *(sb + 1) == esc) {
+ /*
+ * We get a esc + esc seq then keep the one esc
+ * and chop off the other esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == esc && *(sb + 1) == delim) {
+ /*
+ * We get a delim + esc seq then keep the delim
+ * and chop off the esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == delim)
+ break;
+ }
+
+ if (*sb == '\0')
+ sb = NULL;
+ else
+ *sb++ = '\0';
+
+ *s = sb;
+
+ LEAVE();
+ return se;
+}
+
+/**
+ * @brief Convert mac address from string to t_u8 buffer.
+ *
+ * @param mac_addr The buffer to store the mac address in.
+ * @param buf The source of mac address which is a string.
+ *
+ * @return N/A
+ */
+static void
+woal_mac2u8(t_u8 * mac_addr, char *buf)
+{
+ char *begin = buf, *end;
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < ETH_ALEN; ++i) {
+ end = woal_strsep(&begin, ':', '/');
+ if (end)
+ mac_addr[i] = woal_atox(end);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Set WPA passphrase and SSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_passphrase(moal_private * priv, struct iwreq *wrq)
+{
+ t_u16 len = 0;
+ static char buf[256];
+ char *begin, *end, *opt;
+ int ret = 0, action = -1, i;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *mac = NULL;
+
+ ENTER();
+
+ if (!wrq->u.data.length) {
+ PRINTM(MERROR, "Argument missing for setpassphrase\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ if (wrq->u.data.length <= 1) {
+ PRINTM(MERROR, "No valid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Parse the buf to get the cmd_action */
+ begin = buf;
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ strcpy((char *) sec->param.passphrase.ssid.ssid, end);
+ PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid,
+ (int) sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != (MLAN_MAX_PMK_LENGTH * 2)) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex(sec->param.passphrase.psk.pmk.pmk, end,
+ MLAN_MAX_PMK_LENGTH * 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR, "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ strcpy(sec->param.passphrase.psk.passphrase.passphrase, end);
+ sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int) sec->param.passphrase.psk.passphrase.passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (action == 0) {
+ memset(buf, 0, sizeof(buf));
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(buf + len, "ssid:");
+ memcpy(buf + len, sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(buf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *) & sec->param.passphrase.bssid;
+ len += sprintf(buf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(buf + len, "%02x:", mac[i]);
+ len += sprintf(buf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(buf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_PMK_LENGTH; ++i)
+ len +=
+ sprintf(buf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(buf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len +=
+ sprintf(buf + len, "passphrase:%s \n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+ PRINTM(MERROR, "Copy to user failed, len %d\n", len);
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = len;
+ }
+
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupp mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_esupp_mode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & sec->param.esupp_mode,
+ sizeof(int) * 3)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 3;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** AES key length */
+#define AES_KEY_LEN 16
+/**
+ * @brief Adhoc AES control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_adhoc_aes_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ static char buf[256];
+ int ret = 0, action = -1, i;
+ t_u8 key_ascii[32];
+ t_u8 key_hex[16];
+ t_u8 *tmp;
+ mlan_bss_info bss_info;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ memset(key_ascii, 0x00, sizeof(key_ascii));
+ memset(key_hex, 0x00, sizeof(key_hex));
+
+ /* Get current BSS information */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.bss_mode != MLAN_BSS_MODE_IBSS ||
+ bss_info.media_connected == MTRUE) {
+ PRINTM(MERROR, "STA is connected or not in IBSS mode.\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ if (wrq->u.data.length == 1) {
+ /* Get Adhoc AES Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = 0x40000000;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy(key_hex, sec->param.encrypt_key.key_material,
+ sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ wrq->u.data.length = sizeof(key_ascii) + 1;
+
+ tmp = key_ascii;
+ for (i = 0; i < sizeof(key_hex); i++)
+ tmp += sprintf((char *) tmp, "%02x", key_hex[i]);
+ } else if (wrq->u.data.length >= 2) {
+ /* Parse the buf to get the cmd_action */
+ action = woal_atox(&buf[0]);
+ if (action < 1 || action > 2) {
+ PRINTM(MERROR, "Invalid action argument %d\n", action);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+
+ if (action == 1) {
+ /* Set Adhoc AES Key */
+ memcpy(key_ascii, &buf[2], sizeof(key_ascii));
+ woal_ascii2hex(key_hex, (char *) key_ascii, sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = 0x40000000;
+ memcpy(sec->param.encrypt_key.key_material,
+ key_hex, sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (action == 2) {
+ /* Clear Adhoc AES Key */
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = 0x40000000;
+ memset(sec->param.encrypt_key.key_material, 0,
+ sizeof(sec->param.encrypt_key.key_material));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ HEXDUMP("Adhoc AES Key (ASCII)", key_ascii, sizeof(key_ascii));
+ wrq->u.data.length = sizeof(key_ascii);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &key_ascii,
+ sizeof(key_ascii))) {
+ PRINTM(MERROR, "copy_to_user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/**
+ * @brief Manufacturing command ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mfg_command(moal_private * priv, struct iwreq *wrq)
+{
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get MFG command header */
+ if (copy_from_user
+ (&cmd_header, wrq->u.data.pointer, sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "copy from user failed: MFG command header\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.mfgcmd.len = cmd_header.size;
+
+ PRINTM(MINFO, "MFG command len = %lu\n", misc->param.mfgcmd.len);
+
+ if (cmd_header.size > MLAN_SIZE_OF_CMD_BUFFER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.mfgcmd.cmd, wrq->u.data.pointer, cmd_header.size)) {
+ PRINTM(MERROR, "copy from user failed: MFG command\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_MFG_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) misc->param.mfgcmd.cmd,
+ MIN(cmd_header.size, misc->param.mfgcmd.len))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = MIN(cmd_header.size, misc->param.mfgcmd.len);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/**
+ * @brief host command ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_host_command(moal_private * priv, struct iwreq *wrq)
+{
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user
+ (&cmd_header, wrq->u.data.pointer, sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "copy from user failed: Host command header\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ PRINTM(MINFO, "Host command len = %lu\n", misc->param.hostcmd.len);
+
+ if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.hostcmd.cmd, wrq->u.data.pointer,
+ woal_le16_to_cpu(cmd_header.size))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = misc->param.hostcmd.len;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief arpfilter ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_arp_filter(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
+ misc->param.gen_ie.len = wrq->u.data.length;
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.gen_ie.ie_data, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ * When the beacon/probe response has not been buffered, use the saved BSS
+ * information available to provide a minimum response for the application
+ * ioctl retrieval routines. Include:
+ * - Timestamp
+ * - Beacon Period
+ * - Capabilities (including WMM Element if available)
+ * - SSID
+ *
+ * @param ppbuffer Output parameter: Buffer used to create basic scan rsp
+ * @param pbss_desc Pointer to a BSS entry in the scan table to create
+ * scan response from for delivery to the application layer
+ *
+ * @return void
+ */
+static void
+wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ t_u8 *ptmp_buf = *ppbuffer;
+ t_u8 tmp_ssid_hdr[2];
+ t_u8 ie_len = 0;
+
+ if (copy_to_user(ptmp_buf, pbss_desc->time_stamp,
+ sizeof(pbss_desc->time_stamp))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->time_stamp);
+
+ if (copy_to_user(ptmp_buf, &pbss_desc->beacon_period,
+ sizeof(pbss_desc->beacon_period))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->beacon_period);
+
+ if (copy_to_user
+ (ptmp_buf, &pbss_desc->cap_info, sizeof(pbss_desc->cap_info))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->cap_info);
+
+ tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
+ tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
+ if (copy_to_user(ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ ptmp_buf += sizeof(tmp_ssid_hdr);
+
+ if (copy_to_user(ptmp_buf, pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ ptmp_buf += pbss_desc->ssid.ssid_len;
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) + pbss_desc->wmm_ie.vend_hdr.len;
+ if (copy_to_user(ptmp_buf, &pbss_desc->wmm_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->pwpa_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->prsn_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ *ppbuffer = ptmp_buf;
+}
+
+/**
+ * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
+ * Descriptor for inclusion in the ioctl response to the user space
+ * application.
+ *
+ *
+ * @param pbss_desc Pointer to a BSS entry in the scan table to form
+ * scan response from for delivery to the application layer
+ * @param ppbuffer Output parameter: Buffer used to output scan return struct
+ * @param pspace_left Output parameter: Number of bytes available in the
+ * response buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+static int
+wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc,
+ t_u8 ** ppbuffer, int *pspace_left)
+{
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+ wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
+ int space_needed;
+ t_u8 *pcurrent;
+ int variable_size;
+
+ const int fixed_size = (sizeof(tmp_rsp_entry.fixed_field_length)
+ + sizeof(tmp_rsp_entry.fixed_fields)
+ + sizeof(tmp_rsp_entry.bss_info_length));
+
+ ENTER();
+
+ pcurrent = *ppbuffer;
+
+ /* The variable size returned is the stored beacon size */
+ variable_size = pbss_desc->beacon_buf_size;
+
+ /* If we stored a beacon and its size was zero, set the variable size
+ return value to the size of the brief scan response
+ wlan_scan_create_brief_table_entry creates. Also used if we are not
+ configured to store beacons in the first place */
+ if (!variable_size) {
+ variable_size = pbss_desc->ssid.ssid_len + 2;
+ variable_size += (sizeof(pbss_desc->beacon_period)
+ + sizeof(pbss_desc->time_stamp)
+ + sizeof(pbss_desc->cap_info));
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + pbss_desc->wmm_ie.vend_hdr.len);
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->pwpa_ie)).vend_hdr.len);
+ }
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->prsn_ie)).ieee_hdr.len);
+ }
+ }
+ }
+
+ space_needed = fixed_size + variable_size;
+
+ PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n",
+ space_needed, *pspace_left);
+
+ if (space_needed >= *pspace_left) {
+ *pspace_left = 0;
+ LEAVE();
+ return -E2BIG;
+ }
+
+ *pspace_left -= space_needed;
+
+ tmp_rsp_entry.fixed_field_length = sizeof(prsp_entry->fixed_fields);
+
+ memcpy(tmp_rsp_entry.fixed_fields.bssid,
+ pbss_desc->mac_address, sizeof(prsp_entry->fixed_fields.bssid));
+
+ tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
+ tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
+ tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
+ tmp_rsp_entry.bss_info_length = variable_size;
+
+ /*
+ * Copy fixed fields to user space
+ */
+ if (copy_to_user(pcurrent, &tmp_rsp_entry, fixed_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += fixed_size;
+
+ if (pbss_desc->pbeacon_buf) {
+ /*
+ * Copy variable length elements to user space
+ */
+ if (copy_to_user(pcurrent, pbss_desc->pbeacon_buf,
+ pbss_desc->beacon_buf_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += pbss_desc->beacon_buf_size;
+ } else {
+ wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
+ }
+
+ *ppbuffer = pcurrent;
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve the scan response/beacon table
+ *
+ * @param wrq A pointer to iwreq structure
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ * @param scan_start argument
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+moal_ret_get_scan_table_ioctl(struct iwreq *wrq, mlan_scan_resp * scan_resp,
+ t_u32 scan_start)
+{
+ pBSSDescriptor_t pbss_desc, scan_table;
+ mlan_scan_resp *prsp_info;
+ int ret_code;
+ int ret_len;
+ int space_left;
+ t_u8 *pcurrent;
+ t_u8 *pbuffer_end;
+ t_u32 num_scans_done;
+
+ ENTER();
+
+ num_scans_done = 0;
+ ret_code = MLAN_STATUS_SUCCESS;
+
+ prsp_info = (mlan_scan_resp *) wrq->u.data.pointer;
+ prsp_info->pscan_table =
+ (t_u8 *) prsp_info + sizeof(prsp_info->num_in_scan_table);
+ pcurrent = prsp_info->pscan_table;
+
+ pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1;
+ space_left = pbuffer_end - pcurrent;
+ scan_table = (BSSDescriptor_t *) (scan_resp->pscan_table);
+
+ PRINTM(MINFO, "GetScanTable: scan_start req = %ld\n", scan_start);
+ PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+ if (!scan_start) {
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
+
+ /* Use to get current association saved descriptor */
+ pbss_desc = scan_table;
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done = 1;
+ }
+ } else {
+ scan_start--;
+
+ while (space_left
+ && (scan_start + num_scans_done < scan_resp->num_in_scan_table)
+ && (ret_code == MLAN_STATUS_SUCCESS)) {
+
+ pbss_desc = (scan_table + (scan_start + num_scans_done));
+
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor [%ld]\n",
+ scan_start + num_scans_done);
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done++;
+ }
+ }
+ }
+
+ prsp_info->num_in_scan_table = num_scans_done;
+ ret_len = pcurrent - (t_u8 *) wrq->u.data.pointer;
+
+ wrq->u.data.length = ret_len;
+
+ /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were
+ successfully encoded. */
+ LEAVE();
+ return (num_scans_done ? MLAN_STATUS_SUCCESS : ret_code);
+}
+
+/**
+ * @brief Get scan table ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ t_u32 scan_start;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+
+ /* get the whole command from user */
+ if (copy_from_user(&scan_start, wrq->u.data.pointer, sizeof(scan_start))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (scan_start) {
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ } else {
+ scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ status = moal_ret_get_scan_table_ioctl(wrq,
+ &scan->param.scan_resp,
+ scan_start);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ union iwreq_data wrqu;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + wrq->u.data.length);
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+
+ if (copy_from_user(scan->param.user_scan.scan_cfg_buf,
+ wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ } else {
+ }
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Cmd52 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd52rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 buf[7];
+ t_u8 rw, func, data = 0;
+ int reg, ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (copy_from_user(buf, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(buf)))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ rw = buf[0];
+ func = buf[1];
+ reg = buf[5];
+ reg = (reg << 8) + buf[4];
+ reg = (reg << 8) + buf[3];
+ reg = (reg << 8) + buf[2];
+ if (rw)
+ data = buf[6];
+
+ PRINTM(MINFO, "rw=%d, func=%d, reg=0x%08X, data=0x%02X\n", rw, func, reg,
+ data);
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ } else {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func, data,
+ reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cmd53 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd53rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 *buf = NULL;
+ t_u8 rw, func, mode;
+ t_u16 blklen = 0, blknum = 0;
+ int reg = 0, pattern_len = 0, total_len = 0, pos = 0, ret =
+ MLAN_STATUS_SUCCESS;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ if (!(buf = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_ATOMIC))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(data = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_ATOMIC))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (wrq->u.data.length > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Data lengh is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ rw = buf[0]; /* read/write (0/1) */
+ func = buf[1]; /* func (0/1/2) */
+ reg = buf[5]; /* address */
+ reg = (reg << 8) + buf[4];
+ reg = (reg << 8) + buf[3];
+ reg = (reg << 8) + buf[2];
+ mode = buf[6]; /* byte mode/block mode (0/1) */
+ blklen = buf[8]; /* block size */
+ blklen = (blklen << 8) + buf[7];
+ blknum = buf[10]; /* block number or byte number */
+ blknum = (blknum << 8) + buf[9];
+
+ if (mode != BYTE_MODE)
+ mode = BLOCK_MODE;
+ total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
+ if (total_len > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Total data length is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "CMD53 read/write, func = %d, addr = %#x, mode = %d, "
+ "block size = %d, block(byte) number = %d\n",
+ func, reg, mode, blklen, blknum);
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (!sdio_readsb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, data, reg,
+ total_len))
+ PRINTM(MERROR, "sdio_readsb: reading memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ pattern_len = wrq->u.data.length - 11;
+ if (pattern_len > total_len)
+ pattern_len = total_len;
+ memset(data, 0, sizeof(data));
+
+ /* Copy/duplicate the pattern to data buffer */
+ for (pos = 0; pos < total_len; pos++)
+ data[pos] = buf[11 + (pos % pattern_len)];
+
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (!sdio_writesb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, reg, data,
+ total_len))
+ PRINTM(MERROR, "sdio_writesb: writing memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ if (data)
+ kfree(data);
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Set SDIO Multi-point aggregation control parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[6];
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ PRINTM(MERROR, "mpa_ctrl: %d\n", wrq->u.data.length);
+
+ if (wrq->u.data.length > 6) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+
+ misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if user had modified them
+ */
+
+ req->action = MLAN_ACT_GET;
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.length == 0) {
+ data[0] = misc->param.mpa_ctrl.tx_enable;
+ data[1] = misc->param.mpa_ctrl.rx_enable;
+ data[2] = misc->param.mpa_ctrl.tx_buf_size;
+ data[3] = misc->param.mpa_ctrl.rx_buf_size;
+ data[4] = misc->param.mpa_ctrl.tx_max_ports;
+ data[5] = misc->param.mpa_ctrl.rx_max_ports;
+
+ PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ goto done;
+ }
+
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ switch (wrq->u.data.length) {
+ case 6:
+ misc->param.mpa_ctrl.rx_max_ports = data[5];
+ case 5:
+ misc->param.mpa_ctrl.tx_max_ports = data[4];
+ case 4:
+ misc->param.mpa_ctrl.rx_buf_size = data[3];
+ case 3:
+ misc->param.mpa_ctrl.tx_buf_size = data[2];
+ case 2:
+ misc->param.mpa_ctrl.rx_enable = data[1];
+ case 1:
+ /* Set cmd */
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ misc->param.mpa_ctrl.tx_enable = data[0];
+ break;
+ default:
+ PRINTM(MERROR, "Default case error\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) !=
+ MLAN_STATUS_SUCCESS)) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief Set/get TID multi-port eligibility table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_tid_elig_tbl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[8] = { 0 }, ret = 0;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > 8) {
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_TID_ELIG_TBL;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ memcpy(cfg->param.tid_tbl, (t_u32 *) data, sizeof(data));
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ memcpy(data, (int *) cfg->param.tid_tbl, sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 10
+/**
+ * @brief Set/Get scan configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_scan_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[6], ret = 0;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > 6) {
+ ret = -EINVAL;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
+ PRINTM(MERROR, "Invalid argument for scan type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
+ PRINTM(MERROR, "Invalid argument for scan mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
+ PRINTM(MERROR, "Invalid argument for scan probes\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (((data[3] < 0) || (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[4] < 0) || (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[5] < 0) || (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
+ PRINTM(MERROR, "Invalid argument for scan time\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ memcpy(&scan->param.scan_cfg, (t_u32 *) data, sizeof(data));
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ memcpy(data, (int *) &scan->param.scan_cfg, sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** VSIE configuration buffer length */
+#define VSIE_MAX_CFG_LEN (MLAN_MAX_VSIE_LEN - 2 + 3)
+/** VSIE mask to remove the IE */
+#define VSIE_MASK_DISABLE 0x00
+/** VSIE Action : Get */
+#define VSIE_ACTION_GET 0
+/** VSIE Action : Add */
+#define VSIE_ACTION_ADD 1
+/** VSIE Action : Delete */
+#define VSIE_ACTION_DELETE 2
+/**
+ * @brief Get/Add/Remove vendor specific IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_vsie_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, user_data_len = 0, ie_len = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 *buf = NULL;
+
+ ENTER();
+
+ user_data_len = wrq->u.data.length;
+ if (user_data_len < 2 || user_data_len == 3 ||
+ user_data_len > VSIE_MAX_CFG_LEN) {
+ PRINTM(MERROR, "Invalid argument number!\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ if (!(buf = (t_u8 *) kmalloc(VSIE_MAX_CFG_LEN, GFP_ATOMIC))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+ memset(buf, 0, VSIE_MAX_CFG_LEN);
+ if (copy_from_user(buf, wrq->u.data.pointer, user_data_len)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if ((buf[0] > VSIE_ACTION_DELETE) ||
+ (buf[1] > MLAN_MAX_VSIE_NUM - 1) ||
+ ((buf[0] == VSIE_ACTION_ADD) &&
+ !(buf[2] &&
+ buf[2] <=
+ (MLAN_VSIE_MASK_SCAN | MLAN_VSIE_MASK_ASSOC |
+ MLAN_VSIE_MASK_ADHOC)))) {
+ PRINTM(MERROR, "Invalid argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_VS_IE;
+
+ misc->param.vsie.id = buf[1];
+ misc->param.vsie.mask = VSIE_MASK_DISABLE;
+ switch (buf[0]) {
+ case VSIE_ACTION_GET:
+ req->action = MLAN_ACT_GET;
+ break;
+ case VSIE_ACTION_ADD:
+ ie_len = user_data_len - 3;
+ misc->param.vsie.mask = buf[2];
+ misc->param.vsie.ie[1] = ie_len;
+ memcpy(&misc->param.vsie.ie[2], &buf[3], ie_len);
+ case VSIE_ACTION_DELETE:
+ /* Set with mask 0 is remove */
+ req->action = MLAN_ACT_SET;
+ break;
+ default:
+ break;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wrq->u.data.length = misc->param.vsie.ie[1];
+ if (wrq->u.data.length) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &misc->param.vsie.ie[2],
+ wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ps_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[7], ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 3;
+ int i = 3;
+
+ ENTER();
+
+ allowed++; /* For ad-hoc awake period parameter */
+ allowed++; /* For beacon missing timeout parameter */
+ allowed += 2; /* For delay to PS and PS mode parameters */
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > allowed) {
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < PS_NULL_DISABLE)) {
+ PRINTM(MERROR, "Invalid argument for PS null interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] != IGNORE_MULTIPLE_DTIM) &&
+ ((data[1] < MIN_MULTIPLE_DTIM) || (data[1] > MAX_MULTIPLE_DTIM))) {
+ PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[2] < MIN_LISTEN_INTERVAL) {
+ PRINTM(MERROR, "Invalid argument for listen interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[i] != SPECIAL_ADHOC_AWAKE_PD) &&
+ ((data[i] < MIN_ADHOC_AWAKE_PD) ||
+ (data[i] > MAX_ADHOC_AWAKE_PD))) {
+ PRINTM(MERROR, "Invalid argument for adhoc awake period\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != DISABLE_BCN_MISS_TO) &&
+ ((data[i] < MIN_BCN_MISS_TO) || (data[i] > MAX_BCN_MISS_TO))) {
+ PRINTM(MERROR, "Invalid argument for beacon miss timeout\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if (wrq->u.data.length < allowed - 1)
+ data[i] = DELAY_TO_PS_UNCHANGED;
+ else if ((data[i] < MIN_DELAY_TO_PS) || (data[i] > MAX_DELAY_TO_PS)) {
+ PRINTM(MERROR, "Invalid argument for delay to PS\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != PS_MODE_UNCHANGED) && (data[i] != PS_MODE_AUTO) &&
+ (data[i] != PS_MODE_POLL) && (data[i] != PS_MODE_NULL)) {
+ PRINTM(MERROR, "Invalid argument for PS mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_cfg, (t_u32 *) data,
+ sizeof(pm_cfg->param.ps_cfg));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(data, (int *) &pm_cfg->param.ps_cfg, sizeof(pm_cfg->param.ps_cfg));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = allowed;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ * Receive a ADDTS command from the application. The command structure
+ * contains a TSPEC and timeout in milliseconds. The timeout is performed
+ * in the firmware after the ADDTS command frame is sent.
+ *
+ * The TSPEC is received in the API as an opaque block whose length is
+ * calculated from the IOCTL data length. The firmware will send the
+ * entire data block, including the bytes after the TSPEC. This is done
+ * to allow extra IEs to be packaged with the TSPEC in the ADDTS action
+ * frame.
+ *
+ * The IOCTL structure contains two return fields:
+ * - The firmware command result, which indicates failure and timeouts
+ * - The IEEE Status code which contains the corresponding value from
+ * any ADDTS response frame received.
+ *
+ * In addition, the opaque TSPEC data block passed in is replaced with the
+ * TSPEC received in the ADDTS response frame. In case of failure, the
+ * AP may modify the TSPEC on return and in the case of success, the
+ * medium time is returned as calculated by the AP. Along with the TSPEC,
+ * any IEs that are sent in the ADDTS response are also returned and can be
+ * parsed using the IOCTL length as an indicator of extra elements.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure or AP negotiation failure via the commandResult field copied
+ * back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_addts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ static t_u8 dialog_tok = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_addts_req_t addts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
+
+ memset(&addts_ioctl, 0, sizeof(addts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&addts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(addts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if ((++dialog_tok) == 0)
+ dialog_tok = 1;
+ cfg->param.addts.dialog_tok = dialog_tok;
+ cfg->param.addts.timeout = addts_ioctl.timeout_ms;
+ cfg->param.addts.tspec_data_len = (wrq->u.data.length
+ - sizeof(addts_ioctl.timeout_ms)
+ - sizeof(addts_ioctl.cmd_result)
+ -
+ sizeof(addts_ioctl.
+ ieee_status_code));
+
+ memcpy(cfg->param.addts.tspec_data,
+ addts_ioctl.tspec_data, cfg->param.addts.tspec_data_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ addts_ioctl.cmd_result = cfg->param.addts.result;
+ addts_ioctl.ieee_status_code = (t_u8) cfg->param.addts.status_code;
+ memcpy(addts_ioctl.tspec_data,
+ cfg->param.addts.tspec_data, cfg->param.addts.tspec_data_len);
+
+ wrq->u.data.length = (sizeof(addts_ioctl.timeout_ms)
+ + sizeof(addts_ioctl.cmd_result)
+ + sizeof(addts_ioctl.ieee_status_code)
+ + cfg->param.addts.tspec_data_len);
+
+ if (copy_to_user(wrq->u.data.pointer, &addts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ * Receive a DELTS command from the application. The command structure
+ * contains a TSPEC and reason code along with space for a command result
+ * to be returned. The information is packaged is sent to the wlan_cmd.c
+ * firmware command prep and send routines for execution in the firmware.
+ *
+ * The reason code is not used for WMM implementations but is indicated in
+ * the 802.11e specification.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure via the cmd_result field copied back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_delts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_delts_req_t delts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
+
+ memset(&delts_ioctl, 0, sizeof(delts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&delts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(delts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.delts.status_code = (t_u32) delts_ioctl.ieee_reason_code;
+
+ /* Calculate the length of the TSPEC */
+ cfg->param.delts.tspec_data_len = (wrq->u.data.length
+ - sizeof(delts_ioctl.cmd_result)
+ -
+ sizeof(delts_ioctl.
+ ieee_reason_code));
+
+ memcpy(cfg->param.delts.tspec_data,
+ delts_ioctl.tspec_data, cfg->param.delts.tspec_data_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Return the firmware command result back to the application layer */
+ delts_ioctl.cmd_result = cfg->param.delts.result;
+ wrq->u.data.length = sizeof(delts_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &delts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ * Receive a AC Queue configuration command which is used to get, set, or
+ * default the parameters associated with a specific WMM AC Queue.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_config_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_config_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_config *pqcfg = NULL;
+ wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
+
+ memset(&qcfg_ioctl, 0, sizeof(qcfg_ioctl));
+ pqcfg = (mlan_ds_wmm_queue_config *) & pwmm->param.q_cfg;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qcfg_ioctl)))) {
+ PRINTM(MERROR, "QCONFIG: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pqcfg->action = qcfg_ioctl.action;
+ pqcfg->access_category = qcfg_ioctl.access_category;
+ pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&qcfg_ioctl, 0, sizeof(qcfg_ioctl));
+ qcfg_ioctl.action = pqcfg->action;
+ qcfg_ioctl.access_category = pqcfg->access_category;
+ qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
+ wrq->u.data.length = sizeof(qcfg_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &qcfg_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ * Receive a AC Queue statistics command from the application for a specific
+ * WMM AC. The command can:
+ * - Turn stats on
+ * - Turn stats off
+ * - Collect and clear the stats
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_stats_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_stats_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_stats *pqstats = NULL;
+ wlan_ioctl_wmm_queue_stats_t qstats_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS;
+
+ memset(&qstats_ioctl, 0, sizeof(qstats_ioctl));
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qstats_ioctl)))) {
+ PRINTM(MERROR, "QSTATS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy((void *) pqstats, (void *) &qstats_ioctl, sizeof(qstats_ioctl));
+ PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action,
+ qstats_ioctl.access_category);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstats_ioctl, 0, sizeof(qstats_ioctl));
+ memcpy((void *) &qstats_ioctl, (void *) pqstats, sizeof(qstats_ioctl));
+ wrq->u.data.length = sizeof(qstats_ioctl);
+
+ if (copy_to_user
+ (wrq->u.data.pointer, &qstats_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ * Return the following information for each WMM AC:
+ * - WMM IE Acm Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ * - Firmware Delivery Enabled
+ * - Firmware Trigger Enabled
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
+
+ if (wrq->u.data.length == sizeof(qstatus_ioctl)) {
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_NO_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstatus_ioctl, 0, sizeof(qstatus_ioctl));
+ memcpy((void *) &qstatus_ioctl, (void *) &pwmm->param.q_status,
+ sizeof(qstatus_ioctl));
+ wrq->u.data.length = sizeof(qstatus_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &qstatus_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_ts_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_ts_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
+
+ memset(&ts_status_ioctl, 0, sizeof(ts_status_ioctl));
+
+ if (wrq->u.data.length == sizeof(ts_status_ioctl)) {
+ if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(ts_status_ioctl)))) {
+ PRINTM(MERROR, "TSTATUS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&pwmm->param.ts_status, 0, sizeof(ts_status_ioctl));
+ pwmm->param.ts_status.tid = ts_status_ioctl.tid;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&ts_status_ioctl, 0, sizeof(ts_status_ioctl));
+ memcpy((void *) &ts_status_ioctl, (void *) &pwmm->param.ts_status,
+ sizeof(ts_status_ioctl));
+ wrq->u.data.length = sizeof(ts_status_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &ts_status_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSTATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get auth type
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_auth_type(moal_private * priv, struct iwreq *wrq)
+{
+ int auth_type;
+ t_u32 auth_mode;
+ int ret = 0;
+
+ ENTER();
+ if (wrq->u.data.length == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ auth_type = auth_mode;
+ if (copy_to_user(wrq->u.data.pointer, &auth_type, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ if (copy_from_user(&auth_type, wrq->u.data.pointer, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
+ if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
+ (auth_type > MLAN_AUTH_MODE_SHARED))
+ && (auth_type != MLAN_AUTH_MODE_AUTO)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ auth_mode = auth_type;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Get version
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_get_version(moal_handle * handle, char *version, int max_len)
+{
+ union
+ {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+ char fw_ver[32];
+
+ ENTER();
+
+ ver.l = handle->fw_release_number;
+ sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(version, max_len, driver_version, fw_ver);
+
+ LEAVE();
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *) req;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WOAL_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_VERSION: /* Get driver version */
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_VEREXT: /* Get extended driver version */
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_WARMRESET:
+ ret = woal_warm_reset(priv);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_SET_GET_TXRATE:
+ ret = woal_set_get_txrate(priv, wrq);
+ break;
+ case WOAL_SET_GET_REGIONCODE:
+ ret = woal_set_get_regioncode(priv, wrq);
+ break;
+ case WOAL_SET_RADIO:
+ ret = woal_set_get_radio(priv, wrq);
+ break;
+ case WOAL_WMM_ENABLE:
+ ret = woal_wmm_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_11D_ENABLE:
+ ret = woal_11d_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_GET_TX_RX_ANT:
+ ret = woal_set_get_tx_rx_ant(priv, wrq);
+ break;
+ case WOAL_SET_GET_QOS_CFG:
+ ret = woal_set_get_qos_cfg(priv, wrq);
+ break;
+ case WOAL_SET_GET_LDO_CFG:
+ ret = woal_set_get_ldo_cfg(priv, wrq);
+ break;
+#ifdef REASSOCIATION
+ case WOAL_SET_GET_REASSOC:
+ ret = woal_set_get_reassoc(priv, wrq);
+ break;
+#endif /* REASSOCIATION */
+ case WOAL_TXBUF_CFG:
+ ret = woal_txbuf_cfg(priv, wrq);
+ break;
+ case WOAL_SET_GET_WWS_CFG:
+ ret = woal_wws_cfg(priv, wrq);
+ break;
+ case WOAL_SLEEP_PD:
+ ret = woal_sleep_pd(priv, wrq);
+ break;
+ case WOAL_AUTH_TYPE:
+ ret = woal_auth_type(priv, wrq);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_SIXTEEN_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_TX_POWERCFG:
+ ret = woal_tx_power_cfg(priv, wrq);
+ break;
+#ifdef DEBUG_LEVEL1
+ case WOAL_DRV_DBG:
+ ret = woal_drv_dbg(priv, wrq);
+ break;
+#endif
+ case WOAL_BEACON_INTERVAL:
+ ret = woal_beacon_interval(priv, wrq);
+ break;
+ case WOAL_ATIM_WINDOW:
+ ret = woal_atim_window(priv, wrq);
+ break;
+ case WOAL_SIGNAL:
+ ret = woal_get_signal(priv, wrq);
+ break;
+ case WOAL_DEEP_SLEEP:
+ ret = woal_deep_sleep_ioctl(priv, wrq);
+ break;
+ case WOAL_11N_TX_CFG:
+ ret = woal_11n_tx_cfg(priv, wrq);
+ break;
+ case WOAL_11N_AMSDU_AGGR_CTRL:
+ ret = woal_11n_amsdu_aggr_ctrl(priv, wrq);
+ break;
+ case WOAL_11N_HTCAP_CFG:
+ ret = woal_11n_htcap_cfg(priv, wrq);
+ break;
+ case WOAL_PRIO_TBL:
+ ret = woal_11n_prio_tbl(priv, wrq);
+ break;
+ case WOAL_ADDBA_UPDT:
+ ret = woal_addba_para_updt(priv, wrq);
+ break;
+ case WOAL_ADDBA_REJECT:
+ ret = woal_addba_reject(priv, wrq);
+ break;
+ case WOAL_HS_CFG:
+ ret = woal_hs_cfg(priv, wrq, MTRUE);
+ break;
+ case WOAL_HS_SETPARA:
+ ret = woal_hs_setpara(priv, wrq);
+ break;
+ case WOAL_REG_READ_WRITE:
+ ret = woal_reg_read_write(priv, wrq);
+ break;
+ case WOAL_INACTIVITY_TIMEOUT_EXT:
+ ret = woal_inactivity_timeout_ext(priv, wrq);
+ break;
+ case WOAL_SDIO_CLOCK:
+ ret = woal_sdio_clock_ioctl(priv, wrq);
+ break;
+ case WOAL_BAND_CFG:
+ ret = woal_band_cfg(priv, wrq);
+ break;
+ case WOAL_BCA_TIME_SHARE:
+ ret = woal_bca_time_share(priv, wrq);
+ break;
+ case WOAL_TID_ELIG_TBL:
+ ret = woal_set_get_tid_elig_tbl(priv, wrq);
+ break;
+ case WOAL_SCAN_CFG:
+ ret = woal_set_get_scan_cfg(priv, wrq);
+ break;
+ case WOAL_PS_CFG:
+ ret = woal_set_get_ps_cfg(priv, wrq);
+ break;
+ case WOAL_MEM_READ_WRITE:
+ ret = woal_mem_read_write(priv, wrq);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case WOAL_SDIO_MPA_CTRL:
+ ret = woal_do_sdio_mpa_ctrl(priv, wrq);
+ break;
+#endif
+ case WOAL_SLEEP_PARAMS:
+ ret = woal_sleep_params_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOALGETLOG:
+ ret = woal_get_log(priv, wrq);
+ break;
+ case WOAL_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_PASSPHRASE:
+ ret = woal_passphrase(priv, wrq);
+ break;
+ case WOAL_ADHOC_AES:
+ ret = woal_adhoc_aes_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATUS:
+ ret = woal_wmm_queue_status_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_TS_STATUS:
+ ret = woal_wmm_ts_status_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETADDR_GETNONE:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DEAUTH:
+ ret = woal_deauth(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETNONE_GETTWELVE_CHAR:
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_WPS_SESSION:
+ ret = woal_wps_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GET_FOUR_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DATA_RATE:
+ ret = woal_get_txrx_rate(priv, wrq);
+ break;
+ case WOAL_ESUPP_MODE:
+ ret = woal_get_esupp_mode(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+#ifdef MFG_CMD_SUPPORT
+ case WOAL_MFG_CMD:
+ PRINTM(MINFO, "Entering the Manufacturing ioctl SIOCCFMFG\n");
+ ret = woal_mfg_command(priv, wrq);
+ PRINTM(MINFO, "Manufacturing Ioctl %s\n", (ret) ? "failed" : "success");
+ break;
+#endif
+ case WOAL_SET_GET_64_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_ECL_SYS_CLOCK:
+ ret = woal_ecl_sys_clock(priv, wrq);
+ break;
+ }
+ break;
+
+ case WOAL_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_ARP_FILTER:
+ ret = woal_arp_filter(priv, wrq);
+ break;
+ case WOAL_SET_INTS_GET_CHARS:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_READ_EEPROM:
+ ret = woal_read_eeprom(priv, wrq);
+ break;
+ }
+ break;
+ case WOAL_SET_GET_2K_BYTES:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_CMD_52RDWR:
+ ret = woal_cmd52rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_CMD_53RDWR:
+ ret = woal_cmd53rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_USER_SCAN:
+ ret = woal_set_user_scan_ioctl(priv, wrq);
+ break;
+ case WOAL_GET_SCAN_TABLE:
+ ret = woal_get_scan_table_ioctl(priv, wrq);
+ break;
+ case WOAL_VSIE_CFG:
+ ret = woal_vsie_cfg_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_ADDTS:
+ ret = woal_wmm_addts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_DELTS:
+ ret = woal_wmm_delts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_CONFIG:
+ ret = woal_wmm_queue_config_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATS:
+ ret = woal_wmm_queue_stats_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send get FW info request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return None
+ */
+void
+woal_request_get_fw_info(moal_private * priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info;
+ mlan_status status;
+ ENTER();
+ memset(priv->current_addr, 0xff, ETH_ALEN);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->sub_command = MLAN_OID_GET_FW_INFO;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->fw_release_number = info->param.fw_info.fw_ver;
+ if (priv->current_addr[0] == 0xff)
+ memcpy(priv->current_addr, &info->param.fw_info.mac_addr,
+ sizeof(mlan_802_11_mac_addr));
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+ DBG_HEXDUMP(MIF_D, "mac", priv->current_addr, 6);
+ } else
+ PRINTM(MERROR, "get fw info failed! status=%d, error_code=0x%lx\n",
+ status, req->status_code);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return Wireless mode
+ */
+t_u32
+woal_get_mode(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mode = priv->w_stats.status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ switch (bss->param.bss_mode) {
+ case MLAN_BSS_MODE_INFRA:
+ mode = IW_MODE_INFRA;
+ break;
+ case MLAN_BSS_MODE_IBSS:
+ mode = IW_MODE_ADHOC;
+ break;
+ default:
+ mode = IW_MODE_AUTO;
+ break;
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return mode;
+}
+
+/**
+ * @brief Get RSSI info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param signal A pointer tp mlan_ds_get_signal structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL;
+ info->param.signal.selector = ALL_RSSI_INFO_MASK;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (signal)
+ memcpy(signal, &info->param.signal, sizeof(mlan_ds_get_signal));
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param stats A pointer to mlan_ds_get_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (stats)
+ memcpy(stats, &info->param.stats, sizeof(mlan_ds_get_stats));
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param m_rates A pointer to moal_802_11_rates structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_SUPPORTED_RATES;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (m_rates)
+ m_rates->num_of_rates =
+ woal_copy_rates(m_rates->rates, m_rates->num_of_rates,
+ rate->param.rates, MLAN_SUPPORTED_RATES);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param chan_list A pointer to mlan_chan_list structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chan_list)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (chan_list) {
+ memcpy(chan_list, &bss->param.chanlist, sizeof(mlan_chan_list));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get scan table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scan_resp)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+ memcpy((void *) &scan->param.scan_resp, (void *) scan_resp,
+ sizeof(mlan_scan_resp));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (scan_resp) {
+ memcpy(scan_resp, &scan->param.scan_resp, sizeof(mlan_scan_resp));
+ }
+ }
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode Authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.auth_mode = auth_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode A pointer to authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && auth_mode) {
+ *auth_mode = sec->param.auth_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode Encryption mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_mode = encrypt_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode A pointer to encrypt mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && encrypt_mode) {
+ *encrypt_mode = sec->param.encrypt_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set wpa enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wpa_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get WPA enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable A pointer to wpa enable status
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && enable) {
+ *enable = sec->param.wpa_enabled;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Find the best network to associate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *mac = 0;
+
+ ENTER();
+
+ if (!ssid_bssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_FIND_BSS;
+
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ memcpy(ssid_bssid, &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid));
+ mac = (t_u8 *) & ssid_bssid->bssid;
+ PRINTM(MCMND, "Find network: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ssid_bssid->ssid.ssid, mac[0], mac[1], mac[2], mac[3], mac[4],
+ mac[5]);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request a scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param req_ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_scan(moal_private * priv,
+ t_u8 wait_option, mlan_802_11_ssid * req_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&priv->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ priv->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+
+ if (req_ssid && req_ssid->ssid_len != 0) {
+ /* Specific SSID scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID;
+
+ memcpy(scan->param.scan_req.scan_ssid.ssid,
+ req_ssid->ssid, req_ssid->ssid_len);
+ scan->param.scan_req.scan_ssid.ssid_len = req_ssid->ssid_len;
+ } else {
+ /* Normal scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+ if (ret == MLAN_STATUS_FAILURE) {
+ priv->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&priv->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Try Get All */
+ memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
+ memcpy(&sec->param.passphrase.ssid, &ssid_bssid->ssid,
+ sizeof(sec->param.passphrase.ssid));
+ memcpy(&sec->param.passphrase.bssid, &ssid_bssid->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option))
+ goto error;
+ sec->param.ewpa_enabled = MFALSE;
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ if (sec->param.passphrase.psk.passphrase.passphrase_len > 0) {
+ sec->param.ewpa_enabled = MTRUE;
+ }
+ } else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
+ sec->param.ewpa_enabled = MTRUE;
+
+ sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ error:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Change Adhoc Channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param channel The channel to be set.
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+woal_change_adhoc_chan(moal_private * priv, int channel)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ /* Get BSS information */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss_info.bss_mode == MLAN_BSS_MODE_INFRA) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get current channel */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss->param.bss_chan.channel == channel) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ PRINTM(MCMND, "Updating Channel from %d to %d\n",
+ (int) bss->param.bss_chan.channel, channel);
+
+ if (bss_info.media_connected != MTRUE) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Do disonnect */
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ memset((t_u8 *) & bss->param.bssid, 0, ETH_ALEN);
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &bss_info.ssid)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Start/Join Adhoc network */
+ bss->sub_command = MLAN_OID_BSS_START;
+ memset(&bss->param.ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&bss->param.ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief enable wep key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_enable_wep_key(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_disable = MFALSE;
+ sec->param.encrypt_key.key_len = 0;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#if WIRELESS_EXT > 14
+
+/**
+ * @brief This function sends customized event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param str A pointer to event string
+ *
+ * @return N/A
+ */
+void
+woal_send_iwevcustom_event(moal_private * priv, t_s8 * str)
+{
+ union iwreq_data iwrq;
+ char buf[50];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.pointer = buf;
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
+ PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#if WIRELESS_EXT >= 18
+/**
+ * @brief This function sends mic error event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event MIC MERROR EVENT.
+ *
+ * @return N/A
+ */
+void
+woal_send_mic_error_event(moal_private * priv, t_u32 event)
+{
+ union iwreq_data iwrq;
+ struct iw_michaelmicfailure mic;
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(iwrq));
+ memset(&mic, 0, sizeof(mic));
+ if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
+ mic.flags = IW_MICFAILURE_PAIRWISE;
+ else
+ mic.flags = IW_MICFAILURE_GROUP;
+ iwrq.data.pointer = &mic;
+ iwrq.data.length = sizeof(mic);
+
+ wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
+ (char *) &mic);
+
+ LEAVE();
+ return;
+}
+#endif
+
+/**
+ * @brief Handle ioctl resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param req Pointer to mlan_ioctl_req structure
+ *
+ * @return N/A
+ */
+void
+woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req)
+{
+ ENTER();
+
+ if (priv == NULL)
+ return;
+ switch (req->req_id) {
+ case MLAN_IOCTL_GET_INFO:
+ woal_ioctl_get_info_resp(priv, (mlan_ds_get_info *) req->pbuf);
+ break;
+ case MLAN_IOCTL_BSS:
+ woal_ioctl_get_bss_resp(priv, (mlan_ds_bss *) req->pbuf);
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
diff --git a/wlan_src/mlinux/moal_priv.h b/wlan_src/mlinux/moal_priv.h
new file mode 100755
index 0000000..e408f95
--- /dev/null
+++ b/wlan_src/mlinux/moal_priv.h
@@ -0,0 +1,625 @@
+/** @file moal_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/31/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_PRIV_H_
+#define _WOAL_PRIV_H_
+
+/** Offset for subcommand */
+#define SUBCMD_OFFSET 4
+
+/** Command disabled */
+#define CMD_DISABLED 0
+/** Command enabled */
+#define CMD_ENABLED 1
+/** Command get */
+#define CMD_GET 2
+
+/** 2K bytes */
+#define WOAL_2K_BYTES 2000
+
+/** PRIVATE CMD ID */
+#define WOAL_IOCTL 0x8BE0
+
+/** Private command ID to set one int/get word char */
+#define WOAL_SETONEINT_GETWORDCHAR (WOAL_IOCTL + 1)
+/** Private command ID to get version */
+#define WOAL_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_VEREXT 2
+
+/** Private command ID to set/get none */
+#define WOAL_SETNONE_GETNONE (WOAL_IOCTL + 2)
+/** Private command ID for warm reset */
+#define WOAL_WARMRESET 1
+
+/** Private command ID to set/get sixteen int */
+#define WOAL_SET_GET_SIXTEEN_INT (WOAL_IOCTL + 3)
+/** Private command ID to set/get TX power configurations */
+#define WOAL_TX_POWERCFG 1
+#ifdef DEBUG_LEVEL1
+/** Private command ID to set/get driver debug */
+#define WOAL_DRV_DBG 2
+#endif
+/** Private command ID to set/get beacon interval */
+#define WOAL_BEACON_INTERVAL 3
+/** Private command ID to set/get ATIM window */
+#define WOAL_ATIM_WINDOW 4
+/** Private command ID to get RSSI */
+#define WOAL_SIGNAL 5
+/** Private command ID to set/get Deep Sleep mode */
+#define WOAL_DEEP_SLEEP 7
+/** Private command ID for 11n ht configration */
+#define WOAL_11N_TX_CFG 8
+/** Private command ID for 11n usr ht configration */
+#define WOAL_11N_HTCAP_CFG 9
+/** Private command ID for TX Aggregation */
+#define WOAL_PRIO_TBL 10
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_UPDT 11
+/** Private command ID to set/get Host Sleep configuration */
+#define WOAL_HS_CFG 12
+/** Private command ID to set Host Sleep parameters */
+#define WOAL_HS_SETPARA 13
+/** Private command ID to read/write registers */
+#define WOAL_REG_READ_WRITE 14
+/** Private command ID to set/get band/adhocband */
+#define WOAL_BAND_CFG 15
+/** Private command ID to set/get BCA timeshare */
+#define WOAL_BCA_TIME_SHARE 16
+/** Private command ID for TX Aggregation */
+#define WOAL_11N_AMSDU_AGGR_CTRL 17
+/** Private command ID to set/get Inactivity timeout */
+#define WOAL_INACTIVITY_TIMEOUT_EXT 18
+/** Private command ID to turn on/off sdio clock */
+#define WOAL_SDIO_CLOCK 19
+/** Private command ID to set/get tid multi-port eligibility table */
+#define WOAL_TID_ELIG_TBL 20
+/** Private command ID to set/get scan configuration parameter */
+#define WOAL_SCAN_CFG 21
+/** Private command ID to set/get PS configuration parameter */
+#define WOAL_PS_CFG 22
+/** Private command ID to read/write memory */
+#define WOAL_MEM_READ_WRITE 23
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Private command ID to control SDIO MP-A */
+#define WOAL_SDIO_MPA_CTRL 25
+#endif
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_REJECT 27
+/** Private command ID to set/get sleep parameters */
+#define WOAL_SLEEP_PARAMS 28
+
+#ifdef MFG_CMD_SUPPORT
+/** Private command ID for MFG command support */
+#define WOAL_MFG_CMD (WOAL_IOCTL + 4)
+#endif
+
+/** Private command ID to set one int/get one int */
+#define WOAL_SETONEINT_GETONEINT (WOAL_IOCTL + 5)
+/** Private command ID to set/get Tx rate */
+#define WOAL_SET_GET_TXRATE 1
+/** Private command ID to set/get region code */
+#define WOAL_SET_GET_REGIONCODE 2
+/** Private command ID to turn on/off radio */
+#define WOAL_SET_RADIO 3
+/** Private command ID to enable WMM */
+#define WOAL_WMM_ENABLE 4
+/** Private command ID to enable 802.11D */
+#define WOAL_11D_ENABLE 5
+/** Private command ID to set/get tx/rx antenna */
+#define WOAL_SET_GET_TX_RX_ANT 6
+/** Private command ID to set/get QoS configuration */
+#define WOAL_SET_GET_QOS_CFG 7
+/** Private command ID to set/get LDO configuration */
+#define WOAL_SET_GET_LDO_CFG 8
+#ifdef REASSOCIATION
+/** Private command ID to set/get reassociation setting */
+#define WOAL_SET_GET_REASSOC 9
+#endif /* REASSOCIATION */
+/** Private command ID for Updating Transmit buffer configration */
+#define WOAL_TXBUF_CFG 10
+/** Private command ID to set/get WWS mode */
+#define WOAL_SET_GET_WWS_CFG 12
+/** Private command ID to set/get sleep period */
+#define WOAL_SLEEP_PD 13
+/** Private command ID to set/get auth type */
+#define WOAL_AUTH_TYPE 18
+
+/** Private command ID to get log */
+#define WOALGETLOG (WOAL_IOCTL + 7)
+
+/** Private command ID to set a wext address variable */
+#define WOAL_SETADDR_GETNONE (WOAL_IOCTL + 8)
+/** Private command ID to send deauthentication */
+#define WOAL_DEAUTH 1
+
+/** Private command to get/set 256 chars */
+#define WOAL_SET_GET_256_CHAR (WOAL_IOCTL + 9)
+/** Private command to read/write passphrase */
+#define WOAL_PASSPHRASE 1
+/** Private command to get/set Ad-Hoc AES */
+#define WOAL_ADHOC_AES 2
+/** Private command ID to get WMM queue status */
+#define WOAL_WMM_QUEUE_STATUS 4
+/** Private command ID to get Traffic stream status */
+#define WOAL_WMM_TS_STATUS 5
+
+/** Get log buffer size */
+#define GETLOG_BUFSIZE 512
+
+/** Private command ID to set none/get twelve chars*/
+#define WOAL_SETNONE_GETTWELVE_CHAR (WOAL_IOCTL + 11)
+/** Private command ID for WPS session */
+#define WOAL_WPS_SESSION 1
+
+/** Private command ID to set none/get four int */
+#define WOAL_SETNONE_GET_FOUR_INT (WOAL_IOCTL + 13)
+/** Private command ID to get data rates */
+#define WOAL_DATA_RATE 1
+/** Private command ID to get E-Supplicant mode */
+#define WOAL_ESUPP_MODE 2
+
+/** Private command to get/set 64 ints */
+#define WOAL_SET_GET_64_INT (WOAL_IOCTL + 15)
+/** Private command ID to set/get ECL system clock */
+#define WOAL_ECL_SYS_CLOCK 1
+
+/** Private command ID for hostcmd */
+#define WOAL_HOST_CMD (WOAL_IOCTL + 17)
+
+/** Private command ID for arpfilter */
+#define WOAL_ARP_FILTER (WOAL_IOCTL + 19)
+
+/** Private command ID to set ints and get chars */
+#define WOAL_SET_INTS_GET_CHARS (WOAL_IOCTL + 21)
+/** Private command ID to read EEPROM data */
+#define WOAL_READ_EEPROM 1
+
+/** Private command ID to set/get 2K bytes */
+#define WOAL_SET_GET_2K_BYTES (WOAL_IOCTL + 23)
+
+/** Private command ID to read/write Command 52 */
+#define WOAL_CMD_52RDWR 1
+/** Private command ID to read/write Command 53 */
+#define WOAL_CMD_53RDWR 2
+
+/** Private command ID for setuserscan */
+#define WOAL_SET_USER_SCAN 3
+/** Private command ID for getscantable */
+#define WOAL_GET_SCAN_TABLE 4
+
+/** Private command ID for vsiecfg */
+#define WOAL_VSIE_CFG 5
+
+/** Private command ID to request ADDTS */
+#define WOAL_WMM_ADDTS 7
+/** Private command ID to request DELTS */
+#define WOAL_WMM_DELTS 8
+/** Private command ID to queue configuration */
+#define WOAL_WMM_QUEUE_CONFIG 9
+/** Private command ID to queue stats */
+#define WOAL_WMM_QUEUE_STATS 10
+
+/** Private command ID to get BSS type */
+#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_private_args[] = {
+ {
+ WOAL_SETONEINT_GETWORDCHAR,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WOAL_VERSION,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {
+ WOAL_VEREXT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+ {
+ WOAL_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_WARMRESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "warmreset"},
+ {
+ WOAL_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WOAL_SET_GET_TXRATE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txratecfg"},
+ {
+ WOAL_SET_GET_REGIONCODE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "regioncode"},
+ {
+ WOAL_SET_RADIO,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "radioctrl"},
+ {
+ WOAL_WMM_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wmmcfg"},
+ {
+ WOAL_11D_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "11dcfg"},
+ {
+ WOAL_SET_GET_TX_RX_ANT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "antcfg"},
+ {
+ WOAL_SET_GET_QOS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "qoscfg"},
+ {
+ WOAL_SET_GET_LDO_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "ldocfg"},
+ {
+ WOAL_SET_GET_WWS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wwscfg"},
+#ifdef REASSOCIATION
+ {
+ WOAL_SET_GET_REASSOC,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "reassoctrl"},
+#endif
+ {
+ WOAL_TXBUF_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txbufcfg"},
+ {
+ WOAL_SLEEP_PD,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "sleeppd"},
+ {
+ WOAL_AUTH_TYPE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "authtype"},
+ {
+ WOAL_SET_GET_SIXTEEN_INT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ ""},
+ {
+ WOAL_TX_POWERCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "txpowercfg"},
+#ifdef DEBUG_LEVEL1
+ {
+ WOAL_DRV_DBG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "drvdbg"},
+#endif
+ {
+ WOAL_BEACON_INTERVAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bcninterval"},
+ {
+ WOAL_ATIM_WINDOW,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "atimwindow"},
+ {
+ WOAL_SIGNAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getsignal"},
+ {
+ WOAL_DEEP_SLEEP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "deepsleep",
+ },
+ {
+ WOAL_11N_TX_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "httxcfg"},
+ {
+ WOAL_11N_HTCAP_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "htcapinfo"},
+ {
+ WOAL_PRIO_TBL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "aggrpriotbl"},
+ {
+ WOAL_11N_AMSDU_AGGR_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "amsduaggrctrl"},
+ {
+ WOAL_ADDBA_UPDT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbapara"},
+ {
+ WOAL_ADDBA_REJECT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbareject"},
+ {
+ WOAL_HS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hscfg"},
+ {
+ WOAL_HS_SETPARA,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hssetpara"},
+ {
+ WOAL_REG_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "regrdwr"},
+ {
+ WOAL_BAND_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bandcfg"},
+ {
+ WOAL_INACTIVITY_TIMEOUT_EXT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "inactivityto"},
+ {
+ WOAL_SDIO_CLOCK,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sdioclock"},
+ {
+ WOAL_BCA_TIME_SHARE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bcats"},
+ {
+ WOAL_TID_ELIG_TBL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "tideligtbl"},
+ {
+ WOAL_SCAN_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "scancfg"},
+ {
+ WOAL_PS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "pscfg"},
+ {
+ WOAL_MEM_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "memrdwr"},
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ {
+ WOAL_SDIO_MPA_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "mpactrl"},
+#endif
+ {
+ WOAL_SLEEP_PARAMS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sleepparams"},
+ {
+ WOALGETLOG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {
+ WOAL_SETADDR_GETNONE,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_DEAUTH,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ "deauth"},
+ {
+ WOAL_SET_GET_256_CHAR,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ ""},
+ {
+ WOAL_PASSPHRASE,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "passphrase"},
+ {
+ WOAL_ADHOC_AES,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "adhocaes"},
+ {
+ WOAL_WMM_QUEUE_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "qstatus"},
+ {
+ WOAL_WMM_TS_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "ts_status"},
+ {
+ WOAL_SETNONE_GETTWELVE_CHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {
+ WOAL_WPS_SESSION,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "wpssession"},
+ {
+ WOAL_SETNONE_GET_FOUR_INT,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ ""},
+ {
+ WOAL_DATA_RATE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "getdatarate"},
+ {
+ WOAL_ESUPP_MODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "esuppmode"},
+ {
+ WOAL_SET_GET_64_INT,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ ""},
+ {
+ WOAL_ECL_SYS_CLOCK,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ "sysclock"},
+ {
+ WOAL_HOST_CMD,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {
+ WOAL_ARP_FILTER,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "arpfilter"},
+ {
+ WOAL_SET_INTS_GET_CHARS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ ""},
+ {
+ WOAL_READ_EEPROM,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ "rdeeprom"},
+ {
+ WOAL_SET_GET_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ ""},
+ {
+ WOAL_CMD_52RDWR,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "sdcmd52rw"},
+ {
+ WOAL_CMD_53RDWR,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "sdcmd53rw"},
+ {
+ WOAL_SET_USER_SCAN,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "setuserscan"},
+ {
+ WOAL_GET_SCAN_TABLE,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "getscantable"},
+ {
+ WOAL_VSIE_CFG,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "vsiecfg"},
+ {
+ WOAL_WMM_ADDTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "addts"},
+ {
+ WOAL_WMM_DELTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "delts"},
+ {
+ WOAL_WMM_QUEUE_CONFIG,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qconfig"},
+ {
+ WOAL_WMM_QUEUE_STATS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qstats"},
+};
+
+/** Auto Rate */
+#define AUTO_RATE 0xFF
+
+/** moal_802_11_rates */
+typedef struct _moal_802_11_rates
+{
+ /** Num of rates */
+ t_u8 num_of_rates;
+ /** Rates */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+} moal_802_11_rates;
+
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+#endif /* _WOAL_PRIV_H_ */
diff --git a/wlan_src/mlinux/moal_proc.c b/wlan_src/mlinux/moal_proc.c
new file mode 100755
index 0000000..e1244b1
--- /dev/null
+++ b/wlan_src/mlinux/moal_proc.c
@@ -0,0 +1,337 @@
+/** @file moal_proc.c
+ *
+ * @brief This file contains functions for proc file.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define PROC_DIR NULL
+#define MWLAN_PROC_DIR "mwlan/"
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define PROC_DIR &proc_root
+#else
+#define PROC_DIR proc_net
+#endif
+
+static char *szModes[] = {
+ "Ad-hoc",
+ "Managed",
+ "Auto",
+ "Unknown"
+};
+
+extern int drv_mode;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function for info
+ *
+ * @param page Pointer to buffer
+ * @param start Read data starting position
+ * @param offset Offset
+ * @param count Counter
+ * @param eof End of file flag
+ * @param data Data to output
+ *
+ * @return Number of output data
+ */
+static int
+woal_info_proc_read(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct net_device *netdev = data;
+ char fmt[64];
+ moal_private *priv = (moal_private *) netdev_priv(netdev);
+ int i;
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info info;
+ struct dev_mc_list *mcptr = netdev->mc_list;
+
+ if (offset) {
+ *eof = 1;
+ goto exit;
+ }
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ woal_get_version(handle, fmt, sizeof(fmt) - 1);
+ memset(&info, 0, sizeof(info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ p += sprintf(p, "driver_name = " "\"wlan\"\n");
+ }
+ p += sprintf(p, "driver_version = %s", fmt);
+ p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ p += sprintf(p, "bss_mode=\"%s\"\n", szModes[info.bss_mode]);
+ p += sprintf(p, "media_state=\"%s\"\n",
+ ((priv->media_connected ==
+ MFALSE) ? "Disconnected" : "Connected"));
+ p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ p += sprintf(p, "multicast_count=\"%d\"\n", netdev->mc_count);
+ p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+ p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ info.bssid[0], info.bssid[1],
+ info.bssid[2], info.bssid[3],
+ info.bssid[4], info.bssid[5]);
+ p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
+ p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code);
+
+ /*
+ * Put out the multicast list
+ */
+ for (i = 0; i < netdev->mc_count; i++) {
+ p += sprintf(p,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i,
+ mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+ mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+ mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+ mcptr = mcptr->next;
+ }
+ }
+ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+ p += sprintf(p, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+ p += sprintf(p, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
+ exit:
+ return (p - page);
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Convert string to number
+ *
+ * @param s Pointer to numbered string
+ *
+ * @return Converted number from string s
+ */
+int
+woal_string_to_number(char *s)
+{
+ int r = 0;
+ int base = 0;
+ int pn = 1;
+
+ if (!strncmp(s, "-", 1)) {
+ pn = -1;
+ s++;
+ }
+ if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
+ base = 16;
+ s += 2;
+ } else
+ base = 10;
+
+ for (s = s; *s; s++) {
+ if ((*s >= '0') && (*s <= '9'))
+ r = (r * base) + (*s - '0');
+ else if ((*s >= 'A') && (*s <= 'F'))
+ r = (r * base) + (*s - 'A' + 10);
+ else if ((*s >= 'a') && (*s <= 'f'))
+ r = (r * base) + (*s - 'a' + 10);
+ else
+ break;
+ }
+
+ return (r * pn);
+}
+
+/**
+ * @brief Create the top level proc directory
+ *
+ * @param handle Pointer to woal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_init(moal_handle * handle)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ struct proc_dir_entry *pde = PROC_DIR;
+#endif
+ ENTER();
+ PRINTM(MINFO, "Create Proc Interface\n");
+ if (!handle->proc_mwlan) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ /* Check if directory already exists */
+ for (pde = pde->subdir; pde; pde = pde->next) {
+ if (pde->namelen && !strcmp("mwlan", pde->name)) {
+ /* Directory exists */
+ PRINTM(MWARN, "proc interface already exists!\n");
+ handle->proc_mwlan = pde;
+ break;
+ }
+ }
+ if (pde == NULL) {
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan)
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ else
+ atomic_set(&handle->proc_mwlan->count, 1);
+#endif
+ }
+#else
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan) {
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+ }
+#endif
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove the top level proc directory
+ *
+ * @param handle pointer moal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_exit(moal_handle * handle)
+{
+ ENTER();
+ PRINTM(MINFO, "Remove Proc Interface\n");
+ if (handle->proc_mwlan) {
+ /* Remove only if we are the only instance using this */
+ if (atomic_read(&(handle->proc_mwlan->count)) > 1) {
+ PRINTM(MWARN, "More than one interface using proc!\n");
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ atomic_dec(&(handle->proc_mwlan->count));
+#endif
+ remove_proc_entry("mwlan", PROC_DIR);
+ handle->proc_mwlan = NULL;
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Create proc file for interface
+ *
+ * @param priv pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_create_proc_entry(moal_private * priv)
+{
+ struct net_device *dev = priv->netdev;
+ struct proc_dir_entry *r;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ char proc_dir_name[20];
+#endif
+ ENTER();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ if (!priv->proc_entry) {
+ memset(proc_dir_name, 0, sizeof(proc_dir_name));
+ strcpy(proc_dir_name, MWLAN_PROC_DIR);
+ strcat(proc_dir_name, dev->name);
+ /* Try to create mwlan/mlanX first */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ if (priv->proc_entry) {
+ /* Success. Continue normally */
+ if (!priv->phandle->proc_mwlan) {
+ priv->phandle->proc_mwlan = priv->proc_entry->parent;
+ }
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ } else {
+ /* Failure. mwlan may not exist. Try to create that first */
+ priv->phandle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!priv->phandle->proc_mwlan) {
+ /* Failure. Something broken */
+ LEAVE();
+ return;
+ } else {
+ /* Success. Now retry creating mlanX */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ }
+ }
+#else
+ if (priv->phandle->proc_mwlan && !priv->proc_entry) {
+ priv->proc_entry = proc_mkdir(dev->name, priv->phandle->proc_mwlan);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+#endif
+ strcpy(priv->proc_entry_name, dev->name);
+ if (priv->proc_entry) {
+ r = create_proc_read_entry("info", 0, priv->proc_entry,
+ woal_info_proc_read, dev);
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv Pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_proc_remove(moal_private * priv)
+{
+ ENTER();
+ if (priv->phandle->proc_mwlan && priv->proc_entry) {
+ remove_proc_entry("info", priv->proc_entry);
+ remove_proc_entry(priv->proc_entry_name, priv->phandle->proc_mwlan);
+ atomic_dec(&(priv->phandle->proc_mwlan->count));
+ priv->proc_entry = NULL;
+ }
+ LEAVE();
+}
+#endif
diff --git a/wlan_src/mlinux/moal_sdio.h b/wlan_src/mlinux/moal_sdio.h
new file mode 100755
index 0000000..e94a93e
--- /dev/null
+++ b/wlan_src/mlinux/moal_sdio.h
@@ -0,0 +1,94 @@
+/** @file moal_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MOAL_SDIO_H
+#define _MOAL_SDIO_H
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+
+#include "moal_main.h"
+
+#ifndef BLOCK_MODE
+/** Block mode */
+#define BLOCK_MODE 1
+#endif
+
+#ifndef BYTE_MODE
+/** Byte Mode */
+#define BYTE_MODE 0
+#endif
+
+#ifndef FIXED_ADDRESS
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+#endif
+
+/** Default firmware name */
+
+#define DEFAULT_FW_NAME "mrvl/sd8787.bin"
+
+#ifndef DEFAULT_FW_NAME
+#define DEFAULT_FW_NAME ""
+#endif
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** Function to write register */
+mlan_status woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data);
+/** Function to read register */
+mlan_status woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data);
+/** Function to write data to IO memory */
+mlan_status woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+/** Function to read data from IO memory */
+mlan_status woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+
+/** Register to bus driver function */
+mlan_status woal_bus_register(void);
+/** Unregister from bus driver function */
+void woal_bus_unregister(void);
+
+/** Register device function */
+mlan_status woal_register_dev(moal_handle * handle);
+/** Unregister device function */
+void woal_unregister_dev(moal_handle * handle);
+
+int woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option);
+/** Structure: SDIO MMC card */
+struct sdio_mmc_card
+{
+ /** sdio_func structure pointer */
+ struct sdio_func *func;
+ /** moal_handle structure pointer */
+ moal_handle *handle;
+};
+
+#endif /* _MOAL_SDIO_H */
diff --git a/wlan_src/mlinux/moal_sdio_mmc.c b/wlan_src/mlinux/moal_sdio_mmc.c
new file mode 100755
index 0000000..2224602
--- /dev/null
+++ b/wlan_src/mlinux/moal_sdio_mmc.c
@@ -0,0 +1,396 @@
+/** @file moal_sdio_mmc.c
+ *
+ * @brief This file contains SDIO MMC IF (interface) module
+ * related functions.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+ 02/25/09: Initial creation -
+ This file supports SDIO MMC only
+****************************************************/
+
+#include <linux/firmware.h>
+
+#include "moal_sdio.h"
+
+/** define marvell vendor id */
+#define MARVELL_VENDOR_ID 0x02df
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param func A pointer to the sdio_func structure
+ * @return None
+ */
+static void
+woal_sdio_interrupt(struct sdio_func *func)
+{
+ moal_handle *handle;
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->handle) {
+ PRINTM(MINFO,
+ "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
+ func, card);
+ LEAVE();
+ return;
+ }
+ handle = card->handle;
+
+ PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
+ woal_interrupt(handle);
+
+ LEAVE();
+}
+
+/** @brief This function handles client driver probe.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @param id A pointer to sdio_device_id structure.
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = NULL;
+ moal_handle *handle;
+
+ ENTER();
+
+ PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+ func->vendor, func->device, func->class, func->num);
+
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ PRINTM(MFATAL, "Failed to allocate memory in probe function!\n");
+ return -ENOMEM;
+ }
+
+ card->func = func;
+
+ if (NULL == (handle = woal_add_card(card))) {
+ PRINTM(MERROR, "woal_add_card failed\n");
+ kfree(card);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver remove.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @return n/a
+ */
+static void
+woal_sdio_remove(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ PRINTM(MINFO, "SDIO func=%d\n", func->num);
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ woal_remove_card(card);
+ kfree(card);
+ }
+ }
+
+ LEAVE();
+}
+
+/** Device ID for SD8787 */
+#define SD_DEVICE_ID_8787 (0x9119)
+
+/** WLAN IDs */
+static const struct sdio_device_id wlan_ids[] = {
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8787)},
+ {},
+};
+
+static struct sdio_driver wlan_sdio = {
+ .name = "wlan_sdio",
+ .id_table = wlan_ids,
+ .probe = woal_sdio_probe,
+ .remove = woal_sdio_remove,
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ sdio_writeb(((struct sdio_mmc_card *) handle->card)->func, (t_u8) data, reg,
+ (int *) &ret);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+
+ val =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, reg,
+ (int *) &ret);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function writes multiple bytes into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+
+ if (!sdio_writesb
+ (((struct sdio_mmc_card *) handle->card)->func, ioport, buffer,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+
+ return ret;
+}
+
+/**
+ * @brief This function reads multiple bytes from card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+
+ if (!sdio_readsb
+ (((struct sdio_mmc_card *) handle->card)->func, buffer, ioport,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+
+ return ret;
+}
+
+/**
+ * @brief This function registers the IF module in bus driver
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* SDIO Driver Registration */
+ if (sdio_register_driver(&wlan_sdio)) {
+ PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the IF module in bus driver
+ *
+ * @return None
+ */
+void
+woal_bus_unregister(void)
+{
+ ENTER();
+
+ /* SDIO Driver Unregistration */
+ sdio_unregister_driver(&wlan_sdio);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function de-registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return None
+ */
+void
+woal_unregister_dev(moal_handle * handle)
+{
+ ENTER();
+ if (handle->card) {
+ /* Release the SDIO IRQ */
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_irq(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_disable_func(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ sdio_set_drvdata(((struct sdio_mmc_card *) handle->card)->func, NULL);
+
+ PRINTM(MWARN, "Making the sdio dev card as NULL\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_dev(moal_handle * handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = handle->card;
+ struct sdio_func *func;
+
+ ENTER();
+
+ func = card->func;
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+ goto release_host;
+ }
+
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, woal_sdio_interrupt);
+ if (ret) {
+ PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+ goto disable_func;
+ }
+
+ /* Set block size */
+ ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
+ if (ret) {
+ PRINTM(MERROR, "sdio_set_block_seize(): cannot set SDIO block size\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto release_irq;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ handle->hotplug_device = &func->dev;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+
+ release_irq:
+ sdio_release_irq(func);
+ disable_func:
+ sdio_disable_func(func);
+ release_host:
+ sdio_release_host(func);
+ handle->card = NULL;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function set bus clock on/off
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param option TRUE--on , FALSE--off
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option)
+{
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/wlan_src/mlinux/moal_shim.c b/wlan_src/mlinux/moal_shim.c
new file mode 100755
index 0000000..e2d413a
--- /dev/null
+++ b/wlan_src/mlinux/moal_shim.c
@@ -0,0 +1,962 @@
+/** @file moal_shim.c
+ *
+ * @brief This file contains the callback functions registered to MLAN
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** moal_lock */
+typedef struct _moal_lock
+{
+ /** Lock */
+ spinlock_t lock;
+ /** Flags */
+ unsigned long flags;
+} moal_lock;
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern moal_handle *m_handle;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Alloc a buffer
+ *
+ * @param size The size of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store buffer pointer allocated
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_malloc(IN t_u32 size, OUT t_u8 ** ppbuf)
+{
+ if (!(*ppbuf = kmalloc(size, GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: allocate buffer %d failed!\n", __FUNCTION__,
+ (int) size);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ m_handle->malloc_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a buffer
+ *
+ * @param pbuf Pointer to the buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_mfree(IN t_u8 * pbuf)
+{
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+ kfree(pbuf);
+ m_handle->malloc_count--;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Fill memory with constant byte
+ *
+ * @param pmem Pointer to the memory area
+ * @param byte A constant byte
+ * @param num Number of bytes to fill
+ *
+ * @return Pointer to the memory area
+ */
+t_void *
+moal_memset(IN t_void * pmem, IN t_u8 byte, IN t_u32 num)
+{
+ t_void *p = pmem;
+
+ if (pmem && num)
+ p = memset(pmem, byte, num);
+
+ return p;
+}
+
+/**
+ * @brief Copy memory from one area to another
+ *
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memcpy(IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memcpy(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Move memory from one area to another
+ *
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memmove(IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memmove(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Compare two memory areas
+ *
+ * @param pmem1 Pointer to the first memory
+ * @param pmem2 Pointer to the second memory
+ * @param num Number of bytes to compare
+ *
+ * @return Compare result returns by memcmp
+ */
+t_s32
+moal_memcmp(IN const t_void * pmem1, IN const t_void * pmem2, IN t_u32 num)
+{
+ t_s32 result;
+
+ result = memcmp(pmem1, pmem2, num);
+
+ return result;
+}
+
+/**
+ * @brief Retrieves the current system time
+ *
+ * @param psec Pointer to buf for the seconds of system time
+ * @param pusec Pointer to buf the micro seconds of system time
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_get_system_time(OUT t_u32 * psec, OUT t_u32 * pusec)
+{
+ struct timeval t;
+
+ do_gettimeofday(&t);
+ *psec = (t_u32) t.tv_sec;
+ *pusec = (t_u32) t.tv_usec;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the timer
+ *
+ * @param pptimer Pointer to the timer
+ * @param callback Pointer to callback function
+ * @param pcontext Pointer to context
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_timer(OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext), IN t_void * pcontext)
+{
+ moal_drv_timer *timer = NULL;
+
+ if (!
+ (timer =
+ (moal_drv_timer *) kmalloc(sizeof(moal_drv_timer), GFP_ATOMIC))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ woal_initialize_timer(timer, callback, pcontext);
+ *pptimer = (t_void *) timer;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the timer
+ *
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_timer(IN t_void * ptimer)
+{
+ moal_drv_timer *timer = (moal_drv_timer *) ptimer;
+
+ if (timer) {
+ if ((timer->timer_is_canceled == MFALSE) && timer->time_period) {
+ PRINTM(MERROR, "mlan try to free timer without stop timer!\n");
+ woal_cancel_timer(timer);
+ }
+ kfree(timer);
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Start the timer
+ *
+ * @param ptimer Pointer to the timer
+ * @param periodic Periodic timer
+ * @param msec Timer value in milliseconds
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_start_timer(IN t_void * ptimer, IN t_u8 periodic, IN t_u32 msec)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+
+ ((moal_drv_timer *) ptimer)->timer_is_periodic = periodic;
+ woal_mod_timer((moal_drv_timer *) ptimer, msec);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Stop the timer
+ *
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_stop_timer(IN t_void * ptimer)
+{
+
+ if (!ptimer) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ woal_cancel_timer((moal_drv_timer *) ptimer);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the lock
+ *
+ * @param pplock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_lock(OUT t_void ** pplock)
+{
+ moal_lock *mlock = NULL;
+
+ if (!(mlock = (moal_lock *) kmalloc(sizeof(moal_lock), GFP_ATOMIC))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ spin_lock_init(&mlock->lock);
+ *pplock = (t_void *) mlock;
+
+ m_handle->lock_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the lock
+ *
+ * @param plock Lock
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_lock(IN t_void * plock)
+{
+ moal_lock *mlock = plock;
+
+ if (mlock) {
+ kfree(mlock);
+ m_handle->lock_count--;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Request a spin lock
+ *
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_lock(IN t_void * plock)
+{
+ moal_lock *mlock = plock;
+
+ if (mlock) {
+ mlock->flags = 0;
+ spin_lock_irqsave(&mlock->lock, mlock->flags);
+
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief Request a spin_unlock
+ *
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_unlock(IN t_void * plock)
+{
+ moal_lock *mlock = (moal_lock *) plock;
+
+ if (mlock) {
+ spin_unlock_irqrestore(&mlock->lock, mlock->flags);
+
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief This function is called when MLAN completes the initialization firmware.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_init_fw request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ if (status == MLAN_STATUS_SUCCESS)
+ handle->hardware_status = HardwareStatusReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN shutdown firmware is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_shutdown request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ handle->hardware_status = HardwareStatusNotReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when an MLAN IOCTL is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pioctl_req pointer to strutcture mlan_ioctl_req
+ * @param status The status code for mlan_ioctl request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_private *priv = NULL;
+ wait_queue *wait;
+ ENTER();
+
+ atomic_dec(&handle->ioctl_pending);
+ priv = woal_bss_num_to_priv(handle, pioctl_req->bss_num);
+ if (priv == NULL) {
+ PRINTM(MERROR, "%s: priv is null\n", __FUNCTION__);
+ kfree(pioctl_req);
+ goto done;
+ }
+
+ wait = (wait_queue *) pioctl_req->reserved_1;
+ PRINTM(MCMND,
+ "IOCTL completed: id=0x%lx action=%d, status=%d, status_code=0x%lx\n",
+ pioctl_req->req_id, (int) pioctl_req->action, status,
+ pioctl_req->status_code);
+ if (wait) {
+ *wait->condition = MTRUE;
+ wait->status = status;
+ if ((status != MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->status_code == MLAN_ERROR_CMD_TIMEOUT)) {
+ PRINTM(MERROR, "IOCTL: command timeout\n");
+ } else {
+ wake_up_interruptible(wait->wait);
+ }
+ } else {
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_GET))
+ woal_process_ioctl_resp(priv, pioctl_req);
+ if (status != MLAN_STATUS_SUCCESS)
+ PRINTM(MERROR,
+ "IOCTL failed: id=0x%lx, action=%d, status_code=0x%lx\n",
+ pioctl_req->req_id, (int) pioctl_req->action,
+ pioctl_req->status_code);
+ kfree(pioctl_req);
+ }
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates mlan_buffer.
+ *
+ * @param size allocation size requested
+ * @param pmbuf pointer to pointer to the allocated buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_alloc_mlan_buffer(IN t_u32 size, OUT pmlan_buffer * pmbuf)
+{
+ if (NULL == (*pmbuf = woal_alloc_mlan_buffer(size)))
+ return MLAN_STATUS_FAILURE;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ *
+ * @param pmbuf pointer to buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_free_mlan_buffer(IN pmlan_buffer pmbuf)
+{
+ if (!pmbuf)
+ return MLAN_STATUS_FAILURE;
+
+ woal_free_mlan_buffer(pmbuf);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN complete send data packet.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param status The status code for mlan_send_packet request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ struct sk_buff *skb = NULL;
+ int i;
+ ENTER();
+ if (pmbuf) {
+ priv = woal_bss_num_to_priv(pmoal_handle, pmbuf->bss_num);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ priv->netdev->trans_start = jiffies;
+ if (skb) {
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_errors++;
+ }
+ atomic_dec(&handle->tx_pending);
+ for (i = 0; i < handle->priv_num; i++) {
+ if ((handle->priv[i]->bss_type == MLAN_BSS_TYPE_STA) &&
+ (handle->priv[i]->media_connected ||
+ priv->is_adhoc_link_sensed)) {
+ if (netif_queue_stopped(handle->priv[i]->netdev))
+ netif_wake_queue(handle->priv[i]->netdev);
+ }
+ }
+ }
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN complete receiving
+ * data/event/command
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for receive
+ * @param status The status code for mlan_receive request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_recv_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN t_u32 port, IN mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ if (pmbuf) {
+ priv = woal_bss_num_to_priv(handle, pmbuf->bss_num);
+ if (priv && (pmbuf->buf_type == MLAN_BUF_TYPE_DATA) &&
+ (status == MLAN_STATUS_FAILURE)) {
+ priv->stats.rx_dropped++;
+ }
+ woal_free_mlan_buffer(pmbuf);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function write a command/data packet to card.
+ * This function blocks the call until it finishes
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for sent
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_write_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function read data packet/event/command from card.
+ * This function blocks the call until it finish
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for read
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_read_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function writes data into card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_write_reg(IN t_void * pmoal_handle, IN t_u32 reg, IN t_u32 data)
+{
+ return woal_write_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function reads data from card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_reg(IN t_void * pmoal_handle, IN t_u32 reg, OUT t_u32 * data)
+{
+ return woal_read_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function uploads the packet to the network stack
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ struct sk_buff *skb = NULL;
+ ENTER();
+ if (pmbuf) {
+ priv = woal_bss_num_to_priv(pmoal_handle, pmbuf->bss_num);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ if (skb) {
+ skb_reserve(skb, pmbuf->data_offset);
+ skb_put(skb, pmbuf->data_len);
+ pmbuf->pdesc = NULL;
+ pmbuf->pbuf = NULL;
+ pmbuf->data_offset = pmbuf->data_len = 0;
+ } else {
+ if (!(skb = dev_alloc_skb(pmbuf->data_len + MLAN_NET_IP_ALIGN))) {
+ PRINTM(MERROR, "%s fail to alloc skb", __FUNCTION__);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ goto done;
+ }
+ skb_reserve(skb, MLAN_NET_IP_ALIGN);
+ memcpy(skb->data, (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset),
+ pmbuf->data_len);
+ skb_put(skb, pmbuf->data_len);
+ }
+ skb->dev = priv->netdev;
+ skb->protocol = eth_type_trans(skb, priv->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ }
+ }
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function handles event receive
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmevent Pointer to the mlan event structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
+{
+ moal_private *priv = NULL;
+ union iwreq_data wrqu;
+ ENTER();
+
+ PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id);
+ priv = woal_bss_num_to_priv(pmoal_handle, pmevent->bss_num);
+ if (priv == NULL) {
+ PRINTM(MERROR, "%s: priv is null\n", __FUNCTION__);
+ goto done;
+ }
+ switch (pmevent->event_id) {
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED:
+ priv->is_adhoc_link_sensed = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
+ break;
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST:
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ priv->is_adhoc_link_sensed = MFALSE;
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_LOST);
+ break;
+ case MLAN_EVENT_ID_DRV_CONNECTED:
+ if (pmevent->event_len == ETH_ALEN) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, pmevent->event_buf, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_DRV_SCAN_REPORT:
+ PRINTM(MCMND, "Scan report\n");
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ if (priv->scan_pending_on_block == MTRUE) {
+ priv->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&priv->async_sem);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM:
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_OBSS_SCAN_PARAM,
+ strlen(CUS_EVT_OBSS_SCAN_PARAM));
+ pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_OBSS_SCAN_PARAM) +
+ IW_EV_LCP_LEN + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ break;
+ case MLAN_EVENT_ID_FW_BW_CHANGED:
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_BW_CHANGED,
+ strlen(CUS_EVT_BW_CHANGED));
+ pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_BW_CHANGED) + IW_EV_LCP_LEN + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ break;
+ case MLAN_EVENT_ID_FW_DISCONNECTED:
+ priv->media_connected = MFALSE;
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ /* Reset wireless stats signal info */
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.qual.noise = 0;
+#ifdef REASSOCIATION
+ if (priv->phandle->reassoc_on == MTRUE) {
+ PRINTM(MINFO, "Reassoc: trigger the timer\n");
+ priv->reassoc_required = MTRUE;
+ priv->phandle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->reassoc_timer, 500);
+ } else {
+ priv->rate_index = AUTO_RATE;
+ }
+#endif /* REASSOCIATION */
+ break;
+ case MLAN_EVENT_ID_FW_MIC_ERR_UNI:
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_UNI);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_MUL);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_FW_MIC_ERR_UNI);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_HIGH:
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
+ break;
+ case MLAN_EVENT_ID_FW_MAX_FAIL:
+ woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_LOW:
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_LOW:
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH:
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_HIGH:
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+ break;
+ case MLAN_EVENT_ID_FW_LINK_QUALITY:
+ woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY);
+ break;
+ case MLAN_EVENT_ID_FW_PORT_RELEASE:
+ woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE);
+ break;
+ case MLAN_EVENT_ID_FW_PRE_BCN_LOST:
+ woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST);
+ break;
+ case MLAN_EVENT_ID_FW_DS_AWAKE:
+ woal_send_iwevcustom_event(priv, CUS_EVT_DEEP_SLEEP_AWAKE);
+ break;
+ case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
+ woal_send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
+ break;
+ case MLAN_EVENT_ID_FW_WEP_ICV_ERR:
+ DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf,
+ pmevent->event_len);
+ woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR);
+ break;
+
+ case MLAN_EVENT_ID_DRV_DEFER_HANDLING:
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_EVENT_ID_FW_BG_SCAN:
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ break;
+ case MLAN_EVENT_ID_FW_STOP_TX:
+ netif_carrier_off(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_START_TX:
+ netif_carrier_on(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_HS_WAKEUP:
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_send_iwevcustom_event(priv, CUS_EVT_HS_WAKEUP);
+ /* simulate HSCFG_CANCEL command */
+ woal_hs_cfg_cancel(priv, MOAL_NO_WAIT);
+ break;
+ case MLAN_EVENT_ID_DRV_HS_ACTIVATED:
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ woal_send_iwevcustom_event(priv, CUS_EVT_HS_ACTIVATED);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_HS_DEACTIVATED:
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_send_iwevcustom_event(priv, CUS_EVT_HS_DEACTIVATED);
+ break;
+ case MLAN_EVENT_ID_DRV_PASSTHU:
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prints the debug message in mlan
+ *
+ * @param level debug level
+ * @param pformat point to string format buf
+ *
+ * @return N/A
+ */
+t_void
+moal_print(IN t_u32 level, IN t_s8 * pformat, IN ...)
+{
+#ifdef DEBUG_LEVEL1
+ va_list args;
+
+ if (level & MHEX_DUMP) {
+ t_u8 *buf = NULL;
+ int len = 0;
+
+ va_start(args, pformat);
+ buf = (t_u8 *) va_arg(args, t_u8 *);
+ len = (int) va_arg(args, int);
+ va_end(args);
+
+#ifdef DEBUG_LEVEL2
+ if (level & MINFO)
+ HEXDUMP((char *) pformat, buf, len);
+ else
+#endif /* DEBUG_LEVEL2 */
+ {
+ if (level & MCMD_D)
+ DBG_HEXDUMP(MCMD_D, (char *) pformat, buf, len);
+ if (level & MDAT_D)
+ DBG_HEXDUMP(MDAT_D, (char *) pformat, buf, len);
+ if (level & MIF_D)
+ DBG_HEXDUMP(MIF_D, (char *) pformat, buf, len);
+ if (level & MFW_D)
+ DBG_HEXDUMP(MFW_D, (char *) pformat, buf, len);
+ }
+ } else if (drvdbg & level) {
+ va_start(args, pformat);
+#ifndef DEBUG_LEVEL2
+ if (!(level & (MINFO | MWARN | MENTRY)))
+#endif /* DEBUG_LEVEL2 */
+ vprintk(pformat, args);
+ va_end(args);
+ }
+#endif /* DEBUG_LEVEL1 */
+}
diff --git a/wlan_src/mlinux/moal_shim.h b/wlan_src/mlinux/moal_shim.h
new file mode 100755
index 0000000..e5769df
--- /dev/null
+++ b/wlan_src/mlinux/moal_shim.h
@@ -0,0 +1,78 @@
+/** @file moal_shim.h
+ *
+ * @brief This file contains declaration referring to
+ * functions defined in moal module
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+ 10/21/2008: initial version
+************************************************************/
+
+#ifndef _MOAL_H
+#define _MOAL_H
+mlan_status moal_init_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_shutdown_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+mlan_status moal_alloc_mlan_buffer(IN t_u32 size, OUT pmlan_buffer * pmbuf);
+mlan_status moal_free_mlan_buffer(IN pmlan_buffer pmbuf);
+mlan_status moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+mlan_status moal_recv_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+/** moal_write_reg */
+mlan_status moal_write_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+/** moal_read_reg */
+mlan_status moal_read_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+mlan_status moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf);
+mlan_status moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent);
+mlan_status moal_malloc(IN t_u32 size, OUT t_u8 ** ppbuf);
+mlan_status moal_mfree(IN t_u8 * pbuf);
+t_void *moal_memset(IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+t_void *moal_memcpy(IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_void *moal_memmove(IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_s32 moal_memcmp(IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+mlan_status moal_get_system_time(OUT t_u32 * psec, OUT t_u32 * pusec);
+mlan_status moal_init_lock(OUT t_void ** pplock);
+mlan_status moal_free_lock(IN t_void * plock);
+mlan_status moal_spin_lock(IN t_void * plock);
+mlan_status moal_spin_unlock(IN t_void * plock);
+t_void moal_print(IN t_u32 level, IN t_s8 * pformat, IN ...);
+mlan_status moal_init_timer(OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+mlan_status moal_free_timer(IN t_void * ptimer);
+mlan_status moal_start_timer(IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+mlan_status moal_stop_timer(IN t_void * ptimer);
+#endif /*_MOAL_H */
diff --git a/wlan_src/mlinux/moal_wext.c b/wlan_src/mlinux/moal_wext.c
new file mode 100755
index 0000000..f919d5f
--- /dev/null
+++ b/wlan_src/mlinux/moal_wext.c
@@ -0,0 +1,2761 @@
+/** @file moal_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/21/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+
+/** Approximate amount of data needed to pass a scan result back to iwlist */
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_UINT_LEN \
+ + IW_EV_FREQ_LEN \
+ + IW_EV_QUAL_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_PARAM_LEN \
+ + 40) /* 40 for WPAIE */
+/** Macro for minimum size of scan buffer */
+#define MIN_ACCEPTED_GET_SCAN_BUF 8000
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+t_s32
+woal_ssid_cmp(mlan_802_11_ssid * ssid1, mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void
+woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to moal_private structure
+ * @param option Radio Option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_radio(moal_private * priv, t_u8 option)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+ if ((option != 0) && (option != 1)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = option;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Check the size of the string
+ */
+ if (dwrq->length > 16) {
+ LEAVE();
+ return -E2BIG;
+ }
+ memset(priv->nick_name, 0, sizeof(priv->nick_name));
+ memcpy(priv->nick_name, extra, dwrq->length);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Get the Nick Name saved
+ */
+ strncpy(extra, (char *) priv->nick_name, 16);
+ extra[16] = '\0';
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info, char *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ const char *cp;
+ char comm[6] = { "COMM-" };
+ char mrvl[6] = { "MRVL-" };
+ int cnt;
+
+ ENTER();
+
+ strcpy(cwrq, mrvl);
+
+ cp = strstr(driver_version, comm);
+ if (cp == driver_version) /* Skip leading "COMM-" */
+ cp = driver_version + strlen(comm);
+ else
+ cp = driver_version;
+
+ cnt = strlen(mrvl);
+ cwrq += cnt;
+ while (cnt < 16 && (*cp != '-')) {
+ *cwrq++ = toupper(*cp++);
+ cnt++;
+ }
+ *cwrq = '\0';
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+ long f = fwrq->m / 100000;
+ bss->param.bss_chan.freq = f;
+ } else
+ bss->param.bss_chan.channel = fwrq->m;
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fwrq->m = (long) bss->param.bss_chan.freq * 100000;
+ fwrq->i = (long) bss->param.bss_chan.channel;
+ fwrq->e = 1;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq Wireless mode to set
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (*uwrq) {
+ case IW_MODE_INFRA:
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ break;
+ case IW_MODE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ break;
+ case IW_MODE_AUTO:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (bss_info.media_connected == MTRUE) {
+ memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = { 255, 255, 255, 255, 255, 255 };
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ssid_bssid ssid_bssid;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1],
+ (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3],
+ (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+#endif
+
+ /* zero_mac means disconnect */
+ if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ goto done;
+ }
+
+ /* Broadcast MAC means search for best network */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ /* Check if we are already assoicated to the AP */
+ if (bss_info.media_connected == MTRUE) {
+ if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
+ goto done;
+ /* disconnect before try to assoicate to the new AP */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ }
+ memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_ewpa_mode(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv,
+ MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR, "ASSOC: WAP: MAC address not found in BSSID List\n");
+ ret = -ENETUNREACH;
+ goto done;
+ }
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = -1;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ if (vwrq->disabled) {
+ woal_set_radio(priv, 0);
+ goto done;
+ }
+ woal_set_radio(priv, 1);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ req->action = MLAN_ACT_SET;
+ if (!vwrq->fixed)
+ pcfg->param.power_cfg.is_power_auto = 1;
+ else {
+ pcfg->param.power_cfg.is_power_auto = 0;
+ pcfg->param.power_cfg.power_level = vwrq->value;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_bss_info bss_info;
+
+ ENTER();
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ vwrq->value = pcfg->param.power_cfg.power_level;
+ if (pcfg->param.power_cfg.is_power_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ if (bss_info.radio_on) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "PS_MODE set power disabled=%d\n", vwrq->disabled);
+ if (vwrq->disabled)
+ pm_cfg->param.ps_mode = 0;
+ else {
+ /* Check not support case only (vwrq->disabled == FALSE) */
+ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ PRINTM(MERROR, "Setting power timeout command is not supported\n");
+ ret = -EINVAL;
+ goto done;
+ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+ PRINTM(MERROR, "Setting power period command is not supported\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg->param.ps_mode = 1;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (pm_cfg->param.ps_mode)
+ vwrq->disabled = 0;
+ else
+ vwrq->disabled = 1;
+
+ vwrq->value = 0;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /*
+ * The MAC has a 4-bit Total_Tx_Count register
+ * Total_Tx_Count = 1 + Tx_Retry_Count
+ */
+/** Minimum transmission retry count */
+#define TX_RETRY_MIN 0
+/** Maximum transmission retry count */
+#define TX_RETRY_MAX 14
+ if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT;
+ mib->param.retry_count = vwrq->value;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Get Tx retry count */
+ vwrq->value = mib->param.retry_count;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_encrypt_key *pkey = NULL;
+ int index = 0;
+ t_u32 auth_mode = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Check index */
+ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ pkey = (mlan_ds_encrypt_key *) extra;
+ if (pkey->key_len <= MAX_WEP_KEY_SIZE) {
+ dwrq->length = pkey->key_len;
+ dwrq->flags = pkey->key_index + 1;
+ }
+ }
+ sec->param.encrypt_key.key_len = 0;
+ if (dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (index < 0)
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ else
+ sec->param.encrypt_key.key_index = index;
+ if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+ memcpy(sec->param.encrypt_key.key_material, extra, dwrq->length);
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
+ else
+ sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
+ }
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sec->param.encrypt_key.key_disable = MTRUE;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * Do we want to just set the transmit key index ?
+ */
+ if (index < 0) {
+ PRINTM(MINFO, "*** iwconfig mlanX key on ***\n");
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else
+ sec->param.encrypt_key.key_index = index;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+ /* iwconfig mlanX restricted key [1] */
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ } else if (dwrq->flags & IW_ENCODE_OPEN) {
+ /* iwconfig mlanX key [2] open */
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u32 auth_mode;
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (!index)
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ else
+ sec->param.encrypt_key.key_index = index - 1;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(extra, 0, 16);
+ if (sec->param.encrypt_key.key_len) {
+ memcpy(extra, sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ dwrq->length = sec->param.encrypt_key.key_len;
+ dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if (sec->param.encrypt_key.key_disable)
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ else
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_SET;
+ if (vwrq->value == -1) {
+ rate->param.rate_cfg.is_rate_auto = 1;
+ } else {
+ rate->param.rate_cfg.is_rate_auto = 0;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate->param.rate_cfg.rate = vwrq->value / 500000;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (rate->param.rate_cfg.is_rate_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ vwrq->value = rate->param.rate_cfg.rate * 500000;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ rthr = MLAN_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD;
+ mib->param.rts_threshold = rthr;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = mib->param.rts_threshold;
+ vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE)
+ || (vwrq->value > MLAN_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+ int fthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ fthr = MLAN_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD;
+ mib->param.frag_threshold = fthr;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = mib->param.frag_threshold;
+ vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE)
+ || (vwrq->value > MLAN_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int copy_size = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ copy_size = MIN(misc->param.gen_ie.len, dwrq->length);
+ memcpy(extra, misc->param.gen_ie.ie_data, copy_size);
+ dwrq->length = copy_size;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (dwrq->length > MAX_IE_SIZE) {
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+ misc->param.gen_ie.len = dwrq->length;
+ memcpy(misc->param.gen_ie.ie_data, extra, misc->param.gen_ie.len);
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+
+ ENTER();
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ pkey_material = (t_u8 *) (ext + 1);
+ sec->param.encrypt_key.key_len = ext->key_len;
+ /* Disable Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ } else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+ /* Set WEP key */
+ sec->param.encrypt_key.key_index = key_index;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ sec->param.encrypt_key.key_len = 0;
+ }
+ } else {
+ /* Set WPA key */
+ sec->param.encrypt_key.key_index = key_index;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+#define IW_ENCODE_ALG_SMS4 0x20
+ /* Set WAPI key */
+ if (ext->alg == IW_ENCODE_ALG_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) ext->addr.sa_data,
+ ETH_ALEN);
+ memcpy(sec->param.encrypt_key.pn, ext->tx_seq, PN_SIZE);
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_mlme(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *dwrq, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) mlme->addr.sa_data))
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 auth_mode = 0;
+ t_u32 encrypt_mode = 0;
+ ENTER();
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ default:
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+#define IW_AUTH_WAPI_ENABLED 0x20
+ case IW_AUTH_WAPI_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_KEY_MGMT:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 encrypt_mode = 0;
+ t_u32 auth_mode;
+ t_u32 wpa_enable;
+ ENTER();
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
+ ret = -EFAULT;
+ else {
+ if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
+ vwrq->value = IW_AUTH_CIPHER_WEP40;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
+ vwrq->value = IW_AUTH_CIPHER_WEP104;
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
+ ret = -EFAULT;
+ else {
+ if (auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
+ ret = -EFAULT;
+ else
+ vwrq->value = wpa_enable;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_KEY_MGMT:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int i;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iw_range *range = (struct iw_range *) extra;
+ moal_802_11_rates rates;
+ mlan_chan_list chan_list;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(&rates, 0, sizeof(rates));
+ woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
+ range->num_bitrates = rates.num_of_rates;
+
+ for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
+ i++) {
+ range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+
+ memset(&chan_list, 0, sizeof(chan_list));
+
+ woal_get_channel_list(priv, MOAL_IOCTL_WAIT, &chan_list);
+
+ range->num_frequency = MIN(chan_list.num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long) chan_list.cf[i].channel;
+ range->freq[i].m = (long) chan_list.cf[i].freq * 100000;
+ range->freq[i].e = 1;
+ }
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ /*
+ * need to put the right values here
+ */
+/** Maximum quality percentage */
+#define IW_MAX_QUAL_PERCENT 100
+/** Average quality percentage */
+#define IW_AVG_QUAL_PERCENT 70
+ range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+
+ range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+
+ range->sensitivity = 0;
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ range->txpower[0] = bss_info.min_power_level;
+ range->txpower[1] = bss_info.max_power_level;
+ range->num_txpower = 2;
+ range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+int
+woal_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+#endif
+#if WIRELESS_EXT >= 18
+ struct iw_scan_req *req;
+ struct iw_point *dwrq = (struct iw_point *) vwrq;
+#endif
+ mlan_802_11_ssid req_ssid;
+
+ ENTER();
+
+ if (priv->scan_pending_on_block == MTRUE) {
+ PRINTM(MCMND, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+
+#if WIRELESS_EXT >= 18
+ if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+ (dwrq->length == sizeof(struct iw_scan_req))) {
+ req = (struct iw_scan_req *) extra;
+
+ if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
+
+ req_ssid.ssid_len = req->essid_len;
+ memcpy(req_ssid.ssid, (t_u8 *) req->essid, req->essid_len);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+#endif
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if WIRELESS_EXT >= 18
+ }
+#endif
+
+ if (priv->phandle->surprise_removed) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+#endif
+ int ret = 0;
+ t_u32 mode = 0;
+
+ ENTER();
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ /*
+ * Check if we asked for `any' or 'particular'
+ */
+ if (!dwrq->flags) {
+ /* Do normal SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else {
+ /* Set the SSID */
+#if WIRELESS_EXT > 20
+ req_ssid.ssid_len = dwrq->length;
+#else
+ req_ssid.ssid_len = dwrq->length - 1;
+#endif
+ memcpy(req_ssid.ssid, extra,
+ MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
+ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (req_ssid.ssid_len > 0) ? (char *) req_ssid.ssid : "NULL");
+
+ if (dwrq->flags != 0xFFFF) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS != woal_request_scan(priv, MOAL_IOCTL_WAIT,
+ &req_ssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+ }
+
+ /* disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_ewpa_mode(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+
+ if (mode != IW_MODE_ADHOC) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ setessid_ret:
+
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_info.media_connected) {
+ dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
+ memcpy(extra, bss_info.ssid.ssid, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ if (bss_info.scan_table_idx)
+ dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
+ else
+ dwrq->flags = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return MTRUE or MFALSE
+ */
+static BOOLEAN
+woal_ssid_valid(mlan_802_11_ssid * pssid)
+{
+ int ssid_idx;
+
+ ENTER();
+
+ for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++)
+ if (!isprint(pssid->ssid[ssid_idx])) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+int
+woal_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ int i;
+ int j;
+ mlan_scan_resp scan_resp;
+ mlan_bss_info bss_info;
+ BSSDescriptor_t *scan_table;
+ mlan_ds_get_signal rssi;
+ t_u16 buf_size = 16 + 256 * 2;
+ char *buf = NULL;
+ char *ptr;
+ t_u8 *praw_data;
+ int beacon_size;
+ t_u8 *pbeacon;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+
+ ENTER();
+
+ if (priv->scan_pending_on_block == MTRUE)
+ return -EAGAIN;
+
+ if (!(buf = kmalloc((buf_size), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Cannot allocate buffer!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
+ MOAL_IOCTL_WAIT,
+ &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
+ if (dwrq->length)
+ end_buf = extra + dwrq->length;
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
+ }
+ PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
+ (int) scan_resp.num_in_scan_table);
+
+#if WIRELESS_EXT > 13
+ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. The new
+ API using SIOCGIWSCAN is only limited by buffer size WE-14 -> WE-16 the
+ buffer is limited to IW_SCAN_MAX_DATA bytes which is 4096. */
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ PRINTM(MINFO, "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+ ret = -E2BIG;
+ break;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MERROR, "Invalid channel number %d\n",
+ (int) scan_table[i].channel);
+ continue;
+ }
+ PRINTM(MINFO, "i=%d Ssid: %-32s\n", i, scan_table[i].ssid.ssid);
+ if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE) {
+ continue;
+ }
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address, ETH_ALEN);
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add the ESSID */
+ iwe.u.data.length = scan_table[i].ssid.ssid_len;
+
+ if (iwe.u.data.length > 32) {
+ iwe.u.data.length = 32;
+ }
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ (t_s8 *) scan_table[i].ssid.ssid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
+ iwe.u.mode = IW_MODE_ADHOC;
+ else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_AUTO;
+
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long) scan_table[i].freq * 100000;
+ iwe.u.freq.e = 1;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ memset(&iwe, 0, sizeof(iwe));
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
+ iwe.u.qual.qual = 0;
+ if (!bss_info.bcn_nf_last) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise = bss_info.bcn_nf_last;
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ memset(&rssi, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &rssi)) {
+ ret = -EFAULT;
+ break;
+ }
+ iwe.u.qual.level = rssi.data_rssi_avg;
+ }
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (scan_table[i].privacy) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, NULL);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j]) {
+ break;
+ }
+
+ iwe.u.bitrate.value =
+ (scan_table[i].supported_rates[j] & 0x7f) * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ iwe.u.bitrate.value = 22 * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+ }
+
+ /* Check if an event is added */
+ if ((current_val - current_ev) >= IW_EV_PARAM_LEN)
+ current_ev = current_val;
+
+ /* Beacon Interval */
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "Beacon interval=%d", scan_table[i].beacon_period);
+
+ iwe.u.data.length = strlen(buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+
+ /* Parse and send the IEs */
+ pbeacon = scan_table[i].pbeacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+ if (pbeacon) {
+ pbeacon += sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+ beacon_size -= sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+ }
+
+ while (beacon_size >= sizeof(IEEEtypes_Header_t)) {
+ element_id = (IEEEtypes_ElementId_e) (*(t_u8 *) pbeacon);
+ element_len = *((t_u8 *) pbeacon + 1);
+ if (beacon_size < (int) element_len + sizeof(IEEEtypes_Header_t)) {
+ PRINTM(MERROR, "Get scan: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+
+ switch (element_id) {
+ case VENDOR_SPECIFIC_221:
+ case RSN_IE:
+ case WAPI_IE:
+ praw_data = (t_u8 *) pbeacon;
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ memcpy(buf, praw_data,
+ element_len + sizeof(IEEEtypes_Header_t));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = element_len + sizeof(IEEEtypes_Header_t);
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+ break;
+ default:
+ break;
+ }
+ pbeacon += element_len + sizeof(IEEEtypes_Header_t);
+ beacon_size -= element_len + sizeof(IEEEtypes_Header_t);
+ }
+
+#if WIRELESS_EXT > 14
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "band=");
+ memset(&iwe, 0, sizeof(iwe));
+ if (scan_table[i].bss_band == BAND_A)
+ ptr += sprintf(ptr, "a");
+ else
+ ptr += sprintf(ptr, "bg");
+ iwe.u.data.length = strlen(buf);
+ PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+ PRINTM(MINFO, "BUF: %s \n", buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+#endif
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+#endif
+
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) woal_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler) woal_set_sens, /* SIOCSIWSENS */
+ (iw_handler) woal_get_sens, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler) woal_set_wap, /* SIOCSIWAP */
+ (iw_handler) woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) woal_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) woal_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler) woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler) woal_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) woal_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_rate, /* SIOCSIWRATE */
+ (iw_handler) woal_get_rate, /* SIOCGIWRATE */
+ (iw_handler) woal_set_rts, /* SIOCSIWRTS */
+ (iw_handler) woal_get_rts, /* SIOCGIWRTS */
+ (iw_handler) woal_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) woal_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) woal_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) woal_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) woal_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) woal_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) woal_set_power, /* SIOCSIWPOWER */
+ (iw_handler) woal_get_power, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** wlan_handler_def */
+struct iw_handler_def woal_handler_def = {
+ num_standard:sizeof(woal_handler) / sizeof(iw_handler),
+ num_private:sizeof(woal_private_handler) / sizeof(iw_handler),
+ num_private_args:sizeof(woal_private_args) / sizeof(struct iw_priv_args),
+ standard:(iw_handler *) woal_handler,
+ private:(iw_handler *) woal_private_handler,
+ private_args:(struct iw_priv_args *) woal_private_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats:woal_get_wireless_stats,
+#endif
+};
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+woal_get_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u16 wait_option = MOAL_NO_WAIT;
+
+ ENTER();
+
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (write_can_lock(&dev_base_lock)
+ && (!in_atomic() || current->exit_state))
+ wait_option = MOAL_WSTATS_WAIT;
+
+ priv->w_stats.status = woal_get_mode(priv, wait_option);
+ priv->w_stats.discard.retries = priv->stats.tx_errors;
+
+ /* Send RSSI command to get beacon RSSI/NF, valid only if associated */
+ if (priv->media_connected == MTRUE) {
+ woal_get_signal_info(priv, wait_option, NULL);
+ }
+ if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
+ priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+
+ priv->w_stats.qual.qual = 0;
+ PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
+ PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
+ priv->w_stats.discard.code = 0;
+ woal_get_stats_info(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
diff --git a/wlan_src/mlinux/moal_wext.h b/wlan_src/mlinux/moal_wext.h
new file mode 100755
index 0000000..b402e90
--- /dev/null
+++ b/wlan_src/mlinux/moal_wext.h
@@ -0,0 +1,105 @@
+/** @file moal_wext.h
+ *
+ * @brief This file contains definition for wireless extension IOCTL call.
+ *
+ * Copyright (C) 2008-2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_WEXT_H_
+#define _WOAL_WEXT_H_
+
+/** Custom event : AdHoc link sensed */
+#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED"
+/** Custom event : AdHoc link lost */
+#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST"
+/** Custom event : MIC failure, unicast */
+#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast "
+/** Custom event : MIC failure, multicast */
+#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast "
+/** Custom event : Beacon RSSI low */
+#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW"
+/** Custom event : Beacon SNR low */
+#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW"
+/** Custom event : Beacon RSSI high */
+#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH"
+/** Custom event : Beacon SNR high */
+#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
+/** Custom event : Max fail */
+#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
+/** Custom event : Data RSSI low */
+#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
+/** Custom event : Data SNR low */
+#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW"
+/** Custom event : Data RSSI high */
+#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH"
+/** Custom event : Data SNR high */
+#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH"
+/** Custom event : Link Quality */
+#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY"
+/** Custom event : Port Release */
+#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE"
+/** Custom event : Pre-Beacon Lost */
+#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST"
+
+/** Custom event : Deep Sleep awake */
+#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE"
+
+/** Custom event : Host Sleep activated */
+#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED "
+/** Custom event : Host Sleep deactivated */
+#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED "
+/** Custom event : Host Sleep wakeup */
+#define CUS_EVT_HS_WAKEUP "HS_WAKEUP"
+
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication"
+
+/** Custom event : WEP ICV error */
+#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR"
+
+/** Custom event : BW changed */
+#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED"
+/** Custom event : OBSS scan parameter */
+#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM"
+
+/** NF value for default scan */
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((i), (c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((i), (c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((i), (c), (v), (e), (w), (l))
+#else
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((c), (v), (e), (w), (l))
+#endif
+
+extern struct iw_handler_def woal_handler_def;
+struct iw_statistics *woal_get_wireless_stats(struct net_device *dev);
+#endif /* _WOAL_WEXT_H_ */