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