Initial cut of the open ath9k htc firmware.
[open-ath9k-htc-firmware.git] / target_firmware / magpie_fw_dev / target / wmi / wmi_svc.c
1 /*
2  * @File: 
3  * 
4  * @Abstract: Wireless Module Interface Service Implementation
5  * 
6  * @Notes: 
7  * 
8  * 
9  * Copyright (c) 2007 Atheros Communications Inc.
10  * All rights reserved.
11  *
12  */
13 #include <osapi.h>
14 #include <Magpie_api.h>
15 #include <htc.h>
16 #include <htc_services.h>
17 #include <wmi_svc_api.h>
18 #include <adf_os_mem.h> 
19 #include <adf_os_io.h>
20
21 #include "wmi_internal.h"
22
23 static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf,
24                                   adf_nbuf_t pHTCBuf, void *arg)
25 {
26         void *pContext;
27         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
28         WMI_DISPATCH_TABLE *pCurrentTable;
29         WMI_DISPATCH_ENTRY*pCurrentEntry;    
30         WMI_CMD_HANDLER pCmdHandler;
31         A_UINT8* pCmdBuffer; 
32         int i;
33         A_UINT16 cmd;
34         A_UINT16 seq;
35         int length;
36         a_uint8_t *anbdata;
37         a_uint32_t anblen;
38         WMI_CMD_HDR *cmdHdr;
39             
40         adf_os_assert(hdr_buf == ADF_NBUF_NULL);
41
42         do {
43                 length = adf_nbuf_len(pHTCBuf);
44                 if (length < sizeof(WMI_CMD_HDR)) {
45                         break;    
46                 }
47
48                 adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen);
49         
50                 pCurrentTable = pWMI->pDispatchHead;
51                 length = length - sizeof(WMI_CMD_HDR);
52         
53                 cmdHdr = (WMI_CMD_HDR *)anbdata;
54                 cmd = adf_os_ntohs(cmdHdr->commandId);
55                 seq = adf_os_ntohs(cmdHdr->seqNo);
56         
57                 pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR); 
58                 pCmdHandler = NULL;
59         
60                 while (pCurrentTable != NULL) {
61             
62                         pContext = pCurrentTable->pContext;
63                         pCurrentEntry = pCurrentTable->pTable;
64         
65                         /* scan table entries */
66                         for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) {
67                                 if (pCurrentEntry->CmdID == cmd) {
68                                         /* found a match */
69                                         pCmdHandler = pCurrentEntry->pCmdHandler;
70         
71                                         /* optionally check length */
72                                         if ((pCurrentEntry->CheckLength != 0) &&
73                                             (length < pCurrentEntry->CheckLength)) {
74                                                 /* do not process command */
75                                                 pCmdHandler = NULL;
76                                         }
77                                         /* end search */                
78                                         break;    
79                                 }                        
80                         } 
81             
82                         if (pCmdHandler != NULL) {
83                                 /* found a handler */
84                                 break;
85                         }
86                 
87                         /* scan next table */
88                         pCurrentTable = pCurrentTable->pNext;
89                 }
90          
91                 if (NULL == pCmdHandler) {
92                         break;    
93                 }
94             
95                 /* if we get here, we have a command handler to dispatch */
96                 
97                 /* call dispatch function */
98                 pCmdHandler(pContext, cmd, seq, pCmdBuffer, length);
99                   
100         } while (FALSE);
101     
102     
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.
106          * */
107
108         HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf);         
109 }
110
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)
113 {
114         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg;
115         WMI_BUF_CONTEXT *ctx;
116         BUF_POOL_ID poolId;
117     
118         ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(pHTCBuf);
119         
120         if ( ctx->EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
121                 poolId = POOL_ID_WMI_SVC_EVENT;
122         } else {
123                 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
124         }
125         
126         BUF_Pool_free_buf(pWMI->PoolHandle, poolId, pHTCBuf);
127 }
128
129 static A_UINT8 WMIServiceConnect(HTC_SERVICE *pService,
130                                  HTC_ENDPOINT_ID eid, 
131                                  A_UINT8 *pDataIn, 
132                                  int LengthIn,
133                                  A_UINT8 *pDataOut,
134                                  int *pLengthOut)
135 {
136         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)pService->ServiceCtx;
137     
138         /* save the eid to use */
139         pWMI->ControlEp = eid;
140         return HTC_SERVICE_SUCCESS;
141 }
142
143 /**************  public APIS ********************************************/
144     
145 static wmi_handle_t _WMI_Init(WMI_SVC_CONFIG *pWmiConfig)
146 {
147         WMI_SVC_CONTEXT *pWMI = NULL;
148         int eventSize = WMI_SVC_MAX_BUFFERED_EVENT_SIZE + sizeof(WMI_CMD_HDR) + HTC_HDR_SZ;
149     
150         pWMI = (WMI_SVC_CONTEXT *)adf_os_mem_alloc(sizeof(WMI_SVC_CONTEXT));
151         if (pWMI == NULL) {
152                 return NULL;    
153         }
154         
155         pWMI->pDispatchHead = NULL;
156         pWMI->PoolHandle = pWmiConfig->PoolHandle;
157         pWMI->HtcHandle = pWmiConfig->HtcHandle;    
158                                          
159         BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_CMD_REPLY, 
160                              pWmiConfig->MaxCmdReplyEvts, eventSize);
161         
162         BUF_Pool_create_pool(pWmiConfig->PoolHandle, POOL_ID_WMI_SVC_EVENT, 
163                              pWmiConfig->MaxEventEvts, eventSize);
164             
165         /* NOTE: since RAM allocation is zero-initialized, there is nothing to do for the 
166          * direct event pool */
167      
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);
180     
181         return pWMI;
182 }
183
184 static int _WMI_GetPendingEventsCount(wmi_handle_t handle)
185 {
186         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
187         return pWMI->PendingEvents;
188 }
189
190 static int  _WMI_GetControlEp(wmi_handle_t handle)
191 {
192         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
193         return pWMI->ControlEp;
194 }
195
196 static void _WMI_RegisterDispatchTable(wmi_handle_t handle,
197                                        WMI_DISPATCH_TABLE *pDispatchTable)
198 {
199         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
200     
201         if (NULL == pWMI->pDispatchHead) {
202                 pWMI->pDispatchHead = pDispatchTable;
203                 pWMI->pDispatchTail = pDispatchTable;        
204         } else {
205                 /* link to the tail */
206                 pWMI->pDispatchTail->pNext = pDispatchTable;
207                 pWMI->pDispatchTail = pDispatchTable;        
208         }
209 }
210
211 static adf_nbuf_t _WMI_AllocEvent(wmi_handle_t handle, WMI_EVT_CLASS EventClass,
212                                   int Length)
213 {     
214         BUF_POOL_ID poolId;
215         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
216         adf_nbuf_t buf;
217         WMI_BUF_CONTEXT *ctx;
218     
219         if ( EventClass == WMI_EVT_CLASS_CMD_EVENT ) {
220                 poolId = POOL_ID_WMI_SVC_EVENT;
221         } else {
222                 poolId = POOL_ID_WMI_SVC_CMD_REPLY;
223         }
224     
225         buf = BUF_Pool_alloc_buf(pWMI->PoolHandle, 
226                                  poolId, 
227                                  sizeof(WMI_CMD_HDR) + HTC_GetReservedHeadroom(pWMI->HtcHandle));
228      
229         if ( buf != NULL ) {
230                 ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
231                 ctx->EventClass = EventClass;
232         }
233         return buf;
234 }
235
236 static void _WMI_SendEvent(wmi_handle_t handle, adf_nbuf_t pEvt, 
237                            A_UINT16 EventId, A_UINT16 SeqNo, int Length)
238 {
239         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
240         A_UINT8 *pBuffer;
241         
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));
245         
246         HTC_SendMsg(pWMI->HtcHandle, pWMI->ControlEp, pEvt);    
247 }
248
249 static void _WMI_Shutdown(wmi_handle_t handle)
250 {
251         WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle;
252
253         adf_os_mem_free(pWMI);
254 }
255
256 void WMI_service_module_install(WMI_SVC_APIS *pTbl)
257 {
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;
268 }