Home | History | Annotate | Download | only in src
      1 /*
      2  * WlanDrvIf.c
      3  *
      4  * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  *  * Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *  * Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *  * Neither the name Texas Instruments nor the names of its
     18  *    contributors may be used to endorse or promote products derived
     19  *    from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 
     35 /*
     36  * src/esta_drv.c
     37  *
     38  * Kernel level portion of eSTA DK Linux module driver
     39  *
     40  */
     41 
     42 
     43 /** \file   WlanDrvIf.c
     44  *  \brief  The OS-Dependent interfaces of the WLAN driver with external applications:
     45  *          - Configuration utilities (including download, configuration and activation)
     46  *          - Network Stack (Tx and Rx)
     47  *          - Interrupts
     48  *          - Events to external applications
     49  *
     50  *  \see    WlanDrvIf.h, Wext.c
     51  */
     52 
     53 
     54 #include <net/sock.h>
     55 #include <linux/etherdevice.h>
     56 #include <linux/delay.h>
     57 #include <linux/netlink.h>
     58 
     59 #include "WlanDrvIf.h"
     60 #include "osApi.h"
     61 #include "host_platform.h"
     62 #include "context.h"
     63 #include "CmdHndlr.h"
     64 #include "WlanDrvWext.h"
     65 #include "DrvMain.h"
     66 #include "txDataQueue_Api.h"
     67 #include "txMgmtQueue_Api.h"
     68 #include "TWDriver.h"
     69 #include "Ethernet.h"
     70 #ifdef TI_DBG
     71 #include "tracebuf_api.h"
     72 #endif
     73 /* PM hooks */
     74 #ifdef TI_CONFIG_PM_HOOKS
     75 #include "SdioDrv.h"
     76 static int wlanDrvIf_pm_resume(void);
     77 static int wlanDrvIf_pm_suspend(void);
     78 #endif
     79 #include "bmtrace_api.h"
     80 #ifdef STACK_PROFILE
     81 #include "stack_profile.h"
     82 #endif
     83 
     84 /* save driver handle just for module cleanup */
     85 static TWlanDrvIfObj *pDrvStaticHandle;
     86 
     87 #define OS_SPECIFIC_RAM_ALLOC_LIMIT			(0xFFFFFFFF)	/* assume OS never reach that limit */
     88 
     89 
     90 MODULE_DESCRIPTION("TI WLAN Embedded Station Driver");
     91 MODULE_LICENSE("GPL");
     92 
     93 
     94 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
     95 static int wlanDrvIf_Xmit(struct sk_buff *skb, struct net_device *dev);
     96 static int wlanDrvIf_XmitDummy(struct sk_buff *skb, struct net_device *dev);
     97 static struct net_device_stats *wlanDrvIf_NetGetStat(struct net_device *dev);
     98 int wlanDrvIf_Open(struct net_device *dev);
     99 int wlanDrvIf_Release(struct net_device *dev);
    100 
    101 static struct net_device_ops tiwlan_ops_pri = {
    102 	.ndo_open = wlanDrvIf_Open,
    103 	.ndo_stop = wlanDrvIf_Release,
    104 	.ndo_get_stats = wlanDrvIf_NetGetStat,
    105 	.ndo_do_ioctl = NULL,
    106 	.ndo_start_xmit = wlanDrvIf_Xmit,
    107 };
    108 
    109 static struct net_device_ops tiwlan_ops_dummy = {
    110 	.ndo_open = wlanDrvIf_Open,
    111 	.ndo_stop = wlanDrvIf_Release,
    112 	.ndo_get_stats = wlanDrvIf_NetGetStat,
    113 	.ndo_do_ioctl = NULL,
    114 	.ndo_start_xmit = wlanDrvIf_XmitDummy,
    115 };
    116 #endif
    117 
    118 /**
    119  * \fn     wlanDrvIf_Xmit
    120  * \brief  Packets transmission
    121  *
    122  * The network stack calls this function in order to transmit a packet
    123  *     through the WLAN interface.
    124  * The packet is inserted to the drver Tx queues and its handling is continued
    125  *     after switching to the driver context.
    126  *
    127  * \note
    128  * \param  skb - The Linux packet buffer structure
    129  * \param  dev - The driver network-interface handle
    130  * \return 0 (= OK)
    131  * \sa
    132  */
    133 static int wlanDrvIf_Xmit (struct sk_buff *skb, struct net_device *dev)
    134 {
    135 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    136 	TTxCtrlBlk *  pPktCtrlBlk;
    137 	int status;
    138 
    139 	CL_TRACE_START_L1();
    140 
    141 	os_profile (drv, 0, 0);
    142 	drv->stats.tx_packets++;
    143 	drv->stats.tx_bytes += skb->len;
    144 
    145 	/* Allocate a TxCtrlBlk for the Tx packet and save timestamp, length and packet handle */
    146 	pPktCtrlBlk = TWD_txCtrlBlk_Alloc (drv->tCommon.hTWD);
    147 
    148 	pPktCtrlBlk->tTxDescriptor.startTime    = os_timeStampMs(drv); /* remove use of skb->tstamp.off_usec */
    149 	pPktCtrlBlk->tTxDescriptor.length       = skb->len;
    150 	pPktCtrlBlk->tTxPktParams.pInputPkt     = skb;
    151 
    152 	/* Point the first BDL buffer to the Ethernet header, and the second buffer to the rest of the packet */
    153 	pPktCtrlBlk->tTxnStruct.aBuf[0] = skb->data;
    154 	pPktCtrlBlk->tTxnStruct.aLen[0] = ETHERNET_HDR_LEN;
    155 	pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN;
    156 	pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN;
    157 	pPktCtrlBlk->tTxnStruct.aLen[2] = 0;
    158 
    159 	/* Send the packet to the driver for transmission. */
    160 	status = txDataQ_InsertPacket (drv->tCommon.hTxDataQ, pPktCtrlBlk,(TI_UINT8)skb->priority);
    161 
    162 	/* If failed (queue full or driver not running), drop the packet. */
    163     if (status != TI_OK)
    164     {
    165         drv->stats.tx_errors++;
    166     }
    167 	os_profile (drv, 1, 0);
    168 
    169 	CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", "");
    170 
    171 	return 0;
    172 }
    173 /*--------------------------------------------------------------------------------------*/
    174 /**
    175  * \fn     wlanDrvIf_FreeTxPacket
    176  * \brief  Free the OS Tx packet
    177  *
    178  * Free the OS Tx packet after driver processing is finished.
    179  *
    180  * \note
    181  * \param  hOs          - The OAL object handle
    182  * \param  pPktCtrlBlk  - The packet CtrlBlk
    183  * \param  eStatus      - The packet transmission status (OK/NOK)
    184  * \return void
    185  * \sa
    186  */
    187 /*--------------------------------------------------------------------------------------*/
    188 
    189 void wlanDrvIf_FreeTxPacket (TI_HANDLE hOs, TTxCtrlBlk *pPktCtrlBlk, TI_STATUS eStatus)
    190 {
    191 	dev_kfree_skb((struct sk_buff *)pPktCtrlBlk->tTxPktParams.pInputPkt);
    192 }
    193 
    194 /**
    195  * \fn     wlanDrvIf_XmitDummy
    196  * \brief  Dummy transmission handler
    197  *
    198  * This function is registered at the network stack interface as the packets-transmission
    199  *     handler (replacing wlanDrvIf_Xmit) when the driver is not operational.
    200  * Using this dummy handler is more efficient then checking the driver state for every
    201  *     packet transmission.
    202  *
    203  * \note
    204  * \param  skb - The Linux packet buffer structure
    205  * \param  dev - The driver network-interface handle
    206  * \return error
    207  * \sa     wlanDrvIf_Xmit
    208  */
    209 static int wlanDrvIf_XmitDummy (struct sk_buff *skb, struct net_device *dev)
    210 {
    211 	/* Just return error. The driver is not running (network stack frees the packet) */
    212 	return -ENODEV;
    213 }
    214 
    215 
    216 /**
    217  * \fn     wlanDrvIf_NetGetStat
    218  * \brief  Provides driver statistics
    219  *
    220  * Provides driver Tx and Rx statistics to network stack.
    221  *
    222  * \note
    223  * \param  dev - The driver network-interface handle
    224  * \return The statistics pointer
    225  * \sa
    226  */
    227 static struct net_device_stats *wlanDrvIf_NetGetStat (struct net_device *dev)
    228 {
    229 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    230 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_NetGetStat()\n");
    231 
    232 	return &drv->stats;
    233 }
    234 
    235 
    236 /**
    237  * \fn     wlanDrvIf_UpdateDriverState
    238  * \brief  Update the driver state
    239  *
    240  * The DrvMain uses this function to update the OAL with the driver steady state
    241  *     that is relevant for the driver users.
    242  *
    243  * \note
    244  * \param  hOs          - The driver object handle
    245  * \param  eDriverState - The new driver state
    246  * \return void
    247  * \sa
    248  */
    249 void wlanDrvIf_UpdateDriverState (TI_HANDLE hOs, EDriverSteadyState eDriverState)
    250 {
    251 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
    252 
    253 	ti_dprintf(TIWLAN_LOG_OTHER, "wlanDrvIf_UpdateDriverState(): State = %d\n", eDriverState);
    254 
    255 	/* Save the new state */
    256 	drv->tCommon.eDriverState = eDriverState;
    257 
    258 	/* If the new state is not RUNNING, replace the Tx handler to a dummy one. */
    259 	if (eDriverState != DRV_STATE_RUNNING) {
    260 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
    261 		drv->netdev->hard_start_xmit = wlanDrvIf_XmitDummy;
    262 #else
    263 		drv->netdev->netdev_ops = &tiwlan_ops_dummy;
    264 #endif
    265 	}
    266 }
    267 
    268 
    269 /**
    270  * \fn     wlanDrvIf_HandleInterrupt
    271  * \brief  The WLAN interrupt handler
    272  *
    273  * The WLAN driver interrupt handler called in the interrupt context.
    274  * The actual handling is done in the driver's context after switching to the workqueue.
    275  *
    276  * \note
    277  * \param  irq      - The interrupt type
    278  * \param  hDrv     - The driver object handle
    279  * \param  cpu_regs - The CPU registers
    280  * \return IRQ_HANDLED
    281  * \sa
    282  */
    283 irqreturn_t wlanDrvIf_HandleInterrupt (int irq, void *hDrv, struct pt_regs *cpu_regs)
    284 {
    285 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
    286 
    287 	TWD_InterruptRequest (drv->tCommon.hTWD);
    288 
    289 	return IRQ_HANDLED;
    290 }
    291 
    292 
    293 /**
    294  * \fn     PollIrqHandler
    295  * \brief  WLAN IRQ polling handler - for debug!
    296  *
    297  * A debug option to catch the WLAN events in polling instead of interrupts.
    298  * A timer calls this function periodically to check the interrupt status register.
    299  *
    300  * \note
    301  * \param  parm - The driver object handle
    302  * \return void
    303  * \sa
    304  */
    305 #ifdef PRIODIC_INTERRUPT
    306 static void wlanDrvIf_PollIrqHandler (TI_HANDLE parm)
    307 {
    308 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)parm;
    309 
    310 	wlanDrvIf_HandleInterrupt (0, drv, NULL);
    311 	os_periodicIntrTimerStart (drv);
    312 }
    313 #endif
    314 
    315 
    316 /**
    317  * \fn     wlanDrvIf_DriverTask
    318  * \brief  The driver task
    319  *
    320  * This is the driver's task, where most of its job is done.
    321  * External contexts just save required information and schedule the driver's
    322  *     task to continue the handling.
    323  * See more information in the context engine module (context.c).
    324  *
    325  * \note
    326  * \param  hDrv - The driver object handle
    327  * \return void
    328  * \sa
    329  */
    330 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
    331 static void wlanDrvIf_DriverTask (void *hDrv)
    332 {
    333 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
    334 #else
    335 static void wlanDrvIf_DriverTask(struct work_struct *work)
    336 {
    337 #ifdef STACK_PROFILE
    338 	register unsigned long sp asm ("sp");
    339 	unsigned long local_sp = sp;
    340 #endif
    341 	TWlanDrvIfObj *drv = container_of(work, TWlanDrvIfObj, tWork);
    342 #endif
    343 
    344 #ifdef STACK_PROFILE
    345 	unsigned long curr1, base1;
    346 	unsigned long curr2, base2;
    347 	static unsigned long maximum_stack = 0;
    348 #endif
    349 	os_profile (drv, 0, 0);
    350 
    351 #ifdef STACK_PROFILE
    352 	curr1 = check_stack_start(&base1, local_sp + 4, 0);
    353 #endif
    354 
    355 	/* Call the driver main task */
    356 	context_DriverTask (drv->tCommon.hContext);
    357 
    358 	os_profile (drv, 1, 0);
    359 	os_wake_lock_timeout(drv);
    360 	os_wake_unlock(drv);
    361 #ifdef STACK_PROFILE
    362 	curr2 = check_stack_stop(&base2, 0);
    363 	if (base2 == base1) {
    364 	/* if the current measurement is bigger then the maximum store it and print*/
    365 		if ((curr1 - curr2) > maximum_stack) {
    366 			printk("STACK PROFILER GOT THE LOCAL MAXIMMUM!!!! \n");
    367 			printk("current operation stack use=%lu \n",(curr1 - curr2));
    368 			printk("total stack use=%lu \n",8192 - curr2 + base2);
    369 			printk("total stack usage=%lu percent \n",100 * (8192 - curr2 + base2) / 8192);
    370 			maximum_stack = curr1 - curr2;
    371 		}
    372 	}
    373 #endif
    374 }
    375 
    376 
    377 /**
    378  * \fn     wlanDrvIf_LoadFiles
    379  * \brief  Load init files from loader
    380  *
    381  * This function is called from the loader context right after the driver
    382  *     is created (in IDLE state).
    383  * It copies the following files to the driver's memory:
    384  *     - Ini-File - The driver's default parameters values
    385  *     - NVS-File - The NVS data for FW usage
    386  *     - FW-Image - The FW program image
    387  *
    388  * \note
    389  * \param  drv - The driver object handle
    390  * \return void
    391  * \sa     wlanDrvIf_GetFile
    392  */
    393 int wlanDrvIf_LoadFiles (TWlanDrvIfObj *drv, TLoaderFilesData *pInitFiles)
    394 {
    395     if (!pInitFiles)
    396     {
    397         ti_dprintf (TIWLAN_LOG_ERROR, "No Init Files!\n");
    398         return -EINVAL;
    399     }
    400 
    401     if (drv->tCommon.eDriverState != DRV_STATE_IDLE)
    402     {
    403         ti_dprintf (TIWLAN_LOG_ERROR, "Trying to load files not in IDLE state!\n");
    404         return -EINVAL;
    405     }
    406 
    407     if (pInitFiles->uIniFileLength)
    408     {
    409         drv->tCommon.tIniFile.uSize = pInitFiles->uIniFileLength;
    410         drv->tCommon.tIniFile.pImage = kmalloc (pInitFiles->uIniFileLength, GFP_KERNEL);
    411         #ifdef TI_MEM_ALLOC_TRACE
    412           os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, pInitFiles->uIniFileLength, GFP_KERNEL, pInitFiles->uIniFileLength);
    413         #endif
    414         if (!drv->tCommon.tIniFile.pImage)
    415         {
    416             ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for Ini-File!\n");
    417             return -ENOMEM;
    418         }
    419         memcpy (drv->tCommon.tIniFile.pImage,
    420                 &pInitFiles->data[pInitFiles->uNvsFileLength + pInitFiles->uFwFileLength],
    421                 drv->tCommon.tIniFile.uSize);
    422     }
    423 
    424     if (pInitFiles->uNvsFileLength)
    425     {
    426         drv->tCommon.tNvsImage.uSize = pInitFiles->uNvsFileLength;
    427         drv->tCommon.tNvsImage.pImage = kmalloc (drv->tCommon.tNvsImage.uSize, GFP_KERNEL);
    428         #ifdef TI_MEM_ALLOC_TRACE
    429           os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n",
    430               __FUNCTION__, __LINE__, drv->tCommon.tNvsImage.uSize, GFP_KERNEL, drv->tCommon.tNvsImage.uSize);
    431         #endif
    432         if (!drv->tCommon.tNvsImage.pImage)
    433         {
    434             ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for NVS image\n");
    435             return -ENOMEM;
    436         }
    437         memcpy (drv->tCommon.tNvsImage.pImage, &pInitFiles->data[0], drv->tCommon.tNvsImage.uSize );
    438     }
    439 
    440     drv->tCommon.tFwImage.uSize = pInitFiles->uFwFileLength;
    441     if (!drv->tCommon.tFwImage.uSize)
    442     {
    443         ti_dprintf (TIWLAN_LOG_ERROR, "No firmware image\n");
    444         return -EINVAL;
    445     }
    446     drv->tCommon.tFwImage.pImage = os_memoryAlloc (drv, drv->tCommon.tFwImage.uSize);
    447     #ifdef TI_MEM_ALLOC_TRACE
    448       os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n",
    449           __FUNCTION__, __LINE__, drv->tCommon.tFwImage.uSize, GFP_KERNEL, drv->tCommon.tFwImage.uSize);
    450     #endif
    451     if (!drv->tCommon.tFwImage.pImage)
    452     {
    453         ti_dprintf(TIWLAN_LOG_ERROR, "Cannot allocate buffer for firmware image\n");
    454         return -ENOMEM;
    455     }
    456     memcpy (drv->tCommon.tFwImage.pImage,
    457             &pInitFiles->data[pInitFiles->uNvsFileLength],
    458             drv->tCommon.tFwImage.uSize);
    459 
    460     ti_dprintf(TIWLAN_LOG_OTHER, "--------- Eeeprom=%p(%lu), Firmware=%p(%lu), IniFile=%p(%lu)\n",
    461         drv->tCommon.tNvsImage.pImage, drv->tCommon.tNvsImage.uSize,
    462         drv->tCommon.tFwImage.pImage,  drv->tCommon.tFwImage.uSize,
    463         drv->tCommon.tIniFile.pImage,  drv->tCommon.tIniFile.uSize);
    464 
    465     return 0;
    466 }
    467 
    468 
    469 /**
    470  * \fn     wlanDrvIf_GetFile
    471  * \brief  Provides access to a requested init file
    472  *
    473  * Provide the requested file information and call the requester callback.
    474  * Note that in Linux the files were previously loaded to driver memory
    475  *     by the loader (see wlanDrvIf_LoadFiles).
    476  *
    477  * \note
    478  * \param  hOs       - The driver object handle
    479  * \param  pFileInfo - The requested file's properties
    480  * \return TI_OK
    481  * \sa     wlanDrvIf_LoadFiles
    482  */
    483 int wlanDrvIf_GetFile (TI_HANDLE hOs, TFileInfo *pFileInfo)
    484 {
    485 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
    486 
    487 	if (drv == NULL || pFileInfo == NULL) {
    488 		ti_dprintf(TIWLAN_LOG_ERROR, "wlanDrv_GetFile: ERROR: Null File Handler, Exiting");
    489 		return TI_NOK;
    490 	}
    491 
    492 	/* Future option for getting the FW image part by part */
    493 	pFileInfo->hOsFileDesc = NULL;
    494 
    495 	/* Fill the file's location and size in the file's info structure */
    496 	switch (pFileInfo->eFileType)
    497 	{
    498 	case FILE_TYPE_INI:
    499 		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tIniFile.pImage;
    500 		pFileInfo->uLength = drv->tCommon.tIniFile.uSize;
    501 		break;
    502 	case FILE_TYPE_NVS:
    503 		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tNvsImage.pImage;
    504 		pFileInfo->uLength = drv->tCommon.tNvsImage.uSize;
    505 		break;
    506 	case FILE_TYPE_FW:
    507 		if (drv->tCommon.tFwImage.pImage == NULL)
    508 		{
    509 			ti_dprintf(TIWLAN_LOG_ERROR, "wlanDrv_GetFile: ERROR: no Firmware image, exiting\n");
    510 			return TI_NOK;
    511 		}
    512 
    513 		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tFwImage.pImage;
    514 		pFileInfo->bLast		= TI_FALSE;
    515 		pFileInfo->uLength	= 0;
    516 		pFileInfo->uOffset 				= 0;
    517 		pFileInfo->uChunkBytesLeft 		= 0;
    518 		pFileInfo->uChunksLeft 			= BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
    519 		/* check uChunksLeft's Validity */
    520 		if (( pFileInfo->uChunksLeft == 0 ) || ( pFileInfo->uChunksLeft > MAX_CHUNKS_IN_FILE ))
    521 		{
    522 			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() Read Invalid Chunks Left: %d!\n",pFileInfo->uChunksLeft);
    523 			return TI_NOK;
    524 		}
    525 		pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
    526 		/* FALL THROUGH */
    527 	case FILE_TYPE_FW_NEXT:
    528 		/* check dec. validity */
    529 		if ( pFileInfo->uChunkBytesLeft >= pFileInfo->uLength )
    530 		{
    531 			pFileInfo->uChunkBytesLeft 		-= pFileInfo->uLength;
    532 		}
    533 		/* invalid Dec. */
    534 		else
    535 		{
    536 			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() No. of Bytes Left < File Length\n");
    537 			return TI_NOK;
    538 		}
    539 		pFileInfo->pBuffer 	+= pFileInfo->uLength;
    540 
    541 		/* Finished reading all Previous Chunk */
    542 		if ( pFileInfo->uChunkBytesLeft == 0 )
    543 		{
    544 			/* check dec. validity */
    545 			if ( pFileInfo->uChunksLeft > 0 )
    546 			{
    547 				pFileInfo->uChunksLeft--;
    548 			}
    549 			/* invalid Dec. */
    550 			else
    551 			{
    552 				ti_dprintf (TIWLAN_LOG_ERROR, "No. of Bytes Left = 0 and Chunks Left <= 0\n");
    553 				return TI_NOK;
    554 			}
    555 			/* read Chunk's address */
    556 			pFileInfo->uAddress = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
    557 			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
    558 			/* read Portion's length */
    559 			pFileInfo->uChunkBytesLeft = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
    560 			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
    561 		}
    562 		/* Reading Chunk is NOT complete */
    563 		else
    564 		{
    565 			pFileInfo->uAddress += pFileInfo->uLength;
    566 		}
    567 
    568 		if ( pFileInfo->uChunkBytesLeft < OS_SPECIFIC_RAM_ALLOC_LIMIT )
    569 		{
    570 			pFileInfo->uLength = pFileInfo->uChunkBytesLeft;
    571 		}
    572 		else
    573 		{
    574 			pFileInfo->uLength = OS_SPECIFIC_RAM_ALLOC_LIMIT;
    575 		}
    576 
    577 		/* If last chunk to download */
    578 		if (( pFileInfo->uChunksLeft == 0 ) &&
    579 			( pFileInfo->uLength == pFileInfo->uChunkBytesLeft ))
    580 		{
    581 			pFileInfo->bLast = TI_TRUE;
    582 		}
    583 
    584 		break;
    585 	}
    586 
    587 	/* Call the requester callback */
    588 	if (pFileInfo->fCbFunc)
    589 	{
    590 		pFileInfo->fCbFunc (pFileInfo->hCbHndl);
    591 	}
    592 
    593 	return TI_OK;
    594 }
    595 
    596 
    597 /**
    598  * \fn     wlanDrvIf_SetMacAddress
    599  * \brief  Set STA MAC address
    600  *
    601  * Called by DrvMain from init process.
    602  * Copies STA MAC address to the network interface structure.
    603  *
    604  * \note
    605  * \param  hOs      - The driver object handle
    606  * \param  pMacAddr - The STA MAC address
    607  * \return TI_OK
    608  * \sa     wlanDrvIf_LoadFiles
    609  */
    610 void wlanDrvIf_SetMacAddress (TI_HANDLE hOs, TI_UINT8 *pMacAddr)
    611 {
    612 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
    613 
    614 	/* Copy STA MAC address to the network interface structure */
    615 	MAC_COPY (drv->netdev->dev_addr, pMacAddr);
    616 }
    617 
    618 
    619 /**
    620  * \fn     wlanDrvIf_Start
    621  * \brief  Start driver
    622  *
    623  * Called by network stack upon opening network interface (ifconfig up).
    624  * Can also be called from user application or CLI for flight mode.
    625  * Start the driver initialization process up to OPERATIONAL state.
    626  *
    627  * \note
    628  * \param  dev - The driver network-interface handle
    629  * \return 0 if succeeded, error if driver not available
    630  * \sa     wlanDrvIf_Stop
    631  */
    632 int wlanDrvIf_Start (struct net_device *dev)
    633 {
    634 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    635 	int status;
    636 
    637 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Start()\n");
    638 	printk("%s\n", __func__);
    639     if (!drv->tCommon.hDrvMain)
    640     {
    641 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Start() Driver not created!\n");
    642 		return -ENODEV;
    643 	}
    644 
    645 	if (DRV_STATE_FAILED == drv->tCommon.eDriverState)
    646 	{
    647 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Start() Driver failed!\n");
    648 		return -ENODEV;
    649 	}
    650 
    651 	/*
    652 	 *  Insert Start command in DrvMain action queue, request driver scheduling
    653 	 *      and wait for action completion (all init process).
    654 	 */
    655 	os_wake_lock_timeout_enable(drv);
    656 	status = drvMain_InsertAction (drv->tCommon.hDrvMain, ACTION_TYPE_START);
    657 	return (status) ? -1 : 0;
    658 }
    659 
    660 int wlanDrvIf_Open (struct net_device *dev)
    661 {
    662 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    663 	int status = 0;
    664 
    665 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Open()\n");
    666 	printk("%s\n", __func__);
    667 	if (!drv->tCommon.hDrvMain) {
    668 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Open() Driver not created!\n");
    669 		return -ENODEV;
    670 	}
    671 
    672 	if (drv->tCommon.eDriverState == DRV_STATE_STOPPED ||
    673 	    drv->tCommon.eDriverState == DRV_STATE_IDLE) {
    674 		status = wlanDrvIf_Start(dev);
    675 	}
    676 
    677 	/*
    678 	 *  Finalize network interface setup
    679 	 */
    680 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
    681 	drv->netdev->hard_start_xmit = wlanDrvIf_Xmit;
    682 #else
    683 	drv->netdev->netdev_ops = &tiwlan_ops_pri;
    684 #endif
    685 	drv->netdev->addr_len = MAC_ADDR_LEN;
    686 	netif_start_queue (dev);
    687 
    688 	/* register 3430 PM hooks in our SDIO driver */
    689 #ifdef TI_CONFIG_PM_HOOKS
    690 #ifndef CONFIG_MMC_EMBEDDED_SDIO
    691 	sdioDrv_register_pm(wlanDrvIf_pm_resume, wlanDrvIf_pm_suspend);
    692 #endif
    693 #endif
    694 	return status;
    695 }
    696 
    697 /**
    698  * \fn     wlanDrvIf_Stop
    699  * \brief  Stop driver
    700  *
    701  * Called by network stack upon closing network interface (ifconfig down).
    702  * Can also be called from user application or CLI for flight mode.
    703  * Stop the driver and turn off the device.
    704  *
    705  * \note
    706  * \param  dev - The driver network-interface handle
    707  * \return 0 (OK)
    708  * \sa     wlanDrvIf_Start
    709  */
    710 int wlanDrvIf_Stop (struct net_device *dev)
    711 {
    712 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    713 
    714 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Stop()\n");
    715 	printk("%s\n", __func__);
    716 
    717 	if (DRV_STATE_FAILED == drv->tCommon.eDriverState)
    718 	{
    719 		return -ENODEV;
    720 	}
    721 
    722 	/*
    723 	 *  Insert Stop command in DrvMain action queue, request driver scheduling
    724 	 *      and wait for Stop process completion.
    725 	 */
    726 	os_wake_lock_timeout_enable(drv);
    727 	drvMain_InsertAction (drv->tCommon.hDrvMain, ACTION_TYPE_STOP);
    728 	return 0;
    729 }
    730 
    731 int wlanDrvIf_Release (struct net_device *dev)
    732 {
    733 	/* TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev); */
    734 
    735 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Release()\n");
    736 	printk("%s\n", __func__);
    737 	/* Disable network interface queue */
    738 	netif_stop_queue (dev);
    739 	return 0;
    740 }
    741 
    742 /* 3430 PM hooks */
    743 #ifdef TI_CONFIG_PM_HOOKS
    744 static int wlanDrvIf_pm_resume(void)
    745 {
    746     return(wlanDrvIf_Open(pDrvStaticHandle->netdev));
    747 }
    748 
    749 static int wlanDrvIf_pm_suspend(void)
    750 {
    751     wlanDrvIf_Release(pDrvStaticHandle->netdev);
    752     return(wlanDrvIf_Stop(pDrvStaticHandle->netdev));
    753 }
    754 #endif
    755 
    756 /**
    757  * \fn     wlanDrvIf_SetupNetif
    758  * \brief  Setup driver network interface
    759  *
    760  * Called in driver creation process.
    761  * Setup driver network interface.
    762  *
    763  * \note
    764  * \param  drv - The driver object handle
    765  * \return 0 - OK, else - failure
    766  * \sa
    767  */
    768 static int wlanDrvIf_SetupNetif (TWlanDrvIfObj *drv)
    769 {
    770 	struct net_device *dev;
    771 	int res;
    772 
    773 	/* Allocate network interface structure for the driver */
    774 	dev = alloc_etherdev (0);
    775 	if (dev == NULL)
    776 	{
    777 		ti_dprintf (TIWLAN_LOG_ERROR, "alloc_etherdev() failed\n");
    778 		return -ENOMEM;
    779 	}
    780 
    781 	/* Setup the network interface */
    782 	ether_setup (dev);
    783 
    784 	NETDEV_SET_PRIVATE(dev,drv);
    785 	drv->netdev = dev;
    786 	strcpy (dev->name, TIWLAN_DRV_IF_NAME);
    787 	netif_carrier_off (dev);
    788 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
    789 /* the following is required on at least BSP 23.8 and higher.
    790     Without it, the Open function of the driver will not be called
    791     when trying to 'ifconfig up' the interface */
    792 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
    793 	dev->validate_addr = NULL;
    794 #endif
    795 	dev->open = wlanDrvIf_Open;
    796 	dev->stop = wlanDrvIf_Release;
    797 	dev->hard_start_xmit = wlanDrvIf_XmitDummy;
    798 	dev->get_stats = wlanDrvIf_NetGetStat;
    799 	dev->do_ioctl = NULL;
    800 #else
    801 	dev->netdev_ops = &tiwlan_ops_dummy;
    802 #endif
    803 	dev->tx_queue_len = 100;
    804 
    805 	/* Initialize Wireless Extensions interface (WEXT) */
    806 	wlanDrvWext_Init (dev);
    807 
    808 	res = register_netdev (dev);
    809 	if (res != 0)
    810 	{
    811 		ti_dprintf (TIWLAN_LOG_ERROR, "register_netdev() failed : %d\n", res);
    812 		kfree (dev);
    813 		return res;
    814 	}
    815 /*
    816 On the latest Kernel there is no more support for the below macro.
    817 */
    818 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
    819 	SET_MODULE_OWNER (dev);
    820 #endif
    821 	return 0;
    822 }
    823 
    824 /**
    825  * \fn     wlanDrvIf_CommandDone
    826  * \brief  Free current command semaphore.
    827  *
    828  * This routine is called whenever a command has finished executing and Free current command semaphore.
    829  *
    830  * \note
    831  * \param  hOs           - The driver object handle
    832  * \param  pSignalObject - handle to complete mechanism per OS
    833  * \param  CmdResp_p     - respond structure (TCmdRespUnion) for OSE OS only
    834  * \return 0 - OK, else - failure
    835  * \sa     wlanDrvIf_Destroy
    836  */
    837 void wlanDrvIf_CommandDone (TI_HANDLE hOs, void *pSignalObject, TI_UINT8 *CmdResp_p)
    838 {
    839 	/* Free semaphore */
    840 	os_SignalObjectSet (hOs, pSignalObject);
    841 }
    842 
    843 
    844 /**
    845  * \fn     wlanDrvIf_Create
    846  * \brief  Create the driver instance
    847  *
    848  * Allocate driver object.
    849  * Initialize driver OS resources (IRQ, workqueue, events socket)
    850  * Setup driver network interface.
    851  * Create and link all driver modules.
    852  *
    853  * \note
    854  * \param  void
    855  * \return 0 - OK, else - failure
    856  * \sa     wlanDrvIf_Destroy
    857  */
    858 static int wlanDrvIf_Create (void)
    859 {
    860 	TWlanDrvIfObj *drv; /* Dm: Failure is not cleaned properly !!! */
    861 	int rc;
    862 
    863 	/* Allocate driver's structure */
    864 	drv = kmalloc (sizeof(TWlanDrvIfObj), GFP_KERNEL);
    865     if (!drv)
    866     {
    867 		return -ENOMEM;
    868 	}
    869 #ifdef TI_DBG
    870 	tb_init(TB_OPTION_NONE);
    871 #endif
    872 	pDrvStaticHandle = drv;  /* save for module destroy */
    873 #ifdef TI_MEM_ALLOC_TRACE
    874 	os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, sizeof(TWlanDrvIfObj), GFP_KERNEL, sizeof(TWlanDrvIfObj));
    875 #endif
    876 	memset (drv, 0, sizeof(TWlanDrvIfObj));
    877 
    878 	/* Dm:    drv->irq = TNETW_IRQ; */
    879 	drv->tCommon.eDriverState = DRV_STATE_IDLE;
    880 
    881 	drv->tiwlan_wq = create_freezeable_workqueue(DRIVERWQ_NAME);
    882 	if (!drv->tiwlan_wq) {
    883 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Create(): Failed to create workQ!\n");
    884 		rc = -EINVAL;
    885 		goto drv_create_end_1;
    886 	}
    887 	drv->wl_packet = 0;
    888 	drv->wl_count = 0;
    889 #ifdef CONFIG_HAS_WAKELOCK
    890 	wake_lock_init(&drv->wl_wifi, WAKE_LOCK_SUSPEND, "wifi_wake");
    891 	wake_lock_init(&drv->wl_rxwake, WAKE_LOCK_SUSPEND, "wifi_rx_wake");
    892 #endif
    893 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
    894 	INIT_WORK(&drv->tWork, wlanDrvIf_DriverTask, (void *)drv);
    895 #else
    896 	INIT_WORK(&drv->tWork, wlanDrvIf_DriverTask);
    897 #endif
    898 	spin_lock_init (&drv->lock);
    899 
    900 	/* Setup driver network interface. */
    901 	rc = wlanDrvIf_SetupNetif (drv);
    902 	if (rc)	{
    903 		goto drv_create_end_2;
    904 	}
    905 
    906 	/* Create the events socket interface */
    907 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
    908 	drv->wl_sock = netlink_kernel_create( NETLINK_USERSOCK, 0, NULL, THIS_MODULE );
    909 #else
    910 	drv->wl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0, NULL, NULL, THIS_MODULE );
    911 #endif
    912 	if (drv->wl_sock == NULL) {
    913 	        ti_dprintf (TIWLAN_LOG_ERROR, "netlink_kernel_create() failed !\n");
    914 		rc = -EINVAL;
    915 		goto drv_create_end_3;
    916 	}
    917 
    918 	/* Create all driver modules and link their handles */
    919 	rc = drvMain_Create (drv,
    920 			&drv->tCommon.hDrvMain,
    921 			&drv->tCommon.hCmdHndlr,
    922 			&drv->tCommon.hContext,
    923 			&drv->tCommon.hTxDataQ,
    924 			&drv->tCommon.hTxMgmtQ,
    925 			&drv->tCommon.hTxCtrl,
    926 			&drv->tCommon.hTWD,
    927 					&drv->tCommon.hEvHandler,
    928                     &drv->tCommon.hCmdDispatch,
    929 		&drv->tCommon.hReport);
    930 	if (rc != TI_OK) {
    931 		ti_dprintf (TIWLAN_LOG_ERROR, "%s: Failed to dvrMain_Create!\n", __func__);
    932 		rc = -EINVAL;
    933 		goto drv_create_end_4;
    934 	}
    935 	/*
    936 	 *  Initialize interrupts (or polling mode for debug):
    937 	 */
    938 #ifdef PRIODIC_INTERRUPT
    939 	/* Debug mode: Polling (the timer is started by HwInit process) */
    940 	drv->hPollTimer = os_timerCreate ((TI_HANDLE)drv, wlanDrvIf_PollIrqHandler, (TI_HANDLE)drv);
    941 #else
    942 	/* Normal mode: Interrupts (the default mode) */
    943 	rc = hPlatform_initInterrupt (drv, (void*)wlanDrvIf_HandleInterrupt);
    944 	if (rc)	{
    945 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Create(): Failed to register interrupt handler!\n");
    946 		goto drv_create_end_5;
    947 	}
    948 #endif  /* PRIODIC_INTERRUPT */
    949 	return 0;
    950 drv_create_end_5:
    951 	/* Destroy all driver modules */
    952 	if (drv->tCommon.hDrvMain) {
    953 		drvMain_Destroy (drv->tCommon.hDrvMain);
    954 	}
    955 drv_create_end_4:
    956 	if (drv->wl_sock) {
    957 		sock_release (drv->wl_sock->sk_socket);
    958 	}
    959 
    960 drv_create_end_3:
    961 	/* Release the driver network interface */
    962 	if (drv->netdev) {
    963 		unregister_netdev (drv->netdev);
    964 		free_netdev (drv->netdev);
    965 	}
    966 
    967 drv_create_end_2:
    968 #ifdef CONFIG_HAS_WAKELOCK
    969 	wake_lock_destroy(&drv->wl_wifi);
    970 	wake_lock_destroy(&drv->wl_rxwake);
    971 #endif
    972 	if (drv->tiwlan_wq)
    973 		destroy_workqueue(drv->tiwlan_wq);
    974 
    975 drv_create_end_1:
    976 	kfree(drv);
    977 	printk("%s: Fail\n", __func__);
    978 	return rc;
    979 }
    980 
    981 
    982 /**
    983  * \fn     wlanDrvIf_Destroy
    984  * \brief  Destroy the driver instance
    985  *
    986  * Destroy all driver modules.
    987  * Release driver OS resources (IRQ, workqueue, events socket)
    988  * Release driver network interface.
    989  * Free init files memory.
    990  * Free driver object.
    991  *
    992  * \note
    993  * \param  drv - The driver object handle
    994  * \return void
    995  * \sa     wlanDrvIf_Create
    996  */
    997 static void wlanDrvIf_Destroy (TWlanDrvIfObj *drv)
    998 {
    999 	if (!drv)
   1000 		return;
   1001 
   1002 	if (drv->tiwlan_wq) {
   1003 		cancel_work_sync(&drv->tWork);
   1004 		flush_workqueue(drv->tiwlan_wq);
   1005 	}
   1006 
   1007 	/* Release the driver network interface */
   1008 	if (drv->netdev) {
   1009 		netif_stop_queue  (drv->netdev);
   1010 		wlanDrvIf_Stop    (drv->netdev);
   1011 		unregister_netdev (drv->netdev);
   1012 		free_netdev (drv->netdev);
   1013 	}
   1014 
   1015 	/* Destroy all driver modules */
   1016 	if (drv->tCommon.hDrvMain) {
   1017 		drvMain_Destroy (drv->tCommon.hDrvMain);
   1018 	}
   1019 
   1020 	/* close the ipc_kernel socket*/
   1021     if (drv && drv->wl_sock)
   1022     {
   1023 		sock_release (drv->wl_sock->sk_socket);
   1024 	}
   1025 	/* Release the driver interrupt (or polling timer) */
   1026 #ifdef PRIODIC_INTERRUPT
   1027 	os_timerDestroy (drv, drv->hPollTimer);
   1028 #else
   1029     if (drv->irq)
   1030     {
   1031 		hPlatform_freeInterrupt(drv);
   1032 	}
   1033 #endif
   1034 	if (drv->tiwlan_wq)
   1035 		destroy_workqueue(drv->tiwlan_wq);
   1036 
   1037 #ifdef CONFIG_HAS_WAKELOCK
   1038 	wake_lock_destroy(&drv->wl_wifi);
   1039 	wake_lock_destroy(&drv->wl_rxwake);
   1040 #endif
   1041 	/*
   1042 	 *  Free init files memory
   1043 	 */
   1044     if (drv->tCommon.tFwImage.pImage)
   1045     {
   1046         os_memoryFree (drv, drv->tCommon.tFwImage.pImage, drv->tCommon.tFwImage.uSize);
   1047         #ifdef TI_MEM_ALLOC_TRACE
   1048           os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
   1049               __FUNCTION__, __LINE__, drv->tCommon.tFwImage.uSize, -drv->tCommon.tFwImage.uSize);
   1050         #endif
   1051     }
   1052     if (drv->tCommon.tNvsImage.pImage)
   1053     {
   1054         kfree (drv->tCommon.tNvsImage.pImage);
   1055         #ifdef TI_MEM_ALLOC_TRACE
   1056           os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
   1057               __FUNCTION__, __LINE__, drv->tCommon.tNvsImage.uSize, -drv->tCommon.tNvsImage.uSize);
   1058         #endif
   1059     }
   1060     if (drv->tCommon.tIniFile.pImage)
   1061     {
   1062         kfree (drv->tCommon.tIniFile.pImage);
   1063         #ifdef TI_MEM_ALLOC_TRACE
   1064           os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
   1065               __FUNCTION__, __LINE__, drv->tCommon.tIniFile.uSize, -drv->tCommon.tIniFile.uSize);
   1066         #endif
   1067     }
   1068 
   1069     /* Free the driver object */
   1070 #ifdef TI_DBG
   1071 	tb_destroy();
   1072 #endif
   1073 	kfree (drv);
   1074 }
   1075 
   1076 
   1077 /**
   1078  * \fn     wlanDrvIf_ModuleInit  &  wlanDrvIf_ModuleExit
   1079  * \brief  Linux Init/Exit functions
   1080  *
   1081  * The driver Linux Init/Exit functions (insmod/rmmod)
   1082  *
   1083  * \note
   1084  * \param  void
   1085  * \return Init: 0 - OK, else - failure.   Exit: void
   1086  * \sa     wlanDrvIf_Create, wlanDrvIf_Destroy
   1087  */
   1088 #ifndef TI_SDIO_STANDALONE
   1089 static int sdc_ctrl = 2;
   1090 module_param(sdc_ctrl, int, S_IRUGO | S_IWUSR | S_IWGRP);
   1091 
   1092 extern int sdioDrv_init(int sdcnum);
   1093 extern void sdioDrv_exit(void);
   1094 #endif
   1095 
   1096 static int __init wlanDrvIf_ModuleInit (void)
   1097 {
   1098 	printk(KERN_INFO "TIWLAN: driver init\n");
   1099 #ifndef TI_SDIO_STANDALONE
   1100 #ifndef CONFIG_MMC_EMBEDDED_SDIO
   1101 	sdioDrv_init(sdc_ctrl);
   1102 #endif
   1103 #endif
   1104 	return wlanDrvIf_Create ();
   1105 }
   1106 
   1107 static void __exit wlanDrvIf_ModuleExit (void)
   1108 {
   1109 	wlanDrvIf_Destroy (pDrvStaticHandle);
   1110 #ifndef TI_SDIO_STANDALONE
   1111 #ifndef CONFIG_MMC_EMBEDDED_SDIO
   1112 	sdioDrv_exit();
   1113 #endif
   1114 #endif
   1115 	printk (KERN_INFO "TI WLAN: driver unloaded\n");
   1116 }
   1117 
   1118 
   1119 /**
   1120  * \fn     wlanDrvIf_StopTx
   1121  * \brief  block Tx thread until wlanDrvIf_ResumeTx called .
   1122  *
   1123  * This routine is called whenever we need to stop the network stack to send us pakets since one of our Q's is full.
   1124  *
   1125  * \note
   1126  * \param  hOs           - The driver object handle
   1127 * \return
   1128  * \sa     wlanDrvIf_StopTx
   1129  */
   1130 void wlanDrvIf_StopTx (TI_HANDLE hOs)
   1131 {
   1132     TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
   1133 
   1134     netif_stop_queue (drv->netdev);
   1135 }
   1136 
   1137 /**
   1138  * \fn     wlanDrvIf_ResumeTx
   1139  * \brief  Resume Tx thread .
   1140  *
   1141  * This routine is called whenever we need to resume the network stack to send us pakets since our Q's are empty.
   1142  *
   1143  * \note
   1144  * \param  hOs           - The driver object handle
   1145  * \return
   1146  * \sa     wlanDrvIf_ResumeTx
   1147  */
   1148 void wlanDrvIf_ResumeTx (TI_HANDLE hOs)
   1149 {
   1150     TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
   1151 
   1152     netif_wake_queue (drv->netdev);
   1153 }
   1154 
   1155 module_init (wlanDrvIf_ModuleInit);
   1156 module_exit (wlanDrvIf_ModuleExit);
   1157