Setting up repository
[linux-libre-firmware.git] / ath9k_htc / target_firmware / magpie_fw_dev / target / wmi / wmi_svc.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  * All rights reserved.
4  *
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:
8  *
9  *  * Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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
15  *    distribution.
16  *
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.
20  *
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.
34  */
35 /*
36  * @File: 
37  * 
38  * @Abstract: Wireless Module Interface Service Implementation
39  * 
40  * @Notes: 
41  */
42 #include <osapi.h>
43 #include <Magpie_api.h>
44 #include <htc.h>
45 #include <htc_services.h>
46 #include <wmi_svc_api.h>
47 #include <adf_os_mem.h> 
48 #include <adf_os_io.h>
49
50 #include "wmi_internal.h"
51
52 static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf,
53                                   adf_nbuf_t pHTCBuf, void *arg)
54 {
55         void *pContext;
56         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
57         WMI_DISPATCH_TABLE *pCurrentTable;
58         WMI_DISPATCH_ENTRY*pCurrentEntry;    
59         WMI_CMD_HANDLER pCmdHandler;
60         A_UINT8* pCmdBuffer; 
61         int i;
62         A_UINT16 cmd;
63         A_UINT16 seq;
64         int length;
65         a_uint8_t *anbdata;
66         a_uint32_t anblen;
67         WMI_CMD_HDR *cmdHdr;
68             
69         adf_os_assert(hdr_buf == ADF_NBUF_NULL);
70
71         do {
72                 length = adf_nbuf_len(pHTCBuf);
73                 if (length < sizeof(WMI_CMD_HDR)) {
74                         break;    
75                 }
76
77                 adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen);
78         
79                 pCurrentTable = pWMI->pDispatchHead;
80                 length = length - sizeof(WMI_CMD_HDR);
81         
82                 cmdHdr = (WMI_CMD_HDR *)anbdata;
83                 cmd = adf_os_ntohs(cmdHdr->commandId);
84                 seq = adf_os_ntohs(cmdHdr->seqNo);
85         
86                 pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR); 
87                 pCmdHandler = NULL;
88         
89                 while (pCurrentTable != NULL) {
90             
91                         pContext = pCurrentTable->pContext;
92                         pCurrentEntry = pCurrentTable->pTable;
93         
94                         /* scan table entries */
95                         for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) {
96                                 if (pCurrentEntry->CmdID == cmd) {
97                                         /* found a match */
98                                         pCmdHandler = pCurrentEntry->pCmdHandler;
99         
100                                         /* optionally check length */
101                                         if ((pCurrentEntry->CheckLength != 0) &&
102                                             (length < pCurrentEntry->CheckLength)) {
103                                                 /* do not process command */
104                                                 pCmdHandler = NULL;
105                                         }
106                                         /* end search */                
107                                         break;    
108                                 }                        
109                         } 
110             
111                         if (pCmdHandler != NULL) {
112                                 /* found a handler */
113                                 break;
114                         }
115                 
116                         /* scan next table */
117                         pCurrentTable = pCurrentTable->pNext;
118                 }
119          
120                 if (NULL == pCmdHandler) {
121                         break;    
122                 }
123             
124                 /* if we get here, we have a command handler to dispatch */
125                 
126                 /* call dispatch function */
127                 pCmdHandler(pContext, cmd, seq, pCmdBuffer, length);
128                   
129         } while (FALSE);
130     
131     
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.
135          * */
136
137         HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf);         
138 }
139
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)
142 {
143         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
144         WMI_BUF_CONTEXT *ctx;
145         BUF_POOL_ID poolId;
146     
147         ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(pHTCBuf);
148         
149         if ( ctx->EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
150                 poolId = POOL_ID_WMI_SVC_EVENT;
151         } else {
152                 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
153         }
154         
155         BUF_Pool_free_buf(pWMI->PoolHandle, poolId, pHTCBuf);
156 }
157
158 static A_UINT8 WMIServiceConnect(HTC_SERVICE *pService,
159                                  HTC_ENDPOINT_ID eid, 
160                                  A_UINT8 *pDataIn, 
161                                  int LengthIn,
162                                  A_UINT8 *pDataOut,
163                                  int *pLengthOut)
164 {
165         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)pService->ServiceCtx;
166     
167         /* save the eid to use */
168         pWMI->ControlEp = eid;
169         return HTC_SERVICE_SUCCESS;
170 }
171
172 /**************  public APIS ********************************************/
173     
174 static wmi_handle_t _WMI_Init(WMI_SVC_CONFIG *pWmiConfig)
175 {
176         WMI_SVC_CONTEXT *pWMI = NULL;
177         int eventSize = WMI_SVC_MAX_BUFFERED_EVENT_SIZE + sizeof(WMI_CMD_HDR) + HTC_HDR_SZ;
178     
179         pWMI = (WMI_SVC_CONTEXT *)adf_os_mem_alloc(sizeof(WMI_SVC_CONTEXT));
180         if (pWMI == NULL) {
181                 return NULL;    
182         }
183         
184         pWMI->pDispatchHead = NULL;
185         pWMI->PoolHandle = pWmiConfig->PoolHandle;
186         pWMI->HtcHandle = pWmiConfig->HtcHandle;    
187                                          
188         BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_CMD_REPLY, 
189                              pWmiConfig->MaxCmdReplyEvts, eventSize);
190         
191         BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_EVENT, 
192                              pWmiConfig->MaxEventEvts, eventSize);
193             
194         /* NOTE: since RAM allocation is zero-initialized, there is nothing to do for the 
195          * direct event pool */
196      
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);
209     
210         return pWMI;
211 }
212
213 static int _WMI_GetPendingEventsCount(wmi_handle_t handle)
214 {
215         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
216         return pWMI->PendingEvents;
217 }
218
219 static int  _WMI_GetControlEp(wmi_handle_t handle)
220 {
221         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
222         return pWMI->ControlEp;
223 }
224
225 static void _WMI_RegisterDispatchTable(wmi_handle_t handle,
226                                        WMI_DISPATCH_TABLE *pDispatchTable)
227 {
228         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
229     
230         if (NULL == pWMI->pDispatchHead) {
231                 pWMI->pDispatchHead = pDispatchTable;
232                 pWMI->pDispatchTail = pDispatchTable;        
233         } else {
234                 /* link to the tail */
235                 pWMI->pDispatchTail->pNext = pDispatchTable;
236                 pWMI->pDispatchTail = pDispatchTable;        
237         }
238 }
239
240 static adf_nbuf_t _WMI_AllocEvent(wmi_handle_t handle, WMI_EVT_CLASS EventClass,
241                                   int Length)
242 {     
243         BUF_POOL_ID poolId;
244         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
245         adf_nbuf_t buf;
246         WMI_BUF_CONTEXT *ctx;
247     
248         if ( EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
249                 poolId = POOL_ID_WMI_SVC_EVENT;
250         } else {
251                 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
252         }
253     
254         buf = BUF_Pool_alloc_buf(pWMI->PoolHandle, 
255                                  poolId, 
256                                  sizeof(WMI_CMD_HDR) + HTC_GetReservedHeadroom(pWMI->HtcHandle));
257      
258         if ( buf != NULL ) {
259                 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
260                 ctx->EventClass = EventClass;
261         }
262         return buf;
263 }
264
265 static void _WMI_SendEvent(wmi_handle_t handle, adf_nbuf_t pEvt, 
266                            A_UINT16 EventId, A_UINT16 SeqNo, int Length)
267 {
268         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
269         A_UINT8 *pBuffer;
270         
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));
274         
275         HTC_SendMsg(pWMI->HtcHandle, pWMI->ControlEp, pEvt);    
276 }
277
278 static void _WMI_Shutdown(wmi_handle_t handle)
279 {
280         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
281
282         adf_os_mem_free(pWMI);
283 }
284
285 void WMI_service_module_install(WMI_SVC_APIS *pTbl)
286 {
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;
297 }