diff options
Diffstat (limited to 'drivers/sdio/stack/lib/sdio_lib_c.c')
-rw-r--r-- | drivers/sdio/stack/lib/sdio_lib_c.c | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/drivers/sdio/stack/lib/sdio_lib_c.c b/drivers/sdio/stack/lib/sdio_lib_c.c new file mode 100644 index 00000000000..4bc5a83ecf6 --- /dev/null +++ b/drivers/sdio/stack/lib/sdio_lib_c.c @@ -0,0 +1,908 @@ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +@file: sdio_lib_c.c + +@abstract: OS independent SDIO library functions +@category abstract: Support_Reference Support Functions. + +@notes: Support functions for device I/O + +@notice: Copyright (c), 2004-2005 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 SDLIB_ + +#include <linux/sdio/ctsystem.h> +#include <linux/sdio/sdio_busdriver.h> +#include <linux/sdio/_sdio_defs.h> +#include <linux/sdio/sdio_lib.h> +#include "_sdio_lib.h" + +#define _Cmd52WriteByteCommon(pDev, Address, pValue) \ + _SDLIB_IssueCMD52((pDev),0,(Address),(pValue),1,TRUE) +#define _Cmd52ReadByteCommon(pDev, Address, pValue) \ + _SDLIB_IssueCMD52((pDev),0,(Address),pValue,1,FALSE) +#define _Cmd52ReadMultipleCommon(pDev, Address, pBuf,length) \ + _SDLIB_IssueCMD52((pDev),0,(Address),(pBuf),(length),FALSE) + +/* inline version */ +static INLINE void _iSDLIB_SetupCMD52Request(UINT8 FuncNo, + UINT32 Address, + BOOL Write, + UINT8 WriteData, + PSDREQUEST pRequest) { + if (Write) { + SDIO_SET_CMD52_ARG(pRequest->Argument,CMD52_WRITE, + FuncNo, + CMD52_NORMAL_WRITE,Address,WriteData); + } else { + SDIO_SET_CMD52_ARG(pRequest->Argument,CMD52_READ,FuncNo,0,Address,0x00); + } + + pRequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5; + pRequest->Command = CMD52; +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Setup cmd52 requests + + @function name: SDLIB_SetupCMD52Request + @prototype: void SDLIB_SetupCMD52Request(UINT8 FuncNo, + UINT32 Address, + BOOL Write, + UINT8 WriteData, + PSDREQUEST pRequest) + @category: PD_Reference + + @input: FunctionNo - function number. + @input: Address - I/O address, 17-bit register address. + @input: Write - TRUE if a write operation, FALSE for reads. + @input: WriteData - write data, byte to write if write operation. + + @output: pRequest - request is updated with cmd52 parameters + + @return: none + + @notes: This function does not perform any I/O. For register reads, the completion + routine can use the SD_R5_GET_READ_DATA() macro to extract the register value. + The routine should also extract the response flags using the SD_R5_GET_RESP_FLAGS() + macro and check the flags with the SD_R5_ERRORS mask. + + @example: Getting the register value from the completion routine: + flags = SD_R5_GET_RESP_FLAGS(pRequest->Response); + if (flags & SD_R5_ERRORS) { + ... errors + } else { + registerValue = SD_R5_GET_READ_DATA(pRequest->Response); + } + + @see also: SDLIB_IssueCMD52 + @see also: SDDEVICE_CALL_REQUEST_FUNC + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void _SDLIB_SetupCMD52Request(UINT8 FuncNo, + UINT32 Address, + BOOL Write, + UINT8 WriteData, + PSDREQUEST pRequest) +{ + _iSDLIB_SetupCMD52Request(FuncNo,Address,Write,WriteData,pRequest); +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Issue a CMD52 to read or write a register + + @function name: SDLIB_IssueCMD52 + @prototype: SDIO_STATUS SDLIB_IssueCMD52(PSDDEVICE pDevice, + UINT8 FuncNo, + UINT32 Address, + PUINT8 pData, + INT ByteCount, + BOOL Write) + @category: PD_Reference + @input: pDevice - the device that is the target of the command. + @input: FunctionNo - function number of the target. + @input: Address - 17-bit register address. + @input: ByteCount - number of bytes to read or write, + @input: Write - TRUE if a write operation, FALSE for reads. + @input: pData - data buffer for writes. + + @output: pData - data buffer for writes. + + @return: SDIO Status + + @notes: This function will allocate a request and issue multiple byte reads or writes + to satisfy the ByteCount requested. This function is fully synchronous and will block + the caller. + + @see also: SDLIB_SetupCMD52Request + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +SDIO_STATUS _SDLIB_IssueCMD52(PSDDEVICE pDevice, + UINT8 FuncNo, + UINT32 Address, + PUINT8 pData, + INT ByteCount, + BOOL Write) +{ + SDIO_STATUS status = SDIO_STATUS_SUCCESS; + + PSDREQUEST pReq = NULL; + + pReq = SDDeviceAllocRequest(pDevice); + + if (NULL == pReq) { + return SDIO_STATUS_NO_RESOURCES; + } + + while (ByteCount) { + _iSDLIB_SetupCMD52Request(FuncNo,Address,Write,*pData,pReq); + status = SDDEVICE_CALL_REQUEST_FUNC(pDevice,pReq); + if (!SDIO_SUCCESS(status)) { + break; + } + + status = ConvertCMD52ResponseToSDIOStatus(SD_R5_GET_RESP_FLAGS(pReq->Response)); + if (!SDIO_SUCCESS(status)) { + DBG_PRINT(SDDBG_TRACE, ("SDIO Library: CMD52 resp error: 0x%X \n", + SD_R5_GET_RESP_FLAGS(pReq->Response))); + break; + } + if (!Write) { + /* store the byte */ + *pData = SD_R5_GET_READ_DATA(pReq->Response); + } + pData++; + Address++; + ByteCount--; + } + + SDDeviceFreeRequest(pDevice,pReq); + return status; +} + + + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Find a device's tuple. + + @function name: SDLIB_FindTuple + @prototype: SDIO_STATUS SDLIB_FindTuple(PSDDEVICE pDevice, + UINT8 Tuple, + UINT32 *pTupleScanAddress, + PUINT8 pBuffer, + UINT8 *pLength) + + @category: PD_Reference + @input: pDevice - the device that is the target of the command. + @input: Tuple - 8-bit ID of tuple to find + @input: pTupleScanAddress - On entry pTupleScanAddress is the adddress to start scanning + @input: pLength - length of pBuffer + + @output: pBuffer - storage for tuple + @output: pTupleScanAddress - address of the next tuple + @output: pLength - length of tuple read + + @return: status + + @notes: It is possible to have the same tuple ID multiple times with different lengths. This function + blocks and is fully synchronous. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +SDIO_STATUS _SDLIB_FindTuple(PSDDEVICE pDevice, + UINT8 Tuple, + UINT32 *pTupleScanAddress, + PUINT8 pBuffer, + UINT8 *pLength) +{ + SDIO_STATUS status = SDIO_STATUS_SUCCESS; + UINT32 scanStart = *pTupleScanAddress; + UINT8 tupleCode; + UINT8 tupleLink; + + /* sanity check */ + if (scanStart < SDIO_CIS_AREA_BEGIN) { + return SDIO_STATUS_CIS_OUT_OF_RANGE; + } + + while (TRUE) { + /* check for end */ + if (scanStart > SDIO_CIS_AREA_END) { + status = SDIO_STATUS_TUPLE_NOT_FOUND; + break; + } + /* get the code */ + status = _Cmd52ReadByteCommon(pDevice, scanStart, &tupleCode); + if (!SDIO_SUCCESS(status)) { + break; + } + if (CISTPL_END == tupleCode) { + /* found the end */ + status = SDIO_STATUS_TUPLE_NOT_FOUND; + break; + } + /* bump past tuple code */ + scanStart++; + /* get the tuple link value */ + status = _Cmd52ReadByteCommon(pDevice, scanStart, &tupleLink); + if (!SDIO_SUCCESS(status)) { + break; + } + /* bump past tuple link*/ + scanStart++; + /* check tuple we just found */ + if (tupleCode == Tuple) { + DBG_PRINT(SDDBG_TRACE, ("SDIO Library: Tuple:0x%2.2X Found at Address:0x%X, TupleLink:0x%X \n", + Tuple, (scanStart - 2), tupleLink)); + if (tupleLink != CISTPL_LINK_END) { + /* return the next scan address to the caller */ + *pTupleScanAddress = scanStart + tupleLink; + } else { + /* the tuple link is an end marker */ + *pTupleScanAddress = 0xFFFFFFFF; + } + /* go get the tuple */ + status = _Cmd52ReadMultipleCommon(pDevice, scanStart,pBuffer,min(*pLength,tupleLink)); + if (SDIO_SUCCESS(status)) { + /* set the actual return length */ + *pLength = min(*pLength,tupleLink); + } + /* break out of loop */ + break; + } + /*increment past this entire tuple */ + scanStart += tupleLink; + } + + return status; +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Issue an SDIO configuration command. + + @function name: SDLIB_IssueConfig + @prototype: SDIO_STATUS _SDLIB_IssueConfig(PSDDEVICE pDevice, + SDCONFIG_COMMAND Command, + PVOID pData, + INT Length) + + @category: PD_Reference + @input: pDevice - the device that is the target of the command. + @input: Command - command to send, see example. + @input: pData - command's data + @input: Length length of pData + + @output: pData - updated on commands that return data. + + @return: SDIO Status + + @example: Command and data pairs: + Type Data + SDCONFIG_GET_WP SDCONFIG_WP_VALUE + SDCONFIG_SEND_INIT_CLOCKS none + SDCONFIG_SDIO_INT_CTRL SDCONFIG_SDIO_INT_CTRL_DATA + SDCONFIG_SDIO_REARM_INT none + SDCONFIG_BUS_MODE_CTRL SDCONFIG_BUS_MODE_DATA + SDCONFIG_POWER_CTRL SDCONFIG_POWER_CTRL_DATA + + @notes: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +SDIO_STATUS _SDLIB_IssueConfig(PSDDEVICE pDevice, + SDCONFIG_COMMAND Command, + PVOID pData, + INT Length) +{ + SDCONFIG configHdr; + SET_SDCONFIG_CMD_INFO(&configHdr,Command,pData,Length); + return SDDEVICE_CALL_CONFIG_FUNC(pDevice,&configHdr); +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Set function block size + + @function name: SDLIB_SetFunctionBlockSize + @prototype: SDIO_STATUS SDLIB_SetFunctionBlockSize(PSDDEVICE pDevice, + UINT16 BlockSize) + + @category: PD_Reference + @input: pDevice - the device that is the target of the command. + @input: BlockSize - block size to set in function + + @output: none + + @return: SDIO Status + + @notes: Issues CMD52 to set the block size. This function is fully synchronous and may + block. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +SDIO_STATUS _SDLIB_SetFunctionBlockSize(PSDDEVICE pDevice, + UINT16 BlockSize) +{ + UINT8 data[2]; + + /* endian safe */ + data[0] = (UINT8)BlockSize; + data[1] = (UINT8)(BlockSize >> 8); + /* write the function blk size control register */ + return _SDLIB_IssueCMD52(pDevice, + 0, /* function 0 register space */ + FBR_FUNC_BLK_SIZE_LOW_OFFSET(CalculateFBROffset( + SDDEVICE_GET_SDIO_FUNCNO(pDevice))), + data, + 2, + TRUE); +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Print a buffer to the debug output + + @function name: SDLIB_PrintBuffer + @prototype: void SDLIB_PrintBuffer(PUCHAR pBuffer, INT Length, PTEXT pDescription) + @category: Support_Reference + + @input: pBuffer - Hex buffer to be printed. + @input: Length - length of pBuffer. + @input: pDescription - String title to be printed above the dump. + + @output: none + + @return: none + + @notes: Prints the buffer by converting to ASCII and using REL_PRINT() with 16 + bytes per line. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void _SDLIB_PrintBuffer(PUCHAR pBuffer, INT Length, PTEXT pDescription) +{ + TEXT line[49]; + TEXT address[5]; + TEXT ascii[17]; + TEXT temp[5]; + INT i; + UCHAR num; + USHORT offset = 0; + + REL_PRINT(0, + ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + if (pDescription != NULL) { + REL_PRINT(0, ("Description: %s \n\n",pDescription)); + } else { + REL_PRINT(0, ("Description: NONE \n\n")); + } + REL_PRINT(0, + ("Offset Data ASCII \n")); + REL_PRINT(0, + ("--------------------------------------------------------------------------\n")); + + while (Length) { + line[0] = (TEXT)0; + ascii[0] = (TEXT)0; + address[0] = (TEXT)0; + sprintf(address,"%4.4X",offset); + for (i = 0; i < 16; i++) { + if (Length != 0) { + num = *pBuffer; + sprintf(temp,"%2.2X ",num); + strcat(line,temp); + if ((num >= 0x20) && (num <= 0x7E)) { + sprintf(temp,"%c",*pBuffer); + } else { + sprintf(temp,"%c",0x2e); + } + strcat(ascii,temp); + pBuffer++; + Length--; + } else { + /* pad partial line with spaces */ + strcat(line," "); + strcat(ascii," "); + } + } + REL_PRINT(0,("%s %s %s\n", address, line, ascii)); + offset += 16; + } + REL_PRINT(0, + ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Get default operational current + + @function name: SDLIB_GetDefaultOpCurrent + @prototype: SDIO_STATUS SDLIB_GetDefaultOpCurrent(PSDDEVICE pDevice, SD_SLOT_CURRENT *pOpCurrent) + @category: PD_Reference + + @input: pDevice - the device that is the target of the command. + + @output: pOpCurrent - operational current in mA. + + @return: SDIO_STATUS + + @notes: This routine reads the function's CISTPL_FUNCE tuple for the default operational + current. For SDIO 1.0 devices this value is read from the 8-bit TPLFE_OP_MAX_PWR + field. For SDIO 1.1 devices, the HP MAX power field is used only if the device is + operating in HIPWR mode. Otherwise the 8-bit TPLFE_OP_MAX_PWR field is used. + Some systems may restrict high power/current mode and force cards to operate in a + legacy (< 200mA) mode. This function is fully synchronous and will block the caller. + + @example: Getting the default operational current for this function: + // get default operational current + status = SDLIB_GetDefaultOpCurrent(pDevice, &slotCurrent); + if (!SDIO_SUCCESS(status)) { + .. failed + } + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +SDIO_STATUS _SDLIB_GetDefaultOpCurrent(PSDDEVICE pDevice, SD_SLOT_CURRENT *pOpCurrent) +{ + UINT32 nextTpl; + UINT8 tplLength; + struct SDIO_FUNC_EXT_FUNCTION_TPL_1_1 funcTuple; + SDIO_STATUS status; + + /* get the FUNCE tuple */ + nextTpl = SDDEVICE_GET_SDIO_FUNC_CISPTR(pDevice); + tplLength = sizeof(funcTuple); + /* go get the function Extension tuple */ + status = _SDLIB_FindTuple(pDevice, + CISTPL_FUNCE, + &nextTpl, + (PUINT8)&funcTuple, + &tplLength); + + if (!SDIO_SUCCESS(status)) { + DBG_PRINT(SDDBG_ERROR, ("SDLIB_GetDefaultOpCurrent: Failed to get FuncE Tuple: %d \n", status)); + return status; + } + /* use the operational power (8-bit) value of current in mA as default*/ + *pOpCurrent = funcTuple.CommonInfo.OpMaxPwr; + if ((tplLength >= sizeof(funcTuple)) && (SDDEVICE_IS_SDIO_REV_GTEQ_1_10(pDevice))) { + /* we have a 1.1 tuple */ + /* check for HIPWR mode */ + if (SDDEVICE_GET_CARD_FLAGS(pDevice) & CARD_HIPWR) { + /* use the maximum operational power (16 bit ) from the tuple */ + *pOpCurrent = CT_LE16_TO_CPU_ENDIAN(funcTuple.HiPwrMaxPwr); + } + } + return SDIO_STATUS_SUCCESS; +} + + +static INLINE void FreeMessageBlock(PSDMESSAGE_QUEUE pQueue, PSDMESSAGE_BLOCK pMsg) { + SDListInsertHead(&pQueue->FreeMessageList, &pMsg->SDList); +} +static INLINE void QueueMessageBlock(PSDMESSAGE_QUEUE pQueue, PSDMESSAGE_BLOCK pMsg) { + SDListInsertTail(&pQueue->MessageList, &pMsg->SDList); +} +static INLINE void QueueMessageToHead(PSDMESSAGE_QUEUE pQueue, PSDMESSAGE_BLOCK pMsg) { + SDListInsertHead(&pQueue->MessageList, &pMsg->SDList); +} + +static INLINE PSDMESSAGE_BLOCK GetFreeMessageBlock(PSDMESSAGE_QUEUE pQueue) { + PSDLIST pItem = SDListRemoveItemFromHead(&pQueue->FreeMessageList); + if (pItem != NULL) { + return CONTAINING_STRUCT(pItem, SDMESSAGE_BLOCK , SDList); + } + return NULL; +} +static INLINE PSDMESSAGE_BLOCK GetQueuedMessage(PSDMESSAGE_QUEUE pQueue) { + PSDLIST pItem = SDListRemoveItemFromHead(&pQueue->MessageList); + if (pItem != NULL) { + return CONTAINING_STRUCT(pItem, SDMESSAGE_BLOCK , SDList); + } + return NULL; +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @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; +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Delete a message queue + + @function name: SDLIB_DeleteMessageQueue + @prototype: void SDLIB_DeleteMessageQueue(PSDMESSAGE_QUEUE pQueue) + @category: Support_Reference + + @input: pQueue - message queue to delete + + @notes: This function flushes the message queue and frees all memory allocated for + messages. + + @see also: SDLIB_CreateMessageQueue + + @example: Deleting a message queue: + if (pMsgQueue != NULL) { + SDLIB_DeleteMessageQueue(pMsgQueue); + } + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void _DeleteMessageQueue(PSDMESSAGE_QUEUE pQueue) +{ + PSDMESSAGE_BLOCK pMsg; + SDIO_STATUS status; + CT_DECLARE_IRQ_SYNC_CONTEXT(); + + status = CriticalSectionAcquireSyncIrq(&pQueue->MessageCritSection); + + /* cleanup free list */ + while (1) { + pMsg = GetFreeMessageBlock(pQueue); + if (pMsg != NULL) { + KernelFree(pMsg); + } else { + break; + } + } + /* cleanup any in the queue */ + while (1) { + pMsg = GetQueuedMessage(pQueue); + if (pMsg != NULL) { + KernelFree(pMsg); + } else { + break; + } + } + + status = CriticalSectionReleaseSyncIrq(&pQueue->MessageCritSection); + CriticalSectionDelete(&pQueue->MessageCritSection); + KernelFree(pQueue); + +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @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; +} + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @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; +} + +/* the following documents the OS helper APIs */ + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Create an OS-specific helper task/thread + + @function name: SDLIB_OSCreateHelper + @prototype: SDIO_STATUS SDLIB_OSCreateHelper(POSKERNEL_HELPER pHelper, + PHELPER_FUNCTION pFunction, + PVOID pContext) + @category: Support_Reference + + @input: pHelper - caller allocated helper object + @input: pFunction - helper function + @input: pContext - helper context + + @return: SDIO_STATUS + + @notes: This function creates a helper task/thread that runs in a new execution context. The newly + created task/thread invokes the helper function. The thread/task exits when the helper + function returns. The helper function has the prototype of: + THREAD_RETURN HelperFunction(POSKERNEL_HELPER pHelper) + The helper function usually implements a while loop and suspends execution using + SD_WAIT_FOR_WAKEUP(). On exit the helper function can return an OS-specific THREAD_RETURN + code (usually zero). The helper function executes in a fully schedule-able context and + can block on semaphores and sleep. + + @see also: SDLIB_OSDeleteHelper , SD_WAIT_FOR_WAKEUP + + @example: A thread helper function: + THREAD_RETURN HelperFunction(POSKERNEL_HELPER pHelper) + { + SDIO_STATUS status; + PMYCONTEXT pContext = (PMYCONTEXT)SD_GET_OS_HELPER_CONTEXT(pHelper); + // wait for wake up + while(1) { + status = SD_WAIT_FOR_WAKEUP(pHelper); + if (!SDIO_SUCCESS(status)) { + break; + } + if (SD_IS_HELPER_SHUTTING_DOWN(pHelper)) { + //... shutting down + break; + } + // handle wakeup... + } + return 0; + } + + @example: Creating a helper: + status = SDLIB_OSCreateHelper(&pInstance->OSHelper,HelperFunction,pInstance); + if (!SDIO_SUCCESS(status)) { + // failed + } + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @function: Delete an OS helper task/thread + + @function name: SDLIB_OSDeleteHelper + @prototype: void SDLIB_OSDeleteHelper(POSKERNEL_HELPER pHelper) + @category: Support_Reference + + @input: pHelper - caller allocated helper object + + @notes: This function wakes the helper and waits(blocks) until the helper exits. The caller can + only pass an OS helper structure that was initialized sucessfully by + SDLIB_OSCreateHelper. The caller must be in a schedulable context. + + @see also: SDLIB_OSCreateHelper + + @example: Deleting a helper: + if (pInstance->HelperCreated) { + // clean up the helper if we successfully created it + SDLIB_OSDeleteHelper(&pInstance->OSHelper); + } + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + |