blob: 7962f7e51855198487df7a868f6a4839ce1a387d [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/******************************************************************************
23 * wlan_ptt_sock_svc.c
24 *
25 ******************************************************************************/
26#ifdef PTT_SOCK_SVC_ENABLE
27#include <wlan_nlink_srv.h>
28#include <halTypes.h>
29#include <vos_status.h>
30#include <wlan_hdd_includes.h>
31#include <vos_trace.h>
32#include <wlan_nlink_common.h>
33#include <wlan_ptt_sock_svc.h>
34#include <vos_types.h>
35#include <vos_trace.h>
36#ifdef ANI_MANF_DIAG
37#include <wlan_hdd_ftm.h>
38#endif
39
40#define PTT_SOCK_DEBUG
41#ifdef PTT_SOCK_DEBUG
42#define PTT_TRACE(level, args...) VOS_TRACE( VOS_MODULE_ID_HDD, level, ## args)
43#else
44#define PTT_TRACE(level, args...)
45#endif
46// Global variables
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -070047static struct hdd_context_s *pAdapterHandle;
Jeff Johnson295189b2012-06-20 16:38:30 -070048//Utility function to perform endianess swap
49static void ptt_sock_swap_32(void *pBuffer, unsigned int len)
50{
51 v_U32_t *pBuf32, data;
52 v_U8_t *pBuf8;
53 unsigned int i;
54 len &= ~(sizeof(v_U32_t)-1);
55 pBuf32 = (v_U32_t *) pBuffer;
56 pBuf8 = (v_U8_t *) pBuffer;
57 for (i = 0; i < len; i += 4, ++pBuf32, pBuf8 += 4) {
58 data = *pBuf32;
59 pBuf8[0] = (v_U8_t) ((data >> 24) & 0xff);
60 pBuf8[1] = (v_U8_t) ((data >> 16) & 0xff);
61 pBuf8[2] = (v_U8_t) ((data >> 8) & 0xff);
62 pBuf8[3] = (v_U8_t) ((data >> 0) & 0xff);
63 }
64}
65#ifdef PTT_SOCK_DEBUG_VERBOSE
66//Utility function to perform a hex dump
67static void ptt_sock_dump_buf(const unsigned char * pbuf, int cnt)
68{
69 int i;
70 for (i = 0; i < cnt ; i++) {
71 if ((i%16)==0)
72 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"\n%p:", pbuf);
73 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO," %02X", *pbuf);
74 pbuf++;
75 }
76 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"\n");
77}
78#endif
79//Utility function to send a netlink message to an application in user space
80int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid)
81{
82 int err = -1;
83 int payload_len;
84 int tot_msg_len;
85 tAniNlHdr *wnl;
86 struct sk_buff *skb;
87 struct nlmsghdr *nlh;
88 int wmsg_length = be16_to_cpu(wmsg->length);
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -070089 static int nlmsg_seq;
Jeff Johnson295189b2012-06-20 16:38:30 -070090 if (radio < 0 || radio > ANI_MAX_RADIOS) {
91 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n",
92 __FUNCTION__, radio);
93 return -1;
94 }
95 payload_len = wmsg_length + 4; // 4 extra bytes for the radio idx
96 tot_msg_len = NLMSG_SPACE(payload_len);
97 if ((skb = dev_alloc_skb(tot_msg_len)) == NULL) {
98 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: dev_alloc_skb() failed for msg size[%d]\n",
99 __FUNCTION__, tot_msg_len);
100 return -1;
101 }
102 nlh = NLMSG_PUT(skb, pid, nlmsg_seq++, src_mod, payload_len);
103 nlh->nlmsg_flags = NLM_F_REQUEST;
104 wnl = (tAniNlHdr *) nlh;
105 wnl->radio = radio;
106 memcpy(&wnl->wmsg, wmsg, wmsg_length);
107 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: Sending Msg Type [0x%X] to pid[%d]\n",
108 __FUNCTION__, be16_to_cpu(wmsg->type), pid);
109#ifdef PTT_SOCK_DEBUG_VERBOSE
110 ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len);
111#endif
112 err = nl_srv_ucast(skb, pid);
113nlmsg_failure:
114 return err;
115}
116/*
117 * Process tregisteration request and send registration response messages
118 * to the PTT Socket App in user space
119 */
120static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio)
121{
122 tAniNlAppRegReq *reg_req;
123 tAniNlAppRegRsp rspmsg;
124 reg_req = (tAniNlAppRegReq *)(wmsg + 1);
125 memset((char *)&rspmsg, 0, sizeof(rspmsg));
126 //send reg response message to the application
127 rspmsg.ret = ANI_NL_MSG_OK;
128 rspmsg.regReq.type = reg_req->type;
129 /*Save the pid*/
130 pAdapterHandle->ptt_pid = reg_req->pid;
131 rspmsg.regReq.pid= reg_req->pid;
132 rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP);
133 rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg));
134 if (ptt_sock_send_msg_to_app((tAniHdr *)&rspmsg.wniHdr, radio,
135 ANI_NL_MSG_PUMAC, reg_req->pid) < 0)
136 {
137 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Error sending ANI_MSG_APP_REG_RSP to pid[%d]\n",
138 __FUNCTION__, reg_req->pid);
139 }
140}
141/*
142 * Process all the messages from the PTT Socket App in user space
143 */
144static void ptt_proc_pumac_msg(struct sk_buff * skb, tAniHdr *wmsg, int radio)
145{
146 u16 ani_msg_type = be16_to_cpu(wmsg->type);
147 switch(ani_msg_type)
148 {
149 case ANI_MSG_APP_REG_REQ:
150 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: Received ANI_MSG_APP_REG_REQ [0x%X]\n",
151 __FUNCTION__, ani_msg_type);
152 ptt_sock_proc_reg_req(wmsg, radio);
153 break;
154 default:
155 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Received Unknown Msg Type[0x%X]\n",
156 __FUNCTION__, ani_msg_type);
157 break;
158 }
159}
160/*
161 * Process all the messages from the Quarky Client
162 */
163static void ptt_proc_quarky_msg(tAniNlHdr *wnl, tAniHdr *wmsg, int radio)
164{
165 u16 ani_msg_type = be16_to_cpu(wmsg->type);
166 v_U32_t reg_addr;
167 v_U32_t reg_val;
168 v_U32_t len_payload;
169 v_U8_t* buf;
170 unsigned int arg1, arg2, arg3, arg4, cmd;
171 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
172 if (radio < 0 || radio > ANI_MAX_RADIOS) {
173 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: ANI Msg [0x%X] invalid radio id [%d]\n",
174 __FUNCTION__, ani_msg_type, radio);
175 return;
176 }
177 if(ani_msg_type == ANI_MSG_APP_REG_REQ)
178 {
179 ptt_sock_proc_reg_req(wmsg, radio);
180 }
181 else
182 {
183 switch (ani_msg_type)
184 {
185 case PTT_MSG_READ_REGISTER:
186 reg_addr = *(v_U32_t*) ((char*)wmsg + 8);
187 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: PTT_MSG_READ_REGISTER [0x%08lX]\n",
188 __FUNCTION__, reg_addr);
189 vosStatus = sme_DbgReadRegister(pAdapterHandle->hHal, reg_addr, &reg_val);
190 *(v_U32_t*) ((char*)wmsg + 12) = reg_val;
191 if(vosStatus != VOS_STATUS_SUCCESS)
192 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Read Register [0x%08lX] failed!!\n",
193 __FUNCTION__, reg_addr);
194 ptt_sock_send_msg_to_app(wmsg, 0, ANI_NL_MSG_PUMAC, wnl->nlh.nlmsg_pid);
195 break;
196 case PTT_MSG_WRITE_REGISTER:
197 reg_addr = *(v_U32_t*) ((const unsigned char*)wmsg + 8);
198 reg_val = *(v_U32_t*)((const unsigned char*)wmsg + 12);
199 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: PTT_MSG_WRITE_REGISTER Addr [0x%08lX] value [0x%08lX]\n",
200 __FUNCTION__, reg_addr, reg_val);
201 vosStatus = sme_DbgWriteRegister(pAdapterHandle->hHal, reg_addr, reg_val);
202 if(vosStatus != VOS_STATUS_SUCCESS)
203 {
204 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Write Register [0x%08lX] value [0x%08lX] failed!!\n",
205 __FUNCTION__, reg_addr, reg_val);
206 }
207 //send message to the app
208 ptt_sock_send_msg_to_app(wmsg, 0, ANI_NL_MSG_PUMAC, wnl->nlh.nlmsg_pid);
209 break;
210 case PTT_MSG_READ_MEMORY:
211 reg_addr = *(v_U32_t*) ((char*)wmsg + 8);
212 len_payload = *(v_U32_t*) ((char*)wmsg + 12);
213 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: PTT_MSG_READ_MEMORY addr [0x%08lX] bytes [0x%08lX]\n",
214 __FUNCTION__, reg_addr, len_payload);
215 buf = (v_U8_t*)wmsg + 16;
216 vosStatus = sme_DbgReadMemory(pAdapterHandle->hHal, reg_addr, buf, len_payload);
217 if(vosStatus != VOS_STATUS_SUCCESS) {
218 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Memory read failed for [0x%08lX]!!\n",
219 __FUNCTION__, reg_addr);
220 }
221 ptt_sock_swap_32(buf, len_payload);
222 //send message to the app
223 ptt_sock_send_msg_to_app(wmsg, 0, ANI_NL_MSG_PUMAC, wnl->nlh.nlmsg_pid);
224 break;
225 case PTT_MSG_WRITE_MEMORY:
226 reg_addr = *(v_U32_t*) ((char*)wmsg + 8);
227 len_payload = *(v_U32_t*) ((char*)wmsg + 12);
228 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: PTT_MSG_DBG_WRITE_MEMORY addr [0x%08lX] bytes [0x%08lX]\n",
229 __FUNCTION__, reg_addr, len_payload);
230 buf = (v_U8_t*)wmsg + 16;
231 ptt_sock_swap_32(buf, len_payload);
232 vosStatus = sme_DbgWriteMemory(pAdapterHandle->hHal, reg_addr, buf, len_payload);
233 if(vosStatus != VOS_STATUS_SUCCESS)
234 {
235 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Memory write failed for addr [0x%08lX]!!\n",
236 __FUNCTION__, reg_addr);
237 }
238 //send message to the app
239 ptt_sock_send_msg_to_app(wmsg, 0, ANI_NL_MSG_PUMAC, wnl->nlh.nlmsg_pid);
240 break;
241 case PTT_MSG_LOG_DUMP_DBG:
242 cmd = *(unsigned int *) ((char *)wmsg + 8);
243 arg1 = *(unsigned int *) ((char *)wmsg + 12);
244 arg2 = *(unsigned int *) ((char *)wmsg + 16);
245 arg3 = *(unsigned int *) ((char *)wmsg + 20);
246 arg4 = *(unsigned int *) ((char *)wmsg + 24);
247 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: PTT_MSG_LOG_DUMP_DBG %d arg1 %d arg2 %d arg3 %d arg4 %d\n",
248 __FUNCTION__, cmd, arg1, arg2, arg3, arg4);
249#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
250 // FIXME_PRIMA -- need logDump() replacement
251 logPrintf(pAdapterHandle->hHal, cmd, arg1, arg2, arg3, arg4);
252#endif //FEATURE_WLAN_NON_INTEGRATED_SOC
253 //send message to the app
254 ptt_sock_send_msg_to_app(wmsg, 0, ANI_NL_MSG_PUMAC, wnl->nlh.nlmsg_pid);
255 break;
256#ifdef ANI_MANF_DIAG
257 case PTT_MSG_FTM_CMDS_TYPE:
258 wlan_hdd_process_ftm_cmd(pAdapterHandle,wnl);
259 break;
260#endif
261 default:
262 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Unknown ANI Msg [0x%X], length [0x%X]\n",
263 __FUNCTION__, ani_msg_type, be16_to_cpu(wmsg->length ));
264 break;
265 }
266 }
267}
268/*
269 * Process all the Netlink messages from PTT Socket app in user space
270 */
271static int ptt_sock_rx_nlink_msg (struct sk_buff * skb)
272{
273 tAniNlHdr *wnl;
274 int radio;
275 int type;
276 wnl = (tAniNlHdr *) skb->data;
277 radio = wnl->radio;
278 type = wnl->nlh.nlmsg_type;
279 switch (type) {
280 case ANI_NL_MSG_PUMAC: //Message from the PTT socket APP
281 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: Received ANI_NL_MSG_PUMAC Msg [0x%X]\n",
282 __func__, type, radio);
283 ptt_proc_pumac_msg(skb, &wnl->wmsg, radio);
284 break;
285 case ANI_NL_MSG_PTT: //Message from Quarky GUI
286 PTT_TRACE(VOS_TRACE_LEVEL_INFO, "%s: Received ANI_NL_MSG_PTT Msg [0x%X]\n",
287 __func__, type, radio);
288 ptt_proc_quarky_msg(wnl, &wnl->wmsg, radio);
289 break;
290 default:
291 PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: Unknown NL Msg [0x%X]\n",__func__, type);
292 break;
293 }
294 return 0;
295}
296int ptt_sock_activate_svc(void *pAdapter)
297{
298 pAdapterHandle = (struct hdd_context_s*)pAdapter;
299 nl_srv_register(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg);
300 nl_srv_register(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg);
301 return 0;
302}
303#endif //PTT_SOCK_SVC_ENABLE