blob: 89aac4e51cc98ceb44c6a78b73e3f3502955be86 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
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 * 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
28/**
29 * DOC: wlan_hdd_debugfs.c
30 *
31 * This driver currently supports the following debugfs files:
32 * wlan_wcnss/wow_enable to enable/disable WoWL.
33 * wlan_wcnss/wow_pattern to configure WoWL patterns.
34 * wlan_wcnss/pattern_gen to configure periodic TX patterns.
35 */
36
37#ifdef WLAN_OPEN_SOURCE
38#include <wlan_hdd_includes.h>
39#include <wlan_hdd_wowl.h>
40#include <cds_sched.h>
41
42#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
43#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
44#define MAX_USER_COMMAND_SIZE_FRAME 4096
45
46/**
47 * __wcnss_wowenable_write() - wow_enable debugfs handler
48 * @file: debugfs file handle
49 * @buf: text being written to the debugfs
50 * @count: size of @buf
51 * @ppos: (unused) offset into the virtual file system
52 *
53 * Return: number of bytes processed
54 */
55static ssize_t __wcnss_wowenable_write(struct file *file,
56 const char __user *buf, size_t count,
57 loff_t *ppos)
58{
59 hdd_adapter_t *pAdapter;
60 hdd_context_t *hdd_ctx;
61 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
62 char *sptr, *token;
63 uint8_t wow_enable = 0;
64 uint8_t wow_mp = 0;
65 uint8_t wow_pbm = 0;
66 int ret;
67
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053068 ENTER();
69
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070 pAdapter = (hdd_adapter_t *)file->private_data;
71 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053072 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073 "%s: Invalid adapter or adapter has invalid magic.",
74 __func__);
75
76 return -EINVAL;
77 }
78
79 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
80 ret = wlan_hdd_validate_context(hdd_ctx);
81 if (0 != ret)
82 return ret;
83
84
85 if (!sme_is_feature_supported_by_fw(WOW)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053086 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087 "%s: Wake-on-Wireless feature is not supported in firmware!",
88 __func__);
89
90 return -EINVAL;
91 }
92
93 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053094 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080095 "%s: Command length is larger than %d bytes.",
96 __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
97
98 return -EINVAL;
99 }
100
101 /* Get command from user */
102 if (copy_from_user(cmd, buf, count))
103 return -EFAULT;
104 cmd[count] = '\0';
105 sptr = cmd;
106
107 /* Get enable or disable wow */
108 token = strsep(&sptr, " ");
109 if (!token)
110 return -EINVAL;
111 if (kstrtou8(token, 0, &wow_enable))
112 return -EINVAL;
113
114 /* Disable wow */
115 if (!wow_enable) {
116 if (!hdd_exit_wowl(pAdapter)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530117 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800118 "%s: hdd_exit_wowl failed!", __func__);
119
120 return -EFAULT;
121 }
122
123 return count;
124 }
125
126 /* Get enable or disable magic packet mode */
127 token = strsep(&sptr, " ");
128 if (!token)
129 return -EINVAL;
130 if (kstrtou8(token, 0, &wow_mp))
131 return -EINVAL;
132 if (wow_mp > 1)
133 wow_mp = 1;
134
135 /* Get enable or disable pattern byte matching mode */
136 token = strsep(&sptr, " ");
137 if (!token)
138 return -EINVAL;
139 if (kstrtou8(token, 0, &wow_pbm))
140 return -EINVAL;
141 if (wow_pbm > 1)
142 wow_pbm = 1;
143
144 if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530145 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146 "%s: hdd_enter_wowl failed!", __func__);
147
148 return -EFAULT;
149 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530150 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800151 return count;
152}
153
154/**
155 * wcnss_wowenable_write() - SSR wrapper for wcnss_wowenable_write
156 * @file: file pointer
157 * @buf: buffer
158 * @count: count
159 * @ppos: position pointer
160 *
161 * Return: 0 on success, error number otherwise
162 */
163static ssize_t wcnss_wowenable_write(struct file *file,
164 const char __user *buf,
165 size_t count, loff_t *ppos)
166{
167 ssize_t ret;
168
169 cds_ssr_protect(__func__);
170 ret = __wcnss_wowenable_write(file, buf, count, ppos);
171 cds_ssr_unprotect(__func__);
172
173 return ret;
174}
175
176/**
177 * __wcnss_wowpattern_write() - wow_pattern debugfs handler
178 * @file: debugfs file handle
179 * @buf: text being written to the debugfs
180 * @count: size of @buf
181 * @ppos: (unused) offset into the virtual file system
182 *
183 * Return: number of bytes processed
184 */
185static ssize_t __wcnss_wowpattern_write(struct file *file,
186 const char __user *buf, size_t count,
187 loff_t *ppos)
188{
189 hdd_adapter_t *pAdapter = (hdd_adapter_t *) file->private_data;
190 hdd_context_t *hdd_ctx;
191 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
192 char *sptr, *token;
193 uint8_t pattern_idx = 0;
194 uint8_t pattern_offset = 0;
195 char *pattern_buf;
196 char *pattern_mask;
197 int ret;
198
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530199 ENTER();
200
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530202 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 "%s: Invalid adapter or adapter has invalid magic.",
204 __func__);
205
206 return -EINVAL;
207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
210 ret = wlan_hdd_validate_context(hdd_ctx);
211 if (0 != ret)
212 return ret;
213
214 if (!sme_is_feature_supported_by_fw(WOW)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530215 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 "%s: Wake-on-Wireless feature is not supported in firmware!",
217 __func__);
218
219 return -EINVAL;
220 }
221
222 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530223 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224 "%s: Command length is larger than %d bytes.",
225 __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
226
227 return -EINVAL;
228 }
229
230 /* Get command from user */
231 if (copy_from_user(cmd, buf, count))
232 return -EFAULT;
233 cmd[count] = '\0';
234 sptr = cmd;
235
236 /* Get pattern idx */
237 token = strsep(&sptr, " ");
238 if (!token)
239 return -EINVAL;
240
241 if (kstrtou8(token, 0, &pattern_idx))
242 return -EINVAL;
243
244 /* Get pattern offset */
245 token = strsep(&sptr, " ");
246
247 /* Delete pattern if no further argument */
248 if (!token) {
249 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
250
251 return count;
252 }
253
254 if (kstrtou8(token, 0, &pattern_offset))
255 return -EINVAL;
256
257 /* Get pattern */
258 token = strsep(&sptr, " ");
259 if (!token)
260 return -EINVAL;
261
262 pattern_buf = token;
263
264 /* Get pattern mask */
265 token = strsep(&sptr, " ");
266 if (!token)
267 return -EINVAL;
268
269 pattern_mask = token;
270 pattern_mask[strlen(pattern_mask) - 1] = '\0';
271
272 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
273 pattern_buf, pattern_mask);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530274 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800275 return count;
276}
277
278/**
279 * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write
280 * @file: file pointer
281 * @buf: buffer
282 * @count: count
283 * @ppos: position pointer
284 *
285 * Return: 0 on success, error number otherwise
286 */
287static ssize_t wcnss_wowpattern_write(struct file *file,
288 const char __user *buf,
289 size_t count, loff_t *ppos)
290{
291 ssize_t ret;
292
293 cds_ssr_protect(__func__);
294 ret = __wcnss_wowpattern_write(file, buf, count, ppos);
295 cds_ssr_unprotect(__func__);
296
297 return ret;
298}
299
300/**
301 * wcnss_patterngen_write() - pattern_gen debugfs handler
302 * @file: debugfs file handle
303 * @buf: text being written to the debugfs
304 * @count: size of @buf
305 * @ppos: (unused) offset into the virtual file system
306 *
307 * Return: number of bytes processed
308 */
309static ssize_t __wcnss_patterngen_write(struct file *file,
310 const char __user *buf, size_t count,
311 loff_t *ppos)
312{
313 hdd_adapter_t *pAdapter;
314 hdd_context_t *pHddCtx;
315 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
316 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
317
318 char *cmd, *sptr, *token;
319 uint8_t pattern_idx = 0;
320 uint8_t pattern_duration = 0;
321 char *pattern_buf;
322 uint16_t pattern_len = 0;
323 uint16_t i = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530324 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800325 int ret;
326
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530327 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800328
329 pAdapter = (hdd_adapter_t *)file->private_data;
330 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530331 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800332 "%s: Invalid adapter or adapter has invalid magic.",
333 __func__);
334
335 return -EINVAL;
336 }
337
338 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
339 ret = wlan_hdd_validate_context(pHddCtx);
340 if (0 != ret)
341 return ret;
342
343 if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530344 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800345 "%s: Periodic Tx Pattern Offload feature is not supported in firmware!",
346 __func__);
347 return -EINVAL;
348 }
349
350 /* Get command from user */
351 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530352 cmd = qdf_mem_malloc(count + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530354 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355 "%s: Command length is larger than %d bytes.",
356 __func__, MAX_USER_COMMAND_SIZE_FRAME);
357
358 return -EINVAL;
359 }
360
361 if (!cmd) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530362 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 FL("Memory allocation for cmd failed!"));
364 return -ENOMEM;
365 }
366
367 if (copy_from_user(cmd, buf, count)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530368 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 return -EFAULT;
370 }
371 cmd[count] = '\0';
372 sptr = cmd;
373
374 /* Get pattern idx */
375 token = strsep(&sptr, " ");
376 if (!token)
377 goto failure;
378 if (kstrtou8(token, 0, &pattern_idx))
379 goto failure;
380
381 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530382 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383 "%s: Pattern index %d is not in the range (0 ~ %d).",
384 __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
385
386 goto failure;
387 }
388
389 /* Get pattern duration */
390 token = strsep(&sptr, " ");
391 if (!token)
392 goto failure;
393 if (kstrtou8(token, 0, &pattern_duration))
394 goto failure;
395
396 /* Delete pattern using index if duration is 0 */
397 if (!pattern_duration) {
398 delPeriodicTxPtrnParams =
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530399 qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800400 if (!delPeriodicTxPtrnParams) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530401 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402 FL("Memory allocation failed!"));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530403 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800404 return -ENOMEM;
405 }
406 delPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
407 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530408 qdf_copy_macaddr(&delPeriodicTxPtrnParams->mac_address,
Srinivas Girigowdaa5bba7a2015-11-18 22:44:36 -0800409 &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800410
411 /* Delete pattern */
412 status = sme_del_periodic_tx_ptrn(pHddCtx->hHal,
413 delPeriodicTxPtrnParams);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530414 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530415 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416 "%s: sme_del_periodic_tx_ptrn() failed!",
417 __func__);
418
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530419 qdf_mem_free(delPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420 goto failure;
421 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530422 qdf_mem_free(cmd);
423 qdf_mem_free(delPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424 return count;
425 }
426
427 /*
428 * In SAP mode allow configuration without any connection check
429 * In STA mode check if it's in connected state before adding
430 * patterns
431 */
432 hdd_info("device mode %d", pAdapter->device_mode);
433 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) &&
434 (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530435 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436 "%s: Not in Connected state!", __func__);
437 goto failure;
438 }
439
440 /* Get pattern */
441 token = strsep(&sptr, " ");
442 if (!token)
443 goto failure;
444
445 pattern_buf = token;
446 pattern_buf[strlen(pattern_buf) - 1] = '\0';
447 pattern_len = strlen(pattern_buf);
448
449 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
450 if (pattern_len % 2) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530451 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452 "%s: Malformed pattern!", __func__);
453
454 goto failure;
455 } else
456 pattern_len >>= 1;
457
458 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530459 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460 "%s: Not an 802.3 frame!", __func__);
461
462 goto failure;
463 }
464
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530465 addPeriodicTxPtrnParams = qdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 if (!addPeriodicTxPtrnParams) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530467 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 FL("Memory allocation failed!"));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530469 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 return -ENOMEM;
471 }
472
473 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
474 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
475 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530476 qdf_copy_macaddr(&addPeriodicTxPtrnParams->mac_address,
Srinivas Girigowda31896552015-11-18 22:59:52 -0800477 &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478
479 /* Extract the pattern */
480 for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) {
481 addPeriodicTxPtrnParams->ucPattern[i] =
482 (hex_to_bin(pattern_buf[0]) << 4) +
483 hex_to_bin(pattern_buf[1]);
484
485 /* Skip to next byte */
486 pattern_buf += 2;
487 }
488
489 /* Add pattern */
490 status = sme_add_periodic_tx_ptrn(pHddCtx->hHal,
491 addPeriodicTxPtrnParams);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530492 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530493 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494 "%s: sme_add_periodic_tx_ptrn() failed!", __func__);
495
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530496 qdf_mem_free(addPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497 goto failure;
498 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530499 qdf_mem_free(cmd);
500 qdf_mem_free(addPeriodicTxPtrnParams);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530501 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502 return count;
503
504failure:
Rajeev Kumarb08f39c2016-02-04 17:50:54 -0800505 hdd_err("Invalid input. Input format is: ptrn_idx duration pattern");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530506 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 return -EINVAL;
508}
509
510/**
511 * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write
512 * @file: file pointer
513 * @buf: buffer
514 * @count: count
515 * @ppos: position pointer
516 *
517 * Return: 0 on success, error number otherwise
518 */
519static ssize_t wcnss_patterngen_write(struct file *file,
520 const char __user *buf,
521 size_t count, loff_t *ppos)
522{
523 ssize_t ret;
524
525 cds_ssr_protect(__func__);
526 ret = __wcnss_patterngen_write(file, buf, count, ppos);
527 cds_ssr_unprotect(__func__);
528
529 return ret;
530}
531
532/**
533 * __wcnss_debugfs_open() - Generic debugfs open() handler
534 * @inode: inode of the debugfs file
535 * @file: file handle of the debugfs file
536 *
537 * Return: 0
538 */
539static int __wcnss_debugfs_open(struct inode *inode, struct file *file)
540{
541 hdd_adapter_t *adapter;
542 hdd_context_t *hdd_ctx;
543 int ret;
544
545 ENTER();
546
547 if (inode->i_private)
548 file->private_data = inode->i_private;
549
550 adapter = (hdd_adapter_t *)file->private_data;
551 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530552 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800553 "%s: Invalid adapter or adapter has invalid magic.",
554 __func__);
555 return -EINVAL;
556 }
557
558 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
559 ret = wlan_hdd_validate_context(hdd_ctx);
560 if (0 != ret)
561 return ret;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530562 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563 return 0;
564}
565
566/**
567 * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open
568 * @inode: inode pointer
569 * @file: file pointer
570 *
571 * Return: 0 on success, error number otherwise
572 */
573static int wcnss_debugfs_open(struct inode *inode, struct file *file)
574{
575 int ret;
576
577 cds_ssr_protect(__func__);
578 ret = __wcnss_debugfs_open(inode, file);
579 cds_ssr_unprotect(__func__);
580
581 return ret;
582}
583
584static const struct file_operations fops_wowenable = {
585 .write = wcnss_wowenable_write,
586 .open = wcnss_debugfs_open,
587 .owner = THIS_MODULE,
588 .llseek = default_llseek,
589};
590
591static const struct file_operations fops_wowpattern = {
592 .write = wcnss_wowpattern_write,
593 .open = wcnss_debugfs_open,
594 .owner = THIS_MODULE,
595 .llseek = default_llseek,
596};
597
598static const struct file_operations fops_patterngen = {
599 .write = wcnss_patterngen_write,
600 .open = wcnss_debugfs_open,
601 .owner = THIS_MODULE,
602 .llseek = default_llseek,
603};
604
605/**
606 * hdd_debugfs_init() - Initialize debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800607 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800608 *
609 * Register support for the debugfs files supported by the driver.
610 *
611 * NB: The current implementation only supports debugfs operations
612 * on the primary interface, i.e. wlan0
613 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530614 * Return: QDF_STATUS_SUCCESS if all files registered,
615 * QDF_STATUS_E_FAILURE on failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 */
Rajeev Kumardca5f812016-02-04 17:28:06 -0800617QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618{
Rajeev Kumardca5f812016-02-04 17:28:06 -0800619 struct net_device *dev = adapter->dev;
620 adapter->debugfs_phy = debugfs_create_dir(dev->name, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800621
Rajeev Kumardca5f812016-02-04 17:28:06 -0800622 if (NULL == adapter->debugfs_phy)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530623 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800624
625 if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800626 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627 &fops_wowenable))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530628 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800629
630 if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800631 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800632 &fops_wowpattern))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530633 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634
635 if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800636 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637 &fops_patterngen))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530638 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530640 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800641}
642
643/**
644 * hdd_debugfs_exit() - Shutdown debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800645 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800646 *
647 * Unregister support for the debugfs files supported by the driver.
648 *
649 * Return: None
650 */
Rajeev Kumardca5f812016-02-04 17:28:06 -0800651void hdd_debugfs_exit(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800652{
Rajeev Kumardca5f812016-02-04 17:28:06 -0800653 struct net_device *dev = adapter->dev;
654
655 if (adapter->debugfs_phy)
656 debugfs_remove_recursive(adapter->debugfs_phy);
657 else
658 hdd_info("Interface %s has no debugfs entry", dev->name);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800659}
660#endif /* #ifdef WLAN_OPEN_SOURCE */