AJ_EXPORT AJ_Status AJ_WSL_WriteBufListToMBox(uint8_t box, uint8_t endpoint, uint16_t len, AJ_BufList* list) { AJ_Status status = AJ_ERR_SPI_WRITE; uint16_t spaceAvailable = 0; uint16_t bytesRemaining; uint16_t cause = 0; AJ_ASSERT(0 == box); // AJ_InfoPrintf(("=HTC Credits 0:%x, 1:%x, 2:%x\n", AJ_WSL_HTC_Global.endpoints[0].txCredits, AJ_WSL_HTC_Global.endpoints[1].txCredits, AJ_WSL_HTC_Global.endpoints[2].txCredits)); AJ_Time credit_timer; AJ_InitTimer(&credit_timer); while (AJ_WSL_HTC_Global.endpoints[endpoint].txCredits < 1) { // do nothing and wait until there are credits if (AJ_GetElapsedTime(&credit_timer, TRUE) > 1500) { AJ_WSL_HTC_Global.endpoints[endpoint].txCredits++; break; } AJ_YieldCurrentTask(); } // don't let the other tasks interrupt our SPI access AJ_EnterCriticalRegion(); AJ_Time space_timer; AJ_InitTimer(&space_timer); // read space available in mbox from register do { if (AJ_GetElapsedTime(&space_timer, TRUE) > 1500) { spaceAvailable = 0xc5b; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, 1 << 15); break; } status = AJ_WSL_GetWriteBufferSpaceAvailable(&spaceAvailable); } while (spaceAvailable == 0); AJ_ASSERT((status == AJ_OK) && (spaceAvailable >= len)); if ((status == AJ_OK) && (spaceAvailable >= len)) { uint16_t targetAddress; // write size to be transferred status = AJ_WSL_SetDMABufferSize(len); AJ_ASSERT(status == AJ_OK); // write the target address (where we want to send data) // the write should end up at the end of the MBox alias // example 0xFFF - len targetAddress = AJ_WSL_SPI_MBOX_0_EOM_ALIAS - len; status = AJ_WSL_SPI_DMAWriteStart(targetAddress); AJ_ASSERT(status == AJ_OK); bytesRemaining = len; // Take the AJ_BufList to write out and write it out to the SPI interface via DMA AJ_WSL_BufListIterate_DMA(list); // clear the packet available interrupt cause = 0x1f; status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, cause); AJ_ASSERT(status == AJ_OK); AJ_WSL_HTC_Global.endpoints[endpoint].txCredits -= 1; } else { status = AJ_ERR_SPI_NO_SPACE; } AJ_LeaveCriticalRegion(); return status; }
void AJ_WSL_MBoxListenAndProcessTask(void* parameters) { g_b_spi_interrupt_data_ready = FALSE; AJ_WSL_SPI_InitializeSPIController(); set_SPI_registers(); write_BOOT_PARAM(); g_b_spi_interrupt_data_ready = FALSE; // loop and process all of the responses while (1) { AJ_Status status; AJ_WSL_HTC_ProcessInterruptCause(); uint8_t i; for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { do { wsl_work_item* item = NULL; // peek at the queue, then make sure we have enough credits // if we have enough, pull and send the workitem to the MBOX // otherwise, move to the next socket and then eventually out of this loop. // Credits would be available again once AJ_WSL_HTC_ProcessInterruptCause has // read any credit-adjustment trailers status = AJ_QueuePeek(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &item); if ((status != AJ_OK) || (AJ_WSL_HTC_Global.endpoints[item->endpoint].txCredits < 1)) { break; } // pull a work item off of a socket queue and send it AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &item, 0); if (!item) { break; } else { //AJ_AlwaysPrintf(("AJ_WSL_MBoxListenAndProcessTask: %x\n", item->itemType)); AJ_WSL_WriteBufListToMBox(0, item->endpoint, AJ_BufListLengthOnWire(item->list), item->list); /* * if this item is sending data, create a workitem indicating completion * this special check is needed because there is no socket send command in WMI, * otherwise we could handle it in AJ_WSL_WMI_ProcessWMIEvent */ if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX)) { wsl_work_item** ppWork; wsl_work_item* sockWork; sockWork = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(sockWork, 0, sizeof(wsl_work_item)); sockWork->itemType = item->itemType; sockWork->endpoint = item->endpoint; ppWork = &sockWork; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue, ppWork, AJ_TIMER_FOREVER); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); } if (!g_b_spi_interrupt_data_ready) { AJ_YieldCurrentTask(); } g_b_spi_interrupt_data_ready = FALSE; // reset the state of the interrupt signal } }