示例#1
0
static void wlanDrvIf_DriverTask (void *hDrv)
{
	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
#else
static void wlanDrvIf_DriverTask(struct work_struct *work)
{
	TWlanDrvIfObj *drv = container_of(work, TWlanDrvIfObj, tWork);
#endif

#ifdef STACK_PROFILE
	unsigned int curr1,base1;
	unsigned int curr2,base2;
	static unsigned int maximum_stack = 0;
#endif
	TI_BOOL bShouldLock;

	os_profile (drv, 0, 0);

#ifdef STACK_PROFILE
	curr1 = check_stack_start(&base1);
#endif

	/* we must read the value first here */
	bShouldLock = ! context_IsSuspending(pDrvStaticHandle->tCommon.hContext);

	/* Call the driver main task */
	context_DriverTask (drv->tCommon.hContext);

	if (bShouldLock)
	{
		os_wake_lock_timeout(drv);
		os_wake_unlock(drv);
	}

#ifdef STACK_PROFILE
	curr2 = check_stack_stop(&base2);
	if (base2 == base1)
	{
		/* if the current measurement is bigger then the maximum store it and print*/
		if ((curr1 - curr2) > maximum_stack)
		{
			printk("STACK PROFILER GOT THE LOCAL MAXIMMUM!!!! \n");
			printk("current operation stack use =%d \n",(curr1 - curr2));
			printk("total stack use=%d \n",8192 - curr2 + base2);
			printk("total stack usage= %d percent \n",100 * (8192 - curr2 + base2) / 8192);
			maximum_stack = curr1 - curr2;
		}
	}
#endif

	os_profile (drv, 1, 0);
}
示例#2
0
/****************************************************************************************
 *                        os_memoryFree()                                 
 ****************************************************************************************
DESCRIPTION:    This function releases a block of memory previously allocated with the
				os_memoryAlloc function.


ARGUMENTS:		OsContext	-	our adapter context.
				pMemPtr		-	Pointer to the base virtual address of the allocated memory.
								This address was returned by the os_memoryAlloc function.
				Size		-	Specifies the size, in bytes, of the memory block to be released.
								This parameter must be identical to the Length that was passed to
								os_memoryAlloc.

RETURN:			None

NOTES:         	
*****************************************************************************************/
void
os_memoryFree(
        TI_HANDLE OsContext,
        void* pMemPtr,
        TI_UINT32 Size
        )
{
	struct os_mem_block *blk;

	if (!pMemPtr) {
		printk("%s: NULL\n",__func__); 
		return;
	}
	blk = (struct os_mem_block *)((char *)pMemPtr - sizeof(struct os_mem_block));
   
	if (blk->signature != MEM_BLOCK_START)
    {
		printk("\n\n%s: memory block signature is incorrect - 0x%x\n\n\n",
               __FUNCTION__, blk->signature);
        return;
    }
    *(char *)(&blk->signature) = '~';
    if (*(__u32 *)((unsigned char *)blk + blk->size + sizeof(struct os_mem_block))
        != MEM_BLOCK_END)
    {
		printk("\n\n%s: memory block corruption. Size=%u\n\n\n",
               __FUNCTION__, blk->size);
    }

    os_profile (OsContext, 5, blk->size + sizeof(struct os_mem_block) + sizeof(__u32));

    blk->f_free(blk);
}
示例#3
0
/****************************************************************************************
 *                        os_memoryFree()                                 
 ****************************************************************************************
DESCRIPTION:    This function releases a block of memory previously allocated with the
                os_memoryAlloc function.


ARGUMENTS:      OsContext   -   our adapter context.
                pMemPtr     -   Pointer to the base virtual address of the allocated memory.
                                This address was returned by the os_memoryAlloc function.
                Size        -   Specifies the size, in bytes, of the memory block to be released.
                                This parameter must be identical to the Length that was passed to
                                os_memoryAlloc.

RETURN:         None

NOTES:          
*****************************************************************************************/
VOID
os_memoryFree(
        TI_HANDLE OsContext,
        PVOID pMemPtr,
        UINT32 Size
        )
{
    struct os_mem_block *blk =
        (struct os_mem_block *)((char *)pMemPtr - sizeof(struct os_mem_block));
   
#ifdef TI_MEM_ALLOC_TRACE
    os_printf("MTT:%s:%d ::os_memoryFree(0x%p, 0x%p, %lu) : %d\n",__FUNCTION__,__LINE__,OsContext,pMemPtr,Size,-Size);
#endif
    if (blk->signature != MEM_BLOCK_START)
    {
        printk("\n\n%s: memory block signature is incorrect - 0x%x\n\n\n",
               __FUNCTION__, blk->signature);
        return;
    }
    *(char *)(&blk->signature) = '~';
    if (*(__u32 *)((unsigned char *)blk + blk->size + sizeof(struct os_mem_block))
        != MEM_BLOCK_END)
    {
        printk("\n\n%s: memory block corruption. Size=%u\n\n\n",
               __FUNCTION__, blk->size);
    }

    os_profile (OsContext, 5, blk->size + sizeof(struct os_mem_block) + sizeof(__u32));

    blk->f_free(blk);
}
示例#4
0
/****************************************************************************************
 *                        os_memoryPreAlloc()
 ****************************************************************************************
DESCRIPTION:    Gets system-space memory preallocated by kernel.

ARGUMENTS:      OsContext   - our adapter context.
                section     - section number
                Size        - Specifies the size, in bytes, to be allocated.

RETURN:         Pointer to the allocated memory.
                NULL if there is insufficient memory available.
*****************************************************************************************/
PVOID
os_memoryPreAlloc(
        TI_HANDLE OsContext,
        int section,
        UINT32 Size
        )
{
    struct os_mem_block *blk;
    __u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);

#ifdef TI_MEM_ALLOC_TRACE
    os_printf("MTT:%s:%d ::os_memoryPreAlloc(0x%p, %lu) : %lu\n",__FUNCTION__, __LINE__,OsContext,Size,total_size);
#endif
    if( total_size < Size ) { /* Dm: Security fix */
        return NULL;
    }

    blk = (struct os_mem_block *)wifi_kernel_prealloc( section, total_size );
    if( !blk ) {
        return os_memoryAlloc(OsContext, Size);
    }
    blk->f_free = (os_free)os_memoryPreFree;

    os_profile (OsContext, 4, total_size);

    /*list_add(&blk->blk_list, &drv->mem_blocks);*/
    blk->size = Size;
    blk->signature = MEM_BLOCK_START;
    *(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
    return (PVOID)((char *)blk + sizeof(struct os_mem_block));
}
void*
_os_memoryAlloc(
    TI_HANDLE OsContext,
    TI_UINT32 Size,
    TI_UINT32 FileNbr,
    TI_UINT32 LineNbr
)
{
	struct os_mem_block *blk;
	__u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);
	gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;

#ifdef TI_MEM_ALLOC_TRACE
	os_printf("MTT:%s:%d ::os_memoryAlloc(0x%p, %lu) : %lu\n",FileNbr, LineNbr ,OsContext,Size,total_size);
#endif
	/*
	Memory optimization issue. Allocate up to 2 pages (8k) from the SLAB
	    allocator (2^n), otherwise allocate from virtual pool.
	If full Async mode is used, allow up to 6 pages (24k) for DMA-able
	  memory, so the TxCtrlBlk table can be transacted over DMA.
	*/
#ifdef FULL_ASYNC_MODE
	if (total_size < 6 * 4096)
#else
	if (total_size < 2 * 4096)
#endif
	{
		blk = kmalloc(total_size, flags);
		if (!blk) {
			printk(KERN_ERR "%s: NULL from kmalloc\n",__func__);
			return NULL;
		}
		blk->f_free = (os_free)kfree;
	} else {
		/* We expect that the big allocations should be made outside
		     the interrupt, otherwise fail
		*/
		if (in_interrupt()) {
			printk(KERN_ERR "%s: in_interrupt(), returning NULL\n",__func__);
			return NULL;
		}
		blk = vmalloc(total_size);
		if (!blk) {
			printk(KERN_ERR "%s: NULL from vmalloc\n",__func__);
			return NULL;
		}
		blk->f_free = (os_free)vfree;
	}

	os_profile (OsContext, 4, total_size);

	/*list_add(&blk->blk_list, &drv->mem_blocks);*/
	blk->size = Size;
	blk->signature = MEM_BLOCK_START;
	blk->allocFile = FileNbr;
	blk->allocLine = LineNbr;
	*(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
	return (void *)((char *)blk + sizeof(struct os_mem_block));
}
示例#6
0
/****************************************************************************************
 *                        os_memoryAlloc()                                 
 ****************************************************************************************
DESCRIPTION:    Allocates resident (nonpaged) system-space memory.

ARGUMENTS:		OsContext	- our adapter context.
				Size		- Specifies the size, in bytes, to be allocated.

RETURN:			Pointer to the allocated memory.
				NULL if there is insufficient memory available.

NOTES:         	With the call to vmalloc it is assumed that this function will
				never be called in an interrupt context. vmalloc has the potential to
				sleep the caller while waiting for memory to become available.

*****************************************************************************************/
void*
os_memoryAlloc(
        TI_HANDLE OsContext,
        TI_UINT32 Size
        )
{
    struct os_mem_block *blk;
    __u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);

	/* 
		Memory optimization issue. Allocate up to 2 pages (8k) from the SLAB allocator (2^n),
		    otherwise allocate from virtual pool.
        If full Async mode is used, allow up to 6 pages (24k) for DMA-able memory, so the TxCtrlBlk table
            can be transacted over DMA.
	*/
#ifdef FULL_ASYNC_MODE
	if (total_size < 6 * 4096)
#else
    if (total_size < 2 * 4096)  
#endif
    {
        if (in_atomic())
        {
            blk = kmalloc(total_size, GFP_ATOMIC);
        }
        else
        {
            blk = kmalloc(total_size, GFP_KERNEL);
        }
        if (!blk)
        {            
            printk("%s: NULL\n",__func__);	
            return NULL;
        }
        blk->f_free = (os_free)kfree;
    }
    else
    {
		/* We expect that the big allocations should be made outside the interrupt,
			otherwise fail
		*/
		if (in_interrupt())
			return NULL;
        blk = vmalloc(total_size);
        if (!blk)
            return NULL;
        blk->f_free = (os_free)vfree;
    }

    os_profile (OsContext, 4, total_size);

    /*list_add(&blk->blk_list, &drv->mem_blocks);*/
    blk->size = Size;
    blk->signature = MEM_BLOCK_START;
    *(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
    return (void*)((char *)blk + sizeof(struct os_mem_block));
}
/** 
 * \fn     wlanDrvIf_Xmit
 * \brief  Packets transmission
 * 
 * The network stack calls this function in order to transmit a packet
 *     through the WLAN interface.
 * The packet is inserted to the drver Tx queues and its handling is continued
 *     after switching to the driver context.
 *
 * \note   
 * \param  skb - The Linux packet buffer structure
 * \param  dev - The driver network-interface handle
 * \return 0 (= OK)
 * \sa     
 */ 
static int wlanDrvIf_Xmit (struct sk_buff *skb, struct net_device *dev)
{
	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
	TTxCtrlBlk *  pPktCtrlBlk;
	int status;

	CL_TRACE_START_L1();

	os_profile (drv, 0, 0);
	drv->stats.tx_packets++;
	drv->stats.tx_bytes += skb->len;

	/* Allocate a TxCtrlBlk for the Tx packet and save timestamp, length and packet handle */
	pPktCtrlBlk = TWD_txCtrlBlk_Alloc (drv->tCommon.hTWD);

	pPktCtrlBlk->tTxDescriptor.startTime    = os_timeStampMs(drv); /* remove use of skb->tstamp.off_usec */
	pPktCtrlBlk->tTxDescriptor.length       = skb->len;
	pPktCtrlBlk->tTxPktParams.pInputPkt     = skb;

	/* Point the first BDL buffer to the Ethernet header, and the second buffer to the rest of the packet */
	pPktCtrlBlk->tTxnStruct.aBuf[0] = skb->data;
	pPktCtrlBlk->tTxnStruct.aLen[0] = ETHERNET_HDR_LEN;
	pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN;
	pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN;
	pPktCtrlBlk->tTxnStruct.aLen[2] = 0;

	/* Send the packet to the driver for transmission. */
	status = txDataQ_InsertPacket (drv->tCommon.hTxDataQ, pPktCtrlBlk,(TI_UINT8)skb->priority);

	/* If failed (queue full or driver not running), drop the packet. */
    if (status != TI_OK)
    {
        drv->stats.tx_errors++;
    }
	os_profile (drv, 1, 0);

	CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", "");

	return 0;
}
示例#8
0
/****************************************************************************************
 *                        os_memoryAlloc()
 ****************************************************************************************
DESCRIPTION:    Allocates resident (nonpaged) system-space memory.

ARGUMENTS:      OsContext   - our adapter context.
                Size        - Specifies the size, in bytes, to be allocated.

RETURN:         Pointer to the allocated memory.
                NULL if there is insufficient memory available.

NOTES:          With the call to vmalloc it is assumed that this function will
                never be called in an interrupt context. vmalloc has the potential to
                sleep the caller while waiting for memory to become available.

*****************************************************************************************/
PVOID
os_memoryAlloc(
        TI_HANDLE OsContext,
        UINT32 Size
        )
{
    struct os_mem_block *blk;
    __u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);

#ifdef TI_MEM_ALLOC_TRACE
    os_printf("MTT:%s:%d ::os_memoryAlloc(0x%p, %lu) : %lu\n",__FUNCTION__, __LINE__,OsContext,Size,total_size);
#endif
    if( total_size < Size ) { /* Dm: Security fix */
        return NULL;
    }
    /*
        memory optimization issue. Allocate 8 kB and less from the SLAB allocator (2^n)
        otherwise allocate from virtual pool.
    */
    /* 2 pages */
    if (total_size < 2 * 4096)
    {
        if (in_atomic())
            blk = kmalloc(total_size, GFP_ATOMIC);
        else
            blk = kmalloc(total_size, GFP_KERNEL);
        if (!blk)
            return NULL;
        blk->f_free = (os_free)kfree;
    }
    else
    {
        /* We expect that the big allocations should be made outside the interrupt,
            otherwise fail
        */
        if (in_atomic())
            return NULL;
        blk = vmalloc(total_size);
        if (!blk)
            return NULL;
        blk->f_free = (os_free)vfree;
    }

    os_profile (OsContext, 4, total_size);

    /*list_add(&blk->blk_list, &drv->mem_blocks);*/
    blk->size = Size;
    blk->signature = MEM_BLOCK_START;
    *(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
    return (PVOID)((char *)blk + sizeof(struct os_mem_block));
}
示例#9
0
static int xmit_Bridge (struct sk_buff *skb, struct net_device *dev, TIntraBssBridge *pBssBridgeParam)
{
    TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev);
    TTxCtrlBlk *  pPktCtrlBlk;
    TEthernetHeader *pEthHead = (TEthernetHeader *)(skb->data);
    int status;

    CL_TRACE_START_L1();

    os_profile (drv, 0, 0);
    drv->stats.tx_packets++;
    drv->stats.tx_bytes += skb->len;

    /* Allocate a TxCtrlBlk for the Tx packet and save timestamp, length and packet handle */
    pPktCtrlBlk = TWD_txCtrlBlk_Alloc (drv->tCommon.hTWD);
    if (pPktCtrlBlk == NULL)
    {
        drv->stats.tx_errors++;
        os_profile (drv, 1, 0);
        CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", "");
        return 0;
    }

    /* Set interface type according to net device interface number */
    if (drv->tCommon.eIfRole == IF_ROLE_TYPE_AP) 
        SET_PKT_TYPE_IF_ROLE_AP(pPktCtrlBlk);
    else
        SET_PKT_TYPE_IF_ROLE_STA(pPktCtrlBlk);
    pPktCtrlBlk->tTxDescriptor.startTime    = os_timeStampMs(drv); /* remove use of skb->tstamp.off_usec */
    pPktCtrlBlk->tTxDescriptor.length       = skb->len;
    pPktCtrlBlk->tTxPktParams.pInputPkt     = skb;

    /* Check MGMT packet from hostapd, forward it to the Mgmt-Queue and exit without ethernet header */
    if (HTOWLANS(pEthHead->type) == AP_MGMT_ETH_TYPE)
    {
        /* Copy WLAN header into aPktHdr - format for MGMT packets */
        memcpy (pPktCtrlBlk->aPktHdr, skb->data + ETHERNET_HDR_LEN , WLAN_HDR_LEN );

        /* Skip ethernet header, send as management frame */
        pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_MGMT;
        pPktCtrlBlk->tTxnStruct.aBuf[0] = (TI_UINT8 *)pPktCtrlBlk->aPktHdr;
        pPktCtrlBlk->tTxnStruct.aLen[0] = WLAN_HDR_LEN;
        pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN + WLAN_HDR_LEN;
        pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN - WLAN_HDR_LEN;
        pPktCtrlBlk->tTxnStruct.aLen[2] = 0;
        pPktCtrlBlk->tTxPktParams.uInputPktLen = skb->len;
        pPktCtrlBlk->tTxDescriptor.length = (TI_UINT16)((pPktCtrlBlk->tTxnStruct.aLen[0]) + (pPktCtrlBlk->tTxnStruct.aLen[1]));

        status = txMgmtQ_Xmit (drv->tCommon.hTxMgmtQ, pPktCtrlBlk, TI_TRUE);
    }
    else

    {
    /* Point the first BDL buffer to the Ethernet header, and the second buffer to the rest of the packet */
    pPktCtrlBlk->tTxnStruct.aBuf[0] = skb->data;
    pPktCtrlBlk->tTxnStruct.aLen[0] = ETHERNET_HDR_LEN;
    pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN;
    pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN;
    pPktCtrlBlk->tTxnStruct.aLen[2] = 0;

    /* Send the packet to the driver for transmission. */
    status = txDataQ_InsertPacket (drv->tCommon.hTxDataQ, pPktCtrlBlk,(TI_UINT8)skb->priority, pBssBridgeParam);
    }

    /* If failed (queue full or driver not running), drop the packet. */
    if (status != TI_OK)
    {
        drv->stats.tx_errors++;
    }
    os_profile (drv, 1, 0);

    CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", "");

    return 0;
}
static void wlanDrvIf_DriverTask (void *hDrv)
{
	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hDrv;
#else
static void wlanDrvIf_DriverTask(struct work_struct *work)
{
#ifdef STACK_PROFILE
	register unsigned long sp asm ("sp");
	unsigned long local_sp = sp;
#endif
	TWlanDrvIfObj *drv = container_of(work, TWlanDrvIfObj, tWork);
#endif

#ifdef STACK_PROFILE
	unsigned long curr1, base1;
	unsigned long curr2, base2;
	static unsigned long maximum_stack = 0;
#endif   
	os_profile (drv, 0, 0);

#ifdef STACK_PROFILE
	curr1 = check_stack_start(&base1, local_sp + 4, 0);
#endif

	/* Call the driver main task */
	context_DriverTask (drv->tCommon.hContext);

	os_profile (drv, 1, 0);
	os_wake_lock_timeout(drv);
	os_wake_unlock(drv);
#ifdef STACK_PROFILE
	curr2 = check_stack_stop(&base2, 0);
	if (base2 == base1) {
	/* if the current measurement is bigger then the maximum store it and print*/
		if ((curr1 - curr2) > maximum_stack) {
			printk("STACK PROFILER GOT THE LOCAL MAXIMMUM!!!! \n");
			printk("current operation stack use=%lu \n",(curr1 - curr2));
			printk("total stack use=%lu \n",8192 - curr2 + base2);
			printk("total stack usage=%lu percent \n",100 * (8192 - curr2 + base2) / 8192);
			maximum_stack = curr1 - curr2;
		}
	}
#endif
}


/** 
 * \fn     wlanDrvIf_LoadFiles
 * \brief  Load init files from loader
 * 
 * This function is called from the loader context right after the driver
 *     is created (in IDLE state).
 * It copies the following files to the driver's memory:
 *     - Ini-File - The driver's default parameters values
 *     - NVS-File - The NVS data for FW usage
 *     - FW-Image - The FW program image
 *
 * \note   
 * \param  drv - The driver object handle
 * \return void
 * \sa     wlanDrvIf_GetFile
 */ 
int wlanDrvIf_LoadFiles (TWlanDrvIfObj *drv, TLoaderFilesData *pInitFiles)
{
    if (!pInitFiles)
    {
        ti_dprintf (TIWLAN_LOG_ERROR, "No Init Files!\n");
        return -EINVAL;
    }

    if (drv->tCommon.eDriverState != DRV_STATE_IDLE)
    {
        ti_dprintf (TIWLAN_LOG_ERROR, "Trying to load files not in IDLE state!\n");
        return -EINVAL;
    }

    if (pInitFiles->uIniFileLength) 
    {
        drv->tCommon.tIniFile.uSize = pInitFiles->uIniFileLength;
        drv->tCommon.tIniFile.pImage = kmalloc (pInitFiles->uIniFileLength, GFP_KERNEL);
        #ifdef TI_MEM_ALLOC_TRACE        
          os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, pInitFiles->uIniFileLength, GFP_KERNEL, pInitFiles->uIniFileLength);
        #endif
        if (!drv->tCommon.tIniFile.pImage)
        {
            ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for Ini-File!\n");
            return -ENOMEM;
        }
        memcpy (drv->tCommon.tIniFile.pImage,
                &pInitFiles->data[pInitFiles->uNvsFileLength + pInitFiles->uFwFileLength],
                drv->tCommon.tIniFile.uSize);
    }

    if (pInitFiles->uNvsFileLength)
    {
        drv->tCommon.tNvsImage.uSize = pInitFiles->uNvsFileLength;
        drv->tCommon.tNvsImage.pImage = kmalloc (drv->tCommon.tNvsImage.uSize, GFP_KERNEL);
        #ifdef TI_MEM_ALLOC_TRACE        
          os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", 
              __FUNCTION__, __LINE__, drv->tCommon.tNvsImage.uSize, GFP_KERNEL, drv->tCommon.tNvsImage.uSize);
        #endif
        if (!drv->tCommon.tNvsImage.pImage)
        {
            ti_dprintf (TIWLAN_LOG_ERROR, "Cannot allocate buffer for NVS image\n");
            return -ENOMEM;
        }
        memcpy (drv->tCommon.tNvsImage.pImage, &pInitFiles->data[0], drv->tCommon.tNvsImage.uSize );
    }
    
    drv->tCommon.tFwImage.uSize = pInitFiles->uFwFileLength;
    if (!drv->tCommon.tFwImage.uSize)
    {
        ti_dprintf (TIWLAN_LOG_ERROR, "No firmware image\n");
        return -EINVAL;
    }
    drv->tCommon.tFwImage.pImage = os_memoryAlloc (drv, drv->tCommon.tFwImage.uSize);
    #ifdef TI_MEM_ALLOC_TRACE        
      os_printf ("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", 
          __FUNCTION__, __LINE__, drv->tCommon.tFwImage.uSize, GFP_KERNEL, drv->tCommon.tFwImage.uSize);
    #endif
    if (!drv->tCommon.tFwImage.pImage)
    {
        ti_dprintf(TIWLAN_LOG_ERROR, "Cannot allocate buffer for firmware image\n");
        return -ENOMEM;
    }
    memcpy (drv->tCommon.tFwImage.pImage,
            &pInitFiles->data[pInitFiles->uNvsFileLength],
            drv->tCommon.tFwImage.uSize);

    ti_dprintf(TIWLAN_LOG_OTHER, "--------- Eeeprom=%p(%lu), Firmware=%p(%lu), IniFile=%p(%lu)\n", 
        drv->tCommon.tNvsImage.pImage, drv->tCommon.tNvsImage.uSize, 
        drv->tCommon.tFwImage.pImage,  drv->tCommon.tFwImage.uSize,
        drv->tCommon.tIniFile.pImage,  drv->tCommon.tIniFile.uSize);
    
    return 0;
}


/** 
 * \fn     wlanDrvIf_GetFile
 * \brief  Provides access to a requested init file
 * 
 * Provide the requested file information and call the requester callback.
 * Note that in Linux the files were previously loaded to driver memory 
 *     by the loader (see wlanDrvIf_LoadFiles).
 *
 * \note   
 * \param  hOs       - The driver object handle
 * \param  pFileInfo - The requested file's properties
 * \return TI_OK
 * \sa     wlanDrvIf_LoadFiles
 */ 
int wlanDrvIf_GetFile (TI_HANDLE hOs, TFileInfo *pFileInfo)
{
	TWlanDrvIfObj *drv = (TWlanDrvIfObj *)hOs;

	if (drv == NULL || pFileInfo == NULL) {
		ti_dprintf(TIWLAN_LOG_ERROR, "wlanDrv_GetFile: ERROR: Null File Handler, Exiting");
		return TI_NOK;
	}

	/* Future option for getting the FW image part by part */ 
	pFileInfo->hOsFileDesc = NULL;

	/* Fill the file's location and size in the file's info structure */
	switch (pFileInfo->eFileType) 
	{
	case FILE_TYPE_INI: 
		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tIniFile.pImage; 
		pFileInfo->uLength = drv->tCommon.tIniFile.uSize; 
		break;
	case FILE_TYPE_NVS:     
		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tNvsImage.pImage; 
		pFileInfo->uLength = drv->tCommon.tNvsImage.uSize; 
		break;
	case FILE_TYPE_FW:
		if (drv->tCommon.tFwImage.pImage == NULL)
		{
			ti_dprintf(TIWLAN_LOG_ERROR, "wlanDrv_GetFile: ERROR: no Firmware image, exiting\n");
			return TI_NOK;
		}

		pFileInfo->pBuffer = (TI_UINT8 *)drv->tCommon.tFwImage.pImage; 
		pFileInfo->bLast		= TI_FALSE;
		pFileInfo->uLength	= 0;
		pFileInfo->uOffset 				= 0;
		pFileInfo->uChunkBytesLeft 		= 0;
		pFileInfo->uChunksLeft 			= BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
		/* check uChunksLeft's Validity */
		if (( pFileInfo->uChunksLeft == 0 ) || ( pFileInfo->uChunksLeft > MAX_CHUNKS_IN_FILE ))
		{
			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() Read Invalid Chunks Left: %d!\n",pFileInfo->uChunksLeft);
			return TI_NOK;
		}
		pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
		/* FALL THROUGH */
	case FILE_TYPE_FW_NEXT:
		/* check dec. validity */
		if ( pFileInfo->uChunkBytesLeft >= pFileInfo->uLength )
		{
			pFileInfo->uChunkBytesLeft 		-= pFileInfo->uLength;
		}
		/* invalid Dec. */
		else
		{
			ti_dprintf (TIWLAN_LOG_ERROR, "wlanDrvIf_GetFile() No. of Bytes Left < File Length\n");
			return TI_NOK;
		}
		pFileInfo->pBuffer 	+= pFileInfo->uLength; 

		/* Finished reading all Previous Chunk */
		if ( pFileInfo->uChunkBytesLeft == 0 )
		{
			/* check dec. validity */
			if ( pFileInfo->uChunksLeft > 0 )
			{
				pFileInfo->uChunksLeft--;
			}
			/* invalid Dec. */
			else
			{
				ti_dprintf (TIWLAN_LOG_ERROR, "No. of Bytes Left = 0 and Chunks Left <= 0\n");
				return TI_NOK;
			}
			/* read Chunk's address */
			pFileInfo->uAddress = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
			/* read Portion's length */
			pFileInfo->uChunkBytesLeft = BYTE_SWAP_LONG( *((TI_UINT32*)(pFileInfo->pBuffer)) );
			pFileInfo->pBuffer += DRV_ADDRESS_SIZE;
		}
		/* Reading Chunk is NOT complete */
		else
		{
			pFileInfo->uAddress += pFileInfo->uLength;
		}
		
		if ( pFileInfo->uChunkBytesLeft < OS_SPECIFIC_RAM_ALLOC_LIMIT )
		{
			pFileInfo->uLength = pFileInfo->uChunkBytesLeft;
		}
		else
		{
			pFileInfo->uLength = OS_SPECIFIC_RAM_ALLOC_LIMIT;
		}

		/* If last chunk to download */
		if (( pFileInfo->uChunksLeft == 0 ) && 
			( pFileInfo->uLength == pFileInfo->uChunkBytesLeft ))
		{
			pFileInfo->bLast = TI_TRUE;
		}

		break;
	}

	/* Call the requester callback */
	if (pFileInfo->fCbFunc)
	{
		pFileInfo->fCbFunc (pFileInfo->hCbHndl);
	}

	return TI_OK;
}