2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted (subject to the limitations in the
7 * disclaimer below) provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
17 * * Neither the name of Qualcomm Atheros nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
22 * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
23 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
33 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * @Abstract: Wireless Module Interface Service Implementation
43 #include <Magpie_api.h>
45 #include <htc_services.h>
46 #include <wmi_svc_api.h>
47 #include <adf_os_mem.h>
48 #include <adf_os_io.h>
50 #include "wmi_internal.h"
52 static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf,
53 adf_nbuf_t pHTCBuf, void *arg)
56 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
57 WMI_DISPATCH_TABLE *pCurrentTable;
58 WMI_DISPATCH_ENTRY*pCurrentEntry;
59 WMI_CMD_HANDLER pCmdHandler;
69 adf_os_assert(hdr_buf == ADF_NBUF_NULL);
72 length = adf_nbuf_len(pHTCBuf);
73 if (length < sizeof(WMI_CMD_HDR)) {
77 adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen);
79 pCurrentTable = pWMI->pDispatchHead;
80 length = length - sizeof(WMI_CMD_HDR);
82 cmdHdr = (WMI_CMD_HDR *)anbdata;
83 cmd = adf_os_ntohs(cmdHdr->commandId);
84 seq = adf_os_ntohs(cmdHdr->seqNo);
86 pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR);
89 while (pCurrentTable != NULL) {
91 pContext = pCurrentTable->pContext;
92 pCurrentEntry = pCurrentTable->pTable;
94 /* scan table entries */
95 for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) {
96 if (pCurrentEntry->CmdID == cmd) {
98 pCmdHandler = pCurrentEntry->pCmdHandler;
100 /* optionally check length */
101 if ((pCurrentEntry->CheckLength != 0) &&
102 (length < pCurrentEntry->CheckLength)) {
103 /* do not process command */
111 if (pCmdHandler != NULL) {
112 /* found a handler */
116 /* scan next table */
117 pCurrentTable = pCurrentTable->pNext;
120 if (NULL == pCmdHandler) {
124 /* if we get here, we have a command handler to dispatch */
126 /* call dispatch function */
127 pCmdHandler(pContext, cmd, seq, pCmdBuffer, length);
132 /* Invalidate the buffer (including HTC header). Note : we only need to invalidate up to the portion
133 * that was used (cache invalidate will also round up to the nearest cache line).
134 * The rest of the buffer should still be coherent.
137 HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf);
140 /* send completion handler when any HTC buffers are returned */
141 static void _WMI_SendCompleteHandler(HTC_ENDPOINT_ID Endpt, adf_nbuf_t pHTCBuf, void *arg)
143 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
144 WMI_BUF_CONTEXT *ctx;
147 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(pHTCBuf);
149 if ( ctx->EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
150 poolId = POOL_ID_WMI_SVC_EVENT;
152 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
155 BUF_Pool_free_buf(pWMI->PoolHandle, poolId, pHTCBuf);
158 static A_UINT8 WMIServiceConnect(HTC_SERVICE *pService,
165 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)pService->ServiceCtx;
167 /* save the eid to use */
168 pWMI->ControlEp = eid;
169 return HTC_SERVICE_SUCCESS;
172 /************** public APIS ********************************************/
174 static wmi_handle_t _WMI_Init(WMI_SVC_CONFIG *pWmiConfig)
176 WMI_SVC_CONTEXT *pWMI = NULL;
177 int eventSize = WMI_SVC_MAX_BUFFERED_EVENT_SIZE + sizeof(WMI_CMD_HDR) + HTC_HDR_SZ;
179 pWMI = (WMI_SVC_CONTEXT *)adf_os_mem_alloc(sizeof(WMI_SVC_CONTEXT));
184 pWMI->pDispatchHead = NULL;
185 pWMI->PoolHandle = pWmiConfig->PoolHandle;
186 pWMI->HtcHandle = pWmiConfig->HtcHandle;
188 BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_CMD_REPLY,
189 pWmiConfig->MaxCmdReplyEvts, eventSize);
191 BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_EVENT,
192 pWmiConfig->MaxEventEvts, eventSize);
194 /* NOTE: since RAM allocation is zero-initialized, there is nothing to do for the
195 * direct event pool */
197 /* register the WMI control service */
198 pWMI->WMIControlService.ProcessRecvMsg = A_INDIR(wmi_svc_api._WMI_RecvMessageHandler);
199 pWMI->WMIControlService.ProcessSendBufferComplete = A_INDIR(wmi_svc_api._WMI_SendCompleteHandler);
200 pWMI->WMIControlService.ProcessConnect = A_INDIR(wmi_svc_api._WMI_ServiceConnect);
201 pWMI->WMIControlService.MaxSvcMsgSize = WMI_SVC_MSG_SIZE + sizeof(WMI_CMD_HDR);
202 /* all buffers that are sent through the control endpoint are at least WMI_SVC_MAX_BUFFERED_EVENT_SIZE
203 * in size. Any WMI event that supplies a data buffer must insure that the space in the buffer
204 * is at least this size. */
205 pWMI->WMIControlService.TrailerSpcCheckLimit = WMI_SVC_MAX_BUFFERED_EVENT_SIZE;
206 pWMI->WMIControlService.ServiceID = WMI_CONTROL_SVC;
207 pWMI->WMIControlService.ServiceCtx = pWMI;
208 HTC_RegisterService(pWmiConfig->HtcHandle, &pWMI->WMIControlService);
213 static int _WMI_GetPendingEventsCount(wmi_handle_t handle)
215 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
216 return pWMI->PendingEvents;
219 static int _WMI_GetControlEp(wmi_handle_t handle)
221 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
222 return pWMI->ControlEp;
225 static void _WMI_RegisterDispatchTable(wmi_handle_t handle,
226 WMI_DISPATCH_TABLE *pDispatchTable)
228 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
230 if (NULL == pWMI->pDispatchHead) {
231 pWMI->pDispatchHead = pDispatchTable;
232 pWMI->pDispatchTail = pDispatchTable;
234 /* link to the tail */
235 pWMI->pDispatchTail->pNext = pDispatchTable;
236 pWMI->pDispatchTail = pDispatchTable;
240 static adf_nbuf_t _WMI_AllocEvent(wmi_handle_t handle, WMI_EVT_CLASS EventClass,
244 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
246 WMI_BUF_CONTEXT *ctx;
248 if ( EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
249 poolId = POOL_ID_WMI_SVC_EVENT;
251 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
254 buf = BUF_Pool_alloc_buf(pWMI->PoolHandle,
256 sizeof(WMI_CMD_HDR) + HTC_GetReservedHeadroom(pWMI->HtcHandle));
259 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
260 ctx->EventClass = EventClass;
265 static void _WMI_SendEvent(wmi_handle_t handle, adf_nbuf_t pEvt,
266 A_UINT16 EventId, A_UINT16 SeqNo, int Length)
268 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
271 pBuffer = adf_nbuf_push_head(pEvt, sizeof(WMI_CMD_HDR));
272 A_SET_UINT16_FIELD(pBuffer, WMI_CMD_HDR, commandId, adf_os_htons(EventId));
273 A_SET_UINT16_FIELD(pBuffer, WMI_CMD_HDR, seqNo, adf_os_htons(SeqNo));
275 HTC_SendMsg(pWMI->HtcHandle, pWMI->ControlEp, pEvt);
278 static void _WMI_Shutdown(wmi_handle_t handle)
280 WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
282 adf_os_mem_free(pWMI);
285 void WMI_service_module_install(WMI_SVC_APIS *pTbl)
287 pTbl->_WMI_Init = _WMI_Init;
288 pTbl->_WMI_RegisterDispatchTable = _WMI_RegisterDispatchTable;
289 pTbl->_WMI_AllocEvent = _WMI_AllocEvent;
290 pTbl->_WMI_SendEvent = _WMI_SendEvent;
291 pTbl->_WMI_SendCompleteHandler = _WMI_SendCompleteHandler;
292 pTbl->_WMI_GetPendingEventsCount = _WMI_GetPendingEventsCount;
293 pTbl->_WMI_GetControlEp = _WMI_GetControlEp;
294 pTbl->_WMI_Shutdown = _WMI_Shutdown;
295 pTbl->_WMI_RecvMessageHandler = WMIRecvMessageHandler;
296 pTbl->_WMI_ServiceConnect = WMIServiceConnect;