#include "FreeRTOS.h" #include "ameba_soc.h" //#include "rtl8710b_sdio.h" //#include "rtl8711b_tim.h" #include "spdio_api.h" #include "rtl8710b_inic.h" #include "rtl8710b_sdio.h" #define SPDIO_IRQ_PRIORITY 10 #define SPDIO_TX_BUF_SZ_UNIT 64 #define RX_BD_FREE_TH 5 #define MIN_RX_BD_SEND_PKT 2 #define MAX_RX_BD_BUF_SIZE 16380 // the Maximum size for a RX_BD point to, make it 4-bytes aligned typedef struct { u32 Address; /* The TX buffer physical address, it must be 4-bytes aligned */ }SPDIO_TX_BD; /* The RX Buffer Descriptor format */ typedef struct { u32 BuffSize:14; /* bit[13:0], RX Buffer Size, Maximum 16384-1 */ u32 LS:1; /* bit[14], is the Last Segment ? */ u32 FS:1; /* bit[15], is the First Segment ? */ u32 Seq:16; /* bit[31:16], The sequence number, it's no use for now */ u32 PhyAddr; /* The RX buffer physical address, it must be 4-bytes aligned */ } SPDIO_RX_BD; /* the data structer to bind a TX_BD with a TX Packet */ typedef struct { SPDIO_TX_BD *pTXBD; // Point to the TX_BD buffer VOID *priv; u8 isPktEnd; // For a packet over 1 BD , this flag to indicate is this BD contains a packet end u8 isFree; // is this TX BD free } SPDIO_TX_BD_HANDLE; /* the data structer to bind a RX_BD with a RX Packet */ typedef struct { VOID *priv; SPDIO_RX_BD *pRXBD; // Point to the RX_BD buffer INIC_RX_DESC *pRXDESC; // point to the Rx Packet u8 isPktEnd; // For a packet over 1 BD , this flag to indicate is this BD contains a packet end u8 isFree; // is this RX BD free (DMA done and its RX packet has been freed) } SPDIO_RX_BD_HANDLE; typedef struct { VOID *spdio_priv; /*Data from User*/ u8 *pTXBDAddr; /* The TX_BD start address */ SPDIO_TX_BD *pTXBDAddrAligned; /* The TX_BD start address, it must be 4-bytes aligned */ SPDIO_TX_BD_HANDLE* pTXBDHdl; /* point to the allocated memory for TX_BD Handle array */ u16 TXBDWPtr; /* The SDIO TX(Host->Device) BD local write index, different with HW maintained write Index. */ u16 TXBDRPtr; /* The SDIO TX(Host->Device) BD read index */ u16 TXBDRPtrReg; /* The SDIO TX(Host->Device) BD read index has been write to HW register */ u8 TxOverFlow; u8 *pRXBDAddr; /* The RX_BD start address */ SPDIO_RX_BD *pRXBDAddrAligned; /* The RX_BD start address, it must be 8-bytes aligned */ u8 *pRXDESCAddr; INIC_RX_DESC *pRXDESCAddrAligned; SPDIO_RX_BD_HANDLE* pRXBDHdl; /* point to the allocated memory for RX_BD Handle array */ u16 RXBDWPtr; /* The SDIO RX(Device->Host) BD write index */ u16 RXBDRPtr; /* The SDIO RX(Device->Host) BD local read index, different with HW maintained Read Index. */ _sema IrqSema; /* Semaphore for SDIO RX, use to wakeup the SDIO RX task */ xTaskHandle xSDIOIrqTaskHandle; /* The handle of the SDIO Task speical for RX, can be used to delte the task */ } HAL_SPDIO_ADAPTER, *PHAL_SPDIO_ADAPTER; struct spdio_t *g_spdio_priv = NULL; HAL_SPDIO_ADAPTER gSPDIODev; PHAL_SPDIO_ADAPTER pgSPDIODev = NULL; s8 spdio_rx_done_cb(void *padapter, void *data, u16 offset, u16 pktsize, u8 type) { struct spdio_buf_t *buf = (struct spdio_buf_t *)data; struct spdio_t *obj = (struct spdio_t *)padapter; if(obj) return obj->rx_done_cb(obj, buf, (u8 *)(buf->buf_addr+offset), pktsize, type); else DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio rx done callback function is null!"); return SUCCESS; } s8 spdio_tx_done_cb(void *padapter, IN u8 *data) { struct spdio_t *obj = (struct spdio_t *)padapter; struct spdio_buf_t *buf = (struct spdio_buf_t *)data; if(obj) return obj->tx_done_cb(obj, buf); else DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio tx done callback function is null!"); return SUCCESS; } s8 spdio_tx(struct spdio_t *obj, struct spdio_buf_t *pbuf) { PHAL_SPDIO_ADAPTER pgSDIODev = obj->priv; INIC_RX_DESC *pRxDesc; SPDIO_RX_BD_HANDLE *pRxBdHdl; SPDIO_RX_BD *pRXBD; u32 Offset=0; u16 RxBdWrite=0; // to count how much RX_BD used in a Transaction u16 RxBdRdPtr= pgSDIODev->RXBDRPtr; // RX_BD read pointer u32 pkt_size; #if SDIO_RX_PKT_SIZE_OVER_16K u8 needed_rxbd_num; #endif /* check if RX_BD available */ #if SDIO_RX_PKT_SIZE_OVER_16K needed_rxbd_num = ((pbuf->buf_size - 1)/MAX_RX_BD_BUF_SIZE) + MIN_RX_BD_SEND_PKT; #endif if (RxBdRdPtr != pgSDIODev->RXBDWPtr) { if (pgSDIODev->RXBDWPtr > RxBdRdPtr) { #if SDIO_RX_PKT_SIZE_OVER_16K if ((pgSDIODev->RXBDWPtr - RxBdRdPtr) >= (obj->tx_bd_num - needed_rxbd_num)) #else if ((pgSDIODev->RXBDWPtr - RxBdRdPtr) >= (obj->tx_bd_num - MIN_RX_BD_SEND_PKT)) #endif { DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Return_Rx_Data: No Available RX_BD, ReadPtr=%d WritePtr=%d\n", \ RxBdRdPtr, pgSDIODev->RXBDWPtr); return _FALSE; } } else { #if SDIO_RX_PKT_SIZE_OVER_16K if ((RxBdRdPtr - pgSDIODev->RXBDWPtr) <= needed_rxbd_num) #else if ((RxBdRdPtr - pgSDIODev->RXBDWPtr) <= MIN_RX_BD_SEND_PKT) #endif { DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Return_Rx_Data: No Available RX_BD, ReadPtr=%d WritePtr=%d\n", RxBdRdPtr, pgSDIODev->RXBDWPtr); return _FALSE; } } } // TODO: Add RX_DESC before the packet /* a SDIO RX packet will use at least 2 RX_BD, the 1st one is for RX_Desc, other RX_BDs are for packet payload */ /* Use a RX_BD to transmit RX_Desc */ pRXBD = pgSDIODev->pRXBDAddrAligned + pgSDIODev->RXBDWPtr; // get the RX_BD head pRxBdHdl = pgSDIODev->pRXBDHdl + pgSDIODev->RXBDWPtr; pRxDesc = pRxBdHdl->pRXDESC; pRxDesc->type = pbuf->type; pRxDesc->pkt_len = pbuf->buf_size; pRxDesc->offset = sizeof(INIC_RX_DESC); if (!pRxBdHdl->isFree) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Return_Rx_Data: Allocated a non-free RX_BD\n"); } pRxBdHdl->isFree = 0; pRXBD->FS = 1; pRXBD->LS = 0; pRXBD->PhyAddr = (u32)((u8 *)pRxBdHdl->pRXDESC); pRXBD->BuffSize = sizeof(INIC_RX_DESC); pRxBdHdl->isPktEnd = 0; pgSDIODev->RXBDWPtr += 1; if (pgSDIODev->RXBDWPtr >= obj->tx_bd_num) { pgSDIODev->RXBDWPtr -= obj->tx_bd_num; } RxBdWrite++; /* Take RX_BD to transmit packet payload */ pkt_size = pbuf->buf_size; Offset = 0; do { pRXBD = pgSDIODev->pRXBDAddrAligned + pgSDIODev->RXBDWPtr; // get the RX_BD head pRxBdHdl = pgSDIODev->pRXBDHdl + pgSDIODev->RXBDWPtr; pRxBdHdl->isFree = 0; pRXBD->FS = 0; pRXBD->PhyAddr = (u32)((u8 *)pbuf->buf_addr + Offset); #if SDIO_RX_PKT_SIZE_OVER_16K if ((pkt_size - Offset) <= MAX_RX_BD_BUF_SIZE) { pRXBD->BuffSize = pkt_size - Offset; pRxBdHdl->isPktEnd = 1; }else { pRXBD->BuffSize = MAX_RX_BD_BUF_SIZE; pRxBdHdl->isPktEnd = 0; DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Return_Rx_Data: Split RX_BD, Offset=%d PktSize=%d\n", \ Offset, pkt_size); } #else if (pkt_size > MAX_RX_BD_BUF_SIZE) { // if come to here, please enable "SDIO_RX_PKT_SIZE_OVER_16K" DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Return_Rx_Data: The Packet Size bigger than 16K\n"); pkt_size = MAX_RX_BD_BUF_SIZE; } pRXBD->BuffSize = pkt_size; pRxBdHdl->priv = (void*)pbuf; pRxBdHdl->isPktEnd = 1; #endif Offset += pRXBD->BuffSize; // Move the RX_BD Write pointer forward RxBdWrite++; pgSDIODev->RXBDWPtr += 1; if (pgSDIODev->RXBDWPtr >= obj->tx_bd_num) { pgSDIODev->RXBDWPtr -= obj->tx_bd_num; } if (Offset >= pkt_size) { pRXBD->LS = 1; } } while (Offset < pkt_size); if (RxBdWrite > 0) { SDIO_RXBD_WPTR_Set(pgSDIODev->RXBDWPtr); HAL_SDIO_WRITE8(REG_SPDIO_HCI_RX_REQ, BIT_HCI_RX_REQ); } DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Return_Rx_Data(%d)<==\n", RxBdWrite); return _TRUE; } void spdio_structinit(struct spdio_t *obj){ obj->rx_bd_bufsz = SPDIO_RX_BUFSZ_ALIGN(2048+24); //extra 24 bytes for sdio header obj->rx_bd_num = 24; obj->tx_bd_num = 24; obj->priv = NULL; obj->rx_buf = NULL; obj->rx_done_cb = NULL; obj->tx_done_cb = NULL; } /****************************************************************************** * Function: SDIO_TX_FIFO_DataReady * Desc: Handle the SDIO FIFO data ready interrupt. * 1. Send those data to the target driver via callback fun., like WLan. * 2. Allocate a buffer for the TX BD * * Para: * pSDIODev: The SDIO device data structor. ******************************************************************************/ VOID SPDIO_TX_FIFO_DataReady(IN PHAL_SPDIO_ADAPTER pSPDIODev) { SPDIO_TX_BD_HANDLE* pTxBdHdl; PINIC_TX_DESC pTxDesc; volatile u16 TxBDWPtr=0; u8 isForceBreak=0; s8 ret=FAIL; u32 reg; SPDIO_TX_BD *pTXBD = NULL; struct spdio_t *obj = (struct spdio_t *)pSPDIODev->spdio_priv; TxBDWPtr = SDIO_TXBD_WPTR_Get(); if (TxBDWPtr == pSPDIODev->TXBDRPtr) { if (unlikely(pSPDIODev->TxOverFlow != 0)) { pSPDIODev->TxOverFlow = 0; DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO TX Data Read False Triggered!!, TXBDWPtr=0x%x\n", TxBDWPtr); } else { reg = HAL_SDIO_READ32(REG_SPDIO_AHB_DMA_CTRL); DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO TX Overflow Case: Reg DMA_CTRL==0x%x %x %x %x\n", (reg>> 24)&0xff , (reg>>16)&0xff, (reg>>8)&0xff, (reg)&0xff); return; } } do { DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_TX_DataReady: TxBDWPtr=%d TxBDRPtr=%d\n", TxBDWPtr, pSPDIODev->TXBDRPtr); pTXBD= (SPDIO_TX_BD*)(pSPDIODev->pTXBDAddrAligned + pSPDIODev->TXBDRPtr); pTxBdHdl = pSPDIODev->pTXBDHdl + pSPDIODev->TXBDRPtr; pTxDesc = (PINIC_TX_DESC)(pTXBD->Address); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_TX_DataReady: PktSz=%d Offset=%d\n", pTxDesc->txpktsize, pTxDesc->offset); if ((pTxDesc->txpktsize + pTxDesc->offset) <= obj->rx_bd_bufsz) { // use the callback function to fordward this packet to target(WLan) driver ret = spdio_rx_done_cb(obj, (u8*)pTxBdHdl->priv, pTxDesc->offset, pTxDesc->txpktsize, pTxDesc->type); if(ret == FAIL) DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO TX_Callback is Null!\n"); pTXBD->Address = obj->rx_buf[pSPDIODev->TXBDRPtr].buf_addr; } else { // Invalid packet, Just drop it ret = SUCCESS; // pretend we call the TX callback OK } if (SUCCESS != ret) { // may be is caused by TX queue is full, so we skip it and try again later isForceBreak = 1; break; // break the while loop } else { pSPDIODev->TXBDRPtr++; if (pSPDIODev->TXBDRPtr >= obj->rx_bd_num) { pSPDIODev->TXBDRPtr = 0; } pSPDIODev->TXBDRPtrReg = pSPDIODev->TXBDRPtr; SDIO_TXBD_RPTR_Set(pSPDIODev->TXBDRPtrReg); } TxBDWPtr = SDIO_TXBD_WPTR_Get(); if (isForceBreak) { break; // break the TX FIFO DMA Done processing } } while (pSPDIODev->TXBDRPtr != TxBDWPtr); // if not all TX data were processed, set an event to trigger SDIO_Task to process them later if (isForceBreak) { DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_TX Force Break: TXBDWP=0x%x TXBDRP=0x%x\n", TxBDWPtr, pSPDIODev->TXBDRPtr); } } VOID SPDIO_Recycle_Rx_BD (IN PHAL_SPDIO_ADAPTER pgSPDIODev) { SPDIO_RX_BD_HANDLE *pRxBdHdl; SPDIO_RX_BD *pRXBD; u32 PktSize; u32 FreeCnt=0; // for debugging struct spdio_t *obj = (struct spdio_t *)pgSPDIODev->spdio_priv; SDIO_INTConfig(BIT_C2H_DMA_OK, DISABLE); while (SDIO_RXBD_RPTR_Get() != pgSPDIODev->RXBDRPtr) { pRxBdHdl = pgSPDIODev->pRXBDHdl + pgSPDIODev->RXBDRPtr; pRXBD = pRxBdHdl->pRXBD; if (!pRxBdHdl->isFree) { if(pRxBdHdl->isPktEnd){ spdio_tx_done_cb(obj, (u8*)(pRxBdHdl->priv)); } pRxBdHdl->isPktEnd = 0; _memset((void *)(pRxBdHdl->pRXDESC), 0, sizeof(INIC_RX_DESC)); _memset((void *)pRXBD , 0, sizeof(SPDIO_RX_BD)); // clean this RX_BD pRxBdHdl->isFree = 1; } else { DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Recycle_Rx_BD: Warring, Recycle a Free RX_BD,RXBDRPtr=%d\n",pgSPDIODev->RXBDRPtr); } pgSPDIODev->RXBDRPtr++; if (pgSPDIODev->RXBDRPtr >= obj->tx_bd_num) { pgSPDIODev->RXBDRPtr -= obj->tx_bd_num; } } SDIO_INTConfig(BIT_C2H_DMA_OK, ENABLE); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "<==SDIO_Recycle_Rx_BD(%d)\n", FreeCnt); } /****************************************************************************** * Function: SPDIO_IRQ_Handler * Desc: SPDIO device interrupt service routine * 1. Read & clean the interrupt status * 2. Wake up the SDIO task to handle the IRQ event * * Para: * pSDIODev: The SDIO device data structor. ******************************************************************************/ VOID SPDIO_IRQ_Handler(VOID *pData) { PHAL_SPDIO_ADAPTER pSPDIODev = pData; InterruptDis(SDIO_DEVICE_IRQ); rtw_up_sema_from_isr(&pSPDIODev->IrqSema); } VOID SPDIO_IRQ_Handler_BH(VOID *pData) { PHAL_SPDIO_ADAPTER pgSPDIODev = pData; u16 IntStatus; for (;;) { /* Task blocked and wait the semaphore(events) here */ rtw_down_sema(&pgSPDIODev->IrqSema); IntStatus = HAL_SDIO_READ16(REG_SPDIO_CPU_INT_STAS); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "%s:ISRStatus=0x%x\n", __FUNCTION__, IntStatus); HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, IntStatus); // clean the ISR InterruptEn(SDIO_DEVICE_IRQ, SPDIO_IRQ_PRIORITY); if (IntStatus & BIT_C2H_DMA_OK) { SPDIO_Recycle_Rx_BD(pgSPDIODev); } if (IntStatus & BIT_H2C_MSG_INT) { HAL_SDIO_READ32(REG_SPDIO_CPU_H2C_MSG); } if (IntStatus & BIT_H2C_DMA_OK) { SDIO_INTConfig(BIT_H2C_DMA_OK, DISABLE); SPDIO_TX_FIFO_DataReady(pgSPDIODev); SDIO_INTConfig(BIT_H2C_DMA_OK, ENABLE); } if (IntStatus & BIT_TXFIFO_H2C_OVF) { pgSPDIODev->TxOverFlow = 1; } DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "%s @2 IntStatus=0x%x\n", __FUNCTION__, IntStatus); } SDIO_SetEvent(pgSPDIODev, (u32)SDIO_EVENT_IRQ_STOPPED); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO irq Task Stopped!\n"); #if ( INCLUDE_vTaskDelete == 1 ) vTaskDelete(NULL); #endif } /****************************************************************************** * Function: SPDIO_Device_Init * Desc: SDIO mbed device driver initialization. * 1. Allocate SDIO TX BD and RX BD adn RX Desc. * 2. Allocate SDIO RX Buffer Descriptor and RX Buffer. Initial RX related * register. * 3. Register the Interrupt function. * ******************************************************************************/ BOOL SPDIO_Device_Init(struct spdio_t * obj) { int i; SPDIO_TX_BD_HANDLE *pTxBdHdl; SPDIO_RX_BD_HANDLE *pRxBdHdl; int ret; SPDIO_TX_BD *pTXBD = NULL; SDIO_InitTypeDef SDIO_InitStruct; if(obj == NULL){ DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "struct spdio_t must be inited\n"); return FAIL; } DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Device_Init==>\n"); pgSPDIODev = &gSPDIODev; pgSPDIODev->spdio_priv = (void*)obj; obj->priv = (void *)pgSPDIODev; // initial TX BD and RX BD pgSPDIODev->pTXBDAddr = _rtw_malloc((obj->rx_bd_num* sizeof(SPDIO_TX_BD))+3); if (NULL == pgSPDIODev->pTXBDAddr) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for TX_BD Err!!\n"); goto SDIO_INIT_ERR; } pgSPDIODev->pTXBDAddrAligned = (SPDIO_TX_BD*)(((((u32)pgSPDIODev->pTXBDAddr - 1) >> 2) + 1) << 2); // Make it 4-bytes aligned pgSPDIODev->pRXBDAddr = _rtw_malloc((obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7); if (NULL == pgSPDIODev->pRXBDAddr) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_BD Err!!\n"); goto SDIO_INIT_ERR; } pgSPDIODev->pRXBDAddrAligned = (SPDIO_RX_BD*)(((((u32)pgSPDIODev->pRXBDAddr - 1) >> 3) + 1) << 3); // Make it 8-bytes aligned pgSPDIODev->pRXDESCAddr = _rtw_zmalloc((obj->tx_bd_num * sizeof(INIC_RX_DESC)) + 3); if (NULL == pgSPDIODev->pRXDESCAddr) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_DESC Err!!\n"); goto SDIO_INIT_ERR; } pgSPDIODev->pRXDESCAddrAligned = (INIC_RX_DESC*)(((((u32)pgSPDIODev->pRXDESCAddr - 1) >> 2) + 1) << 2); //Make it 4-bytes aligned // Clean boot from wakeup bit SOCPS_BootFromPS(DISABLE); /* SDIO Function & CLock Enable */ RCC_PeriphClockCmd(APBPeriph_SDIOD_ON, APBPeriph_SDIOD_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_SDIOD_OFF, APBPeriph_SDIOD_CLOCK, ENABLE); // SDIO_SCLK / SPI_CLK pin pull-low //PAD_PullCtrl(_PA_3, GPIO_PuPd_DOWN); SDIO_StructInit(&SDIO_InitStruct); SDIO_InitStruct.TXBD_BAR = (u32)pgSPDIODev->pTXBDAddrAligned; SDIO_InitStruct.TXBD_RING_SIZE = obj->rx_bd_num; //SDIO_TX_BD_NUM; SDIO_InitStruct.TX_BUFFER_SIZE = ((((obj->rx_bd_bufsz-1)/SPDIO_TX_BUF_SZ_UNIT)+1)&0xff); SDIO_InitStruct.RXBD_BAR = (u32)pgSPDIODev->pRXBDAddrAligned; SDIO_InitStruct.RXBD_RING_SIZE = obj->tx_bd_num; SDIO_InitStruct.RXBD_FREE_TH = RX_BD_FREE_TH; SDIO_Init((&SDIO_InitStruct)); pgSPDIODev->TXBDWPtr = SDIO_TXBD_WPTR_Get(); pgSPDIODev->TXBDRPtr = pgSPDIODev->TXBDWPtr; pgSPDIODev->TXBDRPtrReg = pgSPDIODev->TXBDWPtr; pgSPDIODev->RXBDWPtr = pgSPDIODev->RXBDRPtr = SDIO_RXBD_RPTR_Get(); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "TXBDWPtr=0x%x TXBDRPtr=0x%x\n", pgSPDIODev->TXBDWPtr, pgSPDIODev->TXBDRPtr); pgSPDIODev->pTXBDHdl = (SPDIO_TX_BD_HANDLE*)_rtw_zmalloc(obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE)); if (NULL == pgSPDIODev->pTXBDHdl) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for TX_BD Handle Err!!\n"); goto SDIO_INIT_ERR; } for(i=0;irx_bd_num;i++){ pTxBdHdl = pgSPDIODev->pTXBDHdl + i; pTxBdHdl->pTXBD= pgSPDIODev->pTXBDAddrAligned + i; // Pre-allocate buffer by User pTxBdHdl->priv = (void *)&obj->rx_buf[i]; pTxBdHdl->pTXBD->Address = (u32)obj->rx_buf[i].buf_addr; if(pTxBdHdl->pTXBD->Address%4){ DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "buffer address must be aligned to 4!!\n"); goto SDIO_INIT_ERR; } if (NULL == (u32*)(pTxBdHdl->pTXBD->Address)) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc buffer for TX_BD Err!!\n"); goto SDIO_INIT_ERR; } pTxBdHdl->isFree = 1; DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "TX_BD%d @ 0x%x 0x%x\n", i, pTxBdHdl, pTxBdHdl->pTXBD); } pgSPDIODev->pRXBDHdl = (SPDIO_RX_BD_HANDLE*)_rtw_zmalloc(obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE)); if (NULL == pgSPDIODev->pRXBDHdl) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_BD Handle Err!!\n"); goto SDIO_INIT_ERR; } for (i=0; itx_bd_num; i++) { pRxBdHdl = pgSPDIODev->pRXBDHdl + i; pRxBdHdl->pRXBD = pgSPDIODev->pRXBDAddrAligned + i; pRxBdHdl->pRXDESC = pgSPDIODev->pRXDESCAddrAligned + i; pRxBdHdl->isFree = 1; } rtw_init_sema(&(pgSPDIODev->IrqSema), 0); if (NULL == pgSPDIODev->IrqSema){ DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init Create IRQ Semaphore Err!!\n"); goto SDIO_INIT_ERR; } ret = xTaskCreate( SPDIO_IRQ_Handler_BH, "SPDIO_IRQ_TASK", ((1024*1)/sizeof(portBASE_TYPE)), (void *)pgSPDIODev, 1 + PRIORITIE_OFFSET, &pgSPDIODev->xSDIOIrqTaskHandle); if (pdTRUE != ret ) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Create IRQ Task Err(%d)!!\n", ret); goto SDIO_INIT_ERR; } //pgSPDIODev->CRPWM = SDIO_RPWM1_Get(); //pgSPDIODev->CRPWM2 = SDIO_RPWM2_Get(); // Indicate Host this is a iNIC FW //SDIO_CPWM2_Set(CPWM2_INIC_FW_RDY_BIT, ENABLE); /* enable the interrupt */ InterruptRegister((IRQ_FUN) SPDIO_IRQ_Handler, SDIO_DEVICE_IRQ, (u32) pgSPDIODev, SPDIO_IRQ_PRIORITY); InterruptEn(SDIO_DEVICE_IRQ, SPDIO_IRQ_PRIORITY); HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, SDIO_INIT_INT_MASK); // Clean pending interrupt first HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_MASK, SDIO_INIT_INT_MASK); // Update the power state indication SDIO_CPWM2_Set(CPWM2_ACT_BIT, ENABLE); /* Indicate the Host system that the TX/RX is ready */ HAL_SDIO_WRITE8(REG_SPDIO_CPU_IND, \ HAL_SDIO_READ8(REG_SPDIO_CPU_IND)|BIT_SYSTEM_TRX_RDY_IND); DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "<==SDIO_Device_Init\n"); return SUCCESS; SDIO_INIT_ERR: if (pgSPDIODev->pRXBDHdl) { _rtw_mfree((u8 *)pgSPDIODev->pRXBDHdl, obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE)); pgSPDIODev->pRXBDHdl = NULL; } if ((pgSPDIODev->pTXBDHdl)) { for (i=0;irx_bd_num;i++){ pTxBdHdl = pgSPDIODev->pTXBDHdl + i; if (pTxBdHdl->pTXBD->Address) { pTxBdHdl->pTXBD->Address = (u32)NULL; } } _rtw_mfree((u8 *)pgSPDIODev->pTXBDHdl, (obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE))); pgSPDIODev->pTXBDHdl = NULL; } if (pgSPDIODev->pRXBDAddr) { _rtw_mfree((u8 *)pgSPDIODev->pRXBDAddr, (obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7); pgSPDIODev->pRXBDAddr = NULL; } if (pgSPDIODev->pTXBDAddr) { _rtw_mfree(pgSPDIODev->pTXBDAddr, ((obj->rx_bd_num * sizeof(SPDIO_TX_BD))+3)); pgSPDIODev->pTXBDAddr = NULL; pgSPDIODev->pTXBDAddrAligned = NULL; } if (pgSPDIODev->pRXDESCAddr) { _rtw_mfree(pgSPDIODev->pRXDESCAddr, (((obj->rx_bd_num)* sizeof(INIC_RX_DESC)) + 3)); pgSPDIODev->pRXDESCAddr = NULL; pgSPDIODev->pRXDESCAddrAligned = NULL; } return FAIL; } /****************************************************************************** * Function: SPDIO_Device_DeInit * Desc: SDIO device driver free resource. This function should be called in * a task. * 1. Free TX FIFO buffer * * Para: * pSDIODev: The SDIO device data structor. ******************************************************************************/ //TODO: Call this function in a task VOID SPDIO_Device_DeInit(VOID) { int i=0; SPDIO_TX_BD_HANDLE *pTxBdHdl; SPDIO_TX_BD *pTXBD = NULL; struct spdio_t * obj; if (NULL == pgSPDIODev) return; obj = pgSPDIODev->spdio_priv; // Indicate the Host that Ameba is InActived SDIO_CPWM2_Set(CPWM2_ACT_BIT, DISABLE); if (pgSPDIODev->pRXBDHdl) { _rtw_mfree((u8 *)pgSPDIODev->pRXBDHdl, obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE)); pgSPDIODev->pRXBDHdl = NULL; } /* Free TX FIFO Buffer */ for (i=0;irx_bd_num;i++) { pTXBD = (SPDIO_TX_BD*)(pgSPDIODev->pTXBDAddrAligned + i); pTxBdHdl = pgSPDIODev->pTXBDHdl + i; if (pTXBD->Address) { pTXBD->Address = (u32)NULL; } } if ((pgSPDIODev->pTXBDHdl)) { for (i=0;irx_bd_num;i++){ pTxBdHdl = pgSPDIODev->pTXBDHdl + i; if (pTxBdHdl->pTXBD->Address) { pTxBdHdl->pTXBD->Address = (u32)NULL; } } _rtw_mfree((u8 *)pgSPDIODev->pTXBDHdl, (obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE))); pgSPDIODev->pTXBDHdl = NULL; } if (pgSPDIODev->pRXBDAddr) { _rtw_mfree((u8 *)pgSPDIODev->pRXBDAddr, (obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7); pgSPDIODev->pRXBDAddr = NULL; } if (pgSPDIODev->pTXBDAddr) { _rtw_mfree(pgSPDIODev->pTXBDAddr, ((obj->rx_bd_num * sizeof(SPDIO_TX_BD))+3)); pgSPDIODev->pTXBDAddr = NULL; pgSPDIODev->pTXBDAddrAligned = NULL; } if (pgSPDIODev->pRXDESCAddr) { _rtw_mfree(pgSPDIODev->pRXDESCAddr, (((obj->rx_bd_num)* sizeof(INIC_RX_DESC)) + 3)); pgSPDIODev->pRXDESCAddr = NULL; pgSPDIODev->pRXDESCAddrAligned = NULL; } SDIO_INTConfig(0xffff, DISABLE); HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, 0xffff); // Clean pending interrupt first InterruptDis(SDIO_DEVICE_IRQ); InterruptUnRegister(SDIO_DEVICE_IRQ); if (pgSPDIODev->IrqSema) { rtw_free_sema(&pgSPDIODev->IrqSema); pgSPDIODev->IrqSema = NULL; } // Reset SDIO DMA SDIO_DMA_Reset(); /* SDIO_OFF Disable, SDIO will lost if SDIO_ON OFF */ SDIOD_OFF_FCTRL(OFF); } void spdio_init(struct spdio_t *obj) { if(obj == NULL){ DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio obj is NULL, spdio init failed!\n"); return; } if((obj->rx_bd_num == 0) ||(obj->rx_bd_bufsz == 0) || (obj->rx_bd_bufsz%64) ||(obj->tx_bd_num == 0) ||(obj->tx_bd_num%2)||(obj->rx_buf == NULL)) { DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio obj resource isn't correctly inited, spdio init failed!\n"); return; } g_spdio_priv = obj; SPDIO_Device_Init(obj); } void spdio_deinit(struct spdio_t *obj) { if(obj == NULL){ SPDIO_API_PRINTK("spdio obj is NULL, spdio deinit failed"); return; } SPDIO_Device_DeInit(); g_spdio_priv = NULL; }