blob: 850405738f758123554ec678c1d105c23f986a3e [file] [log] [blame]
Yue Ma0d4891e2013-08-06 17:01:45 -07001/*
Kiet Lam842dad02014-02-18 18:44:02 -08002 * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
3 *
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.
Yue Ma0d4891e2013-08-06 17:01:45 -070020 */
Kiet Lam842dad02014-02-18 18:44:02 -080021
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
Yue Ma0d4891e2013-08-06 17:01:45 -070028#ifdef WLAN_OPEN_SOURCE
29#include <wlan_hdd_includes.h>
30#include <wlan_hdd_wowl.h>
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +053031#include <vos_sched.h>
Yue Ma0d4891e2013-08-06 17:01:45 -070032
Yue Maddad6a72013-11-19 12:40:59 -080033#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
Yue Ma0d4891e2013-08-06 17:01:45 -070034#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
Yue Mab9c86f42013-08-14 15:59:08 -070035#define MAX_USER_COMMAND_SIZE_FRAME 4096
Yue Ma0d4891e2013-08-06 17:01:45 -070036
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +053037static ssize_t __wcnss_wowenable_write(struct file *file,
Yue Maddad6a72013-11-19 12:40:59 -080038 const char __user *buf, size_t count, loff_t *ppos)
39{
40 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
41
42 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
43 char *sptr, *token;
44 v_U8_t wow_enable = 0;
45 v_U8_t wow_mp = 0;
46 v_U8_t wow_pbm = 0;
47
48 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
49 {
50 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
51 "%s: Invalid adapter or adapter has invalid magic.",
52 __func__);
53
54 return -EINVAL;
55 }
56
57 if (!sme_IsFeatureSupportedByFW(WOW))
58 {
59 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
60 "%s: Wake-on-Wireless feature is not supported "
61 "in firmware!", __func__);
62
63 return -EINVAL;
64 }
65
66 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE)
67 {
68 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
69 "%s: Command length is larger than %d bytes.",
70 __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
71
72 return -EINVAL;
73 }
74
75 /* Get command from user */
76 if (copy_from_user(cmd, buf, count))
77 return -EFAULT;
78 cmd[count] = '\0';
79 sptr = cmd;
80
81 /* Get enable or disable wow */
82 token = strsep(&sptr, " ");
83 if (!token)
84 return -EINVAL;
85 if (kstrtou8(token, 0, &wow_enable))
86 return -EINVAL;
87
88 /* Disable wow */
89 if (!wow_enable) {
c_hpothu01484c02014-05-16 14:05:15 +053090 if (!hdd_exit_wowl(pAdapter, eWOWL_EXIT_USER))
Yue Maddad6a72013-11-19 12:40:59 -080091 {
92 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
93 "%s: hdd_exit_wowl failed!", __func__);
94
95 return -EFAULT;
96 }
97
98 return count;
99 }
100
101 /* Get enable or disable magic packet mode */
102 token = strsep(&sptr, " ");
103 if (!token)
104 return -EINVAL;
105 if (kstrtou8(token, 0, &wow_mp))
106 return -EINVAL;
107 if (wow_mp > 1)
108 wow_mp = 1;
109
110 /* Get enable or disable pattern byte matching mode */
111 token = strsep(&sptr, " ");
112 if (!token)
113 return -EINVAL;
114 if (kstrtou8(token, 0, &wow_pbm))
115 return -EINVAL;
116 if (wow_pbm > 1)
117 wow_pbm = 1;
118
119 if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm))
120 {
121 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
122 "%s: hdd_enter_wowl failed!", __func__);
123
124 return -EFAULT;
125 }
126
127 return count;
128}
129
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +0530130static ssize_t wcnss_wowenable_write(struct file *file,
131 const char __user *buf, size_t count, loff_t *ppos)
132{
133 ssize_t ret;
134
135 vos_ssr_protect(__func__);
136 ret = __wcnss_wowenable_write(file, buf, count, ppos);
137 vos_ssr_unprotect(__func__);
138
139 return ret;
140}
141
142static ssize_t __wcnss_wowpattern_write(struct file *file,
Yue Ma0d4891e2013-08-06 17:01:45 -0700143 const char __user *buf, size_t count, loff_t *ppos)
144{
145 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
146
Yue Ma63993e32013-10-21 23:10:53 -0700147 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
Yue Ma0d4891e2013-08-06 17:01:45 -0700148 char *sptr, *token;
149 v_U8_t pattern_idx = 0;
150 v_U8_t pattern_offset = 0;
151 char *pattern_buf;
Yue Maddad6a72013-11-19 12:40:59 -0800152 char *pattern_mask;
Yue Ma0d4891e2013-08-06 17:01:45 -0700153
154 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
155 {
156 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
157 "%s: Invalid adapter or adapter has invalid magic.",
158 __func__);
159
160 return -EINVAL;
161 }
162
Yue Ma55855df2013-08-26 10:59:03 -0700163 if (!sme_IsFeatureSupportedByFW(WOW))
164 {
165 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
166 "%s: Wake-on-Wireless feature is not supported "
167 "in firmware!", __func__);
168
169 return -EINVAL;
170 }
Yue Ma63993e32013-10-21 23:10:53 -0700171
172 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN)
Yue Ma0d4891e2013-08-06 17:01:45 -0700173 {
174 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
175 "%s: Command length is larger than %d bytes.",
176 __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
177
178 return -EINVAL;
179 }
180
181 /* Get command from user */
182 if (copy_from_user(cmd, buf, count))
183 return -EFAULT;
184 cmd[count] = '\0';
185 sptr = cmd;
186
187 /* Get pattern idx */
188 token = strsep(&sptr, " ");
189 if (!token)
190 return -EINVAL;
191
192 if (kstrtou8(token, 0, &pattern_idx))
193 return -EINVAL;
194
195 /* Get pattern offset */
196 token = strsep(&sptr, " ");
197
198 /* Delete pattern if no further argument */
199 if (!token) {
200 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
201
202 return count;
203 }
204
205 if (kstrtou8(token, 0, &pattern_offset))
206 return -EINVAL;
207
208 /* Get pattern */
209 token = strsep(&sptr, " ");
210 if (!token)
211 return -EINVAL;
212
213 pattern_buf = token;
Yue Maddad6a72013-11-19 12:40:59 -0800214
215 /* Get pattern mask */
216 token = strsep(&sptr, " ");
217 if (!token)
218 return -EINVAL;
219
220 pattern_mask = token;
221 pattern_mask[strlen(pattern_mask) - 1] = '\0';
Yue Ma0d4891e2013-08-06 17:01:45 -0700222
223 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
Yue Maddad6a72013-11-19 12:40:59 -0800224 pattern_buf, pattern_mask);
Yue Ma0d4891e2013-08-06 17:01:45 -0700225
226 return count;
227}
228
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +0530229static ssize_t wcnss_wowpattern_write(struct file *file,
230 const char __user *buf, size_t count, loff_t *ppos)
231{
232 ssize_t ret;
233
234 vos_ssr_protect(__func__);
235 ret = __wcnss_wowpattern_write(file, buf, count, ppos);
236 vos_ssr_unprotect(__func__);
237
238 return ret;
239}
240
241static ssize_t __wcnss_patterngen_write(struct file *file,
Yue Mab9c86f42013-08-14 15:59:08 -0700242 const char __user *buf, size_t count, loff_t *ppos)
243{
244 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
Wilson Yang00256342013-10-10 23:13:38 -0700245 hdd_context_t *pHddCtx;
Yue Mab9c86f42013-08-14 15:59:08 -0700246 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
247 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
248
249 char *cmd, *sptr, *token;
250 v_U8_t pattern_idx = 0;
251 v_U8_t pattern_duration = 0;
252 char *pattern_buf;
253 v_U16_t pattern_len = 0;
254 v_U16_t i = 0;
255
256 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
257 {
258 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
259 "%s: Invalid adapter or adapter has invalid magic.",
260 __func__);
261
262 return -EINVAL;
263 }
264
Wilson Yang00256342013-10-10 23:13:38 -0700265 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
266
Yue Ma55855df2013-08-26 10:59:03 -0700267 if (!sme_IsFeatureSupportedByFW(WLAN_PERIODIC_TX_PTRN))
Yue Mab9c86f42013-08-14 15:59:08 -0700268 {
269 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Yue Ma55855df2013-08-26 10:59:03 -0700270 "%s: Periodic Tx Pattern Offload feature is not supported "
271 "in firmware!", __func__);
Yue Mab9c86f42013-08-14 15:59:08 -0700272
273 return -EINVAL;
274 }
275
276 /* Get command from user */
Yue Maddad6a72013-11-19 12:40:59 -0800277 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Yue Ma63993e32013-10-21 23:10:53 -0700278 cmd = vos_mem_malloc(count + 1);
Yue Mab9c86f42013-08-14 15:59:08 -0700279 else
280 {
281 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Jeff Johnson401c9ae2013-11-13 17:40:46 -0800282 "%s: Command length is larger than %d bytes.",
Yue Mab9c86f42013-08-14 15:59:08 -0700283 __func__, MAX_USER_COMMAND_SIZE_FRAME);
284
285 return -EINVAL;
286 }
287
Yue Ma5ac60e72013-11-16 01:03:02 -0800288 if (!cmd)
289 {
290 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
291 "%s: Memory allocation for cmd failed!", __func__);
292
293 return -EFAULT;
294 }
295
Yue Mab9c86f42013-08-14 15:59:08 -0700296 if (copy_from_user(cmd, buf, count))
297 {
298 vos_mem_free(cmd);
299 return -EFAULT;
300 }
301 cmd[count] = '\0';
302 sptr = cmd;
303
304 /* Get pattern idx */
305 token = strsep(&sptr, " ");
306 if (!token)
307 goto failure;
308 if (kstrtou8(token, 0, &pattern_idx))
309 goto failure;
310
311 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1))
312 {
313 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
314 "%s: Pattern index %d is not in the range (0 ~ %d).",
315 __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
316
317 goto failure;
318 }
319
320 /* Get pattern duration */
321 token = strsep(&sptr, " ");
322 if (!token)
323 goto failure;
324 if (kstrtou8(token, 0, &pattern_duration))
325 goto failure;
326
Yue Ma5ac60e72013-11-16 01:03:02 -0800327 /* Delete pattern using index if duration is 0 */
Yue Mab9c86f42013-08-14 15:59:08 -0700328 if (!pattern_duration)
329 {
330 delPeriodicTxPtrnParams =
331 vos_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800332 if (!delPeriodicTxPtrnParams)
333 {
334 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
335 "%s: Memory allocation for delPeriodicTxPtrnParams "
336 "failed!", __func__);
337
338 vos_mem_free(cmd);
339 return -EFAULT;
340 }
Yue Mab9c86f42013-08-14 15:59:08 -0700341
342 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
343 vos_mem_copy(delPeriodicTxPtrnParams->macAddress,
344 pAdapter->macAddressCurrent.bytes, 6);
345
346 /* Delete pattern */
347 if (eHAL_STATUS_SUCCESS != sme_DelPeriodicTxPtrn(pHddCtx->hHal,
348 delPeriodicTxPtrnParams))
349 {
350 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
351 "%s: sme_DelPeriodicTxPtrn() failed!", __func__);
352
353 vos_mem_free(delPeriodicTxPtrnParams);
354 goto failure;
355 }
356
357 vos_mem_free(delPeriodicTxPtrnParams);
358 vos_mem_free(cmd);
359 return count;
360 }
361
Yue Ma55855df2013-08-26 10:59:03 -0700362 /* Check if it's in connected state only when adding patterns */
363 if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
364 {
365 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
366 "%s: Not in Connected state!", __func__);
Yue Ma5ac60e72013-11-16 01:03:02 -0800367
368 goto failure;
Yue Ma55855df2013-08-26 10:59:03 -0700369 }
370
Yue Mab9c86f42013-08-14 15:59:08 -0700371 /* Get pattern */
372 token = strsep(&sptr, " ");
373 if (!token)
374 goto failure;
375
376 pattern_buf = token;
377 pattern_buf[strlen(pattern_buf) - 1] = '\0';
378 pattern_len = strlen(pattern_buf);
379
380 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
381 if (pattern_len % 2)
382 {
383 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
384 "%s: Malformed pattern!", __func__);
385
386 goto failure;
387 }
388 else
389 pattern_len >>= 1;
390
391 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE)
392 {
393 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
394 "%s: Not an 802.3 frame!", __func__);
395
396 goto failure;
397 }
398
399 addPeriodicTxPtrnParams = vos_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800400 if (!addPeriodicTxPtrnParams)
401 {
402 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
403 "%s: Memory allocation for addPeriodicTxPtrnParams "
404 "failed!", __func__);
405
406 vos_mem_free(cmd);
407 return -EFAULT;
408 }
Yue Mab9c86f42013-08-14 15:59:08 -0700409
410 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
411 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
412 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
413 vos_mem_copy(addPeriodicTxPtrnParams->macAddress,
414 pAdapter->macAddressCurrent.bytes, 6);
415
416 /* Extract the pattern */
417 for(i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++)
418 {
419 addPeriodicTxPtrnParams->ucPattern[i] =
420 (hdd_parse_hex(pattern_buf[0]) << 4) + hdd_parse_hex(pattern_buf[1]);
421
422 /* Skip to next byte */
423 pattern_buf += 2;
424 }
425
426 /* Add pattern */
427 if (eHAL_STATUS_SUCCESS != sme_AddPeriodicTxPtrn(pHddCtx->hHal,
428 addPeriodicTxPtrnParams))
429 {
430 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
431 "%s: sme_AddPeriodicTxPtrn() failed!", __func__);
432
433 vos_mem_free(addPeriodicTxPtrnParams);
434 goto failure;
435 }
436
437 vos_mem_free(addPeriodicTxPtrnParams);
438 vos_mem_free(cmd);
439 return count;
440
441failure:
442 vos_mem_free(cmd);
Sameer Thalappilb492efd2013-10-23 14:21:51 -0700443 return -EINVAL;
Yue Mab9c86f42013-08-14 15:59:08 -0700444}
445
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +0530446static ssize_t wcnss_patterngen_write(struct file *file,
447 const char __user *buf, size_t count, loff_t *ppos)
448{
449 ssize_t ret;
450
451 vos_ssr_protect(__func__);
452 ret = __wcnss_patterngen_write(file, buf, count, ppos);
453 vos_ssr_unprotect(__func__);
454
455 return ret;
456
457}
458
459static int __wcnss_debugfs_open(struct inode *inode, struct file *file)
Yue Ma0d4891e2013-08-06 17:01:45 -0700460{
461 if (inode->i_private)
462 {
463 file->private_data = inode->i_private;
464 }
465
466 return 0;
467}
468
Mahesh A Saptasagard68eb282014-12-17 14:20:19 +0530469static int wcnss_debugfs_open(struct inode *inode, struct file *file)
470{
471 int ret;
472
473 vos_ssr_protect(__func__);
474 ret = __wcnss_debugfs_open(inode, file);
475 vos_ssr_unprotect(__func__);
476
477 return ret;
478}
479
Yue Maddad6a72013-11-19 12:40:59 -0800480static const struct file_operations fops_wowenable = {
481 .write = wcnss_wowenable_write,
482 .open = wcnss_debugfs_open,
483 .owner = THIS_MODULE,
484 .llseek = default_llseek,
485};
486
Yue Ma0d4891e2013-08-06 17:01:45 -0700487static const struct file_operations fops_wowpattern = {
488 .write = wcnss_wowpattern_write,
489 .open = wcnss_debugfs_open,
490 .owner = THIS_MODULE,
491 .llseek = default_llseek,
492};
493
Yue Mab9c86f42013-08-14 15:59:08 -0700494static const struct file_operations fops_patterngen = {
495 .write = wcnss_patterngen_write,
496 .open = wcnss_debugfs_open,
497 .owner = THIS_MODULE,
498 .llseek = default_llseek,
499};
500
Yue Ma0d4891e2013-08-06 17:01:45 -0700501VOS_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter)
502{
503 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
504 pHddCtx->debugfs_phy = debugfs_create_dir("wlan_wcnss", 0);
505
506 if (NULL == pHddCtx->debugfs_phy)
507 return VOS_STATUS_E_FAILURE;
508
Yue Maddad6a72013-11-19 12:40:59 -0800509 if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
510 pHddCtx->debugfs_phy, pAdapter, &fops_wowenable))
511 return VOS_STATUS_E_FAILURE;
512
Yue Ma0d4891e2013-08-06 17:01:45 -0700513 if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
514 pHddCtx->debugfs_phy, pAdapter, &fops_wowpattern))
515 return VOS_STATUS_E_FAILURE;
516
Yue Mab9c86f42013-08-14 15:59:08 -0700517 if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR,
518 pHddCtx->debugfs_phy, pAdapter, &fops_patterngen))
519 return VOS_STATUS_E_FAILURE;
520
Yue Ma0d4891e2013-08-06 17:01:45 -0700521 return VOS_STATUS_SUCCESS;
522}
523
524void hdd_debugfs_exit(hdd_context_t *pHddCtx)
525{
526 debugfs_remove_recursive(pHddCtx->debugfs_phy);
527}
Yue Mab9c86f42013-08-14 15:59:08 -0700528#endif /* #ifdef WLAN_OPEN_SOURCE */
Yue Ma0d4891e2013-08-06 17:01:45 -0700529