4 * @Abstract: Wireless Module Interface Service Implementation
9 * Copyright (c) 2007 Atheros Communications Inc.
10 * All rights reserved.
14 #include <Magpie_api.h>
16 #include <htc_services.h>
17 #include <wmi_svc_api.h>
18 #include <adf_os_mem.h>
19 #include <adf_os_io.h>
21 #include "wmi_internal.h"
23 static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf,
24 adf_nbuf_t pHTCBuf, void *arg)
27 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
28 WMI_DISPATCH_TABLE *pCurrentTable;
29 WMI_DISPATCH_ENTRY*pCurrentEntry;
30 WMI_CMD_HANDLER pCmdHandler;
40 adf_os_assert(hdr_buf == ADF_NBUF_NULL);
43 length = adf_nbuf_len(pHTCBuf);
44 if (length < sizeof(WMI_CMD_HDR)) {
48 adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen);
50 pCurrentTable = pWMI->pDispatchHead;
51 length = length - sizeof(WMI_CMD_HDR);
53 cmdHdr = (WMI_CMD_HDR *)anbdata;
54 cmd = adf_os_ntohs(cmdHdr->commandId);
55 seq = adf_os_ntohs(cmdHdr->seqNo);
57 pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR);
60 while (pCurrentTable != NULL) {
62 pContext = pCurrentTable->pContext;
63 pCurrentEntry = pCurrentTable->pTable;
65 /* scan table entries */
66 for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) {
67 if (pCurrentEntry->CmdID == cmd) {
69 pCmdHandler = pCurrentEntry->pCmdHandler;
71 /* optionally check length */
72 if ((pCurrentEntry->CheckLength != 0) &&
73 (length < pCurrentEntry->CheckLength)) {
74 /* do not process command */
82 if (pCmdHandler != NULL) {
88 pCurrentTable = pCurrentTable->pNext;
91 if (NULL == pCmdHandler) {
95 /* if we get here, we have a command handler to dispatch */
97 /* call dispatch function */
98 pCmdHandler(pContext, cmd, seq, pCmdBuffer, length);
103 /* Invalidate the buffer (including HTC header). Note : we only need to invalidate up to the portion
104 * that was used (cache invalidate will also round up to the nearest cache line).
105 * The rest of the buffer should still be coherent.
108 HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf);
111 /* send completion handler when any HTC buffers are returned */
112 static void _WMI_SendCompleteHandler(HTC_ENDPOINT_ID Endpt, adf_nbuf_t pHTCBuf, void *arg)
114 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
115 WMI_BUF_CONTEXT *ctx;
118 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(pHTCBuf);
120 if ( ctx->EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
121 poolId = POOL_ID_WMI_SVC_EVENT;
123 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
126 BUF_Pool_free_buf(pWMI->PoolHandle, poolId, pHTCBuf);
129 static A_UINT8 WMIServiceConnect(HTC_SERVICE *pService,
136 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)pService->ServiceCtx;
138 /* save the eid to use */
139 pWMI->ControlEp = eid;
140 return HTC_SERVICE_SUCCESS;
143 /************** public APIS ********************************************/
145 static wmi_handle_t _WMI_Init(WMI_SVC_CONFIG *pWmiConfig)
147 WMI_SVC_CONTEXT *pWMI = NULL;
148 int eventSize = WMI_SVC_MAX_BUFFERED_EVENT_SIZE + sizeof(WMI_CMD_HDR) + HTC_HDR_SZ;
150 pWMI = (WMI_SVC_CONTEXT *)adf_os_mem_alloc(sizeof(WMI_SVC_CONTEXT));
155 pWMI->pDispatchHead = NULL;
156 pWMI->PoolHandle = pWmiConfig->PoolHandle;
157 pWMI->HtcHandle = pWmiConfig->HtcHandle;
159 BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_CMD_REPLY,
160 pWmiConfig->MaxCmdReplyEvts, eventSize);
162 BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_EVENT,
163 pWmiConfig->MaxEventEvts, eventSize);
165 /* NOTE: since RAM allocation is zero-initialized, there is nothing to do for the
166 * direct event pool */
168 /* register the WMI control service */
169 pWMI->WMIControlService.ProcessRecvMsg = A_INDIR(wmi_svc_api._WMI_RecvMessageHandler);
170 pWMI->WMIControlService.ProcessSendBufferComplete = A_INDIR(wmi_svc_api._WMI_SendCompleteHandler);
171 pWMI->WMIControlService.ProcessConnect = A_INDIR(wmi_svc_api._WMI_ServiceConnect);
172 pWMI->WMIControlService.MaxSvcMsgSize = WMI_SVC_MSG_SIZE + sizeof(WMI_CMD_HDR);
173 /* all buffers that are sent through the control endpoint are at least WMI_SVC_MAX_BUFFERED_EVENT_SIZE
174 * in size. Any WMI event that supplies a data buffer must insure that the space in the buffer
175 * is at least this size. */
176 pWMI->WMIControlService.TrailerSpcCheckLimit = WMI_SVC_MAX_BUFFERED_EVENT_SIZE;
177 pWMI->WMIControlService.ServiceID = WMI_CONTROL_SVC;
178 pWMI->WMIControlService.ServiceCtx = pWMI;
179 HTC_RegisterService(pWmiConfig->HtcHandle, &pWMI->WMIControlService);
184 static int _WMI_GetPendingEventsCount(wmi_handle_t handle)
186 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
187 return pWMI->PendingEvents;
190 static int _WMI_GetControlEp(wmi_handle_t handle)
192 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
193 return pWMI->ControlEp;
196 static void _WMI_RegisterDispatchTable(wmi_handle_t handle,
197 WMI_DISPATCH_TABLE *pDispatchTable)
199 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
201 if (NULL == pWMI->pDispatchHead) {
202 pWMI->pDispatchHead = pDispatchTable;
203 pWMI->pDispatchTail = pDispatchTable;
205 /* link to the tail */
206 pWMI->pDispatchTail->pNext = pDispatchTable;
207 pWMI->pDispatchTail = pDispatchTable;
211 static adf_nbuf_t _WMI_AllocEvent(wmi_handle_t handle, WMI_EVT_CLASS EventClass,
215 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
217 WMI_BUF_CONTEXT *ctx;
219 if ( EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
220 poolId = POOL_ID_WMI_SVC_EVENT;
222 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
225 buf = BUF_Pool_alloc_buf(pWMI->PoolHandle,
227 sizeof(WMI_CMD_HDR) + HTC_GetReservedHeadroom(pWMI->HtcHandle));
230 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
231 ctx->EventClass = EventClass;
236 static void _WMI_SendEvent(wmi_handle_t handle, adf_nbuf_t pEvt,
237 A_UINT16 EventId, A_UINT16 SeqNo, int Length)
239 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
242 pBuffer = adf_nbuf_push_head(pEvt, sizeof(WMI_CMD_HDR));
243 A_SET_UINT16_FIELD(pBuffer, WMI_CMD_HDR, commandId, adf_os_htons(EventId));
244 A_SET_UINT16_FIELD(pBuffer, WMI_CMD_HDR, seqNo, adf_os_htons(SeqNo));
246 HTC_SendMsg(pWMI->HtcHandle, pWMI->ControlEp, pEvt);
249 static void _WMI_Shutdown(wmi_handle_t handle)
251 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
253 adf_os_mem_free(pWMI);
256 void WMI_service_module_install(WMI_SVC_APIS *pTbl)
258 pTbl->_WMI_Init = _WMI_Init;
259 pTbl->_WMI_RegisterDispatchTable = _WMI_RegisterDispatchTable;
260 pTbl->_WMI_AllocEvent = _WMI_AllocEvent;
261 pTbl->_WMI_SendEvent = _WMI_SendEvent;
262 pTbl->_WMI_SendCompleteHandler = _WMI_SendCompleteHandler;
263 pTbl->_WMI_GetPendingEventsCount = _WMI_GetPendingEventsCount;
264 pTbl->_WMI_GetControlEp = _WMI_GetControlEp;
265 pTbl->_WMI_Shutdown = _WMI_Shutdown;
266 pTbl->_WMI_RecvMessageHandler = WMIRecvMessageHandler;
267 pTbl->_WMI_ServiceConnect = WMIServiceConnect;