blob: f491dea51fad05ded08e60381ec6c7aea0bdb4c4 [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>
31
Yue Maddad6a72013-11-19 12:40:59 -080032#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
Yue Ma0d4891e2013-08-06 17:01:45 -070033#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
Yue Mab9c86f42013-08-14 15:59:08 -070034#define MAX_USER_COMMAND_SIZE_FRAME 4096
Yue Ma0d4891e2013-08-06 17:01:45 -070035
Yue Maddad6a72013-11-19 12:40:59 -080036static ssize_t wcnss_wowenable_write(struct file *file,
37 const char __user *buf, size_t count, loff_t *ppos)
38{
39 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
40
41 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
42 char *sptr, *token;
43 v_U8_t wow_enable = 0;
44 v_U8_t wow_mp = 0;
45 v_U8_t wow_pbm = 0;
46
47 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
48 {
49 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
50 "%s: Invalid adapter or adapter has invalid magic.",
51 __func__);
52
53 return -EINVAL;
54 }
55
56 if (!sme_IsFeatureSupportedByFW(WOW))
57 {
58 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
59 "%s: Wake-on-Wireless feature is not supported "
60 "in firmware!", __func__);
61
62 return -EINVAL;
63 }
64
65 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE)
66 {
67 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
68 "%s: Command length is larger than %d bytes.",
69 __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
70
71 return -EINVAL;
72 }
73
74 /* Get command from user */
75 if (copy_from_user(cmd, buf, count))
76 return -EFAULT;
77 cmd[count] = '\0';
78 sptr = cmd;
79
80 /* Get enable or disable wow */
81 token = strsep(&sptr, " ");
82 if (!token)
83 return -EINVAL;
84 if (kstrtou8(token, 0, &wow_enable))
85 return -EINVAL;
86
87 /* Disable wow */
88 if (!wow_enable) {
89 if (!hdd_exit_wowl(pAdapter))
90 {
91 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
92 "%s: hdd_exit_wowl failed!", __func__);
93
94 return -EFAULT;
95 }
96
97 return count;
98 }
99
100 /* Get enable or disable magic packet mode */
101 token = strsep(&sptr, " ");
102 if (!token)
103 return -EINVAL;
104 if (kstrtou8(token, 0, &wow_mp))
105 return -EINVAL;
106 if (wow_mp > 1)
107 wow_mp = 1;
108
109 /* Get enable or disable pattern byte matching mode */
110 token = strsep(&sptr, " ");
111 if (!token)
112 return -EINVAL;
113 if (kstrtou8(token, 0, &wow_pbm))
114 return -EINVAL;
115 if (wow_pbm > 1)
116 wow_pbm = 1;
117
118 if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm))
119 {
120 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
121 "%s: hdd_enter_wowl failed!", __func__);
122
123 return -EFAULT;
124 }
125
126 return count;
127}
128
Yue Ma0d4891e2013-08-06 17:01:45 -0700129static ssize_t wcnss_wowpattern_write(struct file *file,
130 const char __user *buf, size_t count, loff_t *ppos)
131{
132 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
133
Yue Ma63993e32013-10-21 23:10:53 -0700134 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
Yue Ma0d4891e2013-08-06 17:01:45 -0700135 char *sptr, *token;
136 v_U8_t pattern_idx = 0;
137 v_U8_t pattern_offset = 0;
138 char *pattern_buf;
Yue Maddad6a72013-11-19 12:40:59 -0800139 char *pattern_mask;
Yue Ma0d4891e2013-08-06 17:01:45 -0700140
141 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
142 {
143 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
144 "%s: Invalid adapter or adapter has invalid magic.",
145 __func__);
146
147 return -EINVAL;
148 }
149
Yue Ma55855df2013-08-26 10:59:03 -0700150 if (!sme_IsFeatureSupportedByFW(WOW))
151 {
152 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
153 "%s: Wake-on-Wireless feature is not supported "
154 "in firmware!", __func__);
155
156 return -EINVAL;
157 }
Yue Ma63993e32013-10-21 23:10:53 -0700158
159 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN)
Yue Ma0d4891e2013-08-06 17:01:45 -0700160 {
161 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
162 "%s: Command length is larger than %d bytes.",
163 __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
164
165 return -EINVAL;
166 }
167
168 /* Get command from user */
169 if (copy_from_user(cmd, buf, count))
170 return -EFAULT;
171 cmd[count] = '\0';
172 sptr = cmd;
173
174 /* Get pattern idx */
175 token = strsep(&sptr, " ");
176 if (!token)
177 return -EINVAL;
178
179 if (kstrtou8(token, 0, &pattern_idx))
180 return -EINVAL;
181
182 /* Get pattern offset */
183 token = strsep(&sptr, " ");
184
185 /* Delete pattern if no further argument */
186 if (!token) {
187 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
188
189 return count;
190 }
191
192 if (kstrtou8(token, 0, &pattern_offset))
193 return -EINVAL;
194
195 /* Get pattern */
196 token = strsep(&sptr, " ");
197 if (!token)
198 return -EINVAL;
199
200 pattern_buf = token;
Yue Maddad6a72013-11-19 12:40:59 -0800201
202 /* Get pattern mask */
203 token = strsep(&sptr, " ");
204 if (!token)
205 return -EINVAL;
206
207 pattern_mask = token;
208 pattern_mask[strlen(pattern_mask) - 1] = '\0';
Yue Ma0d4891e2013-08-06 17:01:45 -0700209
210 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
Yue Maddad6a72013-11-19 12:40:59 -0800211 pattern_buf, pattern_mask);
Yue Ma0d4891e2013-08-06 17:01:45 -0700212
213 return count;
214}
215
Yue Mab9c86f42013-08-14 15:59:08 -0700216static ssize_t wcnss_patterngen_write(struct file *file,
217 const char __user *buf, size_t count, loff_t *ppos)
218{
219 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
Wilson Yang00256342013-10-10 23:13:38 -0700220 hdd_context_t *pHddCtx;
Yue Mab9c86f42013-08-14 15:59:08 -0700221 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
222 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
223
224 char *cmd, *sptr, *token;
225 v_U8_t pattern_idx = 0;
226 v_U8_t pattern_duration = 0;
227 char *pattern_buf;
228 v_U16_t pattern_len = 0;
229 v_U16_t i = 0;
230
231 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
232 {
233 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
234 "%s: Invalid adapter or adapter has invalid magic.",
235 __func__);
236
237 return -EINVAL;
238 }
239
Wilson Yang00256342013-10-10 23:13:38 -0700240 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
241
Yue Ma55855df2013-08-26 10:59:03 -0700242 if (!sme_IsFeatureSupportedByFW(WLAN_PERIODIC_TX_PTRN))
Yue Mab9c86f42013-08-14 15:59:08 -0700243 {
244 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Yue Ma55855df2013-08-26 10:59:03 -0700245 "%s: Periodic Tx Pattern Offload feature is not supported "
246 "in firmware!", __func__);
Yue Mab9c86f42013-08-14 15:59:08 -0700247
248 return -EINVAL;
249 }
250
251 /* Get command from user */
Yue Maddad6a72013-11-19 12:40:59 -0800252 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Yue Ma63993e32013-10-21 23:10:53 -0700253 cmd = vos_mem_malloc(count + 1);
Yue Mab9c86f42013-08-14 15:59:08 -0700254 else
255 {
256 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Jeff Johnson401c9ae2013-11-13 17:40:46 -0800257 "%s: Command length is larger than %d bytes.",
Yue Mab9c86f42013-08-14 15:59:08 -0700258 __func__, MAX_USER_COMMAND_SIZE_FRAME);
259
260 return -EINVAL;
261 }
262
Yue Ma5ac60e72013-11-16 01:03:02 -0800263 if (!cmd)
264 {
265 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
266 "%s: Memory allocation for cmd failed!", __func__);
267
268 return -EFAULT;
269 }
270
Yue Mab9c86f42013-08-14 15:59:08 -0700271 if (copy_from_user(cmd, buf, count))
272 {
273 vos_mem_free(cmd);
274 return -EFAULT;
275 }
276 cmd[count] = '\0';
277 sptr = cmd;
278
279 /* Get pattern idx */
280 token = strsep(&sptr, " ");
281 if (!token)
282 goto failure;
283 if (kstrtou8(token, 0, &pattern_idx))
284 goto failure;
285
286 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1))
287 {
288 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
289 "%s: Pattern index %d is not in the range (0 ~ %d).",
290 __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
291
292 goto failure;
293 }
294
295 /* Get pattern duration */
296 token = strsep(&sptr, " ");
297 if (!token)
298 goto failure;
299 if (kstrtou8(token, 0, &pattern_duration))
300 goto failure;
301
Yue Ma5ac60e72013-11-16 01:03:02 -0800302 /* Delete pattern using index if duration is 0 */
Yue Mab9c86f42013-08-14 15:59:08 -0700303 if (!pattern_duration)
304 {
305 delPeriodicTxPtrnParams =
306 vos_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800307 if (!delPeriodicTxPtrnParams)
308 {
309 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
310 "%s: Memory allocation for delPeriodicTxPtrnParams "
311 "failed!", __func__);
312
313 vos_mem_free(cmd);
314 return -EFAULT;
315 }
Yue Mab9c86f42013-08-14 15:59:08 -0700316
317 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
318 vos_mem_copy(delPeriodicTxPtrnParams->macAddress,
319 pAdapter->macAddressCurrent.bytes, 6);
320
321 /* Delete pattern */
322 if (eHAL_STATUS_SUCCESS != sme_DelPeriodicTxPtrn(pHddCtx->hHal,
323 delPeriodicTxPtrnParams))
324 {
325 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
326 "%s: sme_DelPeriodicTxPtrn() failed!", __func__);
327
328 vos_mem_free(delPeriodicTxPtrnParams);
329 goto failure;
330 }
331
332 vos_mem_free(delPeriodicTxPtrnParams);
333 vos_mem_free(cmd);
334 return count;
335 }
336
Yue Ma55855df2013-08-26 10:59:03 -0700337 /* Check if it's in connected state only when adding patterns */
338 if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
339 {
340 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
341 "%s: Not in Connected state!", __func__);
Yue Ma5ac60e72013-11-16 01:03:02 -0800342
343 goto failure;
Yue Ma55855df2013-08-26 10:59:03 -0700344 }
345
Yue Mab9c86f42013-08-14 15:59:08 -0700346 /* Get pattern */
347 token = strsep(&sptr, " ");
348 if (!token)
349 goto failure;
350
351 pattern_buf = token;
352 pattern_buf[strlen(pattern_buf) - 1] = '\0';
353 pattern_len = strlen(pattern_buf);
354
355 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
356 if (pattern_len % 2)
357 {
358 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
359 "%s: Malformed pattern!", __func__);
360
361 goto failure;
362 }
363 else
364 pattern_len >>= 1;
365
366 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE)
367 {
368 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
369 "%s: Not an 802.3 frame!", __func__);
370
371 goto failure;
372 }
373
374 addPeriodicTxPtrnParams = vos_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800375 if (!addPeriodicTxPtrnParams)
376 {
377 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
378 "%s: Memory allocation for addPeriodicTxPtrnParams "
379 "failed!", __func__);
380
381 vos_mem_free(cmd);
382 return -EFAULT;
383 }
Yue Mab9c86f42013-08-14 15:59:08 -0700384
385 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
386 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
387 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
388 vos_mem_copy(addPeriodicTxPtrnParams->macAddress,
389 pAdapter->macAddressCurrent.bytes, 6);
390
391 /* Extract the pattern */
392 for(i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++)
393 {
394 addPeriodicTxPtrnParams->ucPattern[i] =
395 (hdd_parse_hex(pattern_buf[0]) << 4) + hdd_parse_hex(pattern_buf[1]);
396
397 /* Skip to next byte */
398 pattern_buf += 2;
399 }
400
401 /* Add pattern */
402 if (eHAL_STATUS_SUCCESS != sme_AddPeriodicTxPtrn(pHddCtx->hHal,
403 addPeriodicTxPtrnParams))
404 {
405 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
406 "%s: sme_AddPeriodicTxPtrn() failed!", __func__);
407
408 vos_mem_free(addPeriodicTxPtrnParams);
409 goto failure;
410 }
411
412 vos_mem_free(addPeriodicTxPtrnParams);
413 vos_mem_free(cmd);
414 return count;
415
416failure:
417 vos_mem_free(cmd);
Sameer Thalappilb492efd2013-10-23 14:21:51 -0700418 return -EINVAL;
Yue Mab9c86f42013-08-14 15:59:08 -0700419}
420
Yue Ma0d4891e2013-08-06 17:01:45 -0700421static int wcnss_debugfs_open(struct inode *inode, struct file *file)
422{
423 if (inode->i_private)
424 {
425 file->private_data = inode->i_private;
426 }
427
428 return 0;
429}
430
Yue Maddad6a72013-11-19 12:40:59 -0800431static const struct file_operations fops_wowenable = {
432 .write = wcnss_wowenable_write,
433 .open = wcnss_debugfs_open,
434 .owner = THIS_MODULE,
435 .llseek = default_llseek,
436};
437
Yue Ma0d4891e2013-08-06 17:01:45 -0700438static const struct file_operations fops_wowpattern = {
439 .write = wcnss_wowpattern_write,
440 .open = wcnss_debugfs_open,
441 .owner = THIS_MODULE,
442 .llseek = default_llseek,
443};
444
Yue Mab9c86f42013-08-14 15:59:08 -0700445static const struct file_operations fops_patterngen = {
446 .write = wcnss_patterngen_write,
447 .open = wcnss_debugfs_open,
448 .owner = THIS_MODULE,
449 .llseek = default_llseek,
450};
451
Yue Ma0d4891e2013-08-06 17:01:45 -0700452VOS_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter)
453{
454 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
455 pHddCtx->debugfs_phy = debugfs_create_dir("wlan_wcnss", 0);
456
457 if (NULL == pHddCtx->debugfs_phy)
458 return VOS_STATUS_E_FAILURE;
459
Yue Maddad6a72013-11-19 12:40:59 -0800460 if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
461 pHddCtx->debugfs_phy, pAdapter, &fops_wowenable))
462 return VOS_STATUS_E_FAILURE;
463
Yue Ma0d4891e2013-08-06 17:01:45 -0700464 if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
465 pHddCtx->debugfs_phy, pAdapter, &fops_wowpattern))
466 return VOS_STATUS_E_FAILURE;
467
Yue Mab9c86f42013-08-14 15:59:08 -0700468 if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR,
469 pHddCtx->debugfs_phy, pAdapter, &fops_patterngen))
470 return VOS_STATUS_E_FAILURE;
471
Yue Ma0d4891e2013-08-06 17:01:45 -0700472 return VOS_STATUS_SUCCESS;
473}
474
475void hdd_debugfs_exit(hdd_context_t *pHddCtx)
476{
477 debugfs_remove_recursive(pHddCtx->debugfs_phy);
478}
Yue Mab9c86f42013-08-14 15:59:08 -0700479#endif /* #ifdef WLAN_OPEN_SOURCE */
Yue Ma0d4891e2013-08-06 17:01:45 -0700480