blob: ab903223af59a398048fb9d2f38ed6a2e8dab589 [file] [log] [blame]
Yue Ma0d4891e2013-08-06 17:01:45 -07001/*
Madan Mohan Koyyalamudib09e2012013-08-21 17:26:03 -07002 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
Yue Ma0d4891e2013-08-06 17:01:45 -07003 *
Madan Mohan Koyyalamudib09e2012013-08-21 17:26:03 -07004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
Yue Ma0d4891e2013-08-06 17:01:45 -070016 *
Madan Mohan Koyyalamudib09e2012013-08-21 17:26:03 -070017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Yue Ma0d4891e2013-08-06 17:01:45 -070028 */
29
30#ifdef WLAN_OPEN_SOURCE
31#include <wlan_hdd_includes.h>
32#include <wlan_hdd_wowl.h>
33
Yue Maddad6a72013-11-19 12:40:59 -080034#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
Yue Ma0d4891e2013-08-06 17:01:45 -070035#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
Yue Mab9c86f42013-08-14 15:59:08 -070036#define MAX_USER_COMMAND_SIZE_FRAME 4096
Yue Ma0d4891e2013-08-06 17:01:45 -070037
Yue Maddad6a72013-11-19 12:40:59 -080038static ssize_t wcnss_wowenable_write(struct file *file,
39 const char __user *buf, size_t count, loff_t *ppos)
40{
41 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
42
43 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
44 char *sptr, *token;
45 v_U8_t wow_enable = 0;
46 v_U8_t wow_mp = 0;
47 v_U8_t wow_pbm = 0;
48
49 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
50 {
51 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
52 "%s: Invalid adapter or adapter has invalid magic.",
53 __func__);
54
55 return -EINVAL;
56 }
57
58 if (!sme_IsFeatureSupportedByFW(WOW))
59 {
60 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
61 "%s: Wake-on-Wireless feature is not supported "
62 "in firmware!", __func__);
63
64 return -EINVAL;
65 }
66
67 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE)
68 {
69 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
70 "%s: Command length is larger than %d bytes.",
71 __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
72
73 return -EINVAL;
74 }
75
76 /* Get command from user */
77 if (copy_from_user(cmd, buf, count))
78 return -EFAULT;
79 cmd[count] = '\0';
80 sptr = cmd;
81
82 /* Get enable or disable wow */
83 token = strsep(&sptr, " ");
84 if (!token)
85 return -EINVAL;
86 if (kstrtou8(token, 0, &wow_enable))
87 return -EINVAL;
88
89 /* Disable wow */
90 if (!wow_enable) {
91 if (!hdd_exit_wowl(pAdapter))
92 {
93 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
94 "%s: hdd_exit_wowl failed!", __func__);
95
96 return -EFAULT;
97 }
98
99 return count;
100 }
101
102 /* Get enable or disable magic packet mode */
103 token = strsep(&sptr, " ");
104 if (!token)
105 return -EINVAL;
106 if (kstrtou8(token, 0, &wow_mp))
107 return -EINVAL;
108 if (wow_mp > 1)
109 wow_mp = 1;
110
111 /* Get enable or disable pattern byte matching mode */
112 token = strsep(&sptr, " ");
113 if (!token)
114 return -EINVAL;
115 if (kstrtou8(token, 0, &wow_pbm))
116 return -EINVAL;
117 if (wow_pbm > 1)
118 wow_pbm = 1;
119
120 if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm))
121 {
122 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
123 "%s: hdd_enter_wowl failed!", __func__);
124
125 return -EFAULT;
126 }
127
128 return count;
129}
130
Yue Ma0d4891e2013-08-06 17:01:45 -0700131static ssize_t wcnss_wowpattern_write(struct file *file,
132 const char __user *buf, size_t count, loff_t *ppos)
133{
134 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
135
Yue Ma63993e32013-10-21 23:10:53 -0700136 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
Yue Ma0d4891e2013-08-06 17:01:45 -0700137 char *sptr, *token;
138 v_U8_t pattern_idx = 0;
139 v_U8_t pattern_offset = 0;
140 char *pattern_buf;
Yue Maddad6a72013-11-19 12:40:59 -0800141 char *pattern_mask;
Yue Ma0d4891e2013-08-06 17:01:45 -0700142
143 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
144 {
145 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
146 "%s: Invalid adapter or adapter has invalid magic.",
147 __func__);
148
149 return -EINVAL;
150 }
151
Yue Ma55855df2013-08-26 10:59:03 -0700152 if (!sme_IsFeatureSupportedByFW(WOW))
153 {
154 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
155 "%s: Wake-on-Wireless feature is not supported "
156 "in firmware!", __func__);
157
158 return -EINVAL;
159 }
Yue Ma63993e32013-10-21 23:10:53 -0700160
161 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN)
Yue Ma0d4891e2013-08-06 17:01:45 -0700162 {
163 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
164 "%s: Command length is larger than %d bytes.",
165 __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
166
167 return -EINVAL;
168 }
169
170 /* Get command from user */
171 if (copy_from_user(cmd, buf, count))
172 return -EFAULT;
173 cmd[count] = '\0';
174 sptr = cmd;
175
176 /* Get pattern idx */
177 token = strsep(&sptr, " ");
178 if (!token)
179 return -EINVAL;
180
181 if (kstrtou8(token, 0, &pattern_idx))
182 return -EINVAL;
183
184 /* Get pattern offset */
185 token = strsep(&sptr, " ");
186
187 /* Delete pattern if no further argument */
188 if (!token) {
189 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
190
191 return count;
192 }
193
194 if (kstrtou8(token, 0, &pattern_offset))
195 return -EINVAL;
196
197 /* Get pattern */
198 token = strsep(&sptr, " ");
199 if (!token)
200 return -EINVAL;
201
202 pattern_buf = token;
Yue Maddad6a72013-11-19 12:40:59 -0800203
204 /* Get pattern mask */
205 token = strsep(&sptr, " ");
206 if (!token)
207 return -EINVAL;
208
209 pattern_mask = token;
210 pattern_mask[strlen(pattern_mask) - 1] = '\0';
Yue Ma0d4891e2013-08-06 17:01:45 -0700211
212 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
Yue Maddad6a72013-11-19 12:40:59 -0800213 pattern_buf, pattern_mask);
Yue Ma0d4891e2013-08-06 17:01:45 -0700214
215 return count;
216}
217
Yue Mab9c86f42013-08-14 15:59:08 -0700218static ssize_t wcnss_patterngen_write(struct file *file,
219 const char __user *buf, size_t count, loff_t *ppos)
220{
221 hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
Wilson Yang00256342013-10-10 23:13:38 -0700222 hdd_context_t *pHddCtx;
Yue Mab9c86f42013-08-14 15:59:08 -0700223 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
224 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
225
226 char *cmd, *sptr, *token;
227 v_U8_t pattern_idx = 0;
228 v_U8_t pattern_duration = 0;
229 char *pattern_buf;
230 v_U16_t pattern_len = 0;
231 v_U16_t i = 0;
232
233 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
234 {
235 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
236 "%s: Invalid adapter or adapter has invalid magic.",
237 __func__);
238
239 return -EINVAL;
240 }
241
Wilson Yang00256342013-10-10 23:13:38 -0700242 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
243
Yue Ma55855df2013-08-26 10:59:03 -0700244 if (!sme_IsFeatureSupportedByFW(WLAN_PERIODIC_TX_PTRN))
Yue Mab9c86f42013-08-14 15:59:08 -0700245 {
246 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Yue Ma55855df2013-08-26 10:59:03 -0700247 "%s: Periodic Tx Pattern Offload feature is not supported "
248 "in firmware!", __func__);
Yue Mab9c86f42013-08-14 15:59:08 -0700249
250 return -EINVAL;
251 }
252
253 /* Get command from user */
Yue Maddad6a72013-11-19 12:40:59 -0800254 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Yue Ma63993e32013-10-21 23:10:53 -0700255 cmd = vos_mem_malloc(count + 1);
Yue Mab9c86f42013-08-14 15:59:08 -0700256 else
257 {
258 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Jeff Johnson401c9ae2013-11-13 17:40:46 -0800259 "%s: Command length is larger than %d bytes.",
Yue Mab9c86f42013-08-14 15:59:08 -0700260 __func__, MAX_USER_COMMAND_SIZE_FRAME);
261
262 return -EINVAL;
263 }
264
Yue Ma5ac60e72013-11-16 01:03:02 -0800265 if (!cmd)
266 {
267 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
268 "%s: Memory allocation for cmd failed!", __func__);
269
270 return -EFAULT;
271 }
272
Yue Mab9c86f42013-08-14 15:59:08 -0700273 if (copy_from_user(cmd, buf, count))
274 {
275 vos_mem_free(cmd);
276 return -EFAULT;
277 }
278 cmd[count] = '\0';
279 sptr = cmd;
280
281 /* Get pattern idx */
282 token = strsep(&sptr, " ");
283 if (!token)
284 goto failure;
285 if (kstrtou8(token, 0, &pattern_idx))
286 goto failure;
287
288 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1))
289 {
290 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
291 "%s: Pattern index %d is not in the range (0 ~ %d).",
292 __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
293
294 goto failure;
295 }
296
297 /* Get pattern duration */
298 token = strsep(&sptr, " ");
299 if (!token)
300 goto failure;
301 if (kstrtou8(token, 0, &pattern_duration))
302 goto failure;
303
Yue Ma5ac60e72013-11-16 01:03:02 -0800304 /* Delete pattern using index if duration is 0 */
Yue Mab9c86f42013-08-14 15:59:08 -0700305 if (!pattern_duration)
306 {
307 delPeriodicTxPtrnParams =
308 vos_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800309 if (!delPeriodicTxPtrnParams)
310 {
311 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
312 "%s: Memory allocation for delPeriodicTxPtrnParams "
313 "failed!", __func__);
314
315 vos_mem_free(cmd);
316 return -EFAULT;
317 }
Yue Mab9c86f42013-08-14 15:59:08 -0700318
319 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
320 vos_mem_copy(delPeriodicTxPtrnParams->macAddress,
321 pAdapter->macAddressCurrent.bytes, 6);
322
323 /* Delete pattern */
324 if (eHAL_STATUS_SUCCESS != sme_DelPeriodicTxPtrn(pHddCtx->hHal,
325 delPeriodicTxPtrnParams))
326 {
327 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
328 "%s: sme_DelPeriodicTxPtrn() failed!", __func__);
329
330 vos_mem_free(delPeriodicTxPtrnParams);
331 goto failure;
332 }
333
334 vos_mem_free(delPeriodicTxPtrnParams);
335 vos_mem_free(cmd);
336 return count;
337 }
338
Yue Ma55855df2013-08-26 10:59:03 -0700339 /* Check if it's in connected state only when adding patterns */
340 if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
341 {
342 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
343 "%s: Not in Connected state!", __func__);
Yue Ma5ac60e72013-11-16 01:03:02 -0800344
345 goto failure;
Yue Ma55855df2013-08-26 10:59:03 -0700346 }
347
Yue Mab9c86f42013-08-14 15:59:08 -0700348 /* Get pattern */
349 token = strsep(&sptr, " ");
350 if (!token)
351 goto failure;
352
353 pattern_buf = token;
354 pattern_buf[strlen(pattern_buf) - 1] = '\0';
355 pattern_len = strlen(pattern_buf);
356
357 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
358 if (pattern_len % 2)
359 {
360 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
361 "%s: Malformed pattern!", __func__);
362
363 goto failure;
364 }
365 else
366 pattern_len >>= 1;
367
368 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE)
369 {
370 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
371 "%s: Not an 802.3 frame!", __func__);
372
373 goto failure;
374 }
375
376 addPeriodicTxPtrnParams = vos_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Yue Ma5ac60e72013-11-16 01:03:02 -0800377 if (!addPeriodicTxPtrnParams)
378 {
379 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
380 "%s: Memory allocation for addPeriodicTxPtrnParams "
381 "failed!", __func__);
382
383 vos_mem_free(cmd);
384 return -EFAULT;
385 }
Yue Mab9c86f42013-08-14 15:59:08 -0700386
387 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
388 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
389 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
390 vos_mem_copy(addPeriodicTxPtrnParams->macAddress,
391 pAdapter->macAddressCurrent.bytes, 6);
392
393 /* Extract the pattern */
394 for(i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++)
395 {
396 addPeriodicTxPtrnParams->ucPattern[i] =
397 (hdd_parse_hex(pattern_buf[0]) << 4) + hdd_parse_hex(pattern_buf[1]);
398
399 /* Skip to next byte */
400 pattern_buf += 2;
401 }
402
403 /* Add pattern */
404 if (eHAL_STATUS_SUCCESS != sme_AddPeriodicTxPtrn(pHddCtx->hHal,
405 addPeriodicTxPtrnParams))
406 {
407 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
408 "%s: sme_AddPeriodicTxPtrn() failed!", __func__);
409
410 vos_mem_free(addPeriodicTxPtrnParams);
411 goto failure;
412 }
413
414 vos_mem_free(addPeriodicTxPtrnParams);
415 vos_mem_free(cmd);
416 return count;
417
418failure:
419 vos_mem_free(cmd);
Sameer Thalappilb492efd2013-10-23 14:21:51 -0700420 return -EINVAL;
Yue Mab9c86f42013-08-14 15:59:08 -0700421}
422
Yue Ma0d4891e2013-08-06 17:01:45 -0700423static int wcnss_debugfs_open(struct inode *inode, struct file *file)
424{
425 if (inode->i_private)
426 {
427 file->private_data = inode->i_private;
428 }
429
430 return 0;
431}
432
Yue Maddad6a72013-11-19 12:40:59 -0800433static const struct file_operations fops_wowenable = {
434 .write = wcnss_wowenable_write,
435 .open = wcnss_debugfs_open,
436 .owner = THIS_MODULE,
437 .llseek = default_llseek,
438};
439
Yue Ma0d4891e2013-08-06 17:01:45 -0700440static const struct file_operations fops_wowpattern = {
441 .write = wcnss_wowpattern_write,
442 .open = wcnss_debugfs_open,
443 .owner = THIS_MODULE,
444 .llseek = default_llseek,
445};
446
Yue Mab9c86f42013-08-14 15:59:08 -0700447static const struct file_operations fops_patterngen = {
448 .write = wcnss_patterngen_write,
449 .open = wcnss_debugfs_open,
450 .owner = THIS_MODULE,
451 .llseek = default_llseek,
452};
453
Yue Ma0d4891e2013-08-06 17:01:45 -0700454VOS_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter)
455{
456 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
457 pHddCtx->debugfs_phy = debugfs_create_dir("wlan_wcnss", 0);
458
459 if (NULL == pHddCtx->debugfs_phy)
460 return VOS_STATUS_E_FAILURE;
461
Yue Maddad6a72013-11-19 12:40:59 -0800462 if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
463 pHddCtx->debugfs_phy, pAdapter, &fops_wowenable))
464 return VOS_STATUS_E_FAILURE;
465
Yue Ma0d4891e2013-08-06 17:01:45 -0700466 if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
467 pHddCtx->debugfs_phy, pAdapter, &fops_wowpattern))
468 return VOS_STATUS_E_FAILURE;
469
Yue Mab9c86f42013-08-14 15:59:08 -0700470 if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR,
471 pHddCtx->debugfs_phy, pAdapter, &fops_patterngen))
472 return VOS_STATUS_E_FAILURE;
473
Yue Ma0d4891e2013-08-06 17:01:45 -0700474 return VOS_STATUS_SUCCESS;
475}
476
477void hdd_debugfs_exit(hdd_context_t *pHddCtx)
478{
479 debugfs_remove_recursive(pHddCtx->debugfs_phy);
480}
Yue Mab9c86f42013-08-14 15:59:08 -0700481#endif /* #ifdef WLAN_OPEN_SOURCE */
Yue Ma0d4891e2013-08-06 17:01:45 -0700482