]> git.ipfire.org Git - ipfire-2.x.git/commitdiff
kernel: add Marvel uAP module (dreamplug).
authorArne Fitzenreiter <arne_f@ipfire.org>
Thu, 8 May 2014 14:13:25 +0000 (16:13 +0200)
committerArne Fitzenreiter <arne_f@ipfire.org>
Thu, 8 May 2014 14:13:25 +0000 (16:13 +0200)
12 files changed:
config/kernel/kernel.config.armv5tel-ipfire-kirkwood
config/kernel/kernel.config.armv5tel-ipfire-multi
config/kernel/kernel.config.armv5tel-ipfire-rpi
config/kernel/kernel.config.i586-ipfire
config/kernel/kernel.config.i586-ipfire-pae
config/rootfiles/common/armv5tel/linux-kirkwood
config/rootfiles/common/armv5tel/linux-multi
config/rootfiles/common/armv5tel/linux-rpi
config/rootfiles/common/i586/linux
config/rootfiles/packages/linux-pae
lfs/linux
src/patches/linux-3.10.39-add_libertas_uap.patch [new file with mode: 0644]

index 5245a7f8ee6e540711ad14b7bdbd89b395dbfa07..2d9b11521af814fe75e7d2379fca085df32f6c27 100644 (file)
@@ -1934,6 +1934,7 @@ CONFIG_WLAN=y
 CONFIG_LIBERTAS_THINFIRM=m
 # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
 CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_UAP=m
 CONFIG_ATMEL=m
 CONFIG_PCI_ATMEL=m
 CONFIG_AT76C50X_USB=m
index dcd3b08f73f39de8de2d9651439d0c859ad22ca7..dcc177d3ecf9ac10b5da9c31cfbadb98fc399abb 100644 (file)
@@ -2141,6 +2141,7 @@ CONFIG_WLAN=y
 CONFIG_LIBERTAS_THINFIRM=m
 # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
 CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_UAP=m
 CONFIG_ATMEL=m
 CONFIG_PCI_ATMEL=m
 CONFIG_AT76C50X_USB=m
index 84a06d9db4c278e7d4f3d239ae1dcd186265d9d2..0c9b3d20ecfcb2c50937e7cf7c6364c851c20921 100644 (file)
@@ -1530,6 +1530,7 @@ CONFIG_WLAN=y
 CONFIG_LIBERTAS_THINFIRM=m
 # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
 CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_UAP=m
 CONFIG_AT76C50X_USB=m
 CONFIG_USB_ZD1201=m
 CONFIG_USB_NET_RNDIS_WLAN=m
index 2824018f343a4f096b5420387a3ac16e24a2b3f7..246e436ecbcabb1205adfb6f72a78a27cbc136ef 100644 (file)
@@ -2120,6 +2120,7 @@ CONFIG_WLAN=y
 CONFIG_LIBERTAS_THINFIRM=m
 # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
 CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_UAP=m
 CONFIG_AIRO=m
 CONFIG_ATMEL=m
 CONFIG_PCI_ATMEL=m
index d8f452c127ff797488b2a13463a830e903f5f9b1..8dc185bca39b731609e8ba53f51c68d14fd27786 100644 (file)
@@ -2134,6 +2134,7 @@ CONFIG_WLAN=y
 CONFIG_LIBERTAS_THINFIRM=m
 # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
 CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_UAP=m
 CONFIG_AIRO=m
 CONFIG_ATMEL=m
 CONFIG_PCI_ATMEL=m
index cb6858f77e149d2cccf21a51ab8c61ae62e4dbd8..9cb3057d06703e5351e0a17439d92bde524e344e 100644 (file)
@@ -1394,6 +1394,8 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/libertas_tf
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/libertas_tf/libertas_tf.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/libertas_tf/libertas_tf_usb.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/libertas_uap
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/libertas_uap/uap8xxx.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/mac80211_hwsim.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/mwifiex
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/net/wireless/mwifiex/mwifiex.ko
index 89107a3349916082f554708ebaa0ca792f751e4e..1fd840c95e0f0fea857aca51c17e2bf945ecd93a 100644 (file)
@@ -1356,6 +1356,8 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/libertas_tf
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/libertas_tf/libertas_tf.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/libertas_tf/libertas_tf_usb.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/libertas_uap
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/libertas_uap/uap8xxx.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/mac80211_hwsim.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/mwifiex
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/wireless/mwifiex/mwifiex.ko
index 98f513e9b09bc0ae86eac7b3e8e39c9dadee3db4..2ea9efe196523bb47d460b8a3ca7eafb57006b45 100644 (file)
@@ -1125,6 +1125,8 @@ lib/modules/KVER-ipfire-rpi
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/libertas_tf
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/libertas_tf/libertas_tf.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/libertas_tf/libertas_tf_usb.ko
+#lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/libertas_uap
+#lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/libertas_uap/uap8xxx.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/mwifiex
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/mwifiex/mwifiex.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless/mwifiex/mwifiex_sdio.ko
index 25eccdfc9932fe991233b33ae7608f4c659a20a7..48bd9ced554d2b70ae75740e0ce88193275e84e6 100644 (file)
@@ -1648,6 +1648,8 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/libertas_tf
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/libertas_tf/libertas_tf.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/libertas_tf/libertas_tf_usb.ko
+#lib/modules/KVER-ipfire/kernel/drivers/net/wireless/libertas_uap
+#lib/modules/KVER-ipfire/kernel/drivers/net/wireless/libertas_uap/uap8xxx.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/mac80211_hwsim.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/mwifiex
 #lib/modules/KVER-ipfire/kernel/drivers/net/wireless/mwifiex/mwifiex.ko
index e46f855e21d891681f8fac71dda565cc0c45bbe9..eaaa3e589e6c6fdd1e74d4425ce99f8fb10f3689 100644 (file)
@@ -1644,6 +1644,8 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/libertas_tf
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/libertas_tf/libertas_tf.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/libertas_tf/libertas_tf_usb.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/libertas_uap
+#lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/libertas_uap/uap8xxx.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/mac80211_hwsim.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/mwifiex
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/wireless/mwifiex/mwifiex.ko
index e6ac36cee3a57269dd95a47236dc659b80a1dbeb..2bf32d39b8cf9f521cf0955c4495d108ebfaaf3c 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
@@ -138,6 +138,7 @@ endif
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/compat-drivers-3.8.3-ath_ignore_eeprom_regdomain.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.34-iwlwifi-noibss_only_on_radar_chan.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.37-rt2800usb_add_dlink_dwa137_usbid.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.39-add_libertas_uap.patch
 
        # mISDN Patches
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/mISDN_hfc-s_add_id.patch
diff --git a/src/patches/linux-3.10.39-add_libertas_uap.patch b/src/patches/linux-3.10.39-add_libertas_uap.patch
new file mode 100644 (file)
index 0000000..be9a493
--- /dev/null
@@ -0,0 +1,5081 @@
+diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
+index f8f0156..42a0702 100644
+--- a/drivers/net/wireless/Kconfig
++++ b/drivers/net/wireless/Kconfig
+@@ -51,6 +51,14 @@ config LIBERTAS_THINFIRM_USB
+       ---help---
+         A driver for Marvell Libertas 8388 USB devices using thinfirm.
++config LIBERTAS_UAP
++      tristate "Marvell 8xxx Libertas UAP"
++      depends on MAC80211
++      depends on MMC
++      select FW_LOADER
++      ---help---
++        Driver for Marvell Libertas 8xxx micro AP.
++
+ config AIRO
+       tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
+       depends on ISA_DMA_API && (PCI || BROKEN)
+diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
+index 67156ef..475a1b3 100644
+--- a/drivers/net/wireless/Makefile
++++ b/drivers/net/wireless/Makefile
+@@ -37,6 +37,8 @@ obj-$(CONFIG_LIBERTAS)               += libertas/
+ obj-$(CONFIG_LIBERTAS_THINFIRM)       += libertas_tf/
++obj-$(CONFIG_LIBERTAS_UAP)    += libertas_uap/
++
+ obj-$(CONFIG_ADM8211) += adm8211.o
+ obj-$(CONFIG_MWL8K)   += mwl8k.o
+diff --git a/drivers/net/wireless/libertas_uap/Makefile b/drivers/net/wireless/libertas_uap/Makefile
+new file mode 100644
+index 0000000..821f2a4
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/Makefile
+@@ -0,0 +1,6 @@
++obj-$(CONFIG_LIBERTAS_UAP) += uap8xxx.o
++
++uap8xxx-y += uap_main.o uap_sdio_mmc.o
++uap8xxx-$(CONFIG_PROC_FS) += uap_proc.o uap_debug.o
++
++EXTRA_CFLAGS += -DFPNUM='"52"' -DPXA3XX_DMA_ALIGN -DDEBUG_LEVEL1
+diff --git a/drivers/net/wireless/libertas_uap/uap_debug.c b/drivers/net/wireless/libertas_uap/uap_debug.c
+new file mode 100644
+index 0000000..a2f6dc9
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_debug.c
+@@ -0,0 +1,260 @@
++/** @file uap_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 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.
++  *
++  */
++#ifdef CONFIG_PROC_FS
++#include  "uap_headers.h"
++
++/********************************************************
++              Local Variables
++********************************************************/
++
++#define item_size(n) (sizeof ((uap_adapter *)0)->n)
++#define item_addr(n) ((u32) &((uap_adapter *)0)->n)
++
++#define item_dbg_size(n) (sizeof (((uap_adapter *)0)->dbg.n))
++#define item_dbg_addr(n) ((u32) &(((uap_adapter *)0)->dbg.n))
++
++#define item_dev_size(n) (sizeof ((uap_dev_t *)0)->n)
++#define item_dev_addr(n) ((u32) &((uap_dev_t *)0)->n)
++
++/** MicroAp device offset */
++#define OFFSET_UAP_DEV                0x01
++/** Bluetooth adapter offset */
++#define OFFSET_UAP_ADAPTER    0x02
++
++struct debug_data
++{
++    /** Name */
++    char name[32];
++    /** Size */
++    u32 size;
++    /** Address */
++    u32 addr;
++    /** Offset */
++    u32 offset;
++    /** Flag */
++    u32 flag;
++};
++
++/* To debug any member of uap_adapter, simply add one line here.
++ */
++static struct debug_data items[] = {
++    {"cmd_sent", item_dev_size(cmd_sent), 0, item_dev_addr(cmd_sent),
++     OFFSET_UAP_DEV},
++    {"data_sent", item_dev_size(data_sent), 0, item_dev_addr(data_sent),
++     OFFSET_UAP_DEV},
++    {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter),
++     OFFSET_UAP_ADAPTER},
++    {"cmd_pending", item_size(cmd_pending), 0, item_addr(cmd_pending),
++     OFFSET_UAP_ADAPTER},
++    {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
++     item_dbg_addr(num_cmd_host_to_card_failure), OFFSET_UAP_ADAPTER},
++    {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
++     item_dbg_addr(num_tx_host_to_card_failure), OFFSET_UAP_ADAPTER},
++    {"psmode", item_size(psmode), 0, item_addr(psmode), OFFSET_UAP_ADAPTER},
++    {"ps_state", item_size(ps_state), 0, item_addr(ps_state),
++     OFFSET_UAP_ADAPTER},
++#ifdef DEBUG_LEVEL1
++    {"drvdbg", sizeof(drvdbg), (u32) & drvdbg, 0, 0}
++#endif
++};
++
++static int num_of_items = sizeof(items) / sizeof(items[0]);
++
++/********************************************************
++              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    data to output
++ *  @return      number of output data
++ */
++static int uap_debug_proc_show(struct seq_file *s, void *data) {
++    int val = 0;
++    int i;
++
++    struct debug_data *d = (struct debug_data *)s->private;
++
++    if (MODULE_GET == 0)
++        return UAP_STATUS_FAILURE;
++
++    for (i = 0; i < num_of_items; i++) {
++        if (d[i].size == 1)
++            val = *((u8 *) d[i].addr);
++        else if (d[i].size == 2)
++            val = *((u16 *) d[i].addr);
++        else if (d[i].size == 4)
++            val = *((u32 *) d[i].addr);
++
++        seq_printf(s, "%s=%d\n", d[i].name, val);
++    }
++    MODULE_PUT;
++    return 0;
++}
++
++static int uap_debug_proc_open(struct inode* inode, struct file* file) {
++      return single_open(file, uap_debug_proc_show, PDE_DATA(inode));
++}
++
++/**
++ *  @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 ssize_t uap_debug_proc_write(struct file *f, const char __user *buf, size_t cnt, loff_t *data) {
++    int r, i;
++    char *pdata;
++    char *p;
++    char *p0;
++    char *p1;
++    char *p2;
++    struct debug_data *d = (struct debug_data *)PDE_DATA(file_inode(f));
++
++    if (MODULE_GET == 0)
++        return UAP_STATUS_FAILURE;
++
++    pdata = (char *) kmalloc(cnt, GFP_KERNEL);
++    if (pdata == NULL) {
++        MODULE_PUT;
++        return 0;
++    }
++
++    if (copy_from_user(pdata, buf, cnt)) {
++        PRINTM(INFO, "Copy from user failed\n");
++        kfree(pdata);
++        MODULE_PUT;
++        return 0;
++    }
++
++    p0 = pdata;
++    for (i = 0; i < 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 = string_to_number(p2);
++            if (d[i].size == 1)
++                *((u8 *) d[i].addr) = (u8) r;
++            else if (d[i].size == 2)
++                *((u16 *) d[i].addr) = (u16) r;
++            else if (d[i].size == 4)
++                *((u32 *) d[i].addr) = (u32) r;
++            break;
++        } while (TRUE);
++    }
++    kfree(pdata);
++#ifdef DEBUG_LEVEL1
++    printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
++    printk(KERN_ALERT "INFO  (%08lx) %s\n", DBG_INFO,
++           (drvdbg & DBG_INFO) ? "X" : "");
++    printk(KERN_ALERT "WARN  (%08lx) %s\n", DBG_WARN,
++           (drvdbg & DBG_WARN) ? "X" : "");
++    printk(KERN_ALERT "ENTRY (%08lx) %s\n", DBG_ENTRY,
++           (drvdbg & DBG_ENTRY) ? "X" : "");
++    printk(KERN_ALERT "CMD_D (%08lx) %s\n", DBG_CMD_D,
++           (drvdbg & DBG_CMD_D) ? "X" : "");
++    printk(KERN_ALERT "DAT_D (%08lx) %s\n", DBG_DAT_D,
++           (drvdbg & DBG_DAT_D) ? "X" : "");
++    printk(KERN_ALERT "CMND  (%08lx) %s\n", DBG_CMND,
++           (drvdbg & DBG_CMND) ? "X" : "");
++    printk(KERN_ALERT "DATA  (%08lx) %s\n", DBG_DATA,
++           (drvdbg & DBG_DATA) ? "X" : "");
++    printk(KERN_ALERT "ERROR (%08lx) %s\n", DBG_ERROR,
++           (drvdbg & DBG_ERROR) ? "X" : "");
++    printk(KERN_ALERT "FATAL (%08lx) %s\n", DBG_FATAL,
++           (drvdbg & DBG_FATAL) ? "X" : "");
++    printk(KERN_ALERT "MSG   (%08lx) %s\n", DBG_MSG,
++           (drvdbg & DBG_MSG) ? "X" : "");
++#endif
++    MODULE_PUT;
++    return cnt;
++}
++
++static const struct file_operations uap_debug_proc_fops = {
++      .owner   = THIS_MODULE,
++      .open    = uap_debug_proc_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = single_release,
++      .write   = uap_debug_proc_write,
++};
++
++/********************************************************
++              Global Functions
++********************************************************/
++/**
++ *  @brief create debug proc file
++ *
++ *  @param priv          pointer uap_private
++ *  @param dev     pointer net_device
++ *  @return      N/A
++ */
++void
++uap_debug_entry(uap_private * priv, struct net_device *dev)
++{
++    int i;
++
++    if (priv->proc_entry == NULL)
++        return;
++
++    for (i = 0; i < num_of_items; i++) {
++        if (items[i].flag & OFFSET_UAP_ADAPTER)
++            items[i].addr = items[i].offset + (u32) priv->adapter;
++        if (items[i].flag & OFFSET_UAP_DEV)
++            items[i].addr = items[i].offset + (u32) & priv->uap_dev;
++    }
++    proc_create_data("debug", 0644, priv->proc_entry, &uap_debug_proc_fops,
++      &items[0]);
++}
++
++/**
++ *  @brief remove proc file
++ *
++ *  @param priv          pointer uap_private
++ *  @return      N/A
++ */
++void
++uap_debug_remove(uap_private * priv)
++{
++    remove_proc_entry("debug", priv->proc_entry);
++}
++
++#endif
+diff --git a/drivers/net/wireless/libertas_uap/uap_drv.h b/drivers/net/wireless/libertas_uap/uap_drv.h
+new file mode 100644
+index 0000000..5aa009f
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_drv.h
+@@ -0,0 +1,667 @@
++/** @file uap_drv.h
++  * @brief This file contains Linux OS related definitions and
++  * declarations, uAP 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 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 _UAP_DRV_H
++#define _UAP_DRV_H
++
++/** Driver release version */
++#define DRIVER_VERSION                "26146"
++
++/** True */
++#ifndef       TRUE
++#define TRUE                  1
++#endif
++/** False */
++#ifndef       FALSE
++#define       FALSE                   0
++#endif
++
++/** Bit definitions */
++#ifndef BIT
++#define BIT(x)        (1UL << (x))
++#endif
++
++/** Dma addresses are 32-bits wide.  */
++#ifndef __ATTRIB_ALIGN__
++#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
++#endif
++
++/**  attribute pack */
++#ifndef __ATTRIB_PACK__
++#define __ATTRIB_PACK__ __attribute__ ((packed))
++#endif
++
++/** Debug Macro definition*/
++#ifdef        DEBUG_LEVEL1
++
++extern u32 drvdbg;
++
++/** Debug message control bit definition for drvdbg */
++/** Debug message */
++#define       DBG_MSG         BIT(0)
++/** Debug fatal message */
++#define DBG_FATAL     BIT(1)
++/** Debug error message */
++#define DBG_ERROR     BIT(2)
++/** Debug data message */
++#define DBG_DATA      BIT(3)
++/** Debug command message */
++#define DBG_CMND      BIT(4)
++
++/** Debug data */
++#define DBG_DAT_D     BIT(16)
++/** Debug command */
++#define DBG_CMD_D     BIT(17)
++
++/** Debug entry */
++#define DBG_ENTRY     BIT(28)
++/** Debug warning */
++#define DBG_WARN      BIT(29)
++/** Debug info */
++#define DBG_INFO      BIT(30)
++
++/** Print info */
++#define       PRINTM_INFO(msg...)  {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
++/** Print warn message */
++#define       PRINTM_WARN(msg...)  {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
++/** Print entry */
++#define       PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
++/** Print cmd_d */
++#define       PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
++/** Print data_d */
++#define       PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
++/** Print command */
++#define       PRINTM_CMND(msg...)  {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
++/** Print data */
++#define       PRINTM_DATA(msg...)  {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
++/** Print error message */
++#define       PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
++/** Print fatal message */
++#define       PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
++/** Print message */
++#define       PRINTM_MSG(msg...)   {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
++/** Print level */
++#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(INFO, "ASSERT: %s, %s:%i\n",             \
++                     __FUNCTION__, __FILE__, __LINE__);       \
++} while(0)
++
++/** Log enrty point for debugging */
++#define       ENTER()                 PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
++                                                      __FILE__, __LINE__)
++/** Log exit point for debugging */
++#define       LEAVE()                 PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
++                                                      __FILE__, __LINE__)
++
++#ifdef        DEBUG_LEVEL1
++/** Dump buffer length */
++#define DBG_DUMP_BUF_LEN    64
++/** Maximum dump per line */
++#define MAX_DUMP_PER_LINE   16
++/** Data dump length */
++#define DATA_DUMP_LEN       32
++
++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:\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);
++    }
++}
++
++/** Debug command */
++#define DBG_HEXDUMP_CMD_D(x,y,z)    {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
++/** Debug data */
++#define DBG_HEXDUMP_DAT_D(x,y,z)    {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
++/** Debug hexdump */
++#define       DBG_HEXDUMP(level,x,y,z)    DBG_HEXDUMP_##level(x,y,z)
++/** hexdump */
++#define HEXDUMP(x,y,z)              {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
++#else
++/** Do nothing since debugging is not turned on */
++#define DBG_HEXDUMP(level,x,y,z)    do {} while (0)
++/** Do nothing since debugging is not turned on */
++#define HEXDUMP(x,y,z)              do {} while (0)
++#endif
++
++/**
++ * Typedefs
++ */
++/** Unsigned char */
++typedef u8 BOOLEAN;
++
++/*
++ * OS macro definitions
++ */
++/** OS macro to get time */
++#define os_time_get() jiffies
++
++/** OS macro to update transfer start time */
++#define UpdateTransStart(dev) { \
++      dev->trans_start = jiffies; \
++}
++
++/** Try to get a reference to the module */
++#define MODULE_GET    try_module_get(THIS_MODULE)
++/** Decrease module reference count */
++#define MODULE_PUT    module_put(THIS_MODULE)
++
++/** OS macro to initialize semaphore */
++#define OS_INIT_SEMAPHORE(x)  sema_init(x,1)
++/** OS macro to acquire blocking semaphore */
++#define OS_ACQ_SEMAPHORE_BLOCK(x)     down_interruptible(x)
++/** OS macro to acquire non-blocking semaphore */
++#define OS_ACQ_SEMAPHORE_NOBLOCK(x)   down_trylock(x)
++/** OS macro to release semaphore */
++#define OS_REL_SEMAPHORE(x)           up(x)
++
++static inline void
++os_sched_timeout(u32 millisec)
++{
++    set_current_state(TASK_INTERRUPTIBLE);
++    schedule_timeout((millisec * HZ) / 1000);
++}
++
++/** Maximum size of ethernet packet */
++#define MRVDRV_MAXIMUM_ETH_PACKET_SIZE        1514
++
++/** Maximum size of multicast list */
++#define MRVDRV_MAX_MULTICAST_LIST_SIZE        32
++
++/** 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
++
++/** Find number of elements */
++#ifndef NELEMENTS
++#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
++#endif
++
++/** Buffer Constants */
++
++/** Size of command buffer */
++#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
++
++/** Length of device length */
++#define DEV_NAME_LEN                  32
++
++/** Length of ethernet address */
++#ifndef       ETH_ALEN
++#define ETH_ALEN                      6
++#endif
++
++/** Default watchdog timeout */
++#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (2 * HZ)
++
++/** Success */
++#define UAP_STATUS_SUCCESS         (0)
++/** Failure */
++#define UAP_STATUS_FAILURE         (-1)
++/** Not accepted */
++#define UAP_STATUS_NOT_ACCEPTED    (-2)
++
++/** Max loop count (* 100ms) for waiting device ready at init time */
++#define MAX_WAIT_DEVICE_READY_COUNT   50
++
++/** Tx high watermark. Stop Tx queue after this is crossed */
++#define TX_HIGH_WATERMARK   4
++/** Tx low watermark. Restart Tx queue after this is crossed */
++#define TX_LOW_WATERMARK    2
++
++/** 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
++
++/** 20 seconds */
++#define MRVDRV_TIMER_20S              20000
++
++/** Host Command option for wait till Send */
++#define HostCmd_OPTION_WAITFORSEND            0x0001
++/** Host Command option for wait for RSP */
++#define HostCmd_OPTION_WAITFORRSP             0x0002
++/** Host Command option for wait for RSP or Timeout */
++#define HostCmd_OPTION_WAITFORRSP_TIMEOUT     0x0003
++/** Host Command option for wait for RSP of sleep confirm */
++#define HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM   0x0004
++
++/** 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))
++
++/** Private command ID to Host command */
++#define       UAPHOSTCMD                      (SIOCDEVPRIVATE + 1)
++
++/** Private command ID to Power Mode */
++#define       UAP_POWER_MODE                  (SIOCDEVPRIVATE + 3)
++/** sleep_param */
++typedef struct _ps_sleep_param
++{
++    /** control bitmap */
++    u32 ctrl_bitmap;
++    /** minimum sleep period (micro second) */
++    u32 min_sleep;
++    /** maximum sleep period (micro second) */
++    u32 max_sleep;
++} ps_sleep_param;
++
++/** inactivity sleep_param */
++typedef struct _inact_sleep_param
++{
++    /** inactivity timeout (micro second) */
++    u32 inactivity_to;
++    /** miniumu awake period (micro second) */
++    u32 min_awake;
++    /** maximum awake period (micro second) */
++    u32 max_awake;
++} inact_sleep_param;
++
++/** flag for ps mode */
++#define PS_FLAG_PS_MODE                 1
++/** flag for sleep param */
++#define PS_FLAG_SLEEP_PARAM             2
++/** flag for inactivity sleep param */
++#define PS_FLAG_INACT_SLEEP_PARAM       4
++
++/** Disable power mode */
++#define PS_MODE_DISABLE                      0
++/** Enable periodic dtim ps */
++#define PS_MODE_PERIODIC_DTIM                1
++/** Enable inactivity ps */
++#define PS_MODE_INACTIVITY                   2
++
++/** sleep parameter */
++#define SLEEP_PARAMETER                     1
++/** inactivity sleep parameter */
++#define INACTIVITY_SLEEP_PARAMETER          2
++/** ps_mgmt */
++typedef struct _ps_mgmt
++{
++    /** flags for valid field */
++    u16 flags;
++    /** power mode */
++    u16 ps_mode;
++    /** sleep param */
++    ps_sleep_param sleep_param;
++    /** inactivity sleep param */
++    inact_sleep_param inact_param;
++} ps_mgmt;
++
++/** Semaphore structure */
++typedef struct semaphore SEMAPHORE;
++
++/** Global Varibale Declaration */
++/** Private data structure of the device */
++typedef struct _uap_private uap_private;
++/** Adapter data structure of the device */
++typedef struct _uap_adapter uap_adapter;
++/** private structure */
++extern uap_private *uappriv;
++
++/** ENUM definition*/
++
++/** Hardware status codes */
++typedef enum _HARDWARE_STATUS
++{
++    HWReady,
++    HWInitializing,
++    HWReset,
++    HWClosing,
++    HWNotReady
++} HARDWARE_STATUS;
++
++/** info for debug purpose */
++typedef struct _uap_dbg
++{
++        /** Number of host to card command failures */
++    u32 num_cmd_host_to_card_failure;
++        /** Number of host to card Tx failures */
++    u32 num_tx_host_to_card_failure;
++} uap_dbg;
++
++/** Set thread state */
++#define OS_SET_THREAD_STATE(x)                set_current_state(x)
++
++typedef struct
++{
++    /** Task */
++    struct task_struct *task;
++    /** Queue */
++    wait_queue_head_t waitQ;
++    /** PID */
++    pid_t pid;
++    /** Private structure */
++    void *priv;
++} uap_thread;
++
++static inline void
++uap_activate_thread(uap_thread * thr)
++{
++        /** Record the thread pid */
++    thr->pid = current->pid;
++
++        /** Initialize the wait queue */
++    init_waitqueue_head(&thr->waitQ);
++}
++
++static inline void
++uap_deactivate_thread(uap_thread * thr)
++{
++    thr->pid = 0;
++    return;
++}
++
++static inline void
++uap_create_thread(int (*uapfunc) (void *), uap_thread * thr, char *name)
++{
++    thr->task = kthread_run(uapfunc, thr, "%s", name);
++}
++
++static inline int
++uap_terminate_thread(uap_thread * thr)
++{
++    /* Check if the thread is active or not */
++    if (!thr->pid)
++        return -1;
++    kthread_stop(thr->task);
++    return 0;
++}
++
++/** Data structure for the Marvell uAP device */
++typedef struct _uap_dev
++{
++        /** device name */
++    char name[DEV_NAME_LEN];
++        /** card pointer */
++    void *card;
++        /** IO port */
++    u32 ioport;
++        /** Rx unit */
++    u8 rx_unit;
++        /** Data sent:
++          TRUE - Data is sent to fw, no Tx Done received
++          FALSE - Tx done received for previous Tx */
++    BOOLEAN data_sent;
++        /** CMD sent:
++          TRUE - CMD is sent to fw, no CMD Done received
++          FALSE - CMD done received for previous CMD */
++    BOOLEAN cmd_sent;
++        /** netdev pointer */
++    struct net_device *netdev;
++} uap_dev_t, *puap_dev_t;
++
++/** Private structure for the MV device */
++struct _uap_private
++{
++        /** Device open */
++    int open;
++
++        /** Device adapter structure */
++    uap_adapter *adapter;
++        /** Device structure */
++    uap_dev_t uap_dev;
++
++        /** Net device statistics structure */
++    struct net_device_stats stats;
++
++        /** Number of Tx timeouts */
++    u32 num_tx_timeout;
++
++        /** Media connection status */
++    BOOLEAN MediaConnected;
++
++#ifdef CONFIG_PROC_FS
++    struct proc_dir_entry *proc_uap;
++    struct proc_dir_entry *proc_entry;
++#endif                          /* CONFIG_PROC_FS */
++
++        /** Firmware helper */
++    const struct firmware *fw_helper;
++        /** Firmware */
++    const struct firmware *firmware;
++        /** Hotplug device */
++    struct device *hotplug_device;
++        /** thread to service interrupts */
++    uap_thread MainThread;
++        /** Driver lock */
++    spinlock_t driver_lock;
++        /** Driver lock flags */
++    ulong driver_flags;
++
++};
++
++/** PS_CMD_ConfirmSleep */
++typedef struct _PS_CMD_ConfirmSleep
++{
++        /** SDIO Length */
++    u16 SDLen;
++    /** SDIO Type */
++    u16 SDType;
++        /** Command */
++    u16 Command;
++        /** Size */
++    u16 Size;
++        /** Sequence number */
++    u16 SeqNum;
++        /** Result */
++    u16 Result;
++} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
++
++/** Wlan Adapter data structure*/
++struct _uap_adapter
++{
++        /** Power save confirm sleep command */
++    PS_CMD_ConfirmSleep PSConfirmSleep;
++        /** Device status */
++    HARDWARE_STATUS HardwareStatus;
++        /** Interrupt counter */
++    u32 IntCounter;
++        /** Tx packet queue */
++    struct sk_buff_head tx_queue;
++        /** Cmd packet queue */
++    struct sk_buff_head cmd_queue;
++        /** Command sequence number */
++    u16 SeqNum;
++        /** Command buffer */
++    u8 *CmdBuf;
++        /** cmd pending flag */
++    u8 cmd_pending;
++        /** cmd wait option */
++    u8 cmd_wait_option;
++        /** Command buffer length */
++    u32 CmdSize;
++        /** Command wait queue */
++    wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
++        /** Command wait queue state flag */
++    u8 CmdWaitQWoken;
++        /** PnP support */
++    BOOLEAN SurpriseRemoved;
++        /** Debug */
++    uap_dbg dbg;
++        /** Netlink kernel socket */
++    struct sock *nl_sk;
++        /** Semaphore for CMD */
++    SEMAPHORE CmdSem;
++         /** Power Save mode */
++    u8 psmode;
++        /** Power Save state */
++    u8 ps_state;
++        /** Number of wakeup tries */
++    u32 WakeupTries;
++};
++
++static inline int
++os_upload_rx_packet(uap_private * priv, struct sk_buff *skb)
++{
++    skb->dev = priv->uap_dev.netdev;
++    skb->protocol = eth_type_trans(skb, priv->uap_dev.netdev);
++    skb->ip_summed = CHECKSUM_UNNECESSARY;
++    if (in_interrupt())
++        netif_rx(skb);
++    else
++        netif_rx_ni(skb);
++    return 0;
++}
++
++/*
++ *  netif carrier_on/off and start(wake)/stop_queue handling
++ */
++static inline void
++os_carrier_on(uap_private * priv)
++{
++    if (!netif_carrier_ok(priv->uap_dev.netdev) &&
++        (priv->MediaConnected == TRUE)) {
++        netif_carrier_on(priv->uap_dev.netdev);
++    }
++}
++
++static inline void
++os_carrier_off(uap_private * priv)
++{
++    if (netif_carrier_ok(priv->uap_dev.netdev)) {
++        netif_carrier_off(priv->uap_dev.netdev);
++    }
++}
++
++static inline void
++os_start_queue(uap_private * priv)
++{
++    if (netif_queue_stopped(priv->uap_dev.netdev) &&
++        (priv->MediaConnected == TRUE)) {
++        netif_wake_queue(priv->uap_dev.netdev);
++    }
++}
++
++static inline void
++os_stop_queue(uap_private * priv)
++{
++    if (!netif_queue_stopped(priv->uap_dev.netdev)) {
++        netif_stop_queue(priv->uap_dev.netdev);
++    }
++}
++
++/** Interface specific header */
++#define INTF_HEADER_LEN         4
++
++/** headroom alignment for tx packet */
++#define HEADER_ALIGNMENT      8
++
++/** The number of times to try when polling for status bits */
++#define MAX_POLL_TRIES                        100
++
++/** Length of SNAP header */
++#define MRVDRV_SNAP_HEADER_LEN          8
++
++/** Extra length of Tx packet buffer */
++#define EXTRA_LEN     36
++
++/** Buffer size for ethernet Tx packets */
++#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
++      (ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
++
++/** Buffer size for ethernet Rx packets */
++#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
++      (ETH_FRAME_LEN + sizeof(RxPD) \
++       + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
++
++/** Packet type: data, command & event */
++typedef enum _mv_type
++{
++    MV_TYPE_DAT = 0,
++    MV_TYPE_CMD = 1,
++    MV_TYPE_EVENT = 3
++} mv_type;
++
++/** 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)
++
++int uap_process_rx_packet(uap_private * priv, struct sk_buff *skb);
++void uap_interrupt(uap_private * priv);
++uap_private *uap_add_card(void *card);
++int uap_remove_card(void *card);
++int uap_process_event(uap_private * priv, u8 * payload, uint len);
++int uap_soft_reset(uap_private * priv);
++int uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len);
++
++#ifdef CONFIG_PROC_FS
++/** The proc fs interface */
++void uap_proc_entry(uap_private * priv, struct net_device *dev);
++void uap_proc_remove(uap_private * priv);
++int string_to_number(char *s);
++void uap_debug_entry(uap_private * priv, struct net_device *dev);
++void uap_debug_remove(uap_private * priv);
++#endif /* CONFIG_PROC_FS */
++
++int sbi_register(void);
++
++void sbi_unregister(void);
++int sbi_register_dev(uap_private * priv);
++int sbi_unregister_dev(uap_private * priv);
++int sbi_prog_fw_w_helper(uap_private *);
++
++int sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb);
++int sbi_enable_host_int(uap_private * priv);
++int sbi_disable_host_int(uap_private * priv);
++
++int sbi_get_int_status(uap_private * priv, u8 * ireg);
++/** Check firmware status */
++int sbi_check_fw_status(uap_private *, int);
++int sbi_prog_helper(uap_private *);
++
++int sbi_wakeup_firmware(uap_private * priv);
++
++#endif /* _UAP_DRV_H */
+diff --git a/drivers/net/wireless/libertas_uap/uap_fw.h b/drivers/net/wireless/libertas_uap/uap_fw.h
+new file mode 100644
+index 0000000..23a40d6
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_fw.h
+@@ -0,0 +1,359 @@
++/** @file uap_fw.h
++ *
++ * @brief This file contains firmware specific defines.
++ *
++ * 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 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.
++ *
++ */
++/********************************************************
++Change log:
++      02/26/08: Initial creation
++********************************************************/
++
++#ifndef _UAP_FW_H
++#define _UAP_FW_H
++
++/** uap upload size */
++#define       UAP_UPLD_SIZE                   2312
++/** Packet type Micro AP */
++#define PKT_TYPE_MICROAP              1
++/** Packet type client */
++#define PKT_TYPE_CLIENT                       0
++
++/** TxPD descriptor */
++typedef struct _TxPD
++{
++        /** Bss Type */
++    u8 BssType;
++        /** Bss num */
++    u8 BssNum;
++        /** Tx packet length */
++    u16 TxPktLength;
++        /** Tx packet offset */
++    u16 TxPktOffset;
++        /** Tx packet type */
++    u16 TxPktType;
++        /** Tx Control */
++    u32 TxControl;
++        /** reserved */
++    u32 reserved[2];
++} __ATTRIB_PACK__ TxPD, *PTxPD;
++
++/** RxPD Descriptor */
++typedef struct _RxPD
++{
++        /** Bss Type */
++    u8 BssType;
++        /** Bss Num */
++    u8 BssNum;
++        /** Tx packet length */
++    u16 RxPktLength;
++        /** Tx packet offset */
++    u16 RxPktOffset;
++} __ATTRIB_PACK__ RxPD, *PRxPD;
++
++#ifdef BIG_ENDIAN
++/** Convert from 16 bit little endian format to CPU format */
++#define uap_le16_to_cpu(x) le16_to_cpu(x)
++/** Convert from 32 bit little endian format to CPU format */
++#define uap_le32_to_cpu(x) le32_to_cpu(x)
++/** Convert from 64 bit little endian format to CPU format */
++#define uap_le64_to_cpu(x) le64_to_cpu(x)
++/** Convert to 16 bit little endian format from CPU format */
++#define uap_cpu_to_le16(x) cpu_to_le16(x)
++/** Convert to 32 bit little endian format from CPU format */
++#define uap_cpu_to_le32(x) cpu_to_le32(x)
++/** Convert to 64 bit little endian format from CPU format */
++#define uap_cpu_to_le64(x) cpu_to_le64(x)
++
++/** Convert TxPD to little endian format from CPU format */
++#define endian_convert_TxPD(x);                                         \
++    {                                                                   \
++        (x)->TxPktLength = uap_cpu_to_le16((x)->TxPktLength);         \
++        (x)->TxPktOffset = uap_cpu_to_le32((x)->TxPktOffset);         \
++        (x)->TxControl = uap_cpu_to_le32((x)->TxControl);              \
++        (x)->TxPktType = uap_cpu_to_le32((x)->TxPktType);             \
++    }
++
++/** Convert RxPD from little endian format to CPU format */
++#define endian_convert_RxPD(x);                                       \
++    {                                                                 \
++        (x)->RxPktLength = uap_le16_to_cpu((x)->RxPktLength);         \
++        (x)->RxPktOffset = uap_le32_to_cpu((x)->RxPktOffset);         \
++    }
++#else /* BIG_ENDIAN */
++/** Do nothing */
++#define uap_le16_to_cpu(x) x
++/** Do nothing */
++#define uap_le32_to_cpu(x) x
++/** Do nothing */
++#define uap_le64_to_cpu(x) x
++/** Do nothing */
++#define uap_cpu_to_le16(x) x
++/** Do nothing */
++#define uap_cpu_to_le32(x) x
++/** Do nothing */
++#define uap_cpu_to_le64(x) x
++
++/** Do nothing */
++#define endian_convert_TxPD(x)
++/** Do nothing */
++#define endian_convert_RxPD(x)
++#endif /* BIG_ENDIAN */
++
++/** 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: SYS_INFO  */
++#define HOST_CMD_APCMD_SYS_INFO               0x00ae
++/** Host Command id: SYS_RESET  */
++#define HOST_CMD_APCMD_SYS_RESET              0x00af
++/** Host Command id: SYS_CONFIGURE  */
++#define HOST_CMD_APCMD_SYS_CONFIGURE          0x00b0
++/** Host Command id: BSS_START  */
++#define HOST_CMD_APCMD_BSS_START              0x00b1
++/** Host Command id: SYS_STOP  */
++#define HOST_CMD_APCMD_BSS_STOP               0x00b2
++/** Host Command id: STA_LIST  */
++#define HOST_CMD_APCMD_STA_LIST               0x00b3
++/** Host Command id: STA_FILTER_TABLE  */
++#define HOST_CMD_APCMD_STA_FILTER_TABLE       0x00b4
++/** Host Command id: STA_DEAUTH  */
++#define HOST_CMD_APCMD_STA_DEAUTH             0x00b5
++/** Host Command id: SOFT_RESET  */
++#define HOST_CMD_APCMD_SOFT_RESET             0x00d5
++/** Host Command id: POWER_MGMT_EXT  */
++#define HOST_CMD_POWER_MGMT_EXT               0x00ef
++/** Host Command id: SLEEP_CONFIRM*/
++#define HOST_CMD_SLEEP_CONFIRM              0x00d8
++
++/** TLV type : SSID */
++#define TLV_TYPE_SSID                         0x0000
++/** TLV type : Rates */
++#define TLV_TYPE_RATES                                0x0001
++/** TLV type : PHY DS */
++#define TLV_TYPE_PHY_DS                               0x0003
++
++/** TLV Id : Base id */
++#define PROPRIETARY_TLV_BASE_ID               0x0100
++/** TLV Id : AP_MAC_ADDRESS */
++#define MRVL_AP_MAC_ADDRESS_TLV_ID      (PROPRIETARY_TLV_BASE_ID + 43)
++/** TLV Id : Beacon period */
++#define MRVL_BEACON_PERIOD_TLV_ID       (PROPRIETARY_TLV_BASE_ID + 44)
++/** TLV Id : Dtim period */
++#define MRVL_DTIM_PERIOD_TLV_ID         (PROPRIETARY_TLV_BASE_ID + 45)
++/** TLV Id : Basic rates */
++#define MRVL_BASIC_RATES_TLV_ID         (PROPRIETARY_TLV_BASE_ID + 46)
++/** TLV Id : Tx Power */
++#define MRVL_TX_POWER_TLV_ID            (PROPRIETARY_TLV_BASE_ID + 47)
++/** TLV Id : Broadcast SSID control */
++#define MRVL_BCAST_SSID_CTL_TLV_ID      (PROPRIETARY_TLV_BASE_ID + 48)
++/** TLV Id : Preamble control */
++#define MRVL_PREAMBLE_CTL_TLV_ID        (PROPRIETARY_TLV_BASE_ID + 49)
++/** TLV Id : Antenna control */
++#define MRVL_ANTENNA_CTL_TLV_ID         (PROPRIETARY_TLV_BASE_ID + 50)
++/** TLV Id : RTS threshold */
++#define MRVL_RTS_THRESHOLD_TLV_ID       (PROPRIETARY_TLV_BASE_ID + 51)
++/** TLV Id : Radio control */
++#define MRVL_RADIO_CTL_TLV_ID           (PROPRIETARY_TLV_BASE_ID + 52)
++/** TLV Id : TX data rate */
++#define MRVL_TX_DATA_RATE_TLV_ID        (PROPRIETARY_TLV_BASE_ID + 53)
++/** TLV Id : Packet forward control */
++#define MRVL_PKT_FWD_CTL_TLV_ID         (PROPRIETARY_TLV_BASE_ID + 54)
++/** TLV Id : STA info */
++#define MRVL_STA_INFO_TLV_ID            (PROPRIETARY_TLV_BASE_ID + 55)
++/** TLV Id : STA MAC address filter */
++#define MRVL_STA_MAC_ADDR_FILTER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 56)
++/** TLV Id : STA ageout timer */
++#define MRVL_STA_AGEOUT_TIMER_TLV_ID    (PROPRIETARY_TLV_BASE_ID + 57)
++/** TLV Id : Security config */
++#define MRVL_SECURITY_CFG_TLV_ID        (PROPRIETARY_TLV_BASE_ID + 58)
++/** TLV Id : WEP KEY */
++#define MRVL_WEP_KEY_TLV_ID             (PROPRIETARY_TLV_BASE_ID + 59)
++/** TLV Id : WPA Passphrase */
++#define MRVL_WPA_PASSPHRASE_TLV_ID      (PROPRIETARY_TLV_BASE_ID + 60)
++
++/** Action get */
++#define ACTION_GET    0
++/** Action set */
++#define ACTION_SET    1
++/** Length of ethernet address */
++#ifndef       ETH_ALEN
++#define ETH_ALEN                      6
++#endif
++
++/** HostCmd_DS_GEN */
++typedef struct
++{
++    /** Command */
++    u16 Command;
++    /** Size */
++    u16 Size;
++    /** Sequence number */
++    u16 SeqNum;
++    /** Result */
++    u16 Result;
++} __ATTRIB_PACK__ HostCmd_DS_GEN;
++
++/** Size of HostCmd_DS_GEN */
++#define S_DS_GEN    sizeof(HostCmd_DS_GEN)
++
++/** _HostCmd_HEADER*/
++typedef struct
++{
++    /** Command Header : Command */
++    u16 Command;
++    /** Command Header : Size */
++    u16 Size;
++} __ATTRIB_PACK__ HostCmd_HEADER;
++
++/** HostCmd_SYS_CONFIG */
++typedef struct _HostCmd_SYS_CONFIG
++{
++        /** CMD Action GET/SET*/
++    u16 Action;
++        /** Tlv buffer */
++    u8 TlvBuffer[0];
++} __ATTRIB_PACK__ HostCmd_SYS_CONFIG;
++
++/** HostCmd_DS_POWER_MGMT_EXT */
++typedef struct _HostCmd_DS_POWER_MGMT_EXT
++{
++    /** CMD Action Get/Set*/
++    u16 action;
++    /** power mode */
++    u16 power_mode;
++} __ATTRIB_PACK__ HostCmd_DS_POWER_MGMT_EXT;
++
++/** _HostCmd_DS_COMMAND*/
++typedef struct _HostCmd_DS_COMMAND
++{
++
++        /** Command Header : Command */
++    u16 Command;
++        /** Command Header : Size */
++    u16 Size;
++        /** Command Header : Sequence number */
++    u16 SeqNum;
++        /** Command Header : Result */
++    u16 Result;
++        /** Command Body */
++    union
++    {
++        HostCmd_SYS_CONFIG sys_config;
++        HostCmd_DS_POWER_MGMT_EXT pm_cfg;
++
++    } params;
++} __ATTRIB_PACK__ HostCmd_DS_COMMAND;
++
++/** MrvlIEtypesHeader_*/
++typedef struct _MrvlIEtypesHeader
++{
++    /** Header type */
++    u16 Type;
++    /** Header length */
++    u16 Len;
++} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
++
++/** MrvlIEtypes_Data_t */
++typedef struct _MrvlIEtypes_Data_t
++{
++    /** Header */
++    MrvlIEtypesHeader_t Header;
++    /** Data */
++    u8 Data[1];
++} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
++
++/** MrvlIEtypes_ChanListParamSet_t */
++typedef struct _MrvlIEtypes_MacAddr_t
++{
++    /** Header */
++    MrvlIEtypesHeader_t Header;
++    /** AP MAC address */
++    u8 ApMacAddr[ETH_ALEN];
++} __ATTRIB_PACK__ MrvlIEtypes_MacAddr_t;
++
++/** Event ID: BSS started */
++#define MICRO_AP_EV_ID_BSS_START    46
++
++/** Event ID: BSS idle event */
++#define MICRO_AP_EV_BSS_IDLE       67
++
++/** Event ID: BSS active event */
++#define MICRO_AP_EV_BSS_ACTIVE             68
++
++/** Event ID: PS_AWAKE */
++#define EVENT_PS_AWAKE     0x0a
++
++/** Event ID: PS_SLEEP */
++#define EVENT_PS_SLEEP     0x0b
++
++/** PS_STATE */
++typedef enum _PS_STATE
++{
++    PS_STATE_AWAKE,
++    PS_STATE_PRE_SLEEP,
++    PS_STATE_SLEEP
++} PS_STATE;
++
++/** TLV type: AP Sleep param */
++#define TLV_TYPE_AP_SLEEP_PARAM         (PROPRIETARY_TLV_BASE_ID + 106)
++/** TLV type: AP Inactivity Sleep param */
++#define TLV_TYPE_AP_INACT_SLEEP_PARAM   (PROPRIETARY_TLV_BASE_ID + 107)
++
++/** MrvlIEtypes_sleep_param_t */
++typedef struct _MrvlIEtypes_sleep_param_t
++{
++    /** Header */
++    MrvlIEtypesHeader_t header;
++    /** control bitmap */
++    u32 ctrl_bitmap;
++    /** min_sleep */
++    u32 min_sleep;
++    /** max_sleep */
++    u32 max_sleep;
++} __ATTRIB_PACK__ MrvlIEtypes_sleep_param_t;
++
++/** MrvlIEtypes_inact_sleep_param_t */
++typedef struct _MrvlIEtypes_inact_sleep_param_t
++{
++    /** Header */
++    MrvlIEtypesHeader_t header;
++    /** inactivity timeout */
++    u32 inactivity_to;
++    /** min_awake */
++    u32 min_awake;
++    /** max_awake */
++    u32 max_awake;
++} __ATTRIB_PACK__ MrvlIEtypes_inact_sleep_param_t;
++
++/** AP_Event */
++typedef struct _AP_Event
++{
++    /** Event ID */
++    u32 EventId;
++    /*
++     * Reserved for STA_ASSOCIATED event and contains
++     * status information for the MIC_COUNTERMEASURES event.
++     */
++    /** Reserved/status */
++    u16 status;
++    /** AP MAC address */
++    u8 MacAddr[ETH_ALEN];
++} __ATTRIB_PACK__ AP_Event;
++#endif /* _UAP_FW_H */
+diff --git a/drivers/net/wireless/libertas_uap/uap_headers.h b/drivers/net/wireless/libertas_uap/uap_headers.h
+new file mode 100644
+index 0000000..fa09af4
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_headers.h
+@@ -0,0 +1,64 @@
++/** @file uap_headers.h
++ *
++ * @brief This file contains all the necessary include 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 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 _UAP_HEADERS_H
++#define _UAP_HEADERS_H
++
++/* 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/types.h>
++#include    <linux/interrupt.h>
++#include    <linux/proc_fs.h>
++#include    <linux/kthread.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
++#include    <linux/semaphore.h>
++#else
++#include    <asm/semaphore.h>
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++#include    <linux/config.h>
++#endif
++
++/* Net header files */
++#include    <linux/netdevice.h>
++#include    <linux/net.h>
++#include    <linux/skbuff.h>
++#include    <linux/if_ether.h>
++#include    <linux/etherdevice.h>
++#include    <net/sock.h>
++#include    <linux/netlink.h>
++#include    <linux/firmware.h>
++#include    <linux/delay.h>
++
++#include    "uap_drv.h"
++#include    "uap_fw.h"
++
++#include <linux/mmc/sdio.h>
++#include <linux/mmc/sdio_ids.h>
++#include <linux/mmc/sdio_func.h>
++#include <linux/mmc/card.h>
++#include "uap_sdio_mmc.h"
++
++#endif /* _UAP_HEADERS_H */
+diff --git a/drivers/net/wireless/libertas_uap/uap_main.c b/drivers/net/wireless/libertas_uap/uap_main.c
+new file mode 100644
+index 0000000..6ad8403
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_main.c
+@@ -0,0 +1,1817 @@
++/** @file uap_main.c
++  * @brief This file contains the major functions in uAP
++  * driver. It includes init, exit etc..
++  * This file also contains the initialization for SW,
++  * FW and HW
++  *
++  * 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 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 uAP Linux Driver
++  *
++  * @section overview_sec Overview
++  *
++  * This is Linux reference driver for Marvell uAP.
++  *
++  * @section copyright_sec Copyright
++  *
++  * Copyright (C) 2008, Marvell International Ltd.
++  *
++  */
++
++#include      "uap_headers.h"
++
++/**
++ * the global variable of a pointer to uap_private
++ * structure variable
++ */
++uap_private *uappriv = NULL;
++#ifdef DEBUG_LEVEL1
++#define DEFAULT_DEBUG_MASK    (DBG_MSG | DBG_FATAL | DBG_ERROR)
++u32 drvdbg = DEFAULT_DEBUG_MASK;
++#endif
++/** Helper name */
++char *helper_name = NULL;
++/** Firmware name */
++char *fw_name = NULL;
++
++/** Semaphore for add/remove card */
++SEMAPHORE AddRemoveCardSem;
++
++/********************************************************
++              Local Functions
++********************************************************/
++/**
++ *  @brief This function send sleep confirm command to firmware
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
++ */
++static int
++uap_dnld_sleep_confirm_cmd(uap_private * priv)
++{
++    uap_adapter *Adapter = priv->adapter;
++    int ret = UAP_STATUS_SUCCESS;
++    ENTER();
++    PRINTM(CMND, "Sleep confirm\n");
++    Adapter->cmd_pending = TRUE;
++    Adapter->cmd_wait_option = HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM;
++    ret =
++        sbi_host_to_card(priv, (u8 *) & Adapter->PSConfirmSleep,
++                         sizeof(PS_CMD_ConfirmSleep));
++    if (ret != UAP_STATUS_SUCCESS) {
++        Adapter->ps_state = PS_STATE_AWAKE;
++        Adapter->cmd_pending = FALSE;
++        Adapter->cmd_wait_option = FALSE;
++    }
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function process sleep confirm resp from firmware
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @param resp       A pointer to resp buf
++ *  @param resp_len   resp buf len
++ *  @return      UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
++ */
++int
++uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    HostCmd_DS_COMMAND *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    ENTER();
++    PRINTM(CMND, "Sleep confirm resp\n");
++    if (!resp_len) {
++        PRINTM(ERROR, "Cmd Size is 0\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    cmd = (HostCmd_DS_COMMAND *) resp;
++    cmd->Result = uap_le16_to_cpu(cmd->Result);
++    if (cmd->Result != UAP_STATUS_SUCCESS) {
++        PRINTM(ERROR, "HOST_CMD_APCMD_PS_SLEEP_CONFIRM fail=%x\n", cmd->Result);
++        ret = -EFAULT;
++    }
++  done:
++    if (ret == UAP_STATUS_SUCCESS)
++        Adapter->ps_state = PS_STATE_SLEEP;
++    else
++        Adapter->ps_state = PS_STATE_AWAKE;
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function checks condition and prepares to
++ *  send sleep confirm command to firmware if OK.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @return           n/a
++ */
++static void
++uap_ps_cond_check(uap_private * priv)
++{
++    uap_adapter *Adapter = priv->adapter;
++
++    ENTER();
++    if (!priv->uap_dev.cmd_sent &&
++        !Adapter->cmd_pending && !Adapter->IntCounter) {
++        uap_dnld_sleep_confirm_cmd(priv);
++    } else {
++        PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
++               (priv->uap_dev.cmd_sent) ? "D" : "",
++               (Adapter->cmd_pending) ? "C" : "",
++               (Adapter->IntCounter) ? "I" : "");
++    }
++    LEAVE();
++}
++
++/**
++ *  @brief This function add cmd to cmdQ and waiting for response
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param skb           A pointer to the skb for process
++ *  @param wait_option Wait option
++ *  @return      UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
++ */
++static int
++uap_process_cmd(uap_private * priv, struct sk_buff *skb, u8 wait_option)
++{
++    uap_adapter *Adapter = priv->adapter;
++    int ret = UAP_STATUS_SUCCESS;
++    HostCmd_DS_COMMAND *cmd;
++    u8 *headptr;
++    ENTER();
++    if (Adapter->HardwareStatus != HWReady) {
++        PRINTM(ERROR, "Hw not ready, uap_process_cmd\n");
++        kfree(skb);
++        LEAVE();
++        return -EFAULT;
++    }
++    skb->cb[0] = wait_option;
++    headptr = skb->data;
++    *(u16 *) & headptr[0] = uap_cpu_to_le16(skb->len);
++    *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_CMD);
++    cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
++    Adapter->SeqNum++;
++    cmd->SeqNum = uap_cpu_to_le16(Adapter->SeqNum);
++    PRINTM(CMND, "process_cmd: %x\n", cmd->Command);
++    DBG_HEXDUMP(CMD_D, "process_cmd", (u8 *) cmd, cmd->Size);
++    if (!wait_option) {
++        skb_queue_tail(&priv->adapter->cmd_queue, skb);
++        wake_up_interruptible(&priv->MainThread.waitQ);
++        LEAVE();
++        return ret;
++    }
++    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->CmdSem)) {
++        PRINTM(ERROR, "Acquire semaphore error, uap_prepare_cmd\n");
++        kfree(skb);
++        LEAVE();
++        return -EBUSY;
++    }
++    skb_queue_tail(&priv->adapter->cmd_queue, skb);
++    Adapter->CmdWaitQWoken = FALSE;
++    wake_up_interruptible(&priv->MainThread.waitQ);
++    /* Sleep until response is generated by FW */
++    if (wait_option == HostCmd_OPTION_WAITFORRSP_TIMEOUT) {
++        if (!os_wait_interruptible_timeout
++            (Adapter->cmdwait_q, Adapter->CmdWaitQWoken, MRVDRV_TIMER_20S)) {
++            PRINTM(ERROR, "Cmd timeout\n");
++            Adapter->cmd_pending = FALSE;
++            ret = -EFAULT;
++        }
++    } else
++        wait_event_interruptible(Adapter->cmdwait_q, Adapter->CmdWaitQWoken);
++    OS_REL_SEMAPHORE(&Adapter->CmdSem);
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief Inspect the response buffer for pointers to expected TLVs
++ *
++ *
++ *  @param pTlv        Pointer to the start of the TLV buffer to parse
++ *  @param tlvBufSize  Size of the TLV buffer
++ *  @param reqTlvType  request tlv's tlvtype
++ *  @param ppTlv       Output parameter: Pointer to the request TLV if found
++ *
++ *  @return            void
++ */
++static void
++uap_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv, int tlvBufSize,
++                 u16 reqTlvType, MrvlIEtypes_Data_t ** ppTlv)
++{
++    MrvlIEtypes_Data_t *pCurrentTlv;
++    int tlvBufLeft;
++    u16 tlvType;
++    u16 tlvLen;
++
++    ENTER();
++    pCurrentTlv = pTlv;
++    tlvBufLeft = tlvBufSize;
++    *ppTlv = NULL;
++    PRINTM(INFO, "uap_get_tlv: tlvBufSize = %d, reqTlvType=%x\n", tlvBufSize,
++           reqTlvType);
++    while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
++        tlvType = uap_le16_to_cpu(pCurrentTlv->Header.Type);
++        tlvLen = uap_le16_to_cpu(pCurrentTlv->Header.Len);
++        if (reqTlvType == tlvType)
++            *ppTlv = (MrvlIEtypes_Data_t *) pCurrentTlv;
++        if (*ppTlv) {
++            HEXDUMP("TLV Buf", (u8 *) * ppTlv, tlvLen);
++            break;
++        }
++        tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
++        pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
++    }                           /* while */
++    LEAVE();
++}
++
++/**
++ *  @brief This function get mac
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS on success, otherwise failure code
++ */
++static int
++uap_get_mac_address(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u32 CmdSize;
++    HostCmd_DS_COMMAND *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++    MrvlIEtypes_MacAddr_t *pMacAddrTlv;
++    MrvlIEtypes_Data_t *pTlv;
++    u16 tlvBufSize;
++    ENTER();
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++    CmdSize =
++        S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
++    cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_GET);
++    pMacAddrTlv =
++        (MrvlIEtypes_MacAddr_t *) (skb->data + INTF_HEADER_LEN + S_DS_GEN +
++                                   sizeof(HostCmd_SYS_CONFIG));
++    pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
++    pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
++        PRINTM(ERROR, "Fail to process cmd SYS_CONFIGURE Query\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    if (!Adapter->CmdSize) {
++        PRINTM(ERROR, "Cmd Size is 0\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
++    cmd->Result = uap_le16_to_cpu(cmd->Result);
++    if (cmd->Result != UAP_STATUS_SUCCESS) {
++        PRINTM(ERROR, "uap_get_mac_address fail=%x\n", cmd->Result);
++        ret = -EFAULT;
++        goto done;
++    }
++    pTlv =
++        (MrvlIEtypes_Data_t *) (Adapter->CmdBuf + S_DS_GEN +
++                                sizeof(HostCmd_SYS_CONFIG));
++    tlvBufSize = Adapter->CmdSize - S_DS_GEN - sizeof(HostCmd_SYS_CONFIG);
++    uap_get_tlv_ptrs(pTlv, tlvBufSize, MRVL_AP_MAC_ADDRESS_TLV_ID,
++                     (MrvlIEtypes_Data_t **) & pMacAddrTlv);
++    if (pMacAddrTlv) {
++        memcpy(priv->uap_dev.netdev->dev_addr, pMacAddrTlv->ApMacAddr,
++               ETH_ALEN);
++        HEXDUMP("Original MAC addr", priv->uap_dev.netdev->dev_addr, ETH_ALEN);
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function checks the conditions and sends packet to device
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param skb           A pointer to the skb for process
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_process_tx(uap_private * priv, struct sk_buff *skb)
++{
++    uap_adapter *Adapter = priv->adapter;
++    int ret = UAP_STATUS_SUCCESS;
++    TxPD *pLocalTxPD;
++    u8 *headptr;
++    struct sk_buff *newskb;
++    int newheadlen;
++    ENTER();
++    ASSERT(skb);
++    if (!skb) {
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++    if (skb_headroom(skb) < (sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT)) {
++        newheadlen = sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT;
++        PRINTM(WARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
++        /* Insufficient skb headroom - allocate a new skb */
++        newskb = skb_realloc_headroom(skb, newheadlen);
++        if (unlikely(newskb == NULL)) {
++            PRINTM(ERROR, "Tx: Cannot allocate skb\n");
++            ret = UAP_STATUS_FAILURE;
++            goto done;
++        }
++        kfree_skb(skb);
++        skb = newskb;
++        PRINTM(INFO, "new skb headroom %d\n", skb_headroom(skb));
++    }
++    /* headptr should be aligned */
++    headptr = skb->data - sizeof(TxPD) - INTF_HEADER_LEN;
++    headptr = (u8 *) ((u32) headptr & ~((u32) (HEADER_ALIGNMENT - 1)));
++
++    pLocalTxPD = (TxPD *) (headptr + INTF_HEADER_LEN);
++    memset(pLocalTxPD, 0, sizeof(TxPD));
++    pLocalTxPD->BssType = PKT_TYPE_MICROAP;
++    pLocalTxPD->TxPktLength = skb->len;
++    /* offset of actual data */
++    pLocalTxPD->TxPktOffset = (long) skb->data - (long) pLocalTxPD;
++    endian_convert_TxPD(pLocalTxPD);
++    *(u16 *) & headptr[0] =
++        uap_cpu_to_le16(skb->len + ((long) skb->data - (long) headptr));
++    *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_DAT);
++    ret =
++        sbi_host_to_card(priv, headptr,
++                         skb->len + ((long) skb->data - (long) headptr));
++    if (ret) {
++        PRINTM(ERROR, "uap_process_tx Error: sbi_host_to_card failed: 0x%X\n",
++               ret);
++        Adapter->dbg.num_tx_host_to_card_failure++;
++        goto done;
++    }
++    PRINTM(DATA, "Data => FW\n");
++    DBG_HEXDUMP(DAT_D, "Tx", headptr,
++                MIN(skb->len + sizeof(TxPD), DATA_DUMP_LEN));
++  done:
++    /* Freed skb */
++    kfree_skb(skb);
++    LEAVE();
++    return ret;
++}
++
++static struct netlink_kernel_cfg cfg = {
++      .groups = NL_MULTICAST_GROUP,
++};
++
++/**
++ *  @brief This function initializes the adapter structure
++ *  and set default value to the member of adapter.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_init_sw(uap_private * priv)
++{
++    uap_adapter *Adapter = priv->adapter;
++
++    ENTER();
++
++    if (!(Adapter->CmdBuf = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
++        PRINTM(INFO, "Failed to allocate command buffer!\n");
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    Adapter->cmd_pending = FALSE;
++    Adapter->CmdWaitQWoken = FALSE;
++    Adapter->ps_state = PS_STATE_AWAKE;
++    Adapter->WakeupTries = 0;
++
++    memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
++        /** SDIO header */
++    Adapter->PSConfirmSleep.SDLen =
++        uap_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
++    Adapter->PSConfirmSleep.SDType = uap_cpu_to_le16(MV_TYPE_CMD);
++    Adapter->PSConfirmSleep.SeqNum = 0;
++    Adapter->PSConfirmSleep.Command = uap_cpu_to_le16(HOST_CMD_SLEEP_CONFIRM);
++    Adapter->PSConfirmSleep.Size = uap_cpu_to_le16(sizeof(HostCmd_DS_GEN));
++    Adapter->PSConfirmSleep.Result = 0;
++
++    init_waitqueue_head(&Adapter->cmdwait_q);
++    OS_INIT_SEMAPHORE(&Adapter->CmdSem);
++
++    skb_queue_head_init(&Adapter->tx_queue);
++    skb_queue_head_init(&Adapter->cmd_queue);
++
++    /* Status variable */
++    Adapter->HardwareStatus = HWInitializing;
++
++    /* PnP support */
++    Adapter->SurpriseRemoved = FALSE;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
++    Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
++                                           NL_MULTICAST_GROUP, NULL,
++                                           THIS_MODULE);
++#else
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++    Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
++                                           NL_MULTICAST_GROUP, NULL, NULL,
++                                           THIS_MODULE);
++#else
++    Adapter->nl_sk = netlink_kernel_create(&init_net, NETLINK_MARVELL, &cfg);
++#endif
++#endif
++    if (!Adapter->nl_sk) {
++        PRINTM(ERROR,
++               "Could not initialize netlink event passing mechanism!\n");
++    }
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function sends FUNC_INIT command to firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS on success, otherwise failure code
++ */
++static int
++uap_func_init(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u32 CmdSize;
++    HostCmd_DS_GEN *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++    ENTER();
++    if (Adapter->HardwareStatus != HWReady) {
++        PRINTM(ERROR, "uap_func_init:Hardware is not ready!\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++    CmdSize = sizeof(HostCmd_DS_GEN);
++    cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_INIT);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    PRINTM(CMND, "HostCmd_CMD_FUNC_INIT\n");
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
++        PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_INIT\n");
++        ret = -EFAULT;
++        goto done;
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function sends FUNC_SHUTDOWN command to firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS on success, otherwise failure code
++ */
++static int __exit
++uap_func_shutdown(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u32 CmdSize;
++    HostCmd_DS_GEN *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++    ENTER();
++    if (Adapter->HardwareStatus != HWReady) {
++        PRINTM(ERROR, "uap_func_shutdown:Hardware is not ready!\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++    CmdSize = sizeof(HostCmd_DS_GEN);
++    cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_SHUTDOWN);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    PRINTM(CMND, "HostCmd_CMD_FUNC_SHUTDOWN\n");
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
++        PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_SHUTDOWN\n");
++        ret = -EFAULT;
++        goto done;
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function initializes firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_init_fw(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    ENTER();
++    sbi_disable_host_int(priv);
++    /* Check if firmware is already running */
++    if (sbi_check_fw_status(priv, 1) == UAP_STATUS_SUCCESS) {
++        PRINTM(MSG, "UAP FW already running! Skip FW download\n");
++    } else {
++        if ((ret = request_firmware(&priv->fw_helper, helper_name,
++                                    priv->hotplug_device)) < 0) {
++            PRINTM(FATAL,
++                   "request_firmware() failed (helper), error code = %#x\n",
++                   ret);
++            goto done;
++        }
++
++        /* Download the helper */
++        ret = sbi_prog_helper(priv);
++
++        if (ret) {
++            PRINTM(FATAL,
++                   "Bootloader in invalid state! Helper download failed!\n");
++            ret = UAP_STATUS_FAILURE;
++            goto done;
++        }
++        if ((ret = request_firmware(&priv->firmware, fw_name,
++                                    priv->hotplug_device)) < 0) {
++            PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
++            goto done;
++        }
++
++        /* Download the main firmware via the helper firmware */
++        if (sbi_prog_fw_w_helper(priv)) {
++            PRINTM(FATAL, "UAP FW download failed!\n");
++            ret = UAP_STATUS_FAILURE;
++            goto done;
++        }
++        /* Check if the firmware is downloaded successfully or not */
++        if (sbi_check_fw_status(priv, MAX_FIRMWARE_POLL_TRIES) ==
++            UAP_STATUS_FAILURE) {
++            PRINTM(FATAL, "FW failed to be active in time!\n");
++            ret = UAP_STATUS_FAILURE;
++            goto done;
++        }
++        PRINTM(MSG, "UAP FW is active\n");
++    }
++    sbi_enable_host_int(priv);
++    priv->adapter->HardwareStatus = HWReady;
++    if (uap_func_init(priv) != UAP_STATUS_SUCCESS) {
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++  done:
++    if (priv->fw_helper)
++        release_firmware(priv->fw_helper);
++    if (priv->firmware)
++        release_firmware(priv->firmware);
++    LEAVE();
++    return ret;
++
++}
++
++/**
++ *  @brief This function frees the structure of adapter
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      n/a
++ */
++static void
++uap_free_adapter(uap_private * priv)
++{
++    uap_adapter *Adapter = priv->adapter;
++
++    ENTER();
++
++    if (Adapter) {
++        if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
++            sock_release((Adapter->nl_sk)->sk_socket);
++            Adapter->nl_sk = NULL;
++        }
++        if (Adapter->CmdBuf)
++            kfree(Adapter->CmdBuf);
++        skb_queue_purge(&priv->adapter->tx_queue);
++        skb_queue_purge(&priv->adapter->cmd_queue);
++        /* Free the adapter object itself */
++        kfree(Adapter);
++        priv->adapter = NULL;
++    }
++
++    LEAVE();
++}
++
++/**
++ *  @brief This function handles the major job in uap driver.
++ *  it handles the event generated by firmware, rx data received
++ *  from firmware and tx data sent from kernel.
++ *
++ *  @param data    A pointer to uap_thread structure
++ *  @return        BT_STATUS_SUCCESS
++ */
++static int
++uap_service_main_thread(void *data)
++{
++    uap_thread *thread = data;
++    uap_private *priv = thread->priv;
++    uap_adapter *Adapter = priv->adapter;
++    wait_queue_t wait;
++    u8 ireg = 0;
++    struct sk_buff *skb;
++    ENTER();
++    uap_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 ((Adapter->WakeupTries) ||
++            (!Adapter->IntCounter && Adapter->ps_state == PS_STATE_PRE_SLEEP) ||
++            (!priv->adapter->IntCounter
++             && (priv->uap_dev.data_sent ||
++                 skb_queue_empty(&priv->adapter->tx_queue))
++             && (priv->uap_dev.cmd_sent || Adapter->cmd_pending ||
++                 skb_queue_empty(&priv->adapter->cmd_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);
++            /* Cancel pending command */
++            if (Adapter->cmd_pending == TRUE) {
++                /* Wake up cmd Q */
++                Adapter->CmdWaitQWoken = TRUE;
++                wake_up_interruptible(&Adapter->cmdwait_q);
++            }
++            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_STATE_SLEEP) &&
++                   (!skb_queue_empty(&priv->adapter->cmd_queue) ||
++                    !skb_queue_empty(&priv->adapter->tx_queue))) {
++            priv->adapter->WakeupTries++;
++            PRINTM(CMND, "%lu : Wakeup device...\n", os_time_get());
++            sbi_wakeup_firmware(priv);
++            continue;
++        }
++        if (Adapter->ps_state == PS_STATE_PRE_SLEEP)
++            uap_ps_cond_check(priv);
++
++        /* The PS state is changed during processing of Sleep Request event
++           above */
++        if ((Adapter->ps_state == PS_STATE_SLEEP) ||
++            (Adapter->ps_state == PS_STATE_PRE_SLEEP))
++            continue;
++        /* Execute the next command */
++        if (!priv->uap_dev.cmd_sent && !Adapter->cmd_pending &&
++            (Adapter->HardwareStatus == HWReady)) {
++            if (!skb_queue_empty(&priv->adapter->cmd_queue)) {
++                skb = skb_dequeue(&priv->adapter->cmd_queue);
++                if (skb) {
++                    Adapter->CmdSize = 0;
++                    Adapter->cmd_pending = TRUE;
++                    Adapter->cmd_wait_option = skb->cb[0];
++                    if (sbi_host_to_card(priv, skb->data, skb->len)) {
++                        PRINTM(ERROR, "Cmd:sbi_host_to_card failed!\n");
++                        Adapter->cmd_pending = FALSE;
++                        Adapter->dbg.num_cmd_host_to_card_failure++;
++                        /* Wake up cmd Q */
++                        Adapter->CmdWaitQWoken = TRUE;
++                        wake_up_interruptible(&Adapter->cmdwait_q);
++                    } else {
++                        if (Adapter->cmd_wait_option ==
++                            HostCmd_OPTION_WAITFORSEND) {
++                            /* Wake up cmd Q */
++                            Adapter->CmdWaitQWoken = TRUE;
++                            wake_up_interruptible(&Adapter->cmdwait_q);
++                            Adapter->cmd_wait_option = FALSE;
++                        }
++                    }
++                    kfree_skb(skb);
++                }
++            }
++        }
++        if (!priv->uap_dev.data_sent && (Adapter->HardwareStatus == HWReady)) {
++            if (!skb_queue_empty(&priv->adapter->tx_queue)) {
++                skb = skb_dequeue(&priv->adapter->tx_queue);
++                if (skb) {
++                    if (uap_process_tx(priv, skb)) {
++                        priv->stats.tx_dropped++;
++                        priv->stats.tx_errors++;
++                        os_start_queue(priv);
++                    } else {
++                        priv->stats.tx_packets++;
++                        priv->stats.tx_bytes += skb->len;
++                    }
++
++                }
++            }
++        }
++    }
++    uap_deactivate_thread(thread);
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief uap hostcmd ioctl handler
++ *
++ *  @param dev      A pointer to net_device structure
++ *  @param req      A pointer to ifreq structure
++ *  @return         UAP_STATUS_SUCCESS --success, otherwise fail
++ */
++/*********  format of ifr_data *************/
++/*    buf_len + Hostcmd_body             */
++/*    buf_len: 4 bytes                     */
++/*             the length of the buf which */
++/*             can be used to return data  */
++/*             to application            */
++/*    Hostcmd_body                       */
++/*******************************************/
++static int
++uap_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
++{
++    u32 buf_len;
++    HostCmd_HEADER head;
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++    uap_adapter *Adapter = priv->adapter;
++    int ret = UAP_STATUS_SUCCESS;
++    struct sk_buff *skb;
++
++    ENTER();
++
++    /* Sanity check */
++    if (req->ifr_data == NULL) {
++        PRINTM(ERROR, "uap_hostcmd_ioctl() corrupt data\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
++        PRINTM(ERROR, "Copy from user failed\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    memset(&head, 0, sizeof(HostCmd_HEADER));
++    /* Get the command size from user space */
++    if (copy_from_user
++        (&head, req->ifr_data + sizeof(buf_len), sizeof(HostCmd_HEADER))) {
++        PRINTM(ERROR, "Copy from user failed\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    head.Size = uap_le16_to_cpu(head.Size);
++    if (head.Size > MRVDRV_SIZE_OF_CMD_BUFFER) {
++        PRINTM(ERROR, "CmdSize too big=%d\n", head.Size);
++        LEAVE();
++        return -EFAULT;
++    }
++    PRINTM(CMND, "ioctl: hostcmd=%x, size=%d,buf_len=%d\n", head.Command,
++           head.Size, buf_len);
++    skb = dev_alloc_skb(head.Size + INTF_HEADER_LEN);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        LEAVE();
++        return -ENOMEM;
++    }
++
++    /* Get the command from user space */
++    if (copy_from_user
++        (skb->data + INTF_HEADER_LEN, req->ifr_data + sizeof(buf_len),
++         head.Size)) {
++        PRINTM(ERROR, "Copy from user failed\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    skb_put(skb, head.Size + INTF_HEADER_LEN);
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
++        PRINTM(ERROR, "Fail to process cmd\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    if (!Adapter->CmdSize) {
++        PRINTM(ERROR, "Cmd Size is 0\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    if (Adapter->CmdSize > buf_len) {
++        PRINTM(ERROR, "buf_len is too small\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    /* Copy to user */
++    if (copy_to_user
++        (req->ifr_data + sizeof(buf_len), Adapter->CmdBuf, Adapter->CmdSize)) {
++        PRINTM(ERROR, "Copy to user failed!\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief uap power mode ioctl handler
++ *
++ *  @param dev      A pointer to net_device structure
++ *  @param req      A pointer to ifreq structure
++ *  @return         UAP_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
++{
++    ps_mgmt pm_cfg;
++    int ret = UAP_STATUS_SUCCESS;
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb = NULL;
++    HostCmd_DS_COMMAND *cmd;
++    u32 CmdSize;
++    u8 *tlv = NULL;
++    MrvlIEtypes_sleep_param_t *sleep_tlv = NULL;
++    MrvlIEtypes_inact_sleep_param_t *inact_tlv = NULL;
++    u16 tlv_buf_left = 0;
++    MrvlIEtypesHeader_t *tlvbuf = NULL;
++    u16 tlv_type = 0;
++    u16 tlv_len = 0;
++
++    ENTER();
++
++    /* Sanity check */
++    if (req->ifr_data == NULL) {
++        PRINTM(ERROR, "uap_power_mode_ioctl() corrupt data\n");
++        LEAVE();
++        return -EFAULT;
++    }
++
++    memset(&pm_cfg, 0, sizeof(ps_mgmt));
++    if (copy_from_user(&pm_cfg, req->ifr_data, sizeof(ps_mgmt))) {
++        PRINTM(ERROR, "Copy from user failed\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    PRINTM(CMND,
++           "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
++           "inact_to=%d min_awake=%d max_awake=%d\n", pm_cfg.flags,
++           (int) pm_cfg.ps_mode, (int) pm_cfg.sleep_param.ctrl_bitmap,
++           (int) pm_cfg.sleep_param.min_sleep,
++           (int) pm_cfg.sleep_param.max_sleep,
++           (int) pm_cfg.inact_param.inactivity_to,
++           (int) pm_cfg.inact_param.min_awake,
++           (int) pm_cfg.inact_param.max_awake);
++
++    if (pm_cfg.
++        flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
++                  PS_FLAG_INACT_SLEEP_PARAM)) {
++        PRINTM(ERROR, "Invalid parameter: flags = 0x%x\n", pm_cfg.flags);
++        ret = -EINVAL;
++        goto done;
++    }
++    if (pm_cfg.ps_mode > PS_MODE_INACTIVITY) {
++        PRINTM(ERROR, "Invalid parameter: ps_mode = %d\n", (int) pm_cfg.flags);
++        ret = -EINVAL;
++        goto done;
++    }
++
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(INFO, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++
++    CmdSize = S_DS_GEN + sizeof(HostCmd_DS_POWER_MGMT_EXT);
++
++    cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HOST_CMD_POWER_MGMT_EXT);
++    if (!pm_cfg.flags) {
++        cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_GET);
++    } else {
++        cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_SET);
++        cmd->params.pm_cfg.power_mode = uap_cpu_to_le16(pm_cfg.ps_mode);
++        tlv = (u8 *) & cmd->params.pm_cfg + sizeof(HostCmd_DS_POWER_MGMT_EXT);
++
++        if ((pm_cfg.ps_mode) && (pm_cfg.flags & PS_FLAG_SLEEP_PARAM)) {
++            sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
++            sleep_tlv->header.Type = uap_cpu_to_le16(TLV_TYPE_AP_SLEEP_PARAM);
++            sleep_tlv->header.Len =
++                uap_cpu_to_le16(sizeof(MrvlIEtypes_sleep_param_t) -
++                                sizeof(MrvlIEtypesHeader_t));
++            sleep_tlv->ctrl_bitmap =
++                uap_cpu_to_le32(pm_cfg.sleep_param.ctrl_bitmap);
++            sleep_tlv->min_sleep =
++                uap_cpu_to_le32(pm_cfg.sleep_param.min_sleep);
++            sleep_tlv->max_sleep =
++                uap_cpu_to_le32(pm_cfg.sleep_param.max_sleep);
++            CmdSize += sizeof(MrvlIEtypes_sleep_param_t);
++            tlv += sizeof(MrvlIEtypes_sleep_param_t);
++        }
++        if ((pm_cfg.ps_mode == PS_MODE_INACTIVITY) &&
++            (pm_cfg.flags & PS_FLAG_INACT_SLEEP_PARAM)) {
++            inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
++            inact_tlv->header.Type =
++                uap_cpu_to_le16(TLV_TYPE_AP_INACT_SLEEP_PARAM);
++            inact_tlv->header.Len =
++                uap_cpu_to_le16(sizeof(MrvlIEtypes_inact_sleep_param_t) -
++                                sizeof(MrvlIEtypesHeader_t));
++            inact_tlv->inactivity_to =
++                uap_cpu_to_le32(pm_cfg.inact_param.inactivity_to);
++            inact_tlv->min_awake =
++                uap_cpu_to_le32(pm_cfg.inact_param.min_awake);
++            inact_tlv->max_awake =
++                uap_cpu_to_le32(pm_cfg.inact_param.max_awake);
++            CmdSize += sizeof(MrvlIEtypes_inact_sleep_param_t);
++            tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
++        }
++    }
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
++        PRINTM(ERROR, "Fail to process cmd POWER_MODE\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    if (!Adapter->CmdSize) {
++        PRINTM(ERROR, "Cmd Size is 0\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
++    cmd->Result = uap_le16_to_cpu(cmd->Result);
++    if (cmd->Result != UAP_STATUS_SUCCESS) {
++        PRINTM(ERROR, "HOST_CMD_APCMD_POWER_MODE fail=%x\n", cmd->Result);
++        ret = -EFAULT;
++        goto done;
++    }
++    if (pm_cfg.flags) {
++        Adapter->psmode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
++    } else {
++        pm_cfg.flags = PS_FLAG_PS_MODE;
++        pm_cfg.ps_mode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
++        tlv_buf_left =
++            cmd->Size - (sizeof(HostCmd_DS_POWER_MGMT_EXT) + S_DS_GEN);
++        tlvbuf =
++            (MrvlIEtypesHeader_t *) ((u8 *) & cmd->params.pm_cfg +
++                                     sizeof(HostCmd_DS_POWER_MGMT_EXT));
++        while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
++            tlv_type = uap_le16_to_cpu(tlvbuf->Type);
++            tlv_len = uap_le16_to_cpu(tlvbuf->Len);
++            switch (tlv_type) {
++            case TLV_TYPE_AP_SLEEP_PARAM:
++                sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlvbuf;
++                pm_cfg.flags |= PS_FLAG_SLEEP_PARAM;
++                pm_cfg.sleep_param.ctrl_bitmap =
++                    uap_le32_to_cpu(sleep_tlv->ctrl_bitmap);
++                pm_cfg.sleep_param.min_sleep =
++                    uap_le32_to_cpu(sleep_tlv->min_sleep);
++                pm_cfg.sleep_param.max_sleep =
++                    uap_le32_to_cpu(sleep_tlv->max_sleep);
++                break;
++            case TLV_TYPE_AP_INACT_SLEEP_PARAM:
++                inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlvbuf;
++                pm_cfg.flags |= PS_FLAG_INACT_SLEEP_PARAM;
++                pm_cfg.inact_param.inactivity_to =
++                    uap_le32_to_cpu(inact_tlv->inactivity_to);
++                pm_cfg.inact_param.min_awake =
++                    uap_le32_to_cpu(inact_tlv->min_awake);
++                pm_cfg.inact_param.max_awake =
++                    uap_le32_to_cpu(inact_tlv->max_awake);
++                break;
++            }
++            tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
++            tlvbuf =
++                (MrvlIEtypesHeader_t *) ((u8 *) tlvbuf + tlv_len +
++                                         sizeof(MrvlIEtypesHeader_t));
++        }
++        /* Copy to user */
++        if (copy_to_user(req->ifr_data, &pm_cfg, sizeof(ps_mgmt))) {
++            PRINTM(ERROR, "Copy to user failed!\n");
++            LEAVE();
++            return -EFAULT;
++        }
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function send bss_stop command to firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS on success, otherwise failure code
++ */
++static int
++uap_bss_stop(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u32 CmdSize;
++    HostCmd_DS_GEN *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++    ENTER();
++    if (Adapter->HardwareStatus != HWReady) {
++        PRINTM(ERROR, "uap_bss_stop:Hardware is not ready!\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++    CmdSize = sizeof(HostCmd_DS_GEN);
++    cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_BSS_STOP);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    PRINTM(CMND, "APCMD_BSS_STOP\n");
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
++        PRINTM(ERROR, "Fail to process cmd BSS_STOP\n");
++        ret = -EFAULT;
++        goto done;
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/********************************************************
++              Global Functions
++********************************************************/
++/**
++ *  @brief This function send soft_reset command to firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS on success, otherwise failure code
++ */
++int
++uap_soft_reset(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u32 CmdSize;
++    HostCmd_DS_GEN *cmd;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++    ENTER();
++    ret = uap_bss_stop(priv);
++    if (ret != UAP_STATUS_SUCCESS)
++        goto done;
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        ret = -ENOMEM;
++        goto done;
++    }
++    CmdSize = sizeof(HostCmd_DS_GEN);
++    cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SOFT_RESET);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    PRINTM(CMND, "APCMD_SOFT_RESET\n");
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORSEND)) {
++        PRINTM(ERROR, "Fail to process cmd SOFT_RESET\n");
++        ret = -EFAULT;
++        goto done;
++    }
++    Adapter->SurpriseRemoved = TRUE;
++    /* delay to allow hardware complete reset */
++    os_sched_timeout(5);
++    if (priv->MediaConnected == TRUE) {
++        os_stop_queue(priv);
++        os_carrier_off(priv);
++        priv->MediaConnected = FALSE;
++    }
++    Adapter->CmdSize = 0;
++    Adapter->CmdWaitQWoken = TRUE;
++    wake_up_interruptible(&Adapter->cmdwait_q);
++    skb_queue_purge(&priv->adapter->tx_queue);
++    skb_queue_purge(&priv->adapter->cmd_queue);
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function processes received packet and forwards it
++ *  to kernel/upper layer
++ *
++ *  @param priv    A pointer to uap_private
++ *  @param skb     A pointer to skb which includes the received packet
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++uap_process_rx_packet(uap_private * priv, struct sk_buff *skb)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    RxPD *pRxPD;
++    ENTER();
++    priv->adapter->ps_state = PS_STATE_AWAKE;
++    pRxPD = (RxPD *) skb->data;
++    endian_convert_RxPD(pRxPD);
++    DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
++    skb_pull(skb, pRxPD->RxPktOffset);
++    priv->stats.rx_packets++;
++    priv->stats.rx_bytes += skb->len;
++    os_upload_rx_packet(priv, skb);
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function opens the network device
++ *
++ *  @param dev     A pointer to net_device structure
++ *  @return        UAP_STATUS_SUCCESS
++ */
++static int
++uap_open(struct net_device *dev)
++{
++    uap_private *priv = (uap_private *) (uap_private *) netdev_priv(dev);
++    uap_adapter *Adapter = priv->adapter;
++    int i = 0;
++
++    ENTER();
++
++    /* On some systems the device open handler will be called before HW ready. */
++    /* Use the following flag check and wait function to work around the issue. */
++    while ((Adapter->HardwareStatus != HWReady) &&
++           (i < MAX_WAIT_DEVICE_READY_COUNT)) {
++        i++;
++        os_sched_timeout(100);
++    }
++    if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
++        PRINTM(FATAL, "HW not ready, uap_open() return failure\n");
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    if (MODULE_GET == 0)
++        return UAP_STATUS_FAILURE;
++
++    priv->open = TRUE;
++    if (priv->MediaConnected == TRUE) {
++        os_carrier_on(priv);
++        os_start_queue(priv);
++    } else {
++        os_stop_queue(priv);
++        os_carrier_off(priv);
++    }
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function closes the network device
++ *
++ *  @param dev     A pointer to net_device structure
++ *  @return        UAP_STATUS_SUCCESS
++ */
++static int
++uap_close(struct net_device *dev)
++{
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++
++    ENTER();
++    skb_queue_purge(&priv->adapter->tx_queue);
++    os_stop_queue(priv);
++    os_carrier_off(priv);
++
++    MODULE_PUT;
++    priv->open = FALSE;
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function returns the network statistics
++ *
++ *  @param dev     A pointer to uap_private structure
++ *  @return        A pointer to net_device_stats structure
++ */
++static struct net_device_stats *
++uap_get_stats(struct net_device *dev)
++{
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++
++    return &priv->stats;
++}
++
++/**
++ *  @brief This function sets the MAC address to firmware.
++ *
++ *  @param dev     A pointer to uap_private structure
++ *  @param addr    MAC address to set
++ *  @return        UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_set_mac_address(struct net_device *dev, void *addr)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++    struct sockaddr *pHwAddr = (struct sockaddr *) addr;
++    u32 CmdSize;
++    HostCmd_DS_COMMAND *cmd;
++    MrvlIEtypes_MacAddr_t *pMacAddrTlv;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb;
++
++    ENTER();
++
++    /* Dump MAC address */
++    DBG_HEXDUMP(CMD_D, "Original MAC addr", dev->dev_addr, ETH_ALEN);
++    DBG_HEXDUMP(CMD_D, "New MAC addr", pHwAddr->sa_data, ETH_ALEN);
++    if (priv->open && (priv->MediaConnected == TRUE)) {
++        os_carrier_on(priv);
++        os_start_queue(priv);
++    }
++    skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
++    if (!skb) {
++        PRINTM(ERROR, "No free skb\n");
++        LEAVE();
++        return -ENOMEM;
++    }
++    CmdSize =
++        S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
++    cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
++    cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
++    cmd->Size = uap_cpu_to_le16(CmdSize);
++    cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_SET);
++    pMacAddrTlv =
++        (MrvlIEtypes_MacAddr_t *) ((u8 *) cmd + S_DS_GEN +
++                                   sizeof(HostCmd_SYS_CONFIG));
++    pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
++    pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
++    memcpy(pMacAddrTlv->ApMacAddr, pHwAddr->sa_data, ETH_ALEN);
++    skb_put(skb, CmdSize + INTF_HEADER_LEN);
++    PRINTM(CMND, "set_mac_address\n");
++    if (UAP_STATUS_SUCCESS !=
++        uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
++        PRINTM(ERROR, "Fail to set mac address\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    if (!Adapter->CmdSize) {
++        PRINTM(ERROR, "Cmd Size is 0\n");
++        LEAVE();
++        return -EFAULT;
++    }
++    cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
++    cmd->Result = uap_cpu_to_le16(cmd->Result);
++    if (cmd->Result != UAP_STATUS_SUCCESS) {
++        PRINTM(ERROR, "set mac addrress fail,cmd result=%x\n", cmd->Result);
++        ret = -EFAULT;
++    } else
++        memcpy(dev->dev_addr, pHwAddr->sa_data, ETH_ALEN);
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function handles the timeout of packet
++ *  transmission
++ *
++ *  @param dev     A pointer to net_device structure
++ *  @return        n/a
++ */
++static void
++uap_tx_timeout(struct net_device *dev)
++{
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++
++    ENTER();
++
++    PRINTM(DATA, "Tx timeout\n");
++    UpdateTransStart(dev);
++    priv->num_tx_timeout++;
++    priv->adapter->IntCounter++;
++    wake_up_interruptible(&priv->MainThread.waitQ);
++
++    LEAVE();
++}
++
++/**
++ *  @brief This function handles packet transmission
++ *
++ *  @param skb     A pointer to sk_buff structure
++ *  @param dev     A pointer to net_device structure
++ *  @return        UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++    uap_private *priv = (uap_private *) netdev_priv(dev);
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++    PRINTM(DATA, "Data <= kernel\n");
++    DBG_HEXDUMP(DAT_D, "Tx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
++    /* skb sanity check */
++    if (!skb->len || (skb->len > MRVDRV_MAXIMUM_ETH_PACKET_SIZE)) {
++        PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
++               MRVDRV_MAXIMUM_ETH_PACKET_SIZE);
++        priv->stats.tx_dropped++;
++        kfree(skb);
++        goto done;
++    }
++    skb_queue_tail(&priv->adapter->tx_queue, skb);
++    wake_up_interruptible(&priv->MainThread.waitQ);
++    if (skb_queue_len(&priv->adapter->tx_queue) > TX_HIGH_WATERMARK) {
++        UpdateTransStart(dev);
++        os_stop_queue(priv);
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief ioctl function - entry point
++ *
++ *  @param dev      A pointer to net_device structure
++ *  @param req      A pointer to ifreq structure
++ *  @param cmd      command
++ *  @return         UAP_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
++{
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++
++    PRINTM(CMND, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
++
++    switch (cmd) {
++    case UAPHOSTCMD:
++        ret = uap_hostcmd_ioctl(dev, req);
++        break;
++    case UAP_POWER_MODE:
++        ret = uap_power_mode_ioctl(dev, req);
++        break;
++    default:
++        ret = -EINVAL;
++        break;
++    }
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function handles events generated by firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param payload A pointer to payload buffer
++ *  @param len           Length of the payload
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++uap_process_event(uap_private * priv, u8 * payload, uint len)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    uap_adapter *Adapter = priv->adapter;
++    struct sk_buff *skb = NULL;
++    struct nlmsghdr *nlh = NULL;
++    struct sock *sk = Adapter->nl_sk;
++    AP_Event *pEvent;
++
++    ENTER();
++    Adapter->ps_state = PS_STATE_AWAKE;
++    if (len > NL_MAX_PAYLOAD) {
++        PRINTM(ERROR, "event size is too big!!! len=%d\n", len);
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++    pEvent = (AP_Event *) payload;
++    PRINTM(CMND, "Event: %d\n", pEvent->EventId);
++    switch (pEvent->EventId) {
++    case MICRO_AP_EV_ID_BSS_START:
++        memcpy(priv->uap_dev.netdev->dev_addr, pEvent->MacAddr, ETH_ALEN);
++        DBG_HEXDUMP(CMD_D, "BSS MAC addr", priv->uap_dev.netdev->dev_addr,
++                    ETH_ALEN);
++        break;
++    case MICRO_AP_EV_BSS_ACTIVE:
++        // carrier on
++        priv->MediaConnected = TRUE;
++        os_carrier_on(priv);
++        os_start_queue(priv);
++        break;
++    case MICRO_AP_EV_BSS_IDLE:
++        os_stop_queue(priv);
++        os_carrier_off(priv);
++        priv->MediaConnected = FALSE;
++        break;
++    case EVENT_PS_AWAKE:
++        PRINTM(CMND, "UAP: PS_AWAKE\n");
++        Adapter->ps_state = PS_STATE_AWAKE;
++        Adapter->WakeupTries = 0;
++        break;
++    case EVENT_PS_SLEEP:
++        PRINTM(CMND, "UAP: PS_SLEEP\n");
++        Adapter->ps_state = PS_STATE_PRE_SLEEP;
++        break;
++    default:
++        break;
++    }
++    if ((pEvent->EventId == EVENT_PS_AWAKE) ||
++        (pEvent->EventId == EVENT_PS_SLEEP))
++        goto done;
++    if (sk) {
++        /* Allocate skb */
++        if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
++            PRINTM(ERROR, "Could not allocate skb for netlink.\n");
++            ret = UAP_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).portid = 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 = UAP_STATUS_SUCCESS;
++    } else {
++        PRINTM(ERROR, "Could not send event through NETLINK. Link down.\n");
++        ret = UAP_STATUS_FAILURE;
++    }
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @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 priv    A pointer to uap_private structure
++ *  @return        n/a
++ */
++void
++uap_interrupt(uap_private * priv)
++{
++    ENTER();
++    priv->adapter->IntCounter++;
++    priv->adapter->WakeupTries = 0;
++    PRINTM(INFO, "*\n");
++    wake_up_interruptible(&priv->MainThread.waitQ);
++
++    LEAVE();
++
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++/** Network device handlers */
++static const struct net_device_ops uap_netdev_ops = {
++    .ndo_open = uap_open,
++    .ndo_start_xmit = uap_hard_start_xmit,
++    .ndo_stop = uap_close,
++    .ndo_do_ioctl = uap_do_ioctl,
++    .ndo_set_mac_address = uap_set_mac_address,
++    .ndo_tx_timeout = uap_tx_timeout,
++    .ndo_get_stats = uap_get_stats,
++};
++#endif
++
++/**
++ * @brief This function adds the card. it will probe the
++ * card, allocate the uap_priv and initialize the device.
++ *
++ *  @param card    A pointer to card
++ *  @return        A pointer to uap_private structure
++ */
++uap_private *
++uap_add_card(void *card)
++{
++    struct net_device *dev = NULL;
++    uap_private *priv = NULL;
++
++    ENTER();
++
++    if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
++        goto exit_sem_err;
++
++    /* Allocate an Ethernet device */
++    if (!(dev = alloc_etherdev(sizeof(uap_private)))) {
++        PRINTM(FATAL, "Init ethernet device failed!\n");
++        goto error;
++    }
++    priv = (uap_private *) netdev_priv(dev);
++
++    /* Allocate name */
++    if (dev_alloc_name(dev, "uap%d") < 0) {
++        PRINTM(ERROR, "Could not allocate device name!\n");
++        goto error;
++    }
++
++    /* Allocate buffer for uap_adapter */
++    if (!(priv->adapter = kmalloc(sizeof(uap_adapter), GFP_KERNEL))) {
++        PRINTM(FATAL, "Allocate buffer for uap_adapter failed!\n");
++        goto error;
++    }
++    memset(priv->adapter, 0, sizeof(uap_adapter));
++
++    priv->uap_dev.netdev = dev;
++    priv->uap_dev.card = card;
++    priv->MediaConnected = FALSE;
++    uappriv = priv;
++    ((struct sdio_mmc_card *) card)->priv = priv;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++    SET_MODULE_OWNER(dev);
++#endif
++
++    /* Setup the OS Interface to our functions */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
++    dev->open = uap_open;
++    dev->stop = uap_close;
++    dev->hard_start_xmit = uap_hard_start_xmit;
++    dev->tx_timeout = uap_tx_timeout;
++    dev->get_stats = uap_get_stats;
++    dev->do_ioctl = uap_do_ioctl;
++    dev->set_mac_address = uap_set_mac_address;
++    dev->set_multicast_list = uap_set_multicast_list;
++#else
++    dev->netdev_ops = &uap_netdev_ops;
++#endif
++    dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
++    dev->hard_header_len += sizeof(TxPD) + INTF_HEADER_LEN;
++    dev->hard_header_len += HEADER_ALIGNMENT;
++#define NETIF_F_DYNALLOC 16
++    dev->features |= NETIF_F_DYNALLOC;
++    dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
++
++    /* Init SW */
++    if (uap_init_sw(priv)) {
++        PRINTM(FATAL, "Software Init Failed\n");
++        goto error;
++    }
++
++    PRINTM(INFO, "Starting kthread...\n");
++    priv->MainThread.priv = priv;
++    spin_lock_init(&priv->driver_lock);
++    uap_create_thread(uap_service_main_thread, &priv->MainThread,
++                      "uap_main_service");
++    while (priv->MainThread.pid == 0) {
++        os_sched_timeout(2);
++    }
++
++    /* Register the device */
++    if (sbi_register_dev(priv) < 0) {
++        PRINTM(FATAL, "Failed to register uap device!\n");
++        goto err_registerdev;
++    }
++#ifdef FW_DNLD_NEEDED
++    SET_NETDEV_DEV(dev, priv->hotplug_device);
++#endif
++
++    /* Init FW and HW */
++    if (uap_init_fw(priv)) {
++        PRINTM(FATAL, "Firmware Init Failed\n");
++        goto err_init_fw;
++    }
++
++    priv->uap_dev.cmd_sent = FALSE;
++    priv->uap_dev.data_sent = FALSE;
++
++    /* Get mac address from firmware */
++    if (uap_get_mac_address(priv)) {
++        PRINTM(FATAL, "Fail to get mac address\n");
++        goto err_init_fw;
++    }
++    /* Register network device */
++    if (register_netdev(dev)) {
++        printk(KERN_ERR "Cannot register network device!\n");
++        goto err_init_fw;
++    }
++#ifdef CONFIG_PROC_FS
++    uap_proc_entry(priv, dev);
++    uap_debug_entry(priv, dev);
++#endif /* CPNFIG_PROC_FS */
++    OS_REL_SEMAPHORE(&AddRemoveCardSem);
++
++    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);
++    }
++  error:
++    if (dev) {
++        if (dev->reg_state == NETREG_REGISTERED)
++            unregister_netdev(dev);
++        if (priv->adapter)
++            uap_free_adapter(priv);
++        free_netdev(dev);
++        uappriv = NULL;
++    }
++    OS_REL_SEMAPHORE(&AddRemoveCardSem);
++  exit_sem_err:
++    LEAVE();
++    return NULL;
++}
++
++/**
++ *  @brief This function removes the card.
++ *
++ *  @param card    A pointer to card
++ *  @return        UAP_STATUS_SUCCESS
++ */
++int
++uap_remove_card(void *card)
++{
++    uap_private *priv = uappriv;
++    uap_adapter *Adapter;
++    struct net_device *dev;
++
++    ENTER();
++
++    if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
++        goto exit_sem_err;
++
++    if (!priv || !(Adapter = priv->adapter)) {
++        goto exit_remove;
++    }
++    Adapter->SurpriseRemoved = TRUE;
++    if (Adapter->cmd_pending == TRUE) {
++        /* Wake up cmd Q */
++        Adapter->CmdWaitQWoken = TRUE;
++        wake_up_interruptible(&Adapter->cmdwait_q);
++    }
++    dev = priv->uap_dev.netdev;
++    if (priv->MediaConnected == TRUE) {
++        os_stop_queue(priv);
++        os_carrier_off(priv);
++        priv->MediaConnected = FALSE;
++    }
++    Adapter->CmdSize = 0;
++    Adapter->CmdWaitQWoken = TRUE;
++    wake_up_interruptible(&Adapter->cmdwait_q);
++    skb_queue_purge(&priv->adapter->tx_queue);
++    skb_queue_purge(&priv->adapter->cmd_queue);
++
++    /* Disable interrupts on the card */
++    sbi_disable_host_int(priv);
++    PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
++           (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
++    unregister_netdev(dev);
++    PRINTM(INFO, "Unregister finish\n");
++    wake_up_interruptible(&priv->MainThread.waitQ);
++    while (priv->MainThread.pid) {
++        os_sched_timeout(1);
++    }
++
++    if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
++        sock_release((Adapter->nl_sk)->sk_socket);
++        Adapter->nl_sk = NULL;
++    }
++#ifdef CONFIG_PROC_FS
++    uap_debug_remove(priv);
++    uap_proc_remove(priv);
++#endif
++    sbi_unregister_dev(priv);
++    PRINTM(INFO, "Free Adapter\n");
++    uap_free_adapter(priv);
++    priv->uap_dev.netdev = NULL;
++    free_netdev(dev);
++    uappriv = NULL;
++
++  exit_remove:
++    OS_REL_SEMAPHORE(&AddRemoveCardSem);
++  exit_sem_err:
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function initializes module.
++ *
++ *  @return    UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int __init
++uap_init_module(void)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    ENTER();
++
++    OS_INIT_SEMAPHORE(&AddRemoveCardSem);
++    ret = sbi_register();
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function cleans module
++ *
++ *  @return        n/a
++ */
++static void __exit
++uap_cleanup_module(void)
++{
++    ENTER();
++
++    if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
++        goto exit_sem_err;
++
++    if ((uappriv) && (uappriv->adapter)) {
++        uap_func_shutdown(uappriv);
++    }
++    OS_REL_SEMAPHORE(&AddRemoveCardSem);
++  exit_sem_err:
++    sbi_unregister();
++    LEAVE();
++}
++
++module_init(uap_init_module);
++module_exit(uap_cleanup_module);
++module_param(helper_name, charp, 0);
++MODULE_PARM_DESC(helper_name, "Helper name");
++module_param(fw_name, charp, 0);
++MODULE_PARM_DESC(fw_name, "Firmware name");
++
++MODULE_DESCRIPTION("M-UAP Driver");
++MODULE_AUTHOR("Marvell International Ltd.");
++MODULE_VERSION(DRIVER_VERSION);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/wireless/libertas_uap/uap_proc.c b/drivers/net/wireless/libertas_uap/uap_proc.c
+new file mode 100644
+index 0000000..d673f56
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_proc.c
+@@ -0,0 +1,258 @@
++/** @file uap_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 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.
++  *
++  */
++#ifdef CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include "uap_headers.h"
++
++/** /proc directory 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
++
++/********************************************************
++              Local Variables
++********************************************************/
++
++/********************************************************
++              Global Variables
++********************************************************/
++
++/********************************************************
++              Local Functions
++********************************************************/
++
++static int uap_info_proc_show(struct seq_file *s, void *data) {
++    int i;
++    struct net_device *netdev = (struct net_device*)s->private;
++    struct netdev_hw_addr *ha;
++    uap_private *priv = (uap_private *) netdev_priv(netdev);
++
++    seq_printf(s, "driver_name = " "\"uap\"\n");
++    seq_printf(s, "driver_version = %s-(FP%s)", DRIVER_VERSION, FPNUM);
++    seq_printf(s, "\nInterfaceName=\"%s\"\n", netdev->name);
++
++    seq_printf(s, "State=\"%s\"\n",
++                 ((priv->MediaConnected ==
++                   FALSE) ? "Disconnected" : "Connected"));
++    seq_printf(s, "MACAddress=\"%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]);
++    i = 0;
++    netdev_for_each_mc_addr(ha, netdev) {
++        ++i;
++    }
++    seq_printf(s, "MCCount=\"%d\"\n", i);
++
++    /*
++     * Put out the multicast list
++     */
++    i = 0;
++    netdev_for_each_mc_addr(ha, netdev) {
++        seq_printf(s,
++                     "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
++                     i++,
++                     ha->addr[0], ha->addr[1],
++                     ha->addr[2], ha->addr[3],
++                     ha->addr[4], ha->addr[5]);
++    }
++
++    seq_printf(s, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
++    seq_printf(s, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
++    seq_printf(s, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
++    seq_printf(s, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
++    seq_printf(s, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
++    seq_printf(s, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
++    seq_printf(s, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
++    seq_printf(s, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
++    seq_printf(s, "num_tx_timeout = %u\n", priv->num_tx_timeout);
++    seq_printf(s, "carrier %s\n",
++                 ((netif_carrier_ok(priv->uap_dev.netdev)) ? "on" : "off"));
++    seq_printf(s, "tx queue %s\n",
++                 ((netif_queue_stopped(priv->uap_dev.netdev)) ? "stopped" :
++                  "started"));
++
++    return 0;
++}
++
++static int uap_info_proc_open(struct inode *inode, struct file *file) {
++      return single_open(file, uap_info_proc_show, PDE_DATA(inode));
++}
++
++static int uap_hwstatus_proc_show(struct seq_file *s, void *data) {
++    struct net_device *netdev = (struct net_device*)s->private;
++    uap_private *priv = (uap_private *) netdev_priv(netdev);
++
++    MODULE_GET;
++    seq_printf(s, "%d\n", priv->adapter->HardwareStatus);
++    MODULE_PUT;
++
++    return 0;
++}
++
++static int uap_hwstatus_proc_open(struct inode *inode, struct file *file) {
++      return single_open(file, uap_hwstatus_proc_show, PDE_DATA(inode));
++}
++
++static ssize_t uap_hwstatus_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) {
++      struct net_device *netdev = (struct net_device *)PDE_DATA(file_inode(file));
++      uap_private *priv = (uap_private *) netdev_priv(netdev);
++
++      int hwstatus;
++      char value[10];
++
++      if (count > sizeof(value))
++              return count;
++
++      if (copy_from_user(&value, buffer, count))
++              return -EFAULT;
++
++      hwstatus = string_to_number(value);
++      switch (hwstatus) {
++      case HWReset:
++              PRINTM(MSG, "reset hw\n");
++              uap_soft_reset(priv);
++              priv->adapter->HardwareStatus = HWReset;
++              break;
++      default:
++              break;
++      }
++
++      MODULE_PUT;
++      return count;
++}
++
++static const struct file_operations uap_info_proc_fops = {
++      .owner   = THIS_MODULE,
++      .open    = uap_info_proc_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = single_release,
++};
++
++static const struct file_operations uap_hwstatus_proc_fops = {
++      .owner   = THIS_MODULE,
++      .open    = uap_hwstatus_proc_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = single_release,
++      .write   = uap_hwstatus_proc_write,
++};
++
++/********************************************************
++              Global Functions
++********************************************************/
++/**
++ *  @brief create uap proc file
++ *
++ *  @param priv          pointer uap_private
++ *  @param dev     pointer net_device
++ *  @return      N/A
++ */
++void
++uap_proc_entry(uap_private * priv, struct net_device *dev)
++{
++    PRINTM(INFO, "Creating Proc Interface\n");
++    /* Check if uap directory already exists */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
++    struct proc_dir_entry *r = PROC_DIR;
++
++    for (r = r->subdir; r; r = r->next) {
++        if (r->namelen && !strcmp("uap", r->name)) {
++            /* Directory exists */
++            PRINTM(WARN, "proc directory already exists!\n");
++            priv->proc_uap = r;
++            break;
++        }
++    }
++#endif
++    if (!priv->proc_uap) {
++        priv->proc_uap = proc_mkdir("uap", PROC_DIR);
++        if (!priv->proc_uap)
++            return;
++    }
++    priv->proc_entry = proc_mkdir(dev->name, priv->proc_uap);
++
++    if (priv->proc_entry) {
++      proc_create_data("info", 0644, priv->proc_entry, &uap_info_proc_fops, dev);
++      proc_create_data("hwinfo", 0644, priv->proc_entry, &uap_hwstatus_proc_fops, dev);
++    }
++}
++
++/**
++ *  @brief remove proc file
++ *
++ *  @param priv          pointer uap_private
++ *  @return      N/A
++ */
++void
++uap_proc_remove(uap_private * priv)
++{
++    if (priv->proc_uap) {
++        if (priv->proc_entry) {
++            remove_proc_entry("info", priv->proc_entry);
++            remove_proc_entry("hwstatus", priv->proc_entry);
++        }
++        remove_proc_entry(priv->uap_dev.netdev->name, priv->proc_uap);
++    }
++}
++
++/**
++ *  @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);
++}
++
++#endif
+diff --git a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c
+new file mode 100644
+index 0000000..86f55b5
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c
+@@ -0,0 +1,1428 @@
++/** @file uap_sdio_mmc.c
++ *  @brief This file contains SDIO IF (interface) module
++ *  related functions.
++ *
++ * Copyright (C) 2007-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 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.
++ *
++ */
++/****************************************************
++Change log:
++****************************************************/
++
++#include      "uap_sdio_mmc.h"
++
++#include <linux/firmware.h>
++
++/** define SDIO block size */
++/* We support up to 480-byte block size due to FW buffer limitation. */
++#define SD_BLOCK_SIZE         256
++
++/** define allocated buffer size */
++#define ALLOC_BUF_SIZE                (((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
++                                      MRVDRV_SIZE_OF_CMD_BUFFER) + INTF_HEADER_LEN \
++                                      + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
++
++/** Max retry number of CMD53 write */
++#define MAX_WRITE_IOMEM_RETRY 2
++
++/********************************************************
++              Local Variables
++********************************************************/
++
++/** SDIO Rx unit */
++static u8 sdio_rx_unit = 0;
++
++/**Interrupt status */
++static u8 sd_ireg = 0;
++/********************************************************
++              Global Variables
++********************************************************/
++extern u8 *helper_name;
++extern u8 *fw_name;
++/** Default helper name */
++#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
++/** Default firmware name */
++#define DEFAULT_FW_NAME "mrvl/sd8688_ap.bin"
++
++/********************************************************
++              Local Functions
++********************************************************/
++/**
++ *  @brief This function reads the IO register.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param reg           register to be read
++ *  @param dat           A pointer to variable that keeps returned value
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sbi_read_ioreg(uap_private * priv, u32 reg, u8 * dat)
++{
++    struct sdio_mmc_card *card;
++    int ret = UAP_STATUS_FAILURE;
++
++    ENTER();
++
++    card = priv->uap_dev.card;
++    if (!card || !card->func) {
++        PRINTM(ERROR, "sbi_read_ioreg(): card or function is NULL!\n");
++        goto done;
++    }
++
++    *dat = sdio_readb(card->func, reg, &ret);
++    if (ret) {
++        PRINTM(ERROR, "sbi_read_ioreg(): sdio_readb failed! ret=%d\n", ret);
++        goto done;
++    }
++
++    PRINTM(INFO, "sbi_read_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
++           card->func->num, reg, *dat);
++
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function writes the IO register.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param reg           register to be written
++ *  @param dat           the value to be written
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sbi_write_ioreg(uap_private * priv, u32 reg, u8 dat)
++{
++    struct sdio_mmc_card *card;
++    int ret = UAP_STATUS_FAILURE;
++
++    ENTER();
++
++    card = priv->uap_dev.card;
++    if (!card || !card->func) {
++        PRINTM(ERROR, "sbi_write_ioreg(): card or function is NULL!\n");
++        goto done;
++    }
++
++    PRINTM(INFO, "sbi_write_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
++           card->func->num, reg, dat);
++
++    sdio_writeb(card->func, dat, reg, &ret);
++    if (ret) {
++        PRINTM(ERROR, "sbi_write_ioreg(): sdio_readb failed! ret=%d\n", ret);
++        goto done;
++    }
++
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function get rx_unit value
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sd_get_rx_unit(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u8 reg;
++
++    ENTER();
++
++    ret = sbi_read_ioreg(priv, CARD_RX_UNIT_REG, &reg);
++    if (ret == UAP_STATUS_SUCCESS)
++        sdio_rx_unit = reg;
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function reads rx length
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param dat           A pointer to keep returned data
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sd_read_rx_len(uap_private * priv, u16 * dat)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u8 reg;
++
++    ENTER();
++
++    ret = sbi_read_ioreg(priv, CARD_RX_LEN_REG, &reg);
++    if (ret == UAP_STATUS_SUCCESS)
++        *dat = (u16) reg << sdio_rx_unit;
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function reads fw status registers
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param dat           A pointer to keep returned data
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sd_read_firmware_status(uap_private * priv, u16 * dat)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u8 fws0;
++    u8 fws1;
++
++    ENTER();
++
++    ret = sbi_read_ioreg(priv, CARD_FW_STATUS0_REG, &fws0);
++    if (ret < 0) {
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    ret = sbi_read_ioreg(priv, CARD_FW_STATUS1_REG, &fws1);
++    if (ret < 0) {
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    *dat = (((u16) fws1) << 8) | fws0;
++
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function polls the card status register.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @param bits       the bit mask
++ *  @return           UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++mv_sdio_poll_card_status(uap_private * priv, u8 bits)
++{
++    int tries;
++    u8 cs;
++
++    ENTER();
++
++    for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
++        if (sbi_read_ioreg(priv, CARD_STATUS_REG, &cs) < 0)
++            break;
++        else if ((cs & bits) == bits) {
++            LEAVE();
++            return UAP_STATUS_SUCCESS;
++        }
++        udelay(10);
++    }
++
++    PRINTM(WARN, "mv_sdio_poll_card_status failed, tries = %d\n", tries);
++
++    LEAVE();
++    return UAP_STATUS_FAILURE;
++}
++
++/**
++ *  @brief This function set the sdio bus width.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @param mode       1--1 bit mode, 4--4 bit mode
++ *  @return           UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++#if 0
++static int
++sdio_set_bus_width(uap_private * priv, u8 mode)
++{
++    ENTER();
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++#endif
++
++/**
++ *  @brief This function reads data from the card.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @return           UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++sd_card_to_host(uap_private * priv)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u16 buf_len = 0;
++    int buf_block_len;
++    int blksz;
++    struct sk_buff *skb = NULL;
++    u16 type;
++    u8 *payload = NULL;
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "card or function is NULL!\n");
++        ret = UAP_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 = UAP_STATUS_FAILURE;
++        goto exit;
++    }
++
++    /* Allocate buffer */
++    blksz = SD_BLOCK_SIZE;
++    buf_block_len = (buf_len + blksz - 1) / blksz;
++    if (buf_len <= INTF_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
++        PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
++        ret = UAP_STATUS_FAILURE;
++        goto exit;
++    }
++#ifdef PXA3XX_DMA_ALIGN
++    skb = dev_alloc_skb(buf_block_len * blksz + PXA3XX_DMA_ALIGNMENT);
++#else
++    skb = dev_alloc_skb(buf_block_len * blksz);
++#endif
++    if (skb == NULL) {
++        PRINTM(WARN, "No free skb\n");
++        goto exit;
++    }
++#ifdef PXA3XX_DMA_ALIGN
++    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));
++    }
++#endif /* PXA3XX_DMA_ALIGN */
++
++    payload = skb->tail;
++    ret = sdio_readsb(card->func, payload, priv->uap_dev.ioport,
++                      buf_block_len * blksz);
++    if (ret < 0) {
++        PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
++        ret = UAP_STATUS_FAILURE;
++        goto exit;
++    }
++    HEXDUMP("SDIO Blk Rd", payload, blksz * buf_block_len);
++    /*
++     * This is SDIO specific header
++     *  u16 length,
++     *  u16 type (MV_TYPE_DAT = 0, MV_TYPE_CMD = 1, MV_TYPE_EVENT = 3)
++     */
++    buf_len = uap_le16_to_cpu(*(u16 *) & payload[0]);
++    type = uap_le16_to_cpu(*(u16 *) & payload[2]);
++    switch (type) {
++    case MV_TYPE_EVENT:
++        skb_put(skb, buf_len);
++        skb_pull(skb, INTF_HEADER_LEN);
++        uap_process_event(priv, skb->data, skb->len);
++        kfree_skb(skb);
++        skb = NULL;
++        break;
++    case MV_TYPE_CMD:
++        skb_put(skb, buf_len);
++        skb_pull(skb, INTF_HEADER_LEN);
++        priv->adapter->cmd_pending = FALSE;
++        if (priv->adapter->cmd_wait_option ==
++            HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM) {
++            priv->adapter->cmd_wait_option = FALSE;
++            uap_process_sleep_confirm_resp(priv, skb->data, skb->len);
++        } else if (priv->adapter->cmd_wait_option) {
++            memcpy(priv->adapter->CmdBuf, skb->data, skb->len);
++            priv->adapter->CmdSize = skb->len;
++            priv->adapter->cmd_wait_option = FALSE;
++            priv->adapter->CmdWaitQWoken = TRUE;
++            wake_up_interruptible(&priv->adapter->cmdwait_q);
++        }
++        kfree_skb(skb);
++        skb = NULL;
++        break;
++    case MV_TYPE_DAT:
++        skb_put(skb, buf_len);
++        skb_pull(skb, INTF_HEADER_LEN);
++        uap_process_rx_packet(priv, skb);
++        break;
++    default:
++        priv->stats.rx_errors++;
++        priv->stats.rx_dropped++;
++        /* Driver specified event and command resp should be handle here */
++        PRINTM(INFO, "Unknown PKT type:%d\n", type);
++        kfree_skb(skb);
++        skb = NULL;
++        break;
++    }
++  exit:
++    if (ret) {
++        if (skb)
++            kfree_skb(skb);
++    }
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function enables the host interrupts mask
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param mask          the interrupt mask
++ *  @return      UAP_STATUS_SUCCESS
++ */
++static int
++enable_host_int_mask(uap_private * priv, u8 mask)
++{
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++
++    /* Simply write the mask to the register */
++    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, mask);
++
++    if (ret) {
++        PRINTM(WARN, "Unable to enable the host interrupt!\n");
++        ret = UAP_STATUS_FAILURE;
++    }
++
++    LEAVE();
++    return ret;
++}
++
++/**  @brief This function disables the host interrupts mask.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param mask          the interrupt mask
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++disable_host_int_mask(uap_private * priv, u8 mask)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u8 host_int_mask;
++
++    ENTER();
++
++    /* Read back the host_int_mask register */
++    ret = sbi_read_ioreg(priv, HOST_INT_MASK_REG, &host_int_mask);
++    if (ret) {
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++
++    /* Update with the mask and write back to the register */
++    host_int_mask &= ~mask;
++    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, host_int_mask);
++    if (ret < 0) {
++        PRINTM(WARN, "Unable to diable the host interrupt!\n");
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++
++  done:
++    LEAVE();
++    return ret;
++}
++
++/********************************************************
++              Global Functions
++********************************************************/
++
++/**
++ *  @brief This function handles the interrupt.
++ *
++ *  @param func          A pointer to sdio_func structure.
++ *  @return      n/a
++ */
++static void
++sbi_interrupt(struct sdio_func *func)
++{
++    struct sdio_mmc_card *card;
++    uap_private *priv;
++    u8 ireg = 0;
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++
++    card = sdio_get_drvdata(func);
++    if (!card || !card->priv) {
++        PRINTM(MSG, "%s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
++               __FUNCTION__, func, card);
++        LEAVE();
++        return;
++    }
++    priv = card->priv;
++#ifdef FW_WAKEUP_TIME
++    if ((priv->adapter->wt_pwrup_sending != 0L) &&
++        (priv->adapter->wt_int == 0L))
++        priv->adapter->wt_int = get_utimeofday();
++#endif
++
++    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);
++        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;
++
++    uap_interrupt(priv);
++  done:
++    LEAVE();
++}
++
++/**
++ *  @brief This function probe the card
++ *
++ *  @param func    A pointer to sdio_func structure
++ *  @param id    A pointer to structure sd_device_id
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++static int
++uap_probe(struct sdio_func *func, const struct sdio_device_id *id)
++{
++    int ret = UAP_STATUS_FAILURE;
++    struct sdio_mmc_card *card = NULL;
++
++    ENTER();
++
++    PRINTM(MSG, "%s: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
++           __FUNCTION__, func->vendor, func->device, func->class, func->num);
++
++    card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
++    if (!card) {
++        ret = -ENOMEM;
++        goto done;
++    }
++
++    card->func = func;
++
++    if (!uap_add_card(card)) {
++        PRINTM(ERROR, "%s: uap_add_callback failed\n", __FUNCTION__);
++        kfree(card);
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++
++    ret = UAP_STATUS_SUCCESS;
++
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function removes the card
++ *
++ *  @param func    A pointer to sdio_func structure
++ *  @return        N/A
++ */
++static void
++uap_remove(struct sdio_func *func)
++{
++    struct sdio_mmc_card *card;
++
++    ENTER();
++
++    if (func) {
++        card = sdio_get_drvdata(func);
++        if (card) {
++            uap_remove_card(card);
++            kfree(card);
++        }
++    }
++
++    LEAVE();
++}
++
++#ifdef CONFIG_PM
++/**
++ *  @brief This function handles client driver suspend
++ *
++ *  @param func    A pointer to sdio_func structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++uap_suspend(struct sdio_func *func)
++{
++    ENTER();
++    LEAVE();
++    return 0;
++}
++
++/**
++ *  @brief This function handles client driver resume
++ *
++ *  @param func    A pointer to sdio_func structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++uap_resume(struct sdio_func *func)
++{
++    ENTER();
++    LEAVE();
++    return 0;
++}
++#endif
++
++/** Device ID for SD8688 */
++#define  SD_DEVICE_ID_8688_UAP 0x9104
++/** UAP IDs */
++static const struct sdio_device_id uap_ids[] = {
++    {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SD_DEVICE_ID_8688_UAP)},
++    {},
++};
++
++MODULE_DEVICE_TABLE(sdio, uap_ids);
++
++static struct sdio_driver uap_sdio = {
++    .name = "uap_sdio",
++    .id_table = uap_ids,
++    .probe = uap_probe,
++    .remove = uap_remove,
++#ifdef CONFIG_PM
++/*    .suspend        = uap_suspend, */
++/*    .resume = uap_resume, */
++#endif
++
++};
++
++/**
++ *  @brief This function registers the IF module in bus driver.
++ *
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int __init
++sbi_register()
++{
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++
++    /* SDIO Driver Registration */
++    if (sdio_register_driver(&uap_sdio) != 0) {
++        PRINTM(FATAL, "SDIO Driver Registration Failed \n");
++        ret = UAP_STATUS_FAILURE;
++    }
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function de-registers the IF module in bus driver.
++ *
++ *  @return      n/a
++ */
++void __exit
++sbi_unregister(void)
++{
++    ENTER();
++
++    /* SDIO Driver Unregistration */
++    sdio_unregister_driver(&uap_sdio);
++
++    LEAVE();
++}
++
++/**
++ *  @brief This function checks the interrupt status and handle it accordingly.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param ireg    A pointer to variable that keeps returned value
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_get_int_status(uap_private * priv, u8 * ireg)
++{
++    int ret = UAP_STATUS_SUCCESS;
++    u8 sdio_ireg = 0;
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++
++    ENTER();
++
++    *ireg = 0;
++    OS_INT_DISABLE;
++    sdio_ireg = sd_ireg;
++    sd_ireg = 0;
++    OS_INT_RESTORE;
++
++    sdio_claim_host(card->func);
++
++    if (sdio_ireg & DN_LD_HOST_INT_STATUS) {    /* tx_done INT */
++        if (!priv->uap_dev.cmd_sent) {  /* tx_done already received */
++            PRINTM(INFO,
++                   "warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
++                   priv->uap_dev.cmd_sent, sdio_ireg);
++        } else {
++            priv->uap_dev.cmd_sent = FALSE;
++            priv->uap_dev.data_sent = FALSE;
++            if ( (priv->uap_dev.netdev->reg_state == NETREG_REGISTERED) && (skb_queue_len(&priv->adapter->tx_queue) < TX_LOW_WATERMARK)) {
++                os_start_queue(priv);
++          }
++        }
++    }
++    if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
++        sd_card_to_host(priv);
++    }
++
++    *ireg = sdio_ireg;
++    ret = UAP_STATUS_SUCCESS;
++    sdio_release_host(card->func);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function disables the host interrupts.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_disable_host_int(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    int ret;
++
++    ENTER();
++
++    sdio_claim_host(card->func);
++    ret = disable_host_int_mask(priv, HIM_DISABLE);
++    sdio_release_host(card->func);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function enables the host interrupts.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS
++ */
++int
++sbi_enable_host_int(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    int ret;
++
++    ENTER();
++
++    sdio_claim_host(card->func);
++    ret = enable_host_int_mask(priv, HIM_ENABLE);
++    sdio_release_host(card->func);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function de-registers the device.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS
++ */
++int
++sbi_unregister_dev(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "Error: card or function is NULL!\n");
++        goto done;
++    }
++
++    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);
++
++  done:
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++
++/**
++ *  @brief This function registers the device.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_register_dev(uap_private * priv)
++{
++    int ret = UAP_STATUS_FAILURE;
++    u8 reg;
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    struct sdio_func *func;
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "Error: card or function is NULL!\n");
++        goto done;
++    }
++
++    func = card->func;
++
++    /* Initialize the private structure */
++    priv->uap_dev.ioport = 0;
++
++    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, sbi_interrupt);
++    if (ret) {
++        PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
++        goto disable_func;
++    }
++
++    /* Read the IO port */
++    ret = sbi_read_ioreg(priv, IO_PORT_0_REG, &reg);
++    if (ret)
++        goto release_irq;
++    else
++        priv->uap_dev.ioport |= reg;
++
++    ret = sbi_read_ioreg(priv, IO_PORT_1_REG, &reg);
++    if (ret)
++        goto release_irq;
++    else
++        priv->uap_dev.ioport |= (reg << 8);
++
++    ret = sbi_read_ioreg(priv, IO_PORT_2_REG, &reg);
++    if (ret)
++        goto release_irq;
++    else
++        priv->uap_dev.ioport |= (reg << 16);
++
++    PRINTM(INFO, "SDIO FUNC #%d IO port: 0x%x\n", func->num,
++           priv->uap_dev.ioport);
++
++    ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
++    if (ret) {
++        PRINTM(ERROR, "%s: cannot set SDIO block size\n", __FUNCTION__);
++        ret = UAP_STATUS_FAILURE;
++        goto release_irq;
++    }
++    priv->hotplug_device = &func->dev;
++
++    if (helper_name == NULL) {
++        helper_name = DEFAULT_HELPER_NAME;
++    }
++    if (fw_name == NULL) {
++        fw_name = DEFAULT_FW_NAME;
++    }
++    sdio_release_host(func);
++
++    sdio_set_drvdata(func, card);
++
++    ret = UAP_STATUS_SUCCESS;
++    goto done;
++
++  release_irq:
++    sdio_release_irq(func);
++  disable_func:
++    sdio_disable_func(func);
++  release_host:
++    sdio_release_host(func);
++
++  done:
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function sends data to the card.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param payload A pointer to the data/cmd buffer
++ *  @param nb    the length of data/cmd
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    int ret = UAP_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 UAP_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
++    priv->uap_dev.cmd_sent = TRUE;
++    priv->uap_dev.data_sent = TRUE;
++    do {
++        /* Transfer data to card */
++        ret = sdio_writesb(card->func, priv->uap_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 = UAP_STATUS_FAILURE;
++            if (i > MAX_WRITE_IOMEM_RETRY)
++                goto exit;
++        } else {
++            HEXDUMP("SDIO Blk Wr", payload, nb);
++        }
++    } while (ret == UAP_STATUS_FAILURE);
++  exit:
++    sdio_release_host(card->func);
++#ifdef PXA3XX_DMA_ALIGN
++    if (tmpbuf)
++        kfree(tmpbuf);
++#endif
++    if (ret == UAP_STATUS_FAILURE) {
++        priv->uap_dev.cmd_sent = FALSE;
++        priv->uap_dev.data_sent = FALSE;
++    }
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function reads CIS information.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param cisinfo A pointer to CIS information output buffer
++ *  @param cislen  A pointer to length of CIS info output buffer
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++#if 0
++static int
++sbi_get_cis_info(uap_private * priv, void *cisinfo, int *cislen)
++{
++#define CIS_PTR (0x8000)
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    unsigned int i, cis_ptr = CIS_PTR;
++    int ret = UAP_STATUS_FAILURE;
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "sbi_get_cis_info(): card or function is NULL!\n");
++        goto exit;
++    }
++#define MAX_SDIO_CIS_INFO_LEN (256)
++    if (!cisinfo || (*cislen < MAX_SDIO_CIS_INFO_LEN)) {
++        PRINTM(WARN, "ERROR! get_cis_info: insufficient buffer passed\n");
++        goto exit;
++    }
++
++    *cislen = MAX_SDIO_CIS_INFO_LEN;
++
++    sdio_claim_host(card->func);
++
++    PRINTM(INFO, "cis_ptr=%#x\n", cis_ptr);
++
++    /* Read the Tuple Data */
++    for (i = 0; i < *cislen; i++) {
++        ((unsigned char *) cisinfo)[i] =
++            sdio_readb(card->func, cis_ptr + i, &ret);
++        if (ret) {
++            PRINTM(WARN, "get_cis_info error: ret=%d\n", ret);
++            ret = UAP_STATUS_FAILURE;
++            goto done;
++        }
++        PRINTM(INFO, "cisinfo[%d]=%#x\n", i, ((unsigned char *) cisinfo)[i]);
++    }
++
++  done:
++    sdio_release_host(card->func);
++  exit:
++    LEAVE();
++    return ret;
++}
++#endif
++/**
++ *  @brief This function downloads helper image to the card.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @return           UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_prog_helper(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    u8 *helper = NULL;
++    int helperlen;
++    int ret = UAP_STATUS_SUCCESS;
++    void *tmphlprbuf = NULL;
++    int tmphlprbufsz;
++    u8 *hlprbuf;
++    int hlprblknow;
++    u32 tx_len;
++#ifdef FW_DOWNLOAD_SPEED
++    u32 tv1, tv2;
++#endif
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "sbi_prog_helper(): card or function is NULL!\n");
++        goto done;
++    }
++
++    if (priv->fw_helper) {
++        helper = (u8 *) priv->fw_helper->data;
++        helperlen = priv->fw_helper->size;
++    } else {
++        PRINTM(MSG, "No helper image found! Terminating download.\n");
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
++           helperlen, SD_BLOCK_SIZE);
++
++#ifdef FW_DOWNLOAD_SPEED
++    tv1 = get_utimeofday();
++#endif
++
++#ifdef PXA3XX_DMA_ALIGN
++    tmphlprbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
++#else /* !PXA3XX_DMA_ALIGN */
++    tmphlprbufsz = UAP_UPLD_SIZE;
++#endif /* !PXA3XX_DMA_ALIGN */
++    tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
++    if (!tmphlprbuf) {
++        PRINTM(ERROR,
++               "Unable to allocate buffer for helper. Terminating download\n");
++        ret = UAP_STATUS_FAILURE;
++        goto done;
++    }
++    memset(tmphlprbuf, 0, tmphlprbufsz);
++#ifdef PXA3XX_DMA_ALIGN
++    hlprbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, PXA3XX_DMA_ALIGNMENT);
++#else /* !PXA3XX_DMA_ALIGN */
++    hlprbuf = (u8 *) tmphlprbuf;
++#endif /* !PXA3XX_DMA_ALIGN */
++
++    sdio_claim_host(card->func);
++
++    /* Perform helper data transfer */
++    tx_len = (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE) - INTF_HEADER_LEN;
++    hlprblknow = 0;
++    do {
++        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
++        ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
++        if (ret < 0) {
++            PRINTM(FATAL, "Helper download poll status timeout @ %d\n",
++                   hlprblknow);
++            goto done;
++        }
++
++        /* More data? */
++        if (hlprblknow >= helperlen)
++            break;
++
++        /* Set blocksize to transfer - checking for last block */
++        if (helperlen - hlprblknow < tx_len)
++            tx_len = helperlen - hlprblknow;
++
++        /* Set length to the 4-byte header */
++        *(u32 *) hlprbuf = uap_cpu_to_le32(tx_len);
++
++        /* Copy payload to buffer */
++        memcpy(&hlprbuf[INTF_HEADER_LEN], &helper[hlprblknow], tx_len);
++
++        PRINTM(INFO, ".");
++
++        /* Send data */
++        ret = sdio_writesb(card->func, priv->uap_dev.ioport,
++                           hlprbuf, FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE);
++
++        if (ret < 0) {
++            PRINTM(FATAL, "IO error during helper download @ %d\n", hlprblknow);
++            goto done;
++        }
++
++        hlprblknow += tx_len;
++    } while (TRUE);
++
++#ifdef FW_DOWNLOAD_SPEED
++    tv2 = get_utimeofday();
++    PRINTM(INFO, "helper: %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
++
++    /* Write last EOF data */
++    PRINTM(INFO, "\nTransferring helper image EOF block\n");
++    memset(hlprbuf, 0x0, SD_BLOCK_SIZE);
++    ret = sdio_writesb(card->func, priv->uap_dev.ioport,
++                       hlprbuf, SD_BLOCK_SIZE);
++
++    if (ret < 0) {
++        PRINTM(FATAL, "IO error in writing helper image EOF block\n");
++        goto done;
++    }
++
++    ret = UAP_STATUS_SUCCESS;
++
++  done:
++    sdio_release_host(card->func);
++    if (tmphlprbuf)
++        kfree(tmphlprbuf);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function downloads firmware image to the card.
++ *
++ *  @param priv       A pointer to uap_private structure
++ *  @return           UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_prog_fw_w_helper(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    u8 *firmware = NULL;
++    int firmwarelen;
++    u8 base0;
++    u8 base1;
++    int ret = UAP_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 (!card || !card->func) {
++        PRINTM(ERROR, "sbi_prog_fw_w_helper(): card or function is NULL!\n");
++        goto done;
++    }
++
++    if (priv->firmware) {
++        firmware = (u8 *) priv->firmware->data;
++        firmwarelen = priv->firmware->size;
++    } else {
++        PRINTM(MSG, "No firmware image found! Terminating download.\n");
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++
++    PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
++
++#ifdef FW_DOWNLOAD_SPEED
++    tv1 = get_utimeofday();
++#endif
++
++#ifdef PXA3XX_DMA_ALIGN
++    tmpfwbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
++#else /* PXA3XX_DMA_ALIGN */
++    tmpfwbufsz = UAP_UPLD_SIZE;
++#endif /* PXA3XX_DMA_ALIGN */
++    tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
++    if (!tmpfwbuf) {
++        PRINTM(ERROR,
++               "Unable to allocate buffer for firmware. Terminating download.\n");
++        ret = UAP_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 /* PXA3XX_DMA_ALIGN */
++
++    sdio_claim_host(card->func);
++
++    /* Perform firmware data transfer */
++    offset = 0;
++    do {
++        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
++        ret = mv_sdio_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++) {
++            if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_0, &base0)) < 0) {
++                PRINTM(WARN, "Dev BASE0 register read failed:"
++                       " base0=0x%04X(%d). Terminating download.\n", base0,
++                       base0);
++                ret = UAP_STATUS_FAILURE;
++                goto done;
++            }
++            if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_1, &base1)) < 0) {
++                PRINTM(WARN, "Dev BASE1 register read failed:"
++                       " base1=0x%04X(%d). Terminating download.\n", base1,
++                       base1);
++                ret = UAP_STATUS_FAILURE;
++                goto done;
++            }
++            len = (((u16) base1) << 8) | base0;
++
++            /* For SD8688 wait until the length is not 0, 1 or 2 before
++               downloading the first FW block, since BOOT code writes the
++               register to indicate the helper/FW download winner, the value
++               could be 1 or 2 (Func1 or Func2). */
++            if ((len && offset) || (len > 2))
++                break;
++            udelay(10);
++        }
++
++        if (len == 0)
++            break;
++        else if (len > UAP_UPLD_SIZE) {
++            PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
++                   offset, len);
++            ret = UAP_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 = UAP_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 - 1) / SD_BLOCK_SIZE;
++
++            /* Copy payload to buffer */
++            memcpy(fwbuf, &firmware[offset], txlen);
++        }
++
++        /* Send data */
++        ret = sdio_writesb(card->func, priv->uap_dev.ioport,
++                           fwbuf, tx_blocks * SD_BLOCK_SIZE);
++
++        if (ret < 0) {
++            PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
++                   offset);
++            if (sbi_write_ioreg(priv, CONFIGURATION_REG, 0x04) < 0) {
++                PRINTM(ERROR, "write ioreg failed (CFG)\n");
++            }
++        }
++
++        offset += txlen;
++    } while (TRUE);
++
++    PRINTM(INFO, "\nFW download over, size %d bytes\n", offset);
++
++    ret = UAP_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
++    sdio_release_host(card->func);
++    if (tmpfwbuf)
++        kfree(tmpfwbuf);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function checks if the firmware is ready to accept
++ *  command or not.
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param pollnum Poll number
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_check_fw_status(uap_private * priv, int pollnum)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    int ret = UAP_STATUS_SUCCESS;
++    u16 firmwarestat;
++    int tries;
++
++    ENTER();
++
++    sdio_claim_host(card->func);
++
++    /* Wait for firmware initialization event */
++    for (tries = 0; tries < pollnum; tries++) {
++        if ((ret = sd_read_firmware_status(priv, &firmwarestat)) < 0)
++            continue;
++        if (firmwarestat == FIRMWARE_READY) {
++            ret = UAP_STATUS_SUCCESS;
++            break;
++        } else {
++            mdelay(10);
++            ret = UAP_STATUS_FAILURE;
++        }
++    }
++
++    if (ret < 0)
++        goto done;
++
++    ret = UAP_STATUS_SUCCESS;
++    sd_get_rx_unit(priv);
++
++  done:
++    sdio_release_host(card->func);
++
++    LEAVE();
++    return ret;
++}
++
++/**
++ *  @brief This function set bus clock on/off
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @param option    TRUE--on , FALSE--off
++ *  @return      UAP_STATUS_SUCCESS
++ */
++#if 0
++static int
++sbi_set_bus_clock(uap_private * priv, u8 option)
++{
++    ENTER();
++    LEAVE();
++    return UAP_STATUS_SUCCESS;
++}
++#endif
++
++/**
++ *  @brief This function wakeup firmware
++ *
++ *  @param priv    A pointer to uap_private structure
++ *  @return      UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
++ */
++int
++sbi_wakeup_firmware(uap_private * priv)
++{
++    struct sdio_mmc_card *card = priv->uap_dev.card;
++    int ret = UAP_STATUS_SUCCESS;
++
++    ENTER();
++
++    if (!card || !card->func) {
++        PRINTM(ERROR, "card or function is NULL!\n");
++        LEAVE();
++        return UAP_STATUS_FAILURE;
++    }
++    sdio_claim_host(card->func);
++    sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
++    sdio_release_host(card->func);
++    LEAVE();
++    return ret;
++}
+diff --git a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h
+new file mode 100644
+index 0000000..191c67f
+--- /dev/null
++++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h
+@@ -0,0 +1,136 @@
++/** @file uap_sdio_mmc.h
++ *  @brief This file contains SDIO IF (interface) module
++ *  related macros, enum, and structure.
++ *
++ * Copyright (C) 2007-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 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.
++ *
++ */
++/****************************************************
++Change log:
++      10/10/07: initial version
++****************************************************/
++
++#ifndef       _UAP_SDIO_MMC_H
++#define       _UAP_SDIO_MMC_H
++
++#include      <linux/mmc/sdio.h>
++#include      <linux/mmc/sdio_ids.h>
++#include      <linux/mmc/sdio_func.h>
++#include      <linux/mmc/card.h>
++
++#include      "uap_headers.h"
++
++/** The number of times to try when waiting for downloaded firmware to
++     become active. (polling the scratch register). */
++#define MAX_FIRMWARE_POLL_TRIES               100
++
++/** Firmware ready */
++#define FIRMWARE_READY                        0xfedc
++
++/** Number of firmware blocks to transfer */
++#define FIRMWARE_TRANSFER_NBLOCK      2
++
++/* Host Control Registers */
++/** Host Control Registers : I/O port 0 */
++#define IO_PORT_0_REG                 0x00
++/** Host Control Registers : I/O port 1 */
++#define IO_PORT_1_REG                 0x01
++/** Host Control Registers : I/O port 2 */
++#define IO_PORT_2_REG                 0x02
++
++/** Host Control Registers : Configuration */
++#define CONFIGURATION_REG             0x03
++/** 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             0x04
++/** 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            0x05
++/** 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 F1 read base 0 */
++#define HOST_F1_RD_BASE_0             0x10
++/** Host F1 read base 1 */
++#define HOST_F1_RD_BASE_1             0x11
++
++/** Card Control Registers : Card status register */
++#define CARD_STATUS_REG               0x20
++/** 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 : Card OCR 0 register */
++#define CARD_OCR_0_REG                0x34
++/** Card Control Registers : Card OCR 1 register */
++#define CARD_OCR_1_REG                0x35
++
++/** Firmware status 0 register */
++#define CARD_FW_STATUS0_REG           0x40
++/** Firmware status 1 register */
++#define CARD_FW_STATUS1_REG           0x41
++/** Rx length register */
++#define CARD_RX_LEN_REG                       0x42
++/** Rx unit register */
++#define CARD_RX_UNIT_REG              0x43
++
++/** Chip Id Register 0 */
++#define CARD_CHIP_ID_0_REG            0x801c
++/** Chip Id Register 1 */
++#define CARD_CHIP_ID_1_REG            0x801d
++
++#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_DMA_ALIGN */
++
++struct sdio_mmc_card
++{
++        /** sdio_func structure pointer */
++    struct sdio_func *func;
++        /** uap_private structure pointer */
++    uap_private *priv;
++};
++
++#endif /* _UAP_SDIO_MMC_H */