diff options
Diffstat (limited to 'drivers/sdio/stack/busdriver/sdio_bus_events.c')
-rw-r--r-- | drivers/sdio/stack/busdriver/sdio_bus_events.c | 1040 |
1 files changed, 0 insertions, 1040 deletions
diff --git a/drivers/sdio/stack/busdriver/sdio_bus_events.c b/drivers/sdio/stack/busdriver/sdio_bus_events.c deleted file mode 100644 index 5b3148d6752..00000000000 --- a/drivers/sdio/stack/busdriver/sdio_bus_events.c +++ /dev/null @@ -1,1040 +0,0 @@ -/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -@file: sdio_bus_events.c - -@abstract: OS independent bus driver support - -#notes: this file contains various event handlers and helpers - -@notice: Copyright (c), 2004-2006 Atheros Communications, Inc. - - - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Portions of this code were developed with information supplied from the - * SD Card Association Simplified Specifications. The following conditions and disclaimers may apply: - * - * The following conditions apply to the release of the SD simplified specification (�Simplified - * Specification�) by the SD Card Association. The Simplified Specification is a subset of the complete - * SD Specification which is owned by the SD Card Association. This Simplified Specification is provided - * on a non-confidential basis subject to the disclaimers below. Any implementation of the Simplified - * Specification may require a license from the SD Card Association or other third parties. - * Disclaimers: - * The information contained in the Simplified Specification is presented only as a standard - * specification for SD Cards and SD Host/Ancillary products and is provided "AS-IS" without any - * representations or warranties of any kind. No responsibility is assumed by the SD Card Association for - * any damages, any infringements of patents or other right of the SD Card Association or any third - * parties, which may result from its use. No license is granted by implication, estoppel or otherwise - * under any patent or other rights of the SD Card Association or any third party. Nothing herein shall - * be construed as an obligation by the SD Card Association to disclose or distribute any technical - * information, know-how or other confidential information to any third party. - * - * - * The initial developers of the original code are Seung Yi and Paul Lever - * - * sdio@atheros.com - * - * - -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -#define MODULE_NAME SDBUSDRIVER -#include <linux/sdio/ctsystem.h> -#include <linux/sdio/sdio_busdriver.h> -#include <linux/sdio/sdio_lib.h> -#include "_busdriver.h" -#include <linux/sdio/_sdio_defs.h> -#include <linux/sdio/mmc_defs.h> - -static SDIO_STATUS ScanSlotForCard(PSDHCD pHcd, - PBOOL pCardPresent); -static void GetPendingIrqComplete(PSDREQUEST pReq); -static void ProcessPendingIrqs(PSDHCD pHcd, UINT8 IntPendingMsk); - -/* - * DeviceDetach - tell core a device was removed from a slot -*/ -SDIO_STATUS DeviceDetach(PSDHCD pHcd) -{ - SDCONFIG_SDIO_INT_CTRL_DATA irqData; - - ZERO_OBJECT(irqData); - - DBG_PRINT(SDDBG_TRACE, ("+SDIO Bus Driver: DeviceDetach\n")); - /* tell any function drivers we are gone */ - RemoveHcdFunctions(pHcd); - /* delete the devices associated with this HCD */ - DeleteDevices(pHcd); - /* check and see if there are any IRQs that were left enabled */ - if (pHcd->IrqsEnabled) { - irqData.SlotIRQEnable = FALSE; - /* turn off IRQ detection in HCD */ - _IssueConfig(pHcd,SDCONFIG_SDIO_INT_CTRL,(PVOID)&irqData, sizeof(irqData)); - } - - /* reset hcd state */ - ResetHcdState(pHcd); - - DBG_PRINT(SDDBG_TRACE, ("-SDIO Bus Driver: DeviceDetach\n")); - return SDIO_STATUS_SUCCESS; -} - -/* - * DeviceAttach - tell core a device was inserted into a slot -*/ -SDIO_STATUS DeviceAttach(PSDHCD pHcd) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - PSDDEVICE pDevice = NULL; - UINT ii; - - - if (IS_CARD_PRESENT(pHcd)) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: DeviceAttach called on occupied slot!\n")); - return SDIO_STATUS_ERROR; - } - - DBG_PRINT(SDDBG_TRACE, ("+SDIO Bus Driver: DeviceAttach bdctxt:0x%X \n", (UINT32)pBusContext)); - - if (IS_HCD_RAW(pHcd)) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver: RAW HCD (%s) device attach \n",pHcd->pName)); - /* this is a raw HCD */ - memset(&pHcd->CardProperties,0,sizeof(pHcd->CardProperties)); - pHcd->CardProperties.Flags = CARD_RAW; - pHcd->CardProperties.IOFnCount = 0; - /* for raw HCD, set up minimum parameters - * since we cannot determine these values using any standard, use values - * reported by the HCD */ - /* the operational rate is just the max clock rate reported */ - pHcd->CardProperties.OperBusClock = pHcd->MaxClockRate; - /* the max bytes per data transfer is just the max bytes per block */ - pHcd->CardProperties.OperBlockLenLimit = pHcd->MaxBytesPerBlock; - /* if the raw HCD uses blocks to transfer, report the operational size - * from the HCD max value */ - pHcd->CardProperties.OperBlockCountLimit = pHcd->MaxBlocksPerTrans; - /* set the slot preferred voltage */ - pHcd->CardProperties.CardVoltage = pHcd->SlotVoltagePreferred; - } else { - /* initialize this card and get card properties */ - if (!SDIO_SUCCESS((status = SDInitializeCard(pHcd)))) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: DeviceAttach, failed to initialize card, %d\n", - status)); - return status; - } - } - - /* check for SD or MMC, this must be done first as the query may involve - * de-selecting the card */ - do { - if (!(pHcd->CardProperties.Flags & (CARD_MMC | CARD_SD | CARD_RAW))) { - /* none of these were discovered */ - break; - } - pDevice = AllocateDevice(pHcd); - if (NULL == pDevice) { - break; - } - if (pHcd->CardProperties.Flags & CARD_RAW) { - /* set function number to 1 for IRQ processing */ - SDDEVICE_SET_SDIO_FUNCNO(pDevice,1); - } else { - /* get the ID info for the SD/MMC Card */ - if (!SDIO_SUCCESS((status = SDQuerySDMMCInfo(pDevice)))) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: DeviceAttach, query SDMMC Info failed \n")); - FreeDevice(pDevice); - break; - } - } - AddDeviceToList(pDevice); - /* look for a function driver to handle this card */ - ProbeForFunction(pDevice, pHcd); - } while (FALSE); - - /* create a device for each I/O function */ - for(ii= 1; ii <= pHcd->CardProperties.IOFnCount; ii++) { - pDevice = AllocateDevice(pHcd); - if (NULL == pDevice) { - break; - } - /* set the function number */ - SDDEVICE_SET_SDIO_FUNCNO(pDevice,ii); - /* get the ID info for each I/O function */ - if (!SDIO_SUCCESS((status = SDQuerySDIOInfo(pDevice)))) { - DBG_PRINT(SDDBG_ERROR, - ("SDIO Bus Driver: DeviceAttach, could not query SDIO Info, funcNo:%d status:%d \n", - ii, status)); - FreeDevice(pDevice); - /* keep loading other functions */ - continue; - } - AddDeviceToList(pDevice); - /* look for a function driver to handle this card */ - ProbeForFunction(pDevice, pHcd); - } - - - DBG_PRINT(SDDBG_TRACE, ("-SDIO Bus Driver: DeviceAttach \n")); - return status; -} - -static INLINE void CompleteRequestCheckCancel(PSDHCD pHcd, PSDREQUEST pReqToComplete) -{ - BOOL cancel = FALSE; - PSDFUNCTION pFunc = NULL; - - /* handle cancel of current request */ - if (pReqToComplete->Flags & SDREQ_FLAGS_CANCELED) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver - _SDIO_HandleHcdEvent: cancelling req 0X%X\n", (UINT)pReqToComplete)); - cancel = TRUE; - pReqToComplete->Status = SDIO_STATUS_CANCELED; - pFunc = pReqToComplete->pFunction; - DBG_ASSERT(pFunc != NULL); - } - - DoRequestCompletion(pReqToComplete, pHcd); - - if (cancel) { - SignalSet(&pFunc->CleanupReqSig); - } -} - -/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - @function: Indicate to the SDIO bus driver (core) of an event in the host controller - driver. - - @function name: SDIO_HandleHcdEvent - @prototype: SDIO_STATUS SDIO_HandleHcdEvent(PSDHCD pHcd, HCD_EVENT Event) - @category: HD_Reference - - @input: pHcd - the host controller structure that was registered - HCD_EVENT - event code - - @output: none - - @return: SDIO_STATUS - - @notes: - The host controller driver can indicate asynchronous events by calling this - function with an appropriate event code. Refer to the HDK help manual for - more information on the event types - - @example: Example of indicating a card insertion event: - SDIO_HandleHcdEvent(&Hcd, EVENT_HCD_ATTACH); - -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -SDIO_STATUS _SDIO_HandleHcdEvent(PSDHCD pHcd, HCD_EVENT Event) -{ - PSDREQUEST pReq; - PSDREQUEST pReqToComplete = NULL; - PSDREQUEST pNextReq = NULL; - SDIO_STATUS status; - CT_DECLARE_IRQ_SYNC_CONTEXT(); - - DBG_PRINT(SDIODBG_HCD_EVENTS, ("SDIO Bus Driver: _SDIO_HandleHcdEvent, event type 0x%X, HCD:0x%X\n", - Event, (UINT)pHcd)); - - if (Event == EVENT_HCD_TRANSFER_DONE) { - pReq = GET_CURRENT_REQUEST(pHcd); - if (NULL == pReq) { - DBG_ASSERT(FALSE); - return SDIO_STATUS_ERROR; - } - - status = _AcquireHcdLock(pHcd); - if (SDIO_SUCCESS(status)) { - /* null out the current request */ - SET_CURRENT_REQUEST(pHcd, NULL); - status = _ReleaseHcdLock(pHcd); - } else { - DBG_PRINT(SDDBG_ERROR, - ("SDIO Bus Driver: SDIO_HandleHcdEvent Failed to acquire HCD lock \n")); - return SDIO_STATUS_ERROR; - } - - /* note: the queue is still marked busy to prevent other threads/tasks from starting - * new requests while we are handling completion , some completed requests are - * marked as barrier requests which must be handled atomically */ - - status = pReq->Status; - DBG_PRINT(SDIODBG_REQUESTS, - ("+SDIO Bus Driver: Handling Transfer Done (CMD:%d, Status:%d) from HCD:0x%08X \n", - pReq->Command, status, (INT)pHcd)); - /* check SPI mode conversion */ - if (IS_HCD_BUS_MODE_SPI(pHcd) && SDIO_SUCCESS(status)) { - if (!(pReq->Flags & SDREQ_FLAGS_RESP_SKIP_SPI_FILT) && !(pReq->Flags & SDREQ_FLAGS_PSEUDO) && - (GET_SDREQ_RESP_TYPE(pReq->Flags) != SDREQ_FLAGS_NO_RESP)) { - ConvertSPI_Response(pReq, NULL); - } - } - - DBG_PRINT(SDIODBG_REQUESTS, ("SDIO Bus Driver: Completing Request:0x%08X \n",(INT)pReq)); - - if (!SDIO_SUCCESS(status) && - (status != SDIO_STATUS_CANCELED) && - !(pReq->Flags & SDREQ_FLAGS_CANCELED) && - (pReq->RetryCount > 0)) { - /* retry the request if it failed, was NOT cancelled and the retry count - * is greater than zero */ - pReq->RetryCount--; - pReqToComplete = NULL; - /* clear SPI converted flag */ - pReq->Flags &= ~SDREQ_FLAGS_RESP_SPI_CONVERTED; - pNextReq = pReq; - } else { - /* complete the request */ - if (pReq->Flags & SDREQ_FLAGS_BARRIER) { - /* a barrier request must be completed before the next bus request is - * started */ - CompleteRequestCheckCancel(pHcd, pReq); - if (!ForceAllRequestsAsync()) { - if (CHECK_API_VERSION_COMPAT(pHcd,2,6)) { - /* the request was completed, decrement recursion count */ - status = _AcquireHcdLock(pHcd); - if (!SDIO_SUCCESS(status)) { - return status; - } - pHcd->Recursion--; - DBG_ASSERT(pHcd->Recursion >= 0); - status = _ReleaseHcdLock(pHcd); - } else { - /* reset bit */ - AtomicTest_Clear(&pHcd->HcdFlags, HCD_REQUEST_CALL_BIT); - } - } - pReqToComplete = NULL; - } else { - /* complete this after the next request has - * been started */ - pReqToComplete = pReq; - } - } - - /* acquire the hcd lock to look at the queues */ - status = _AcquireHcdLock(pHcd); - if (SDIO_SUCCESS(status)) { - if (pReqToComplete != NULL) { - /* queue the request that was completed */ - QueueRequest(&pHcd->CompletedRequestQueue, pReqToComplete); - } - if (NULL == pNextReq) { - /* check the queue for the next request */ - DBG_PRINT(SDIODBG_REQUESTS, ("SDIO Bus Driver: Checking queue.. \n")); - /* check to see if the HCD was already working on one. This occurs if - * the current request being completed was a barrier request and the - * barrier completion routine submitted a new request to the head of the - * queue */ - if (GET_CURRENT_REQUEST(pHcd) == NULL) { - pNextReq = DequeueRequest(&pHcd->RequestQueue); - if (NULL == pNextReq) { - /* nothing in the queue, mark it not busy */ - MarkQueueNotBusy(&pHcd->RequestQueue); - DBG_PRINT(SDIODBG_REQUESTS, ("SDIO Bus Driver: Queue idle \n")); - } else { - DBG_PRINT(SDIODBG_REQUESTS, ("SDIO Bus Driver: Next request in queue: 0x%X \n", - (INT)pNextReq)); - } - } else { - DBG_PRINT(SDIODBG_REQUESTS, - ("SDIO Bus Driver: Busy Queue from barrier request \n")); - } - } - - if (pNextReq != NULL) { - /* a new request will be submitted to the HCD below, - * check recursion while we have the lock */ - if (CHECK_API_VERSION_COMPAT(pHcd,2,6)) { - CHECK_HCD_RECURSE(pHcd,pNextReq); - } - } - status = _ReleaseHcdLock(pHcd); - } else { - DBG_PRINT(SDDBG_ERROR, - ("SDIO Bus Driver: SDIO_HandleHcdEvent Failed to acquire HCD lock \n")); - return SDIO_STATUS_ERROR; - } - /* check for the next request to issue */ - if (pNextReq != NULL) { - DBG_PRINT(SDIODBG_REQUESTS, ("SDIO Bus Driver: Starting Next Request: 0x%X \n", - (INT)pNextReq)); - SET_CURRENT_REQUEST(pHcd,pNextReq); - status = CallHcdRequest(pHcd); - /* check and see if the HCD completed the request in the callback */ - if (status != SDIO_STATUS_PENDING) { - /* recurse and process the request */ - _SDIO_HandleHcdEvent(pHcd, EVENT_HCD_TRANSFER_DONE); - } - } - - /* now empty the completed request queue - * - this guarantees in-order completion even during recursion */ - status = _AcquireHcdLock(pHcd); - if (SDIO_SUCCESS(status)) { - while (1) { - pReqToComplete = DequeueRequest(&pHcd->CompletedRequestQueue); - status = _ReleaseHcdLock(pHcd); - if (pReqToComplete != NULL) { - CompleteRequestCheckCancel(pHcd, pReqToComplete); - if (!CHECK_API_VERSION_COMPAT(pHcd,2,6)) { - if (!ForceAllRequestsAsync()) { - /* reset bit */ - AtomicTest_Clear(&pHcd->HcdFlags, HCD_REQUEST_CALL_BIT); - } - } - /* re-acquire lock */ - status = _AcquireHcdLock(pHcd); - if (!SDIO_SUCCESS(status)) { - return SDIO_STATUS_ERROR; - } - if (CHECK_API_VERSION_COMPAT(pHcd,2,6)) { - if (!ForceAllRequestsAsync()) { - /* while we have the lock, decrement recursion count each time - * we complete a request */ - pHcd->Recursion--; - DBG_ASSERT(pHcd->Recursion >= 0); - } - } - } else { - /* we're done */ - break; - } - } - } else { - DBG_PRINT(SDDBG_ERROR, - ("SDIO Bus Driver: SDIO_HandleHcdEvent Failed to acquire HCD lock \n")); - return SDIO_STATUS_ERROR; - } - DBG_PRINT(SDIODBG_REQUESTS, ("-SDIO Bus Driver: Transfer Done Handled \n")); - return SDIO_STATUS_SUCCESS; - } - - switch(Event) { - case EVENT_HCD_ATTACH: - case EVENT_HCD_DETACH: - /* card detect helper does the actual attach detach */ - return PostCardDetectEvent(pBusContext,Event,pHcd); - case EVENT_HCD_SDIO_IRQ_PENDING: - return DeviceInterrupt(pHcd); - default: - DBG_PRINT(SDDBG_ERROR, ("-SDIO Bus Driver: SDIO_HandleHcdEvent, invalid event type 0x%X, HCD:0x%X\n", - Event, (UINT)pHcd)); - return SDIO_STATUS_INVALID_PARAMETER; - } - -} - -/* card detect helper function */ -THREAD_RETURN CardDetectHelperFunction(POSKERNEL_HELPER pHelper) -{ - SDIO_STATUS status; - HCD_EVENT_MESSAGE message; - INT length; - - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver - CardDetectHelperFunction starting up: 0x%X \n", (INT)pHelper)); - - while (1) { - - /* wait for wake up event */ - status = SD_WAIT_FOR_WAKEUP(pHelper); - if (!SDIO_SUCCESS(status)) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver - Card Detect Helper Semaphore Pend Error:%d \n", - status)); - break; - } - - if (SD_IS_HELPER_SHUTTING_DOWN(pHelper)) { - /* cleanup message queue on shutdown */ - while (1) { - length = sizeof(message); - /* get a message */ - status = SDLIB_GetMessage(pBusContext->pCardDetectMsgQueue, - &message, &length); - if (!SDIO_SUCCESS(status)) { - break; - } - if (message.pHcd != NULL) { - /* decrement HCD reference count */ - OS_DecHcdReference(message.pHcd); - } - } - - break; - } - - while (1) { - length = sizeof(message); - /* get a message */ - status = SDLIB_GetMessage(pBusContext->pCardDetectMsgQueue, - &message, &length); - if (!SDIO_SUCCESS(status)) { - break; - } - - switch (message.Event) { - case EVENT_HCD_ATTACH: - DeviceAttach(message.pHcd); - break; - case EVENT_HCD_DETACH: - DeviceDetach(message.pHcd); - break; - case EVENT_HCD_CD_POLLING: - /* run detector */ - RunCardDetect(); - break; - default: - DBG_ASSERT(FALSE); - break; - } - - if (message.pHcd != NULL) { - /* message was processed, decrement reference count */ - OS_DecHcdReference(message.pHcd); - } - } - } - - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver - Card Detect Helper Exiting.. \n")); - return 0; -} - - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - RunCardDetect - run card detect on host controller slots that require polling - Input: - Output: - Return: - Notes: This function is called from the card detect timer thread -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -void RunCardDetect(void) -{ - BOOL CDPollingRequired = FALSE; - PSDLIST pListItem; - PSDHCD pHcd; - BOOL cardPresent; - - DBG_PRINT(SDIODBG_CD_TIMER, ("+SDIO Bus Driver: RunCardDetect\n")); - - /* protect the HCD list */ - if (!SDIO_SUCCESS(SemaphorePendInterruptable(&pBusContext->HcdListSem))) { - DBG_ASSERT(FALSE); - return; /* wait interrupted */ - } - /* while we are running the detector we are blocking HCD removal*/ - SDITERATE_OVER_LIST(&pBusContext->HcdList, pListItem) { - pHcd = CONTAINING_STRUCT(pListItem, SDHCD, SDList); - /* does the HCD require polling ? */ - if (pHcd->Attributes & SDHCD_ATTRIB_SLOT_POLLING) { - DBG_PRINT(SDIODBG_CD_TIMER, ("SDIO Bus Driver: Found HCD requiring polling \n")); - /* set flag to queue the timer */ - CDPollingRequired = TRUE; - if (IS_CARD_PRESENT(pHcd)) { - /* there is a device in the slot */ - cardPresent = TRUE; - if (SDIO_SUCCESS(ScanSlotForCard(pHcd,&cardPresent))) { - if (!cardPresent) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver CD Polling.. Card Removal Detected\n")); - DeviceDetach(pHcd); - } - } - } else { - cardPresent = FALSE; - if (SDIO_SUCCESS(ScanSlotForCard(pHcd,&cardPresent))) { - if (cardPresent) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver CD Polling.. Card Detected\n")); - DeviceAttach(pHcd); - } - } - } - } - - DBG_PRINT(SDIODBG_CD_TIMER, ("SDIO Bus Driver: moving to next hcd:0x%X \n", - (INT)pListItem->pNext)); - } - - /* check if we need to queue the timer */ - if (CDPollingRequired && !pBusContext->CDTimerQueued) { - pBusContext->CDTimerQueued = TRUE; - DBG_PRINT(SDIODBG_CD_TIMER, ("SDIO Bus Driver: Queuing Card detect timer \n")); - if (!SDIO_SUCCESS( - QueueTimer(SDIOBUS_CD_TIMER_ID, pBusContext->CDPollingInterval))) { - DBG_PRINT(SDDBG_WARN, ("SDIO Bus Driver: failed to queue CD timer \n")); - pBusContext->CDTimerQueued = FALSE; - } - } - /* release HCD list lock */ - SemaphorePost(&pBusContext->HcdListSem); - DBG_PRINT(SDIODBG_CD_TIMER, ("-SDIO Bus Driver: RunCardDetect\n")); -} - - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ScanSlotForCard - scan slot for a card - Input: pHcd - the hcd - Output: pCardPresent - card present flag (set/cleared on return) - Return: - Notes: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -static SDIO_STATUS ScanSlotForCard(PSDHCD pHcd,PBOOL pCardPresent) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - UINT8 temp; - - DBG_PRINT(SDIODBG_CD_TIMER, ("+SDIO Bus Driver: ScanSlotForCard\n")); - - do { - if (!IS_CARD_PRESENT(pHcd)) { - INT dbgLvl; - dbgLvl = DBG_GET_DEBUG_LEVEL(); - DBG_SET_DEBUG_LEVEL(SDDBG_WARN); - status = CardInitSetup(pHcd); - DBG_SET_DEBUG_LEVEL(dbgLvl); - if (!SDIO_SUCCESS(status)) { - break; - } - /* issue go-idle */ - if (IS_HCD_BUS_MODE_SPI(pHcd)) { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_RESP_R1,NULL); - } else { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_NO_RESP,NULL); - } - /* try SDIO */ - status = TestPresence(pHcd,CARD_SDIO,NULL); - if (SDIO_SUCCESS(status)) { - *pCardPresent = TRUE; - break; - } - /* issue go-idle */ - if (IS_HCD_BUS_MODE_SPI(pHcd)) { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_RESP_R1,NULL); - } else { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_NO_RESP,NULL); - } - /* try SD */ - status = TestPresence(pHcd,CARD_SD,NULL); - if (SDIO_SUCCESS(status)) { - *pCardPresent = TRUE; - break; - } - /* issue go-idle */ - if (IS_HCD_BUS_MODE_SPI(pHcd)) { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_RESP_R1,NULL); - } else { - _IssueSimpleBusRequest(pHcd,CMD0,0,SDREQ_FLAGS_NO_RESP,NULL); - } - /* try MMC */ - status = TestPresence(pHcd,CARD_MMC,NULL); - if (SDIO_SUCCESS(status)) { - *pCardPresent = TRUE; - break; - } - } else { - if (pHcd->CardProperties.Flags & CARD_SDIO) { -#ifdef DUMP_INT_PENDING - temp = 0; - /* handy debug prints to check interrupt status and print pending register */ - status = Cmd52ReadByteCommon(pHcd->pPseudoDev, SDIO_INT_ENABLE_REG, &temp); - if (SDIO_SUCCESS(status) && (temp != 0)) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver: INT Enable Reg: 0x%2.2X\n", temp)); - status = Cmd52ReadByteCommon(pHcd->pPseudoDev, SDIO_INT_PENDING_REG, &temp); - if (SDIO_SUCCESS(status)) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver: INT Pend Reg: 0x%2.2X\n", temp)); - } - } -#endif - /* for SDIO cards, read the revision register */ - status = Cmd52ReadByteCommon(pHcd->pPseudoDev, CCCR_SDIO_REVISION_REG, &temp); - } else if (pHcd->CardProperties.Flags & (CARD_SD | CARD_MMC)) { - /* for SD/MMC cards, issue SEND_STATUS */ - if (IS_HCD_BUS_MODE_SPI(pHcd)) { - /* SPI uses the SPI R2 response */ - status = _IssueSimpleBusRequest(pHcd, - CMD13, - 0, - SDREQ_FLAGS_RESP_R2, - NULL); - } else { - status = _IssueSimpleBusRequest(pHcd, - CMD13, - (pHcd->CardProperties.RCA << 16), - SDREQ_FLAGS_RESP_R1,NULL); - } - } else { - DBG_ASSERT(FALSE); - } - if (!SDIO_SUCCESS(status)) { - /* card is gone */ - *pCardPresent = FALSE; - } - } - } while (FALSE); - - if (status == SDIO_STATUS_BUS_RESP_TIMEOUT) { - status = SDIO_STATUS_SUCCESS; - } - - DBG_PRINT(SDIODBG_CD_TIMER, ("-SDIO Bus Driver: ScanSlotForCard status:%d\n", - status)); - - return status; -} - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - DeviceInterrupt - handle device interrupt - Input: pHcd - host controller - Output: - Return: - Notes: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -SDIO_STATUS DeviceInterrupt(PSDHCD pHcd) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - SDIO_STATUS status2; - PSDREQUEST pReq = NULL; - CT_DECLARE_IRQ_SYNC_CONTEXT(); - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("+SDIO Bus Driver: DeviceInterrupt\n")); - - if (!IS_CARD_PRESENT(pHcd)) { - DBG_PRINT(SDDBG_ERROR, ("-SDIO Bus Driver: Device interrupt asserted on empty slot!\n")); - return SDIO_STATUS_ERROR; - } - - do { - /* for RAW HCDs or HCDs flagged for single-function IRQ optimization */ - if (IS_HCD_RAW(pHcd) || (pHcd->HcdFlags & (1 << HCD_IRQ_NO_PEND_CHECK))) { - status = _AcquireHcdLock(pHcd); - if (!SDIO_SUCCESS(status)) { - return status; - } - if (pHcd->IrqProcState != SDHCD_IDLE) { - status = SDIO_STATUS_ERROR; - status2 = _ReleaseHcdLock(pHcd); - } else { - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver : Device Interrupt \n")); - /* mark that we are processing */ - pHcd->IrqProcState = SDHCD_IRQ_PENDING; - status2 = _ReleaseHcdLock(pHcd); - /* process Irqs for raw hcds or HCDs with the single function optimization */ - /* force processing of function 1 interrupt */ - ProcessPendingIrqs(pHcd, (1 << 1)); - } - DBG_PRINT(SDIODBG_FUNC_IRQ, ("-SDIO Bus Driver: DeviceInterrupt: %d\n", status)); - /* done with RAW irqs */ - return status; - } - - /* pre-allocate a request to get the pending bits, we have to do this outside the - * hcd lock acquisition */ - pReq = AllocateRequest(); - - if (NULL == pReq) { - status = SDIO_STATUS_NO_RESOURCES; - break; - } - - status = _AcquireHcdLock(pHcd); - - if (!SDIO_SUCCESS(status)) { - break; - } - - if (pHcd->IrqProcState != SDHCD_IDLE) { - status = SDIO_STATUS_ERROR; - } else { - /* mark that we are processing */ - pHcd->IrqProcState = SDHCD_IRQ_PENDING; - /* build argument to read IRQ pending register */ - SDIO_SET_CMD52_READ_ARG(pReq->Argument,0,SDIO_INT_PENDING_REG); - pReq->Command = CMD52; - pReq->Flags = SDREQ_FLAGS_TRANS_ASYNC | SDREQ_FLAGS_RESP_SDIO_R5; - pReq->pCompleteContext = (PVOID)pHcd; - pReq->pCompletion = GetPendingIrqComplete; - pReq->RetryCount = SDBUS_MAX_RETRY; - } - - status2 = _ReleaseHcdLock(pHcd); - - if (!SDIO_SUCCESS(status2)) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: lock release error: %d\n", status2)); - } - - } while (FALSE); - - if (SDIO_SUCCESS(status)) { - DBG_ASSERT(pReq != NULL); - IssueRequestToHCD(pHcd,pReq); - status = SDIO_STATUS_PENDING; - } else { - if (pReq != NULL) { - FreeRequest(pReq); - } - } - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("-SDIO Bus Driver: DeviceInterrupt: %d\n", status)); - return status; -} - - -/* SDIO IRQ helper */ -THREAD_RETURN SDIOIrqHelperFunction(POSKERNEL_HELPER pHelper) -{ - PSDHCD pHcd; - SDIO_STATUS status; - PSDLIST pListItem; - PSDDEVICE pDevice; - UINT8 funcMask; - PSDDEVICE pDeviceIRQ[7]; - UINT deviceIrqCount = 0; - UINT ii; - - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver - SDIOIrqHelperFunction starting up \n")); - - pHcd = (PSDHCD)pHelper->pContext; - DBG_ASSERT(pHcd != NULL); - - while (1) { - - /* wait for wake up event */ - status = SD_WAIT_FOR_WAKEUP(pHelper); - - if (!SDIO_SUCCESS(status)) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver - SDIOIrqHelperFunction Pend Error:%d \n", - status)); - break; - } - - if (SD_IS_HELPER_SHUTTING_DOWN(pHelper)) { - break; - } - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver - Pending IRQs:0x%X \n", - pHcd->PendingHelperIrqs)); - - /* take the device list lock as we iterate through the list, this blocks - * device removals */ - status = SemaphorePendInterruptable(&pBusContext->DeviceListSem); - if (!SDIO_SUCCESS(status)) { - break; - } - /* walk through the device list matching HCD and interrupting function */ - SDITERATE_OVER_LIST(&pBusContext->DeviceList, pListItem) { - pDevice = CONTAINING_STRUCT(pListItem, SDDEVICE, SDList); - /* check if device belongs to the HCD */ - if (pDevice->pHcd != pHcd){ - /* not on this hcd */ - continue; - } - funcMask = 1 << SDDEVICE_GET_SDIO_FUNCNO(pDevice); - /* check device function against the pending mask */ - if (!(funcMask & pHcd->PendingHelperIrqs)) { - /* this one is not scheduled for the helper */ - continue; - } - /* clear bit */ - pHcd->PendingHelperIrqs &= ~funcMask; - /* check for sync IRQ and call handler */ - if (pDevice->pIrqFunction != NULL) { - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: Calling IRQ Handler. Fn:%d\n", - SDDEVICE_GET_SDIO_FUNCNO(pDevice))); - /* save the device so we can process it without holding any locks */ - pDeviceIRQ[deviceIrqCount++] = pDevice; - } else { - /* this is actually okay if the device is removing, the callback - * is NULLed out */ - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: No IRQ handler Fn:%d\n", - SDDEVICE_GET_SDIO_FUNCNO(pDevice))); - } - } - /* should have handled all these */ - DBG_ASSERT(pHcd->PendingHelperIrqs == 0); - pHcd->PendingHelperIrqs = 0; - SemaphorePost(&pBusContext->DeviceListSem); - for (ii = 0; ii < deviceIrqCount; ii++) { - /* now call the function */ - SDDEVICE_CALL_IRQ_HANDLER(pDeviceIRQ[ii]); - } - deviceIrqCount = 0; - } - - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver - SDIOIrqHelperFunction Exiting.. \n")); - return 0; -} - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - GetPendingIrqComplete - completion routine for getting pending IRQs - Input: pRequest - completed request - Output: - Return: - Notes: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -static void GetPendingIrqComplete(PSDREQUEST pReq) -{ - UINT8 intPendingMsk; - PSDHCD pHcd; - - do { - pHcd = (PSDHCD)pReq->pCompleteContext; - DBG_ASSERT(pHcd != NULL); - - if (!SDIO_SUCCESS(pReq->Status)) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: Failed to get Interrupt pending register Err:%d\n", - pReq->Status)); - break; - } - - if (SD_R5_GET_RESP_FLAGS(pReq->Response) & SD_R5_ERRORS) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: CMD52 resp error: 0x%X \n", - SD_R5_GET_RESP_FLAGS(pReq->Response))); - break; - } - /* extract the pending mask */ - intPendingMsk = SD_R5_GET_READ_DATA(pReq->Response) & SDIO_INT_PEND_MASK; - /* process them */ - ProcessPendingIrqs(pHcd, intPendingMsk); - - } while (FALSE); - - FreeRequest(pReq); - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("-SDIO Bus Driver: GetPendingIrqComplete \n")); -} - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ProcessPendingIrqs - processing pending Irqs - Input: pHcd - host controller - Input: IntPendingMsk - pending irq bit mask - Output: - Return: - Notes: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -static void ProcessPendingIrqs(PSDHCD pHcd, UINT8 IntPendingMsk) -{ - PSDLIST pListItem; - PSDDEVICE pDevice; - UINT8 funcMask; - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - CT_DECLARE_IRQ_SYNC_CONTEXT(); - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("+SDIO Bus Driver: ProcessPendingIrqs \n")); - do { - /* acquire lock to protect configuration and irq enables */ - status = _AcquireHcdLock(pHcd); - if (!SDIO_SUCCESS(status)) { - break; - } - - /* sanity check */ - if ((IntPendingMsk & pHcd->IrqsEnabled) != IntPendingMsk) { - DBG_PRINT(SDDBG_ERROR, - ("SDIO Bus Driver: IRQs asserting when not enabled : curr:0x%X , card reports: 0x%X\n", - pHcd->IrqsEnabled, IntPendingMsk)); - /* remove the pending IRQs that are not enabled */ - IntPendingMsk &= pHcd->IrqsEnabled; - /* fall through */ - } - - if (!IntPendingMsk) { - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver: No interrupts on HCD:0x%X \n", (INT)pHcd)); - pHcd->IrqProcState = SDHCD_IDLE; - if (pHcd->IrqsEnabled) { - /* only re-arm if there are IRQs enabled */ - _IssueConfig(pHcd,SDCONFIG_SDIO_REARM_INT,NULL,0); - } - status = _ReleaseHcdLock(pHcd); - break; - } - /* reset helper IRQ bits */ - pHcd->PendingHelperIrqs = 0; - /* save pending IRQ acks */ - pHcd->PendingIrqAcks = IntPendingMsk; - status = _ReleaseHcdLock(pHcd); - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: INTs Pending - 0x%2.2X \n", IntPendingMsk)); - /* take the device list lock as we iterate through the list, this blocks - * device removals */ - status = SemaphorePendInterruptable(&pBusContext->DeviceListSem); - if (!SDIO_SUCCESS(status)) { - break; - } - /* walk through the device list matching HCD and interrupting function */ - SDITERATE_OVER_LIST(&pBusContext->DeviceList, pListItem) { - pDevice = CONTAINING_STRUCT(pListItem, SDDEVICE, SDList); - /* check if device belongs to the HCD */ - if (pDevice->pHcd != pHcd){ - /* not on this hcd */ - continue; - } - funcMask = 1 << SDDEVICE_GET_SDIO_FUNCNO(pDevice); - /* check device function against the pending mask */ - if (!(funcMask & IntPendingMsk)) { - /* this one is not interrupting */ - continue; - } - /* check for async IRQ and call handler */ - if (pDevice->pIrqAsyncFunction != NULL) { - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: Calling Async IRQ Handler. Fn:%d\n", - SDDEVICE_GET_SDIO_FUNCNO(pDevice))); - SDDEVICE_CALL_IRQ_ASYNC_HANDLER(pDevice); - } else { - /* this one needs the helper */ - pHcd->PendingHelperIrqs |= funcMask; - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: No Async IRQ, Pending Helper Fn:%d\n", - SDDEVICE_GET_SDIO_FUNCNO(pDevice))); - } - } - /* release HCD list lock */ - SemaphorePost(&pBusContext->DeviceListSem); - /* check for helper IRQs */ - if (pHcd->PendingHelperIrqs) { - pHcd->IrqProcState = SDHCD_IRQ_HELPER; - DBG_PRINT(SDIODBG_FUNC_IRQ, ("SDIO Bus Driver: Waking IRQ Helper \n")); - if (!SDIO_SUCCESS(SD_WAKE_OS_HELPER(&pHcd->SDIOIrqHelper))) { - DBG_PRINT(SDDBG_ERROR, ("SDIO Bus Driver: failed to wake helper! \n")); - } - } - } while (FALSE); - - DBG_PRINT(SDIODBG_FUNC_IRQ, ("-SDIO Bus Driver: ProcessPendingIrqs \n")); -} - -SDIO_STATUS TryNoIrqPendingCheck(PSDDEVICE pDevice) -{ - if (pDevice->pHcd->CardProperties.IOFnCount > 1) { - /* not supported on multi-function cards */ - DBG_PRINT(SDDBG_WARN, ("SDIO Bus Driver: IRQ Pending Check cannot be bypassed, (Funcs:%d)\n", - pDevice->pHcd->CardProperties.IOFnCount)); - return SDIO_STATUS_UNSUPPORTED; - } - - DBG_PRINT(SDDBG_TRACE, ("SDIO Bus Driver: pending IRQ check bypassed \n")); - /* set flag to optimize this */ - AtomicTest_Set(&pDevice->pHcd->HcdFlags, HCD_IRQ_NO_PEND_CHECK); - return SDIO_STATUS_SUCCESS; -} - - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - SDIO_NotifyTimerTriggered - notification handler that a timer expired - Input: TimerID - ID of timer that expired - Output: - Return: - Notes: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ -void SDIO_NotifyTimerTriggered(INT TimerID) -{ - - switch (TimerID) { - case SDIOBUS_CD_TIMER_ID: - pBusContext->CDTimerQueued = FALSE; - /* post an HCD polling event to the helper thread */ - PostCardDetectEvent(pBusContext, EVENT_HCD_CD_POLLING, NULL); - break; - default: - DBG_ASSERT(FALSE); - } - -} |