• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
wlanDrvIf_Xmit(struct sk_buff * skb,struct net_device * dev)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 		drv->stats.tx_errors++;
165 	}
166 	os_profile (drv, 1, 0);
167 
168 	CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", "");
169 
170 	return 0;
171 }
172 /*--------------------------------------------------------------------------------------*/
173 /**
174  * \fn     wlanDrvIf_FreeTxPacket
175  * \brief  Free the OS Tx packet
176  *
177  * Free the OS Tx packet after driver processing is finished.
178  *
179  * \note
180  * \param  hOs          - The OAL object handle
181  * \param  pPktCtrlBlk  - The packet CtrlBlk
182  * \param  eStatus      - The packet transmission status (OK/NOK)
183  * \return void
184  * \sa
185  */
186 /*--------------------------------------------------------------------------------------*/
187 
wlanDrvIf_FreeTxPacket(TI_HANDLE hOs,TTxCtrlBlk * pPktCtrlBlk,TI_STATUS eStatus)188 void wlanDrvIf_FreeTxPacket (TI_HANDLE hOs, TTxCtrlBlk *pPktCtrlBlk, TI_STATUS eStatus)
189 {
190 	dev_kfree_skb((struct sk_buff *)pPktCtrlBlk->tTxPktParams.pInputPkt);
191 }
192 
193 /**
194  * \fn     wlanDrvIf_XmitDummy
195  * \brief  Dummy transmission handler
196  *
197  * This function is registered at the network stack interface as the packets-transmission
198  *     handler (replacing wlanDrvIf_Xmit) when the driver is not operational.
199  * Using this dummy handler is more efficient then checking the driver state for every
200  *     packet transmission.
201  *
202  * \note
203  * \param  skb - The Linux packet buffer structure
204  * \param  dev - The driver network-interface handle
205  * \return error
206  * \sa     wlanDrvIf_Xmit
207  */
wlanDrvIf_XmitDummy(struct sk_buff * skb,struct net_device * dev)208 static int wlanDrvIf_XmitDummy (struct sk_buff *skb, struct net_device *dev)
209 {
210 	/* Just return error. The driver is not running (network stack frees the packet) */
211 	return -ENODEV;
212 }
213 
214 
215 /**
216  * \fn     wlanDrvIf_NetGetStat
217  * \brief  Provides driver statistics
218  *
219  * Provides driver Tx and Rx statistics to network stack.
220  *
221  * \note
222  * \param  dev - The driver network-interface handle
223  * \return The statistics pointer
224  * \sa
225  */
wlanDrvIf_NetGetStat(struct net_device * dev)226 static struct net_device_stats *wlanDrvIf_NetGetStat (struct net_device *dev)
227 {
228 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
229 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_NetGetStat()\n");
230 
231 	return &drv->stats;
232 }
233 
234 
235 /**
236  * \fn     wlanDrvIf_UpdateDriverState
237  * \brief  Update the driver state
238  *
239  * The DrvMain uses this function to update the OAL with the driver steady state
240  *     that is relevant for the driver users.
241  *
242  * \note
243  * \param  hOs          - The driver object handle
244  * \param  eDriverState - The new driver state
245  * \return void
246  * \sa
247  */
wlanDrvIf_UpdateDriverState(TI_HANDLE hOs,EDriverSteadyState eDriverState)248 void wlanDrvIf_UpdateDriverState (TI_HANDLE hOs, EDriverSteadyState eDriverState)
249 {
250 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
251 
252 	ti_dprintf(TIWLAN_LOG_OTHER, "wlanDrvIf_UpdateDriverState(): State = %d\n", eDriverState);
253 
254 	/* Save the new state */
255 	drv->tCommon.eDriverState = eDriverState;
256 
257 	/* If the new state is not RUNNING, replace the Tx handler to a dummy one. */
258 	if (eDriverState != DRV_STATE_RUNNING) {
259 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
260 		drv->netdev->hard_start_xmit = wlanDrvIf_XmitDummy;
261 #else
262 		drv->netdev->netdev_ops = &tiwlan_ops_dummy;
263 #endif
264 	}
265 }
266 
267 
268 /**
269  * \fn     wlanDrvIf_HandleInterrupt
270  * \brief  The WLAN interrupt handler
271  *
272  * The WLAN driver interrupt handler called in the interrupt context.
273  * The actual handling is done in the driver's context after switching to the workqueue.
274  *
275  * \note
276  * \param  irq      - The interrupt type
277  * \param  hDrv     - The driver object handle
278  * \param  cpu_regs - The CPU registers
279  * \return IRQ_HANDLED
280  * \sa
281  */
wlanDrvIf_HandleInterrupt(int irq,void * hDrv,struct pt_regs * cpu_regs)282 irqreturn_t wlanDrvIf_HandleInterrupt (int irq, void *hDrv, struct pt_regs *cpu_regs)
283 {
284 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
285 
286 	TWD_InterruptRequest (drv->tCommon.hTWD);
287 
288 	return IRQ_HANDLED;
289 }
290 
291 
292 /**
293  * \fn     PollIrqHandler
294  * \brief  WLAN IRQ polling handler - for debug!
295  *
296  * A debug option to catch the WLAN events in polling instead of interrupts.
297  * A timer calls this function periodically to check the interrupt status register.
298  *
299  * \note
300  * \param  parm - The driver object handle
301  * \return void
302  * \sa
303  */
304 #ifdef PRIODIC_INTERRUPT
wlanDrvIf_PollIrqHandler(TI_HANDLE parm)305 static void wlanDrvIf_PollIrqHandler (TI_HANDLE parm)
306 {
307 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)parm;
308 
309 	wlanDrvIf_HandleInterrupt (0, drv, NULL);
310 	os_periodicIntrTimerStart (drv);
311 }
312 #endif
313 
314 
315 /**
316  * \fn     wlanDrvIf_DriverTask
317  * \brief  The driver task
318  *
319  * This is the driver's task, where most of its job is done.
320  * External contexts just save required information and schedule the driver's
321  *     task to continue the handling.
322  * See more information in the context engine module (context.c).
323  *
324  * \note
325  * \param  hDrv - The driver object handle
326  * \return void
327  * \sa
328  */
329 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
wlanDrvIf_DriverTask(void * hDrv)330 static void wlanDrvIf_DriverTask (void *hDrv)
331 {
332 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
333 #else
334 static void wlanDrvIf_DriverTask(struct work_struct *work)
335 {
336 #ifdef STACK_PROFILE
337 	register unsigned long sp asm ("sp");
338 	unsigned long local_sp = sp;
339 #endif
340 	TWlanDrvIfObj *drv = container_of(work, TWlanDrvIfObj, tWork);
341 #endif
342 
343 #ifdef STACK_PROFILE
344 	unsigned long curr1, base1;
345 	unsigned long curr2, base2;
346 	static unsigned long maximum_stack = 0;
347 #endif
348 	os_profile (drv, 0, 0);
349 
350 #ifdef STACK_PROFILE
351 	curr1 = check_stack_start(&base1, local_sp + 4, 0);
352 #endif
353 
354 	/* Call the driver main task */
355 	context_DriverTask (drv->tCommon.hContext);
356 
357 	os_profile (drv, 1, 0);
358 	os_wake_lock_timeout(drv);
359 	os_wake_unlock(drv);
360 #ifdef STACK_PROFILE
361 	curr2 = check_stack_stop(&base2, 0);
362 	if (base2 == base1) {
363 	/* if the current measurement is bigger then the maximum store it and print*/
364 		if ((curr1 - curr2) > maximum_stack) {
365 			printk("STACK PROFILER GOT THE LOCAL MAXIMMUM!!!! \n");
366 			printk("current operation stack use=%lu \n",(curr1 - curr2));
367 			printk("total stack use=%lu \n",8192 - curr2 + base2);
368 			printk("total stack usage=%lu percent \n",100 * (8192 - curr2 + base2) / 8192);
369 			maximum_stack = curr1 - curr2;
370 		}
371 	}
372 #endif
373 }
374 
375 
376 /**
377  * \fn     wlanDrvIf_LoadFiles
378  * \brief  Load init files from loader
379  *
380  * This function is called from the loader context right after the driver
381  *     is created (in IDLE state).
382  * It copies the following files to the driver's memory:
383  *     - Ini-File - The driver's default parameters values
384  *     - NVS-File - The NVS data for FW usage
385  *     - FW-Image - The FW program image
386  *
387  * \note
388  * \param  drv - The driver object handle
389  * \return void
390  * \sa     wlanDrvIf_GetFile
391  */
392 int wlanDrvIf_LoadFiles (TWlanDrvIfObj *drv, TLoaderFilesData *pInitFiles)
393 {
394     if (!pInitFiles)
395     {
396         ti_dprintf (TIWLAN_LOG_ERROR, "No Init Files!\n");
397         return -EINVAL;
398     }
399 
400     if (drv->tCommon.eDriverState != DRV_STATE_IDLE)
401     {
402         ti_dprintf (TIWLAN_LOG_ERROR, "Trying to load files not in IDLE state!\n");
403         return -EINVAL;
404     }
405 
406     if (pInitFiles->uIniFileLength)
407     {
408         drv->tCommon.tIniFile.uSize = pInitFiles->uIniFileLength;
409         drv->tCommon.tIniFile.pImage = kmalloc (pInitFiles->uIniFileLength, GFP_KERNEL);
410         #ifdef TI_MEM_ALLOC_TRACE
411           os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, pInitFiles->uIniFileLength, GFP_KERNEL, pInitFiles->uIniFileLength);
412         #endif
413         if (!drv->tCommon.tIniFile.pImage)
414         {
415             ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for Ini-File!\n");
416             return -ENOMEM;
417         }
418         memcpy (drv->tCommon.tIniFile.pImage,
419                 &pInitFiles->data[pInitFiles->uNvsFileLength + pInitFiles->uFwFileLength],
420                 drv->tCommon.tIniFile.uSize);
421     }
422 
423     if (pInitFiles->uNvsFileLength)
424     {
425         drv->tCommon.tNvsImage.uSize = pInitFiles->uNvsFileLength;
426         drv->tCommon.tNvsImage.pImage = kmalloc (drv->tCommon.tNvsImage.uSize, GFP_KERNEL);
427         #ifdef TI_MEM_ALLOC_TRACE
428           os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n",
429               __FUNCTION__, __LINE__, drv->tCommon.tNvsImage.uSize, GFP_KERNEL, drv->tCommon.tNvsImage.uSize);
430         #endif
431         if (!drv->tCommon.tNvsImage.pImage)
432         {
433             ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for NVS image\n");
434             return -ENOMEM;
435         }
436         memcpy (drv->tCommon.tNvsImage.pImage, &pInitFiles->data[0], drv->tCommon.tNvsImage.uSize );
437     }
438 
439     drv->tCommon.tFwImage.uSize = pInitFiles->uFwFileLength;
440     if (!drv->tCommon.tFwImage.uSize)
441     {
442         ti_dprintf (TIWLAN_LOG_ERROR, "No firmware image\n");
443         return -EINVAL;
444     }
445     drv->tCommon.tFwImage.pImage = os_memoryAlloc (drv, drv->tCommon.tFwImage.uSize);
446     #ifdef TI_MEM_ALLOC_TRACE
447       os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n",
448           __FUNCTION__, __LINE__, drv->tCommon.tFwImage.uSize, GFP_KERNEL, drv->tCommon.tFwImage.uSize);
449     #endif
450     if (!drv->tCommon.tFwImage.pImage)
451     {
452         ti_dprintf(TIWLAN_LOG_ERROR, "Cannot allocate buffer for firmware image\n");
453         return -ENOMEM;
454     }
455     memcpy (drv->tCommon.tFwImage.pImage,
456             &pInitFiles->data[pInitFiles->uNvsFileLength],
457             drv->tCommon.tFwImage.uSize);
458 
459     ti_dprintf(TIWLAN_LOG_OTHER, "--------- Eeeprom=%p(%lu), Firmware=%p(%lu), IniFile=%p(%lu)\n",
460         drv->tCommon.tNvsImage.pImage, drv->tCommon.tNvsImage.uSize,
461         drv->tCommon.tFwImage.pImage,  drv->tCommon.tFwImage.uSize,
462         drv->tCommon.tIniFile.pImage,  drv->tCommon.tIniFile.uSize);
463 
464     return 0;
465 }
466 
467 
468 /**
469  * \fn     wlanDrvIf_GetFile
470  * \brief  Provides access to a requested init file
471  *
472  * Provide the requested file information and call the requester callback.
473  * Note that in Linux the files were previously loaded to driver memory
474  *     by the loader (see wlanDrvIf_LoadFiles).
475  *
476  * \note
477  * \param  hOs       - The driver object handle
478  * \param  pFileInfo - The requested file's properties
479  * \return TI_OK
480  * \sa     wlanDrvIf_LoadFiles
481  */
482 int wlanDrvIf_GetFile (TI_HANDLE hOs, TFileInfo *pFileInfo)
483 {
484     TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
485 
486 	if (drv == NULL || pFileInfo == NULL) {
487 		ti_dprintf(TIWLAN_LOG_ERROR, "wlanDrv_GetFile: ERROR: Null File Handler, Exiting");
488 		return TI_NOK;
489 	}
490 
491     /* Future option for getting the FW image part by part */
492     pFileInfo->hOsFileDesc = NULL;
493 
494     /* Fill the file's location and size in the file's info structure */
495     switch (pFileInfo->eFileType)
496     {
497     case FILE_TYPE_INI:
498         pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tIniFile.pImage;
499         pFileInfo->uLength = drv->tCommon.tIniFile.uSize;
500         break;
501     case FILE_TYPE_NVS:
502         pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tNvsImage.pImage;
503         pFileInfo->uLength = drv->tCommon.tNvsImage.uSize;
504         break;
505 	case FILE_TYPE_FW:
506 		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tFwImage.pImage;
507 		pFileInfo->bLast		= TI_FALSE;
508 		pFileInfo->uLength	= 0;
509 		pFileInfo->uOffset 				= 0;
510 		pFileInfo->uChunkBytesLeft 		= 0;
511 		pFileInfo->uChunksLeft 			= BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
512 		/* check uChunksLeft's Validity */
513 		if (( pFileInfo->uChunksLeft == 0 ) || ( pFileInfo->uChunksLeft > MAX_CHUNKS_IN_FILE ))
514 		{
515 			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() Read Invalid Chunks Left: %d!\n",pFileInfo->uChunksLeft);
516 			return TI_NOK;
517 		}
518 		pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
519 		/* FALL THROUGH */
520 	case FILE_TYPE_FW_NEXT:
521 		/* check dec. validity */
522 		if ( pFileInfo->uChunkBytesLeft >= pFileInfo->uLength )
523 		{
524 			pFileInfo->uChunkBytesLeft 		-= pFileInfo->uLength;
525 		}
526 		/* invalid Dec. */
527 		else
528 		{
529 			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() No. of Bytes Left < File Length\n");
530 			return TI_NOK;
531 		}
532 		pFileInfo->pBuffer 	+= pFileInfo->uLength;
533 
534 		/* Finished reading all Previous Chunk */
535 		if ( pFileInfo->uChunkBytesLeft == 0 )
536 		{
537 			/* check dec. validity */
538 			if ( pFileInfo->uChunksLeft > 0 )
539 			{
540 				pFileInfo->uChunksLeft--;
541 			}
542 			/* invalid Dec. */
543 			else
544 			{
545 				ti_dprintf (TIWLAN_LOG_ERROR, "No. of Bytes Left = 0 and Chunks Left <= 0\n");
546 				return TI_NOK;
547 			}
548 			/* read Chunk's address */
549 			pFileInfo->uAddress = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
550 			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
551 			/* read Portion's length */
552 			pFileInfo->uChunkBytesLeft = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
553 			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
554 		}
555 		/* Reading Chunk is NOT complete */
556 		else
557 		{
558 			pFileInfo->uAddress += pFileInfo->uLength;
559 		}
560 
561 		if ( pFileInfo->uChunkBytesLeft < OS_SPECIFIC_RAM_ALLOC_LIMIT )
562 		{
563 			pFileInfo->uLength = pFileInfo->uChunkBytesLeft;
564 		}
565 		else
566 		{
567 			pFileInfo->uLength = OS_SPECIFIC_RAM_ALLOC_LIMIT;
568 		}
569 
570 		/* If last chunk to download */
571 		if (( pFileInfo->uChunksLeft == 0 ) &&
572 			( pFileInfo->uLength == pFileInfo->uChunkBytesLeft ))
573 		{
574 			pFileInfo->bLast = TI_TRUE;
575 		}
576 
577         break;
578     }
579 
580     /* Call the requester callback */
581     if (pFileInfo->fCbFunc)
582     {
583         pFileInfo->fCbFunc (pFileInfo->hCbHndl);
584     }
585 
586     return TI_OK;
587 }
588 
589 
590 /**
591  * \fn     wlanDrvIf_SetMacAddress
592  * \brief  Set STA MAC address
593  *
594  * Called by DrvMain from init process.
595  * Copies STA MAC address to the network interface structure.
596  *
597  * \note
598  * \param  hOs      - The driver object handle
599  * \param  pMacAddr - The STA MAC address
600  * \return TI_OK
601  * \sa     wlanDrvIf_LoadFiles
602  */
603 void wlanDrvIf_SetMacAddress (TI_HANDLE hOs, TI_UINT8 *pMacAddr)
604 {
605 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;
606 
607 	/* Copy STA MAC address to the network interface structure */
608 	MAC_COPY (drv->netdev->dev_addr, pMacAddr);
609 }
610 
611 
612 /**
613  * \fn     wlanDrvIf_Start
614  * \brief  Start driver
615  *
616  * Called by network stack upon opening network interface (ifconfig up).
617  * Can also be called from user application or CLI for flight mode.
618  * Start the driver initialization process up to OPERATIONAL state.
619  *
620  * \note
621  * \param  dev - The driver network-interface handle
622  * \return 0 if succeeded, error if driver not available
623  * \sa     wlanDrvIf_Stop
624  */
625 int wlanDrvIf_Start (struct net_device *dev)
626 {
627 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
628 
629 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Start()\n");
630 	printk("%s\n", __func__);
631 	if (!drv->tCommon.hDrvMain) {
632 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Start() Driver not created!\n");
633 		return -ENODEV;
634 	}
635 
636 	/*
637 	 *  Insert Start command in DrvMain action queue, request driver scheduling
638 	 *      and wait for action completion (all init process).
639 	 */
640 	os_wake_lock_timeout_enable(drv);
641 	drvMain_InsertAction (drv->tCommon.hDrvMain, ACTION_TYPE_START);
642 	return 0;
643 }
644 
645 int wlanDrvIf_Open (struct net_device *dev)
646 {
647 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
648 
649 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Open()\n");
650 	printk("%s\n", __func__);
651 	if (!drv->tCommon.hDrvMain) {
652 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Open() Driver not created!\n");
653 		return -ENODEV;
654 	}
655 
656 	if (drv->tCommon.eDriverState != DRV_STATE_RUNNING) {
657 		wlanDrvIf_Start(dev);
658 	}
659 
660 	/*
661 	 *  Finalize network interface setup
662 	 */
663 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
664 	drv->netdev->hard_start_xmit = wlanDrvIf_Xmit;
665 #else
666 	drv->netdev->netdev_ops = &tiwlan_ops_pri;
667 #endif
668 	drv->netdev->addr_len = MAC_ADDR_LEN;
669 	netif_start_queue (dev);
670 
671 	/* register 3430 PM hooks in our SDIO driver */
672 #ifdef TI_CONFIG_PM_HOOKS
673 #ifndef CONFIG_MMC_EMBEDDED_SDIO
674 	sdioDrv_register_pm(wlanDrvIf_pm_resume, wlanDrvIf_pm_suspend);
675 #endif
676 #endif
677 	return 0;
678 }
679 
680 /**
681  * \fn     wlanDrvIf_Stop
682  * \brief  Stop driver
683  *
684  * Called by network stack upon closing network interface (ifconfig down).
685  * Can also be called from user application or CLI for flight mode.
686  * Stop the driver and turn off the device.
687  *
688  * \note
689  * \param  dev - The driver network-interface handle
690  * \return 0 (OK)
691  * \sa     wlanDrvIf_Start
692  */
693 int wlanDrvIf_Stop (struct net_device *dev)
694 {
695 	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
696 
697 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Stop()\n");
698 	printk("%s\n", __func__);
699 	/*
700 	 *  Insert Stop command in DrvMain action queue, request driver scheduling
701 	 *      and wait for Stop process completion.
702 	 */
703 	os_wake_lock_timeout_enable(drv);
704 	drvMain_InsertAction (drv->tCommon.hDrvMain, ACTION_TYPE_STOP);
705 	return 0;
706 }
707 
708 int wlanDrvIf_Release (struct net_device *dev)
709 {
710 	/* TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev); */
711 
712 	ti_dprintf (TIWLAN_LOG_OTHER, "wlanDrvIf_Release()\n");
713 	printk("%s\n", __func__);
714 	/* Disable network interface queue */
715 	netif_stop_queue (dev);
716 	return 0;
717 }
718 
719 /* 3430 PM hooks */
720 #ifdef TI_CONFIG_PM_HOOKS
721 static int wlanDrvIf_pm_resume(void)
722 {
723 	return(wlanDrvIf_Start(pDrvStaticHandle->netdev));
724 }
725 
726 static int wlanDrvIf_pm_suspend(void)
727 {
728 	return(wlanDrvIf_Stop(pDrvStaticHandle->netdev));
729 }
730 #endif
731 
732 
733 /**
734  * \fn     wlanDrvIf_SetupNetif
735  * \brief  Setup driver network interface
736  *
737  * Called in driver creation process.
738  * Setup driver network interface.
739  *
740  * \note
741  * \param  drv - The driver object handle
742  * \return 0 - OK, else - failure
743  * \sa
744  */
745 static int wlanDrvIf_SetupNetif (TWlanDrvIfObj *drv)
746 {
747 	struct net_device *dev;
748 	int res;
749 
750 	/* Allocate network interface structure for the driver */
751 	dev = alloc_etherdev (0);
752 	if (dev == NULL) {
753 		ti_dprintf (TIWLAN_LOG_ERROR, "alloc_etherdev() failed\n");
754 		return -ENOMEM;
755 	}
756 
757 	/* Setup the network interface */
758 	ether_setup (dev);
759 
760 	NETDEV_SET_PRIVATE(dev,drv);
761 	drv->netdev = dev;
762 	strcpy (dev->name, TIWLAN_DRV_IF_NAME);
763 	netif_carrier_off (dev);
764 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
765 /* the following is required on at least BSP 23.8 and higher.
766     Without it, the Open function of the driver will not be called
767     when trying to 'ifconfig up' the interface */
768 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
769 	dev->validate_addr = NULL;
770 #endif
771 	dev->open = wlanDrvIf_Open;
772 	dev->stop = wlanDrvIf_Release;
773 	dev->hard_start_xmit = wlanDrvIf_XmitDummy;
774 	dev->get_stats = wlanDrvIf_NetGetStat;
775 	dev->do_ioctl = NULL;
776 #else
777 	dev->netdev_ops = &tiwlan_ops_dummy;
778 #endif
779 	dev->tx_queue_len = 100;
780 
781 	/* Initialize Wireless Extensions interface (WEXT) */
782 	wlanDrvWext_Init (dev);
783 
784 	res = register_netdev (dev);
785 	if (res != 0) {
786 		ti_dprintf (TIWLAN_LOG_ERROR, "register_netdev() failed : %d\n", res);
787 		kfree (dev);
788 		return res;
789 	}
790 /*
791 On the latest Kernel there is no more support for the below macro.
792 */
793 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
794 	SET_MODULE_OWNER (dev);
795 #endif
796 	return 0;
797 }
798 
799 /**
800  * \fn     wlanDrvIf_CommandDone
801  * \brief  Free current command semaphore.
802  *
803  * This routine is called whenever a command has finished executing and Free current command semaphore.
804  *
805  * \note
806  * \param  hOs           - The driver object handle
807  * \param  pSignalObject - handle to complete mechanism per OS
808  * \param  CmdResp_p     - respond structure (TCmdRespUnion) for OSE OS only
809  * \return 0 - OK, else - failure
810  * \sa     wlanDrvIf_Destroy
811  */
812 void wlanDrvIf_CommandDone (TI_HANDLE hOs, void *pSignalObject, TI_UINT8 *CmdResp_p)
813 {
814 	/* Free semaphore */
815 	os_SignalObjectSet (hOs, pSignalObject);
816 }
817 
818 
819 /**
820  * \fn     wlanDrvIf_Create
821  * \brief  Create the driver instance
822  *
823  * Allocate driver object.
824  * Initialize driver OS resources (IRQ, workqueue, events socket)
825  * Setup driver network interface.
826  * Create and link all driver modules.
827  *
828  * \note
829  * \param  void
830  * \return 0 - OK, else - failure
831  * \sa     wlanDrvIf_Destroy
832  */
833 static int wlanDrvIf_Create (void)
834 {
835 	TWlanDrvIfObj *drv; /* Dm: Failure is not cleaned properly !!! */
836 	int rc;
837 
838 	/* Allocate driver's structure */
839 	drv = kmalloc (sizeof(TWlanDrvIfObj), GFP_KERNEL);
840 	if (!drv) {
841 		return -ENOMEM;
842 	}
843 #ifdef TI_DBG
844 	tb_init(TB_OPTION_NONE);
845 #endif
846 	pDrvStaticHandle = drv;  /* save for module destroy */
847 #ifdef TI_MEM_ALLOC_TRACE
848 	os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, sizeof(TWlanDrvIfObj), GFP_KERNEL, sizeof(TWlanDrvIfObj));
849 #endif
850 	memset (drv, 0, sizeof(TWlanDrvIfObj));
851 
852 	/* Dm:    drv->irq = TNETW_IRQ; */
853 	drv->tCommon.eDriverState = DRV_STATE_IDLE;
854 
855 	drv->tiwlan_wq = create_freezeable_workqueue(DRIVERWQ_NAME);
856 	if (!drv->tiwlan_wq) {
857 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Create(): Failed to create workQ!\n");
858 		rc = -EINVAL;
859 		goto drv_create_end_1;
860 	}
861 	drv->wl_packet = 0;
862 	drv->wl_count = 0;
863 #ifdef CONFIG_HAS_WAKELOCK
864 	wake_lock_init(&drv->wl_wifi, WAKE_LOCK_SUSPEND, "wifi_wake");
865 	wake_lock_init(&drv->wl_rxwake, WAKE_LOCK_SUSPEND, "wifi_rx_wake");
866 #endif
867 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
868 	INIT_WORK(&drv->tWork, wlanDrvIf_DriverTask, (void *)drv);
869 #else
870 	INIT_WORK(&drv->tWork, wlanDrvIf_DriverTask);
871 #endif
872 	spin_lock_init (&drv->lock);
873 
874 	/* Setup driver network interface. */
875 	rc = wlanDrvIf_SetupNetif (drv);
876 	if (rc)	{
877 		goto drv_create_end_2;
878 	}
879 
880 	/* Create the events socket interface */
881 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
882 	drv->wl_sock = netlink_kernel_create( NETLINK_USERSOCK, 0, NULL, THIS_MODULE );
883 #else
884 	drv->wl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0, NULL, NULL, THIS_MODULE );
885 #endif
886 	if (drv->wl_sock == NULL) {
887 	        ti_dprintf (TIWLAN_LOG_ERROR, "netlink_kernel_create() failed !\n");
888 		rc = -EINVAL;
889 		goto drv_create_end_3;
890 	}
891 
892 	/* Create all driver modules and link their handles */
893 	rc = drvMain_Create (drv,
894 			&drv->tCommon.hDrvMain,
895 			&drv->tCommon.hCmdHndlr,
896 			&drv->tCommon.hContext,
897 			&drv->tCommon.hTxDataQ,
898 			&drv->tCommon.hTxMgmtQ,
899 			&drv->tCommon.hTxCtrl,
900 			&drv->tCommon.hTWD,
901 			&drv->tCommon.hEvHandler);
902 	if (rc != TI_OK) {
903 		ti_dprintf (TIWLAN_LOG_ERROR, "%s: Failed to dvrMain_Create!\n", __func__);
904 		rc = -EINVAL;
905 		goto drv_create_end_4;
906 	}
907 	/*
908 	 *  Initialize interrupts (or polling mode for debug):
909 	 */
910 #ifdef PRIODIC_INTERRUPT
911 	/* Debug mode: Polling (the timer is started by HwInit process) */
912 	drv->hPollTimer = os_timerCreate ((TI_HANDLE)drv, wlanDrvIf_PollIrqHandler, (TI_HANDLE)drv);
913 #else
914 	/* Normal mode: Interrupts (the default mode) */
915 	rc = hPlatform_initInterrupt (drv, (void*)wlanDrvIf_HandleInterrupt);
916 	if (rc)	{
917 		ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_Create(): Failed to register interrupt handler!\n");
918 		goto drv_create_end_5;
919 	}
920 #endif  /* PRIODIC_INTERRUPT */
921 	return 0;
922 drv_create_end_5:
923 	/* Destroy all driver modules */
924 	if (drv->tCommon.hDrvMain) {
925 		drvMain_Destroy (drv->tCommon.hDrvMain);
926 	}
927 drv_create_end_4:
928 	if (drv->wl_sock) {
929 		sock_release (drv->wl_sock->sk_socket);
930 	}
931 
932 drv_create_end_3:
933 	/* Release the driver network interface */
934 	if (drv->netdev) {
935 		unregister_netdev (drv->netdev);
936 		free_netdev (drv->netdev);
937 	}
938 
939 drv_create_end_2:
940 #ifdef CONFIG_HAS_WAKELOCK
941 	wake_lock_destroy(&drv->wl_wifi);
942 	wake_lock_destroy(&drv->wl_rxwake);
943 #endif
944 	if (drv->tiwlan_wq)
945 		destroy_workqueue(drv->tiwlan_wq);
946 
947 drv_create_end_1:
948 	kfree(drv);
949 	printk("%s: Fail\n", __func__);
950 	return rc;
951 }
952 
953 
954 /**
955  * \fn     wlanDrvIf_Destroy
956  * \brief  Destroy the driver instance
957  *
958  * Destroy all driver modules.
959  * Release driver OS resources (IRQ, workqueue, events socket)
960  * Release driver network interface.
961  * Free init files memory.
962  * Free driver object.
963  *
964  * \note
965  * \param  drv - The driver object handle
966  * \return void
967  * \sa     wlanDrvIf_Create
968  */
969 static void wlanDrvIf_Destroy (TWlanDrvIfObj *drv)
970 {
971 	/* Release the driver network interface */
972 	if (drv->netdev) {
973 		netif_stop_queue  (drv->netdev);
974 		wlanDrvIf_Stop    (drv->netdev);
975 		unregister_netdev (drv->netdev);
976 		free_netdev (drv->netdev);
977 	}
978 	/* Destroy all driver modules */
979 	if (drv->tCommon.hDrvMain) {
980 		drvMain_Destroy (drv->tCommon.hDrvMain);
981 	}
982 
983 	/* close the ipc_kernel socket*/
984 	if (drv && drv->wl_sock) {
985 		sock_release (drv->wl_sock->sk_socket);
986 	}
987 	/* Release the driver interrupt (or polling timer) */
988 #ifdef PRIODIC_INTERRUPT
989 	os_timerDestroy (drv, drv->hPollTimer);
990 #else
991 	if (drv->irq) {
992 		hPlatform_freeInterrupt(drv);
993 	}
994 #endif
995 	if (drv->tiwlan_wq)
996 		destroy_workqueue(drv->tiwlan_wq);
997 
998 #ifdef CONFIG_HAS_WAKELOCK
999 	wake_lock_destroy(&drv->wl_wifi);
1000 	wake_lock_destroy(&drv->wl_rxwake);
1001 #endif
1002 	/*
1003 	 *  Free init files memory
1004 	 */
1005 	if (drv->tCommon.tFwImage.pImage) {
1006 		os_memoryFree (drv, drv->tCommon.tFwImage.pImage, drv->tCommon.tFwImage.uSize);
1007 #ifdef TI_MEM_ALLOC_TRACE
1008 		os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
1009 			__FUNCTION__, __LINE__, drv->tCommon.tFwImage.uSize,
1010 			-drv->tCommon.tFwImage.uSize);
1011 #endif
1012 	}
1013 	if (drv->tCommon.tNvsImage.pImage) {
1014 		kfree (drv->tCommon.tNvsImage.pImage);
1015 #ifdef TI_MEM_ALLOC_TRACE
1016 		os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
1017 			__FUNCTION__, __LINE__, drv->tCommon.tNvsImage.uSize,
1018 			-drv->tCommon.tNvsImage.uSize);
1019 #endif
1020 	}
1021 	if (drv->tCommon.tIniFile.pImage) {
1022 		kfree (drv->tCommon.tIniFile.pImage);
1023 #ifdef TI_MEM_ALLOC_TRACE
1024 		os_printf ("MTT:%s:%d ::kfree(0x%p) : %d\n",
1025 			__FUNCTION__, __LINE__, drv->tCommon.tIniFile.uSize,
1026 			-drv->tCommon.tIniFile.uSize);
1027 #endif
1028 	}
1029 
1030     /* Free the driver object */
1031 #ifdef TI_DBG
1032 	tb_destroy();
1033 #endif
1034 	kfree (drv);
1035 }
1036 
1037 
1038 /**
1039  * \fn     wlanDrvIf_ModuleInit  &  wlanDrvIf_ModuleExit
1040  * \brief  Linux Init/Exit functions
1041  *
1042  * The driver Linux Init/Exit functions (insmod/rmmod)
1043  *
1044  * \note
1045  * \param  void
1046  * \return Init: 0 - OK, else - failure.   Exit: void
1047  * \sa     wlanDrvIf_Create, wlanDrvIf_Destroy
1048  */
1049 #ifndef TI_SDIO_STANDALONE
1050 static int sdc_ctrl = 2;
1051 module_param(sdc_ctrl, int, S_IRUGO | S_IWUSR | S_IWGRP);
1052 
1053 extern int sdioDrv_init(int sdcnum);
1054 extern void sdioDrv_exit(void);
1055 #endif
1056 
1057 static int __init wlanDrvIf_ModuleInit (void)
1058 {
1059 	printk(KERN_INFO "TIWLAN: driver init\n");
1060 #ifndef TI_SDIO_STANDALONE
1061 #ifndef CONFIG_MMC_EMBEDDED_SDIO
1062 	sdioDrv_init(sdc_ctrl);
1063 #endif
1064 #endif
1065 	return wlanDrvIf_Create ();
1066 }
1067 
1068 static void __exit wlanDrvIf_ModuleExit (void)
1069 {
1070 	wlanDrvIf_Destroy (pDrvStaticHandle);
1071 #ifndef TI_SDIO_STANDALONE
1072 #ifndef CONFIG_MMC_EMBEDDED_SDIO
1073 	sdioDrv_exit();
1074 #endif
1075 #endif
1076 	printk (KERN_INFO "TI WLAN: driver unloaded\n");
1077 }
1078 
1079 module_init (wlanDrvIf_ModuleInit);
1080 module_exit (wlanDrvIf_ModuleExit);
1081