void hifRWCompletionHandler(SDREQUEST *request) { void *context; A_STATUS status = A_OK; HIF_DEVICE *device; BUS_REQUEST *busrequest; busrequest = (BUS_REQUEST *)request->pCompleteContext; AR_DEBUG_ASSERT(busrequest->request == request); device = busrequest->device; context = busrequest->context; if (!SDIO_SUCCESS(request->Status)) { status = A_ERROR; } /* free the request, we have all the info we need */ hifFreeBusRequest(device,busrequest); busrequest = NULL; if (device->shutdownInProgress) { device->htcCallbacks.rwCompletionHandler(context, A_ERROR); return; } device->htcCallbacks.rwCompletionHandler(context, status); }
/* * SDIO_RegisterFunction - register a function driver */ SDIO_STATUS SDIO_RegisterFunction(PSDFUNCTION pFunction) { int error; SDIO_STATUS status; DBG_PRINT(SDDBG_TRACE, ("SDIO BusDriver - SDIO_RegisterFunction\n")); /* since we do PnP registration first, we need to check the version */ if (!CHECK_FUNCTION_DRIVER_VERSION(pFunction)) { DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: Function Major Version Mismatch (hcd = %d, bus driver = %d)\n", GET_SDIO_STACK_VERSION_MAJOR(pFunction), CT_SDIO_STACK_VERSION_MAJOR(g_Version))); return SDIO_STATUS_INVALID_PARAMETER; } /* we are the exported verison, call the internal verison after registering with the bus we handle probes internally to the bus driver */ if ((error = RegisterDriver(pFunction)) < 0) { DBG_PRINT(SDDBG_ERROR, ("SDIO BusDriver - SDIO_RegisterFunction, failed to register with system bus driver: %d\n", error)); status = OSErrorToSDIOError(error); } else { status = _SDIO_RegisterFunction(pFunction); if (!SDIO_SUCCESS(status)) { UnregisterDriver(pFunction); } } return status; }
/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @function: Post a message queue @function name: SDLIB_PostMessage @prototype: SDIO_STATUS SDLIB_PostMessage(PSDMESSAGE_QUEUE pQueue, PVOID pMessage, INT MessageLength) @category: Support_Reference @input: pQueue - message queue to post to @input: pMessage - message to post @input: MessageLength - length of message (for validation) @return: SDIO_STATUS @notes: The message queue uses an internal list of user defined message structures. When posting a message the message is copied into an allocated structure and queued. The memory pointed to by pMessage does not need to be allocated and can reside on the stack. The length of the message to post can be smaller that the maximum message size. This allows for variable length messages up to the maximum message size. This function returns SDIO_STATUS_NO_RESOURCES, if the message queue is full. This function returns SDIO_STATUS_BUFFER_TOO_SMALL, if the message size exceeds the maximum size of a message. Posting and getting messsages from a message queue is safe in any driver context. @see also: SDLIB_CreateMessageQueue , SDLIB_GetMessage @example: Posting a message MyMessage message; // set up message message.code = MESSAGE_DATA_READY; message.pData = pInstance->pDataBuffers[currentIndex]; // post message status = SDLIB_PostMessage(pInstance->pReadQueue,&message,sizeof(message)); if (!SDIO_SUCCESS(status)) { // failed } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ SDIO_STATUS _PostMessage(PSDMESSAGE_QUEUE pQueue, PVOID pMessage, INT MessageLength) { SDIO_STATUS status2; SDIO_STATUS status = SDIO_STATUS_SUCCESS; PSDMESSAGE_BLOCK pMsg; CT_DECLARE_IRQ_SYNC_CONTEXT(); if (MessageLength > pQueue->MaxMessageLength) { return SDIO_STATUS_BUFFER_TOO_SMALL; } status = CriticalSectionAcquireSyncIrq(&pQueue->MessageCritSection); if (!SDIO_SUCCESS(status)) { return status; } do { /* get a message block */ pMsg = GetFreeMessageBlock(pQueue); if (NULL == pMsg) { status = SDIO_STATUS_NO_RESOURCES; break; } /* copy the message */ memcpy(pMsg->MessageStart,pMessage,MessageLength); /* set the length of the message */ pMsg->MessageLength = MessageLength; /* queue the message to the list */ QueueMessageBlock(pQueue,pMsg); } while (FALSE); status2 = CriticalSectionReleaseSyncIrq(&pQueue->MessageCritSection); return status; }
void SampleCompleteDMATransferCallback(pContext) { PSDHCD_HW_DEVICE pHWDevice = (PSDHCD_HW_DEVICE)pContext; PSDHCD_DEVICE pDevice; SDIO_STATUS status = SDIO_STATUS_SUCCESS; DBG_PRINT(ATH_SPI_TRACE_DATA, ("SPI DMA COMPLETE - \n")); /* TODO : driver should check if DMA completed successfully, this is platform dependent */ pDevice = pHWDevice->pDevice; do { if (!SDIO_SUCCESS(status)) { break; } if (pHWDevice->CommonBufferDMA && pDevice->CurrentTransferDirRx) { /* copy common buffer back for RX */ HcdCommonBufferCopy(pDevice->CurrentDmaWidth, pDevice->pCurrentBuffer, pHWDevice->pDmaCommonBuffer, pDevice->CurrentTransferLength, pDevice->HostDMABufferCopyMode); } } while (FALSE); return; }
/* ------ Functions ------ */ A_STATUS HIFInit(OSDRV_CALLBACKS *callbacks) { SDIO_STATUS status; AR_DEBUG_ASSERT(callbacks != NULL); A_REGISTER_MODULE_DEBUG_INFO(hif); /* Store the callback and event handlers */ osdrvCallbacks = *callbacks; /* Register with bus driver core */ status = SDIO_RegisterFunction(&FunctionContext.function); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); return SDIO_SUCCESS(status) ? A_OK : A_ERROR; }
/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @function: Create a message queue @function name: SDLIB_CreateMessageQueue @prototype: PSDMESSAGE_QUEUE SDLIB_CreateMessageQueue(INT MaxMessages, INT MaxMessageLength) @category: Support_Reference @input: MaxMessages - Maximum number of messages this queue supports @input: MaxMessageLength - Maximum size of each message @return: Message queue object, NULL on failure @notes: This function creates a simple first-in-first-out message queue. The caller must determine the maximum number of messages the queue supports and the size of each message. This function will pre-allocate memory for each message. A producer of data posts a message using SDLIB_PostMessage with a user defined data structure. A consumer of this data can retrieve the message (in FIFO order) using SDLIB_GetMessage. A message queue does not provide a signaling mechanism for notifying a consumer of data. Notifying a consumer is user defined. @see also: SDLIB_DeleteMessageQueue, SDLIB_GetMessage, SDLIB_PostMessage. @example: Creating a message queue: typedef struct _MyMessage { UINT8 Code; PVOID pDataBuffer; } MyMessage; // create message queue, 16 messages max. pMsgQueue = SDLIB_CreateMessageQueue(16,sizeof(MyMessage)); if (NULL == pMsgQueue) { .. failed } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ PSDMESSAGE_QUEUE _CreateMessageQueue(INT MaxMessages, INT MaxMessageLength) { PSDMESSAGE_QUEUE pQueue = NULL; SDIO_STATUS status = SDIO_STATUS_SUCCESS; INT ii; PSDMESSAGE_BLOCK pMsg; do { pQueue = (PSDMESSAGE_QUEUE)KernelAlloc(sizeof(SDMESSAGE_QUEUE)); if (NULL == pQueue) { status = SDIO_STATUS_NO_RESOURCES; break; } SDLIST_INIT(&pQueue->MessageList); SDLIST_INIT(&pQueue->FreeMessageList); pQueue->MaxMessageLength = MaxMessageLength; status = CriticalSectionInit(&pQueue->MessageCritSection); if (!SDIO_SUCCESS(status)) { break; } /* allocate message blocks */ for (ii = 0; ii < MaxMessages; ii++) { pMsg = (PSDMESSAGE_BLOCK)KernelAlloc(sizeof(SDMESSAGE_BLOCK) + MaxMessageLength -1); if (NULL == pMsg) { break; } FreeMessageBlock(pQueue, pMsg); } if (0 == ii) { status = SDIO_STATUS_NO_RESOURCES; break; } } while (FALSE); if (!SDIO_SUCCESS(status)) { if (pQueue != NULL) { _DeleteMessageQueue(pQueue); pQueue = NULL; } } return pQueue; }
void HIFAckInterrupt(HIF_DEVICE *device) { SDIO_STATUS status; /* Acknowledge our function IRQ */ status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ACK_IRQ, NULL, 0); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); }
/////////////////////////////////////////////////////////////////////////////// // DRG_Init - the init entry point for the memory driver // Input: dwContext - the context for this init // Output: // Return: non-zero context // Notes: /////////////////////////////////////////////////////////////////////////////// extern DWORD WINAPI DRG_Init(DWORD dwContext) { PWCHAR pRegPath = NULL; DWORD dwRetCode = 0; HANDLE wlanHandle = NULL; SDIO_CLIENT_INIT_CONTEXT *pContext; DWORD initContext = 0; SDIO_STATUS status; do { status = SDLIB_GetRegistryKeyDWORD(HKEY_LOCAL_MACHINE, (WCHAR *)dwContext, DEVLOAD_CLIENTINFO_VALNAME, (DWORD *)&pContext); if (!SDIO_SUCCESS(status)) { break; } if (pContext->Magic != SDIO_CLIENT_INIT_MAGIC) { return 0; } memcpy(&g_ClientInitContext,pContext,sizeof(SDIO_CLIENT_INIT_CONTEXT)); if (drvInit() != A_OK) { break; } if (!createRegKeyValues()) { break; } // // Create Named Event to notify AR6K Monitor Service program // wlanHandle = CreateEvent (NULL, FALSE, FALSE, L"ATHRWLAN6KEVENT"); dwRetCode = GetLastError (); if (NULL == wlanHandle) { break; } // // Set the event to trigger the service // SetEvent (wlanHandle); /* just return non-zero */ initContext = 1; } while (FALSE); return initContext; }
void HIFMaskInterrupt(HIF_DEVICE *device) { SDIO_STATUS status; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->handle != NULL); /* Mask our function IRQ */ status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_MASK_IRQ, NULL, 0); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); }
/* read write an internal SPI register- ALWAYS synchronous */ static A_STATUS SPIReadWriteInternal(HIF_DEVICE *device, UINT16 address, UINT16 *pValue, BOOL Read) { SDIO_STATUS status; SDREQUEST *sdrequest; BUS_REQUEST *busrequest = NULL; A_STATUS a_status = A_OK; do { /* Allocate a new bus request */ busrequest = hifAllocateBusRequest(device); if (busrequest == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate bus request\n")); a_status = A_ERROR; break; } sdrequest = busrequest->request; if (Read) { ATH_SET_PIO_INTERNAL_READ_OPERATION(sdrequest,address); } else { ATH_SET_PIO_INTERNAL_WRITE_OPERATION(sdrequest,address,*pValue); } /* always synchronous */ sdrequest->Flags = SDREQ_FLAGS_RAW; sdrequest->pCompleteContext = NULL; sdrequest->pCompletion = NULL; /* issue the request */ status = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest); if (!SDIO_SUCCESS(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Spi Internal Read/Write failure: %d\n", status)); a_status = A_ERROR; } else { if (Read) { /* get the read result */ *pValue = ATH_GET_PIO_INTERNAL_READ_RESULT(sdrequest); } } } while (FALSE); if (busrequest != NULL) { hifFreeBusRequest(device, busrequest); } return a_status; }
/* ASYNC completion callback */ static void HifReadWriteScatterCompletion(SDREQUEST *sdrequest) { HIF_SCATTER_REQ *pReq = sdrequest->pCompleteContext; HIF_DEVICE *device; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("+HIF Scatter Completion \n")); if (!SDIO_SUCCESS(sdrequest->Status)) { pReq->CompletionStatus = A_ERROR; } else { pReq->CompletionStatus = A_OK; } device = GET_HIFDEVICE_SR(pReq); /* complete the request */ pReq->CompletionRoutine(pReq); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("-HIF Scatter Completion \n")); }
void HIFUnMaskInterrupt(HIF_DEVICE *device) { SDIO_STATUS status; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->handle != NULL); /* Unmask our function IRQ */ status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ, NULL, 0); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); /* * It was observed that if ar6000 module was removed while an interrupt * was pending then when its reloaded subsequently, the hcd/bus driver * expects an explicit acknowledgment before it can start reporting * interrupts. Under normal conditions, this should be harmless. */ HIFAckInterrupt(device); }
void HIFShutDownDevice(HIF_DEVICE *device) { SDIO_STATUS status; if (device != NULL) { device->shutdownInProgress = TRUE; AR_DEBUG_ASSERT(device->handle != NULL); } else { /* * Unregister with bus driver core. This should flush the pending * requests in the HCD's queues. */ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Unregistering with the bus driver\n")); status = SDIO_UnregisterFunction(&FunctionContext.function); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); } }
/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @function: Get a message from a message queue @function name: SDLIB_GetMessage @prototype: SDIO_STATUS SDLIB_GetMessage(PSDMESSAGE_QUEUE pQueue, PVOID pData, INT *pBufferLength) @category: Support_Reference @input: pQueue - message queue to retreive a message from @input: pBufferLength - on entry, the length of the data buffer @output: pData - buffer to hold the message @output: pBufferLength - on return, contains the number of bytes copied @return: SDIO_STATUS @notes: The message queue uses an internal list of user defined message structures. The message is dequeued (FIFO order) and copied to the callers buffer. The internal allocation for the message is returned back to the message queue. This function returns SDIO_STATUS_NO_MORE_MESSAGES if the message queue is empty. If the length of the buffer is smaller than the length of the message at the head of the queue,this function returns SDIO_STATUS_BUFFER_TOO_SMALL and returns the required length in pBufferLength. @see also: SDLIB_CreateMessageQueue , SDLIB_PostMessage @example: Getting a message MyMessage message; INT length; // set length length = sizeof(message); // post message status = SDLIB_GetMessage(pInstance->pReadQueue,&message,&length); if (!SDIO_SUCCESS(status)) { // failed } @example: Checking queue for a message and getting the size of the message INT length; // use zero length to get the size of the message length = 0; status = SDLIB_GetMessage(pInstance->pReadQueue,NULL,&length); if (status == SDIO_STATUS_NO_MORE_MESSAGES) { // no messages in queue } else if (status == SDIO_STATUS_BUFFER_TOO_SMALL) { // message exists in queue and length of message is returned messageSizeInQueue = length; } else { // some other failure } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ SDIO_STATUS _GetMessage(PSDMESSAGE_QUEUE pQueue, PVOID pData, INT *pBufferLength) { SDIO_STATUS status2; SDIO_STATUS status = SDIO_STATUS_SUCCESS; PSDMESSAGE_BLOCK pMsg; CT_DECLARE_IRQ_SYNC_CONTEXT(); status = CriticalSectionAcquireSyncIrq(&pQueue->MessageCritSection); if (!SDIO_SUCCESS(status)) { return status; } do { pMsg = GetQueuedMessage(pQueue); if (NULL == pMsg) { status = SDIO_STATUS_NO_MORE_MESSAGES; break; } if (*pBufferLength < pMsg->MessageLength) { /* caller buffer is too small */ *pBufferLength = pMsg->MessageLength; /* stick it back to the front */ QueueMessageToHead(pQueue, pMsg); status = SDIO_STATUS_BUFFER_TOO_SMALL; break; } /* copy the message to the callers buffer */ memcpy(pData,pMsg->MessageStart,pMsg->MessageLength); /* return actual length */ *pBufferLength = pMsg->MessageLength; /* return this message block back to the free list */ FreeMessageBlock(pQueue, pMsg); } while (FALSE); status2 = CriticalSectionReleaseSyncIrq(&pQueue->MessageCritSection); return status; }
SDHCD_HW_DEVICE *InitializeSPIHW(PTSTR pRegPath) { PSDHCD_DEVICE pDevice; SDHCD_HW_DEVICE *pHWDevice; DWORD threadId; SDIO_STATUS status = SDIO_STATUS_SUCCESS; do { /* for now this is a static, single instance allocation */ pHWDevice = &g_HWDevice; ZERO_POBJECT(pHWDevice); pDevice = &pHWDevice->SpiCommon; pHWDevice->pDevice = pDevice; /* set the HW portion */ pDevice->pHWDevice = pHWDevice; pHWDevice = GET_HW_DEVICE(pDevice); SET_SDIO_STACK_VERSION(&pDevice->Hcd); pDevice->Hcd.pName = SDIO_RAW_BD_BASE; pDevice->Hcd.Attributes = 0; pDevice->Hcd.pContext = pDevice; pDevice->Hcd.pRequest = HcdRequest; pDevice->Hcd.pConfigure = HcdConfig; /* TODO : adjust these to match controller hardware */ pDevice->OperationalClock = 12000000; /* 12 mhz */ pDevice->Hcd.MaxBytesPerBlock = 4096; /* used as a hint to indicate max size of common buffer */ pDevice->Hcd.MaxBlocksPerTrans = 1; /* must be one*/ pDevice->Hcd.MaxClockRate = 48000000; /* 48 Mhz */ pDevice->PowerUpDelay = 100; /* set all the supported frame widths the controller can do * 8/16/24/32 bit frames */ pDevice->SpiHWCapabilitiesFlags = HW_SPI_FRAME_WIDTH_8 | HW_SPI_FRAME_WIDTH_16 | HW_SPI_FRAME_WIDTH_24 | HW_SPI_FRAME_WIDTH_32; pDevice->MiscFlags |= MISC_FLAG_DUMP_STATE_ON_SHUTDOWN | MISC_FLAG_RESET_SPI_IF_SHUTDOWN; SDLIB_InitializeWorkerTask(&pHWDevice->IOCompleteWorkTask, IOCompleteWork, pHWDevice); pHWDevice->pWorker = SDLIB_CreateWorker(WORKER_THREAD_PRIORITY); if (NULL == pHWDevice->pWorker) { status = SDIO_STATUS_NO_RESOURCES; break; } /* TODO : allocate hardware resources (I/O , interrupt, DMA etc..) */ /*************************************/ status = HcdInitialize(pDevice); /* initialize common layer */ if (!SDIO_SUCCESS(status)) { DBG_PRINT(SDDBG_ERROR, ("SPI - failed to init common layer, status =%d\n", status)); break; } pHWDevice->InitStateMask |= SDHC_COMMON_INIT; /* create the interrupt event */ pHWDevice->hIstEventSPIGpioIRQ = CreateEvent(NULL, FALSE, FALSE, NULL); if (NULL == pHWDevice->hIstEventSPIGpioIRQ) { status = SDIO_STATUS_NO_RESOURCES; break; } /* TODO set appropriate system interrupt for GPIO IRQ, * GPIO IRQ must be level sensitive, active LOW */ pHWDevice->SysIntrSPIGpioIRQ = 0; /* TODO : uncomment the following to associate the GPIO IRQ to the interrupt event : if (!InterruptInitialize(pHWDevice->SysIntrSPIGpioIRQ, pHWDevice->hIstEventSPIGpioIRQ, NULL, 0)) { DBG_PRINT(SDDBG_ERROR,("SPI HCD: Failed to initialize Interrupt! \n")); status = SDIO_STATUS_NO_RESOURCES; break; } */ /* create the IST thread */ pHWDevice->hIstSPIGpioIRQ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SpiGpioIRQInterruptThread, (LPVOID)pHWDevice, 0, &threadId); if (NULL == pHWDevice->hIstSPIGpioIRQ) { status = SDIO_STATUS_NO_RESOURCES; DBG_PRINT(SDDBG_ERROR,("SPI HCD: Failed to Create IST! \n")); break; } /* register with the SDIO bus driver */ if (!SDIO_SUCCESS((status = SDIO_RegisterHostController(&pDevice->Hcd)))) { DBG_PRINT(SDDBG_ERROR, ("SPI HCD: Probe - failed to register with host, status =%d\n",status)); break; } pHWDevice->InitStateMask |= SDHC_REGISTERED; } while (FALSE); if (!SDIO_SUCCESS(status)) { if (pHWDevice != NULL) { CleanupSPIHW(pHWDevice); pHWDevice = NULL; } } else { DBG_PRINT(SDDBG_ERROR, ("SPI - HCD ready! \n")); } DBG_PRINT(SDDBG_TRACE, ("-SPI HCD: Setup - status : %d\n", status)); return SDIO_SUCCESS(status) ? pHWDevice : NULL; }
static A_STATUS HifReadWriteScatter(HIF_DEVICE *device, HIF_SCATTER_REQ *pReq) { A_STATUS status = A_EINVAL; SDREQUEST *sdrequest; A_UINT8 rw; A_UINT8 mode; A_UINT8 funcNo; A_UINT8 opcode; A_UINT16 count; SDIO_STATUS sdiostatus; A_UINT32 request = pReq->Request; do { AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("HIF Scatter : %d Scatter Entries: %d\n", pReq->TotalLength, pReq->ValidScatterEntries)); if (pReq->TotalLength > MAX_SCATTER_REQ_TRANSFER_SIZE) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid length: %d \n", pReq->TotalLength)); break; } if (pReq->TotalLength == 0) { A_ASSERT(FALSE); break; } /* get the sd bus request associated with this scatter request */ sdrequest = GET_SDREQUEST_SR(pReq); if (request & HIF_SYNCHRONOUS) { sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS; sdrequest->pCompleteContext = NULL; sdrequest->pCompletion = NULL; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,(" Synchronous \n")); } else if (request & HIF_ASYNCHRONOUS) { sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS | SDREQ_FLAGS_TRANS_ASYNC; sdrequest->pCompleteContext = pReq; sdrequest->pCompletion = HifReadWriteScatterCompletion; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,(" Asynchronous \n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid execution mode: 0x%08x\n", request)); break; } if (!(request & HIF_EXTENDED_IO)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid command type: 0x%08x\n", request)); break; } sdrequest->Command = CMD53; if (!(request & HIF_BLOCK_BASIS)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid data mode: 0x%08x\n", request)); break; } /* only block-mode commands */ mode = CMD53_BLOCK_BASIS; sdrequest->BlockLen = HIF_MBOX_BLOCK_SIZE; sdrequest->BlockCount = pReq->TotalLength / HIF_MBOX_BLOCK_SIZE; count = sdrequest->BlockCount; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, (" Block mode (BlockLen: %d, BlockCount: %d)\n", sdrequest->BlockLen, sdrequest->BlockCount)); if (request & HIF_WRITE) { rw = CMD53_WRITE; sdrequest->Flags |= SDREQ_FLAGS_DATA_WRITE; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, (" Direction: Write\n")); } else if (request & HIF_READ) { rw = CMD53_READ; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, (" Direction: Read\n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid direction: 0x%08x\n", request)); break; } if (request & HIF_FIXED_ADDRESS) { opcode = CMD53_FIXED_ADDRESS; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, (" Address mode: Fixed\n")); } else if (request & HIF_INCREMENTAL_ADDRESS) { opcode = CMD53_INCR_ADDRESS; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, (" Address mode: Incremental\n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid address mode: 0x%08x\n", request)); break; } funcNo = SDDEVICE_GET_SDIO_FUNCNO(device->handle); SDIO_SET_CMD53_ARG(sdrequest->Argument, rw, funcNo, mode, opcode, pReq->Address, count); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("HIF Scatter : SDIO CMD53 card address: 0x%X blocks: %d\n", pReq->Address, count)); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("HIF Scatter : SDIO CMD53 , request flags:0x%X arg:0x%X\n", sdrequest->Flags, sdrequest->Argument)); status = SetupBusRequestForDMA(device, sdrequest, pReq); if (A_FAILED(status)){ break; } if (sdrequest->pDataBuffer == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, (" sdrequest->pDataBuffer is NULL!!!\n")); status = A_ERROR; // A_ASSERT(FALSE); break; } /* Send the command out */ sdiostatus = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest); if (!SDIO_SUCCESS(sdiostatus)) { status = A_ERROR; break; } status = A_OK; } while (FALSE); if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) { pReq->CompletionStatus = status; pReq->CompletionRoutine(pReq); status = A_OK; } return status; }
A_STATUS HIFReadWrite(HIF_DEVICE *device, A_UINT32 address, A_UCHAR *buffer, A_UINT32 length, A_UINT32 request, void *context) { SDIO_STATUS status; SDREQUEST *sdrequest; BUS_REQUEST *busrequest = NULL; A_STATUS a_status = A_OK; /* Return any new requests if the shutdown is already in progress */ if (device->shutdownInProgress) { if (request & HIF_ASYNCHRONOUS) { device->htcCallbacks.rwCompletionHandler(context, A_ERROR); return A_PENDING; } return A_ERROR; } AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->handle != NULL); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Device: %p\n", device)); if (length > device->curBlockSize) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid data length: %d\n", length)); return A_ERROR; } /* * We do not differentiate between the extended and the basic I/O so * we do not process the request type. */ /* * We do not differentiate between the byte and block data mode so * we do not process the request dmode. */ do { /* Addressing mode */ if (request & HIF_FIXED_ADDRESS) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Address mode: Fixed\n")); } else if (request & HIF_INCREMENTAL_ADDRESS) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Address mode: Incremental\n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid address mode: 0x%08x\n", request)); a_status = A_ERROR; break; } /* * Mailbox write. Adjust the address so that the last byte * falls on the EOM address. */ if (request & HIF_WRITE) { if ((address >= HIF_MBOX_START_ADDR(0)) && (address <= HIF_MBOX_END_ADDR(3))) { DBG_ASSERT(length <= HIF_MBOX_WIDTH); address += (HIF_MBOX_WIDTH - length); } } /* Allocate a new bus request */ busrequest = hifAllocateBusRequest(device); if (busrequest == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate bus request\n")); a_status = A_ERROR; break; } sdrequest = busrequest->request; sdrequest->pDataBuffer = buffer; if (request & HIF_SYNCHRONOUS) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Execution mode: Synchronous\n")); sdrequest->Flags = SDREQ_FLAGS_RAW; sdrequest->pCompleteContext = NULL; sdrequest->pCompletion = NULL; } else if (request & HIF_ASYNCHRONOUS) { /* Populate the bus request to be passed in as context */ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Execution mode: Asynchronous\n")); /* setup async context */ busrequest->device = device; busrequest->context = context; sdrequest->pCompleteContext = busrequest; sdrequest->Flags = SDREQ_FLAGS_RAW | SDREQ_FLAGS_TRANS_ASYNC; sdrequest->pCompletion = hifRWCompletionHandler; } /* Indicate to the bus driver if its a read or a write */ if (request & HIF_WRITE) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Direction: Write\n")); if (((address >= HIF_MBOX_START_ADDR(0)) && (address <= HIF_MBOX_END_ADDR(3)))) { /* trapping HTC WRITE to mailbox, these will use the special DMA operation */ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("--- MAILBOX WRITE ACCESS!!!!\n")); ATH_SET_DMA_OPERATION(sdrequest,ATH_TRANS_WRITE,address,length); } else { ATH_SET_PIO_EXTERNAL_WRITE_OPERATION(sdrequest, address, (request & HIF_INCREMENTAL_ADDRESS) ? TRUE : FALSE, length); } } else if (request & HIF_READ) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("Direction: Read\n")); if (((address >= HIF_MBOX_START_ADDR(0)) && (address <= HIF_MBOX_END_ADDR(3)))) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" --- MAILBOX READ ACCESS!!!!\n")); /* trapping on HTC READ mailbox , these will use the special DMA operation */ ATH_SET_DMA_OPERATION(sdrequest,ATH_TRANS_READ,address,length); } else { ATH_SET_PIO_EXTERNAL_READ_OPERATION(sdrequest, address, request & HIF_INCREMENTAL_ADDRESS ? TRUE : FALSE, length); } } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Invalid direction: 0x%08x\n", request)); a_status = A_ERROR; break; } /* issue the request */ status = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest); if (!SDIO_SUCCESS(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF Read/Write failure: %d\n", status)); a_status = A_ERROR; } } while (FALSE); if ((busrequest != NULL) && (request & HIF_SYNCHRONOUS)) { hifFreeBusRequest(device,busrequest); } return a_status; }