blob: 91fa02146805d061b50d0336a57356a4f6b7a8c2 [file] [log] [blame]
Yue Ma0d4891e2013-08-06 17:01:45 -07001/*
Kiet Lamaa8e15a2014-02-11 23:30:06 -08002 * Copyright (c) 2012-2013 Qualcomm Atheros, Inc.
3 * All Rights Reserved.
4 * Qualcomm Atheros Confidential and Proprietary.
Yue Ma0d4891e2013-08-06 17:01:45 -07005 */
Yue Ma0d4891e2013-08-06 17:01:45 -07006#ifdef WLAN_OPEN_SOURCE
7#include <wlan_hdd_includes.h>
8#include <wlan_hdd_wowl.h>
9
Yue Maddad6a72013-11-19 12:40:59 -080010#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
Yue Ma0d4891e2013-08-06 17:01:45 -070011#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
Yue Mab9c86f42013-08-14 15:59:08 -070012#define MAX_USER_COMMAND_SIZE_FRAME 4096
Yue Ma0d4891e2013-08-06 17:01:45 -070013
Yue Maddad6a72013-11-19 12:40:59 -080014static ssize_t wcnss_wowenable_write(struct file *file,
15 const char __user *buf, size_t count, loff_t *ppos)
16{
17 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
18
19 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
20 char *sptr, *token;
21 v_U8_t wow_enable = 0;
22 v_U8_t wow_mp = 0;
23 v_U8_t wow_pbm = 0;
24
25 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
26 {
27 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
28 "%s: Invalid adapter or adapter has invalid magic.",
29 __func__);
30
31 return -EINVAL;
32 }
33
34 if (!sme_IsFeatureSupportedByFW(WOW))
35 {
36 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
37 "%s: Wake-on-Wireless feature is not supported "
38 "in firmware!", __func__);
39
40 return -EINVAL;
41 }
42
43 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE)
44 {
45 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
46 "%s: Command length is larger than %d bytes.",
47 __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
48
49 return -EINVAL;
50 }
51
52 /* Get command from user */
53 if (copy_from_user(cmd, buf, count))
54 return -EFAULT;
55 cmd[count] = '\0';
56 sptr = cmd;
57
58 /* Get enable or disable wow */
59 token = strsep(&sptr, " ");
60 if (!token)
61 return -EINVAL;
62 if (kstrtou8(token, 0, &wow_enable))
63 return -EINVAL;
64
65 /* Disable wow */
66 if (!wow_enable) {
67 if (!hdd_exit_wowl(pAdapter))
68 {
69 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
70 "%s: hdd_exit_wowl failed!", __func__);
71
72 return -EFAULT;
73 }
74
75 return count;
76 }
77
78 /* Get enable or disable magic packet mode */
79 token = strsep(&sptr, " ");
80 if (!token)
81 return -EINVAL;
82 if (kstrtou8(token, 0, &wow_mp))
83 return -EINVAL;
84 if (wow_mp > 1)
85 wow_mp = 1;
86
87 /* Get enable or disable pattern byte matching mode */
88 token = strsep(&sptr, " ");
89 if (!token)
90 return -EINVAL;
91 if (kstrtou8(token, 0, &wow_pbm))
92 return -EINVAL;
93 if (wow_pbm > 1)
94 wow_pbm = 1;
95
96 if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm))
97 {
98 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
99 "%s: hdd_enter_wowl failed!", __func__);
100
101 return -EFAULT;
102 }
103
104 return count;
105}
106
Yue Ma0d4891e2013-08-06 17:01:45 -0700107static ssize_t wcnss_wowpattern_write(struct file *file,
108 const char __user *buf, size_t count, loff_t *ppos)
109{
110 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
111
Yue Ma63993e32013-10-21 23:10:53 -0700112 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
Yue Ma0d4891e2013-08-06 17:01:45 -0700113 char *sptr, *token;
114 v_U8_t pattern_idx = 0;
115 v_U8_t pattern_offset = 0;
116 char *pattern_buf;
Yue Maddad6a72013-11-19 12:40:59 -0800117 char *pattern_mask;
Yue Ma0d4891e2013-08-06 17:01:45 -0700118
119 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
120 {
121 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
122 "%s: Invalid adapter or adapter has invalid magic.",
123 __func__);
124
125 return -EINVAL;
126 }
127
Yue Ma55855df2013-08-26 10:59:03 -0700128 if (!sme_IsFeatureSupportedByFW(WOW))
129 {
130 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
131 "%s: Wake-on-Wireless feature is not supported "
132 "in firmware!", __func__);
133
134 return -EINVAL;
135 }
Yue Ma63993e32013-10-21 23:10:53 -0700136
137 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN)
Yue Ma0d4891e2013-08-06 17:01:45 -0700138 {
139 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
140 "%s: Command length is larger than %d bytes.",
141 __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
142
143 return -EINVAL;
144 }
145
146 /* Get command from user */
147 if (copy_from_user(cmd, buf, count))
148 return -EFAULT;
149 cmd[count] = '\0';
150 sptr = cmd;
151
152 /* Get pattern idx */
153 token = strsep(&sptr, " ");
154 if (!token)
155 return -EINVAL;
156
157 if (kstrtou8(token, 0, &pattern_idx))
158 return -EINVAL;
159
160 /* Get pattern offset */
161 token = strsep(&sptr, " ");
162
163 /* Delete pattern if no further argument */
164 if (!token) {
165 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
166
167 return count;
168 }
169
170 if (kstrtou8(token, 0, &pattern_offset))
171 return -EINVAL;
172
173 /* Get pattern */
174 token = strsep(&sptr, " ");
175 if (!token)
176 return -EINVAL;
177
178 pattern_buf = token;
Yue Maddad6a72013-11-19 12:40:59 -0800179
180 /* Get pattern mask */
181 token = strsep(&sptr, " ");
182 if (!token)
183 return -EINVAL;
184
185 pattern_mask = token;
186 pattern_mask[strlen(pattern_mask) - 1] = '\0';
Yue Ma0d4891e2013-08-06 17:01:45 -0700187
188 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
Yue Maddad6a72013-11-19 12:40:59 -0800189 pattern_buf, pattern_mask);
Yue Ma0d4891e2013-08-06 17:01:45 -0700190
191 return count;
192}
193
Yue Mab9c86f42013-08-14 15:59:08 -0700194static ssize_t wcnss_patterngen_write(struct file *file,
195 const char __user *buf, size_t count, loff_t *ppos)
196{
197 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
Wilson Yang00256342013-10-10 23:13:38 -0700198 hdd_context_t *pHddCtx;
Yue Mab9c86f42013-08-14 15:59:08 -0700199 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
200 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
201
202 char *cmd, *sptr, *token;
203 v_U8_t pattern_idx = 0;
204 v_U8_t pattern_duration = 0;
205 char *pattern_buf;
206 v_U16_t pattern_len = 0;
207 v_U16_t i = 0;
208
209 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
210 {
211 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
212 "%s: Invalid adapter or adapter has invalid magic.",
213 __func__);
214
215 return -EINVAL;
216 }
217
Wilson Yang00256342013-10-10 23:13:38 -0700218 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
219
Yue Ma55855df2013-08-26 10:59:03 -0700220 if (!sme_IsFeatureSupportedByFW(WLAN_PERIODIC_TX_PTRN))
Yue Mab9c86f42013-08-14 15:59:08 -0700221 {
222 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Yue Ma55855df2013-08-26 10:59:03 -0700223 "%s: Periodic Tx Pattern Offload feature is not supported "
224 "in firmware!", __func__);
Yue Mab9c86f42013-08-14 15:59:08 -0700225
226 return -EINVAL;
227 }
228
229 /* Get command from user */
Yue Maddad6a72013-11-19 12:40:59 -0800230 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Yue Ma63993e32013-10-21 23:10:53 -0700231 cmd = vos_mem_malloc(count + 1);
Yue Mab9c86f42013-08-14 15:59:08 -0700232 else
233 {
234 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Jeff Johnson401c9ae2013-11-13 17:40:46 -0800235 "%s: Command length is larger than %d bytes.",
Yue Mab9c86f42013-08-14 15:59:08 -0700236 __func__, MAX_USER_COMMAND_SIZE_FRAME);
237
238 return -EINVAL;
239 }
240
Yue Ma5ac60e72013-11-16 01:03:02 -0800241 if (!cmd)
242 {
243 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
244 "%s: Memory allocation for cmd failed!", __func__);
245
246 return -EFAULT;
247 }
248
Yue Mab9c86f42013-08-14 15:59:08 -0700249 if (copy_from_user(cmd, buf, count))
250 {
251 vos_mem_free(cmd);
252 return -EFAULT;
253 }
254 cmd[count] = '\0';
255 sptr = cmd;
256
257 /* Get pattern idx */
258 token = strsep(&sptr, " ");
259 if (!token)
260 goto failure;
261 if (kstrtou8(token, 0, &pattern_idx))
262 goto failure;
263
264 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1))
265 {
266 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
267 "%s: Pattern index %d is not in the range (0 ~ %d).",
268 __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
269
270 goto failure;
271 }
272
273 /* Get pattern duration */
274 token = strsep(&sptr, " ");
275 if (!token)
276 goto failure;
277 if (kstrtou8(token, 0, &pattern_duration))
278 goto failure;
279
Yue Ma5ac60e72013-11-16 01:03:02 -0800280 /* Delete pattern using index if duration is 0 */
Yue Mab9c86f42013-08-14 15:59:08 -0700281 if (!pattern_duration)
282 {
283 delPeriodicTxPtrnParams =
284 vos_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800285 if (!delPeriodicTxPtrnParams)
286 {
287 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
288 "%s: Memory allocation for delPeriodicTxPtrnParams "
289 "failed!", __func__);
290
291 vos_mem_free(cmd);
292 return -EFAULT;
293 }
Yue Mab9c86f42013-08-14 15:59:08 -0700294
295 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
296 vos_mem_copy(delPeriodicTxPtrnParams->macAddress,
297 pAdapter->macAddressCurrent.bytes, 6);
298
299 /* Delete pattern */
300 if (eHAL_STATUS_SUCCESS != sme_DelPeriodicTxPtrn(pHddCtx->hHal,
301 delPeriodicTxPtrnParams))
302 {
303 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
304 "%s: sme_DelPeriodicTxPtrn() failed!", __func__);
305
306 vos_mem_free(delPeriodicTxPtrnParams);
307 goto failure;
308 }
309
310 vos_mem_free(delPeriodicTxPtrnParams);
311 vos_mem_free(cmd);
312 return count;
313 }
314
Yue Ma55855df2013-08-26 10:59:03 -0700315 /* Check if it's in connected state only when adding patterns */
316 if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
317 {
318 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
319 "%s: Not in Connected state!", __func__);
Yue Ma5ac60e72013-11-16 01:03:02 -0800320
321 goto failure;
Yue Ma55855df2013-08-26 10:59:03 -0700322 }
323
Yue Mab9c86f42013-08-14 15:59:08 -0700324 /* Get pattern */
325 token = strsep(&sptr, " ");
326 if (!token)
327 goto failure;
328
329 pattern_buf = token;
330 pattern_buf[strlen(pattern_buf) - 1] = '\0';
331 pattern_len = strlen(pattern_buf);
332
333 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
334 if (pattern_len % 2)
335 {
336 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
337 "%s: Malformed pattern!", __func__);
338
339 goto failure;
340 }
341 else
342 pattern_len >>= 1;
343
344 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE)
345 {
346 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
347 "%s: Not an 802.3 frame!", __func__);
348
349 goto failure;
350 }
351
352 addPeriodicTxPtrnParams = vos_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800353 if (!addPeriodicTxPtrnParams)
354 {
355 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
356 "%s: Memory allocation for addPeriodicTxPtrnParams "
357 "failed!", __func__);
358
359 vos_mem_free(cmd);
360 return -EFAULT;
361 }
Yue Mab9c86f42013-08-14 15:59:08 -0700362
363 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
364 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
365 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
366 vos_mem_copy(addPeriodicTxPtrnParams->macAddress,
367 pAdapter->macAddressCurrent.bytes, 6);
368
369 /* Extract the pattern */
370 for(i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++)
371 {
372 addPeriodicTxPtrnParams->ucPattern[i] =
373 (hdd_parse_hex(pattern_buf[0]) << 4) + hdd_parse_hex(pattern_buf[1]);
374
375 /* Skip to next byte */
376 pattern_buf += 2;
377 }
378
379 /* Add pattern */
380 if (eHAL_STATUS_SUCCESS != sme_AddPeriodicTxPtrn(pHddCtx->hHal,
381 addPeriodicTxPtrnParams))
382 {
383 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
384 "%s: sme_AddPeriodicTxPtrn() failed!", __func__);
385
386 vos_mem_free(addPeriodicTxPtrnParams);
387 goto failure;
388 }
389
390 vos_mem_free(addPeriodicTxPtrnParams);
391 vos_mem_free(cmd);
392 return count;
393
394failure:
395 vos_mem_free(cmd);
Sameer Thalappilb492efd2013-10-23 14:21:51 -0700396 return -EINVAL;
Yue Mab9c86f42013-08-14 15:59:08 -0700397}
398
Yue Ma0d4891e2013-08-06 17:01:45 -0700399static int wcnss_debugfs_open(struct inode *inode, struct file *file)
400{
401 if (inode->i_private)
402 {
403 file->private_data = inode->i_private;
404 }
405
406 return 0;
407}
408
Yue Maddad6a72013-11-19 12:40:59 -0800409static const struct file_operations fops_wowenable = {
410 .write = wcnss_wowenable_write,
411 .open = wcnss_debugfs_open,
412 .owner = THIS_MODULE,
413 .llseek = default_llseek,
414};
415
Yue Ma0d4891e2013-08-06 17:01:45 -0700416static const struct file_operations fops_wowpattern = {
417 .write = wcnss_wowpattern_write,
418 .open = wcnss_debugfs_open,
419 .owner = THIS_MODULE,
420 .llseek = default_llseek,
421};
422
Yue Mab9c86f42013-08-14 15:59:08 -0700423static const struct file_operations fops_patterngen = {
424 .write = wcnss_patterngen_write,
425 .open = wcnss_debugfs_open,
426 .owner = THIS_MODULE,
427 .llseek = default_llseek,
428};
429
Yue Ma0d4891e2013-08-06 17:01:45 -0700430VOS_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter)
431{
432 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
433 pHddCtx->debugfs_phy = debugfs_create_dir("wlan_wcnss", 0);
434
435 if (NULL == pHddCtx->debugfs_phy)
436 return VOS_STATUS_E_FAILURE;
437
Yue Maddad6a72013-11-19 12:40:59 -0800438 if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
439 pHddCtx->debugfs_phy, pAdapter, &fops_wowenable))
440 return VOS_STATUS_E_FAILURE;
441
Yue Ma0d4891e2013-08-06 17:01:45 -0700442 if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
443 pHddCtx->debugfs_phy, pAdapter, &fops_wowpattern))
444 return VOS_STATUS_E_FAILURE;
445
Yue Mab9c86f42013-08-14 15:59:08 -0700446 if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR,
447 pHddCtx->debugfs_phy, pAdapter, &fops_patterngen))
448 return VOS_STATUS_E_FAILURE;
449
Yue Ma0d4891e2013-08-06 17:01:45 -0700450 return VOS_STATUS_SUCCESS;
451}
452
453void hdd_debugfs_exit(hdd_context_t *pHddCtx)
454{
455 debugfs_remove_recursive(pHddCtx->debugfs_phy);
456}
Yue Mab9c86f42013-08-14 15:59:08 -0700457#endif /* #ifdef WLAN_OPEN_SOURCE */
Yue Ma0d4891e2013-08-06 17:01:45 -0700458