source: G950FXXS5DSI1
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / dhd_linux_exportfs.c
CommitLineData
1cac41cb
MB
1/*
2 * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3 * Basically selected code segments from usb-cdc.c and usb-rndis.c
4 *
5 * Copyright (C) 1999-2019, Broadcom.
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
5a068558 28 * $Id: dhd_linux_exportfs.c 808910 2019-03-11 10:44:36Z $
1cac41cb
MB
29 */
30#include <linux/kobject.h>
31#include <linux/proc_fs.h>
32#include <linux/sysfs.h>
33#include <osl.h>
34#include <dhd_dbg.h>
35#include <dhd_linux_priv.h>
36#ifdef DHD_ADPS_BAM_EXPORT
37#include <wl_bam.h>
38#endif // endif
39
40/* ----------------------------------------------------------------------------
41 * Infrastructure code for sysfs interface support for DHD
42 *
43 * What is sysfs interface?
44 * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
45 *
46 * Why sysfs interface?
47 * This is the Linux standard way of changing/configuring Run Time parameters
48 * for a driver. We can use this interface to control "linux" specific driver
49 * parameters.
50 *
51 * -----------------------------------------------------------------------------
52 */
53
54#if defined(DHD_TRACE_WAKE_LOCK)
55extern atomic_t trace_wklock_onoff;
56
57/* Function to show the history buffer */
58static ssize_t
59show_wklock_trace(struct dhd_info *dev, char *buf)
60{
61 ssize_t ret = 0;
62 dhd_info_t *dhd = (dhd_info_t *)dev;
63
64 buf[ret] = '\n';
65 buf[ret+1] = 0;
66
67 dhd_wk_lock_stats_dump(&dhd->pub);
68 return ret+1;
69}
70
71/* Function to enable/disable wakelock trace */
72static ssize_t
73wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count)
74{
75 unsigned long onoff;
76 dhd_info_t *dhd = (dhd_info_t *)dev;
77 BCM_REFERENCE(dhd);
78
79 onoff = bcm_strtoul(buf, NULL, 10);
80 if (onoff != 0 && onoff != 1) {
81 return -EINVAL;
82 }
83
84 atomic_set(&trace_wklock_onoff, onoff);
85 if (atomic_read(&trace_wklock_onoff)) {
86 printk("ENABLE WAKLOCK TRACE\n");
87 } else {
88 printk("DISABLE WAKELOCK TRACE\n");
89 }
90
91 return (ssize_t)(onoff+1);
92}
93#endif /* DHD_TRACE_WAKE_LOCK */
94
95#if defined(DHD_LB_TXP)
96static ssize_t
97show_lbtxp(struct dhd_info *dev, char *buf)
98{
99 ssize_t ret = 0;
100 unsigned long onoff;
101 dhd_info_t *dhd = (dhd_info_t *)dev;
102
103 onoff = atomic_read(&dhd->lb_txp_active);
104 ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
105 onoff);
106 return ret;
107}
108
109static ssize_t
110lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
111{
112 unsigned long onoff;
113 dhd_info_t *dhd = (dhd_info_t *)dev;
114 int i;
115
116 onoff = bcm_strtoul(buf, NULL, 10);
117
118 sscanf(buf, "%lu", &onoff);
119 if (onoff != 0 && onoff != 1) {
120 return -EINVAL;
121 }
122 atomic_set(&dhd->lb_txp_active, onoff);
123
124 /* Since the scheme is changed clear the counters */
125 for (i = 0; i < NR_CPUS; i++) {
126 DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]);
127 DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]);
128 }
129
130 return count;
131}
132
133#endif /* DHD_LB_TXP */
134
135#if defined(DHD_LB_RXP)
136static ssize_t
137show_lbrxp(struct dhd_info *dev, char *buf)
138{
139 ssize_t ret = 0;
140 unsigned long onoff;
141 dhd_info_t *dhd = (dhd_info_t *)dev;
142
143 onoff = atomic_read(&dhd->lb_rxp_active);
144 ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
145 onoff);
146 return ret;
147}
148
149static ssize_t
150lbrxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
151{
152 unsigned long onoff;
153 dhd_info_t *dhd = (dhd_info_t *)dev;
154 int i, j;
155
156 onoff = bcm_strtoul(buf, NULL, 10);
157
158 sscanf(buf, "%lu", &onoff);
159 if (onoff != 0 && onoff != 1) {
160 return -EINVAL;
161 }
162 atomic_set(&dhd->lb_rxp_active, onoff);
163
164 /* Since the scheme is changed clear the counters */
165 for (i = 0; i < NR_CPUS; i++) {
166 DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]);
167 for (j = 0; j < HIST_BIN_SIZE; j++) {
168 DHD_LB_STATS_CLR(dhd->napi_rx_hist[j][i]);
169 }
170 }
171
172 return count;
173}
174#endif /* DHD_LB_RXP */
175
176/*
177 * Generic Attribute Structure for DHD.
178 * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have
179 * to instantiate an object of type dhd_attr, populate it with
180 * the required show/store functions (ex:- dhd_attr_cpumask_primary)
181 * and add the object to default_attrs[] array, that gets registered
182 * to the kobject of dhd (named bcm-dhd).
183 */
184
185struct dhd_attr {
186 struct attribute attr;
187 ssize_t(*show)(struct dhd_info *, char *);
188 ssize_t(*store)(struct dhd_info *, const char *, size_t count);
189};
190
191#if defined(DHD_TRACE_WAKE_LOCK)
192static struct dhd_attr dhd_attr_wklock =
193 __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff);
194#endif /* defined(DHD_TRACE_WAKE_LOCK */
195
196#if defined(DHD_LB_TXP)
197static struct dhd_attr dhd_attr_lbtxp =
198 __ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff);
199#endif /* DHD_LB_TXP */
200
201#if defined(DHD_LB_RXP)
202static struct dhd_attr dhd_attr_lbrxp =
203 __ATTR(lbrxp, 0660, show_lbrxp, lbrxp_onoff);
204#endif /* DHD_LB_RXP */
205
206/* Attribute object that gets registered with "bcm-dhd" kobject tree */
207static struct attribute *default_attrs[] = {
208#if defined(DHD_TRACE_WAKE_LOCK)
209 &dhd_attr_wklock.attr,
210#endif // endif
211#if defined(DHD_LB_TXP)
212 &dhd_attr_lbtxp.attr,
213#endif /* DHD_LB_TXP */
214#if defined(DHD_LB_RXP)
215 &dhd_attr_lbrxp.attr,
216#endif /* DHD_LB_RXP */
217 NULL
218};
219
220#define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj)
221#define to_attr(a) container_of(a, struct dhd_attr, attr)
222
223/*
224 * bcm-dhd kobject show function, the "attr" attribute specifices to which
225 * node under "bcm-dhd" the show function is called.
226 */
227static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf)
228{
229#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
230#pragma GCC diagnostic push
231#pragma GCC diagnostic ignored "-Wcast-qual"
232#endif // endif
233 dhd_info_t *dhd = to_dhd(kobj);
234 struct dhd_attr *d_attr = to_attr(attr);
235#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
236#pragma GCC diagnostic pop
237#endif // endif
238 int ret;
239
240 if (d_attr->show)
241 ret = d_attr->show(dhd, buf);
242 else
243 ret = -EIO;
244
245 return ret;
246}
247
248/*
249 * bcm-dhd kobject show function, the "attr" attribute specifices to which
250 * node under "bcm-dhd" the store function is called.
251 */
252static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr,
253 const char *buf, size_t count)
254{
255#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
256#pragma GCC diagnostic push
257#pragma GCC diagnostic ignored "-Wcast-qual"
258#endif // endif
259 dhd_info_t *dhd = to_dhd(kobj);
260 struct dhd_attr *d_attr = to_attr(attr);
261#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
262#pragma GCC diagnostic pop
263#endif // endif
264 int ret;
265
266 if (d_attr->store)
267 ret = d_attr->store(dhd, buf, count);
268 else
269 ret = -EIO;
270
271 return ret;
272
273}
274
275static struct sysfs_ops dhd_sysfs_ops = {
276 .show = dhd_show,
277 .store = dhd_store,
278};
279
280static struct kobj_type dhd_ktype = {
281 .sysfs_ops = &dhd_sysfs_ops,
282 .default_attrs = default_attrs,
283};
284
285#ifdef DHD_MAC_ADDR_EXPORT
286struct ether_addr sysfs_mac_addr;
287static ssize_t
288show_mac_addr(struct dhd_info *dev, char *buf)
289{
290 ssize_t ret = 0;
291
292 ret = scnprintf(buf, PAGE_SIZE - 1, MACF,
293 (uint32)sysfs_mac_addr.octet[0], (uint32)sysfs_mac_addr.octet[1],
294 (uint32)sysfs_mac_addr.octet[2], (uint32)sysfs_mac_addr.octet[3],
295 (uint32)sysfs_mac_addr.octet[4], (uint32)sysfs_mac_addr.octet[5]);
296
297 return ret;
298}
299
300static ssize_t
301set_mac_addr(struct dhd_info *dev, const char *buf, size_t count)
302{
303 if (!bcm_ether_atoe(buf, &sysfs_mac_addr)) {
304 DHD_ERROR(("Invalid Mac Address \n"));
305 return -EINVAL;
306 }
307
308 DHD_ERROR(("Mac Address set with "MACDBG"\n", MAC2STRDBG(&sysfs_mac_addr)));
309
310 return count;
311}
312
313static struct dhd_attr dhd_attr_cntl_macaddr =
314 __ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr);
315#endif /* DHD_MAC_ADDR_EXPORT */
316
317#ifdef DHD_FW_COREDUMP
318
319#ifdef CUSTOMER_HW4_DEBUG
320#define MEMDUMPINFO PLATFORM_PATH".memdump.info"
321#elif (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__))
322#define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
323#else
324#define MEMDUMPINFO_LIVE "/installmedia/.memdump.info"
325#define MEMDUMPINFO_INST "/data/.memdump.info"
326#define MEMDUMPINFO MEMDUMPINFO_LIVE
327#endif /* CUSTOMER_HW4_DEBUG */
328
329uint32
330get_mem_val_from_file(void)
331{
332 struct file *fp = NULL;
333 uint32 mem_val = DUMP_MEMFILE_MAX;
334 char *p_mem_val = NULL;
335 char *filepath = MEMDUMPINFO;
336 int ret = 0;
337
338 /* Read memdump info from the file */
339 fp = filp_open(filepath, O_RDONLY, 0);
340 if (IS_ERR(fp)) {
341 DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
342#if defined(CONFIG_X86)
343 /* Check if it is Live Brix Image */
344 if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) {
345 goto done;
346 }
347 /* Try if it is Installed Brix Image */
348 filepath = MEMDUMPINFO_INST;
349 DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
350 fp = filp_open(filepath, O_RDONLY, 0);
351 if (IS_ERR(fp)) {
352 DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
353 goto done;
354 }
355#else /* Non Brix Android platform */
356 goto done;
357#endif /* CONFIG_X86 && OEM_ANDROID */
358 }
359
360 /* Handle success case */
361 ret = kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
362 if (ret < 0) {
363 DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
364 filp_close(fp, NULL);
365 goto done;
366 }
367
368 p_mem_val = (char*)&mem_val;
369 p_mem_val[sizeof(uint32) - 1] = '\0';
370 mem_val = bcm_atoi(p_mem_val);
371
372 filp_close(fp, NULL);
373
374done:
375 return mem_val;
376}
377
378void dhd_get_memdump_info(dhd_pub_t *dhd)
379{
380#ifndef DHD_EXPORT_CNTL_FILE
381 uint32 mem_val = DUMP_MEMFILE_MAX;
382
383 mem_val = get_mem_val_from_file();
384 if (mem_val != DUMP_MEMFILE_MAX)
385 dhd->memdump_enabled = mem_val;
386#ifdef DHD_INIT_DEFAULT_MEMDUMP
387 if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX)
388 mem_val = DUMP_MEMFILE_BUGON;
389#endif /* DHD_INIT_DEFAULT_MEMDUMP */
390#else
391#ifdef DHD_INIT_DEFAULT_MEMDUMP
392 if (dhd->memdump_enabled == 0 || dhd->memdump_enabled == DUMP_MEMFILE_MAX)
393 dhd->memdump_enabled = DUMP_MEMFILE_BUGON;
394#endif /* DHD_INIT_DEFAULT_MEMDUMP */
395#endif /* !DHD_EXPORT_CNTL_FILE */
396 DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, dhd->memdump_enabled));
397}
398
399#ifdef DHD_EXPORT_CNTL_FILE
400static ssize_t
401show_memdump_info(struct dhd_info *dev, char *buf)
402{
403 ssize_t ret = 0;
404 dhd_pub_t *dhdp;
405
406 if (!dev) {
407 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
408 return ret;
409 }
410
411 dhdp = &dev->pub;
412 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", dhdp->memdump_enabled);
413 return ret;
414}
415
416static ssize_t
417set_memdump_info(struct dhd_info *dev, const char *buf, size_t count)
418{
419 unsigned long memval;
420 dhd_pub_t *dhdp;
421
422 if (!dev) {
423 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
424 return count;
425 }
426 dhdp = &dev->pub;
427
428 memval = bcm_strtoul(buf, NULL, 10);
429 sscanf(buf, "%lu", &memval);
430
431 dhdp->memdump_enabled = (uint32)memval;
432
433 DHD_ERROR(("%s: MEMDUMP ENABLED = %iu\n", __FUNCTION__, dhdp->memdump_enabled));
434 return count;
435}
436
437static struct dhd_attr dhd_attr_cntl_memdump =
438 __ATTR(memdump, 0660, show_memdump_info, set_memdump_info);
439#endif /* DHD_EXPORT_CNTL_FILE */
440#endif /* DHD_FW_COREDUMP */
441
442#ifdef BCMASSERT_LOG
443#ifdef CUSTOMER_HW4_DEBUG
444#define ASSERTINFO PLATFORM_PATH".assert.info"
445#else
446#define ASSERTINFO "/installmedia/.assert.info"
447#endif /* CUSTOMER_HW4_DEBUG */
448int
449get_assert_val_from_file(void)
450{
451 struct file *fp = NULL;
452 char *filepath = ASSERTINFO;
453 char *p_mem_val = NULL;
454 int mem_val = -1;
455
456 /*
457 * Read assert info from the file
458 * 0: Trigger Kernel crash by panic()
459 * 1: Print out the logs and don't trigger Kernel panic. (default)
460 * 2: Trigger Kernel crash by BUG()
461 * File doesn't exist: Keep default value (1).
462 */
463 fp = filp_open(filepath, O_RDONLY, 0);
464 if (IS_ERR(fp)) {
465 DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
466 } else {
467 int ret = kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
468 if (ret < 0) {
469 DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
470 } else {
471 p_mem_val = (char *)&mem_val;
472 p_mem_val[sizeof(uint32) - 1] = '\0';
473 mem_val = bcm_atoi(p_mem_val);
474 DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val));
475 }
476 filp_close(fp, NULL);
477 }
478
479#ifdef CUSTOERM_HW4_DEBUG
480 mem_val = (mem_val >= 0) ? mem_val : 1;
481#else
482 mem_val = (mem_val >= 0) ? mem_val : 0;
483#endif /* CUSTOMER_HW4_DEBUG */
484 return mem_val;
485}
486
487void dhd_get_assert_info(dhd_pub_t *dhd)
488{
489#ifndef DHD_EXPORT_CNTL_FILE
490 int mem_val = -1;
491
492 mem_val = get_assert_val_from_file();
493
494 g_assert_type = mem_val;
495#endif /* !DHD_EXPORT_CNTL_FILE */
496}
497
498#ifdef DHD_EXPORT_CNTL_FILE
499static ssize_t
500show_assert_info(struct dhd_info *dev, char *buf)
501{
502 ssize_t ret = 0;
503
504 if (!dev) {
505 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
506 return ret;
507 }
508
509 ret = scnprintf(buf, PAGE_SIZE -1, "%d\n", g_assert_type);
510 return ret;
511
512}
513
514static ssize_t
515set_assert_info(struct dhd_info *dev, const char *buf, size_t count)
516{
517 unsigned long assert_val;
518
519 assert_val = bcm_strtoul(buf, NULL, 10);
520 sscanf(buf, "%lu", &assert_val);
521
522 g_assert_type = (uint32)assert_val;
523
524 DHD_ERROR(("%s: ASSERT ENABLED = %lu\n", __FUNCTION__, assert_val));
525 return count;
526
527}
528
529static struct dhd_attr dhd_attr_cntl_assert =
530 __ATTR(assert, 0660, show_assert_info, set_assert_info);
531#endif /* DHD_EXPORT_CNTL_FILE */
532#endif /* BCMASSERT_LOG */
533
534#ifdef DHD_EXPORT_CNTL_FILE
535#if defined(WRITE_WLANINFO)
536static ssize_t
537show_wifiver_info(struct dhd_info *dev, char *buf)
538{
539 ssize_t ret = 0;
540
541 ret = scnprintf(buf, PAGE_SIZE -1, "%s", version_info);
542 return ret;
543}
544
545static ssize_t
546set_wifiver_info(struct dhd_info *dev, const char *buf, size_t count)
547{
548 DHD_ERROR(("Do not set version info\n"));
549 return -EINVAL;
550}
551
552static struct dhd_attr dhd_attr_cntl_wifiver =
553 __ATTR(wifiver, 0660, show_wifiver_info, set_wifiver_info);
554#endif /* WRITE_WLANINFO */
555
556#if defined(USE_CID_CHECK)
557char cidinfostr[MAX_VNAME_LEN];
558
559static ssize_t
560show_cid_info(struct dhd_info *dev, char *buf)
561{
562 ssize_t ret = 0;
563
564 ret = scnprintf(buf, PAGE_SIZE -1, "%s", cidinfostr);
565 return ret;
566}
567
568static ssize_t
569set_cid_info(struct dhd_info *dev, const char *buf, size_t count)
570{
571 int len = strlen(buf) + 1;
572 int maxstrsz;
573 maxstrsz = MAX_VNAME_LEN;
574
575 scnprintf(cidinfostr, ((len > maxstrsz) ? maxstrsz : len), "%s", buf);
576 DHD_INFO(("%s : CID info string\n", cidinfostr));
577 return count;
578}
579
580static struct dhd_attr dhd_attr_cntl_cidinfo =
581 __ATTR(cid, 0660, show_cid_info, set_cid_info);
582#endif /* USE_CID_CHECK */
583
584#if defined(GEN_SOFTAP_INFO_FILE)
585char softapinfostr[SOFTAP_INFO_BUF_SZ];
586static ssize_t
587show_softap_info(struct dhd_info *dev, char *buf)
588{
589 ssize_t ret = 0;
590
591 ret = scnprintf(buf, PAGE_SIZE -1, "%s", softapinfostr);
592 return ret;
593}
594
595static ssize_t
596set_softap_info(struct dhd_info *dev, const char *buf, size_t count)
597{
598 DHD_ERROR(("Do not set sofap related info\n"));
599 return -EINVAL;
600}
601
602static struct dhd_attr dhd_attr_cntl_softapinfo =
603 __ATTR(softap, 0660, show_softap_info, set_softap_info);
604#endif /* GEN_SOFTAP_INFO_FILE */
605
606#if defined(MIMO_ANT_SETTING)
607unsigned long antsel;
608
609static ssize_t
610show_ant_info(struct dhd_info *dev, char *buf)
611{
612 ssize_t ret = 0;
613
614 ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", antsel);
615 return ret;
616}
617
618static ssize_t
619set_ant_info(struct dhd_info *dev, const char *buf, size_t count)
620{
621 unsigned long ant_val;
622
623 ant_val = bcm_strtoul(buf, NULL, 10);
624 sscanf(buf, "%lu", &ant_val);
625
626 /*
627 * Check value
628 * 0 - Not set, handle same as file not exist
629 */
630 if (ant_val > 3) {
631 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
632 __FUNCTION__, ant_val));
633 return -EINVAL;
634 }
635
636 antsel = ant_val;
637 DHD_ERROR(("[WIFI_SEC] %s: Set Antinfo val = %lu \n", __FUNCTION__, antsel));
638 return count;
639}
640
641static struct dhd_attr dhd_attr_cntl_antinfo =
642 __ATTR(ant, 0660, show_ant_info, set_ant_info);
643#endif /* MIMO_ANT_SETTING */
644
645#ifdef DHD_PM_CONTROL_FROM_FILE
646extern bool g_pm_control;
647extern uint32 pmmode_val;
648static ssize_t
649show_pm_info(struct dhd_info *dev, char *buf)
650{
651 ssize_t ret = 0;
652
653 if (!g_pm_control) {
654 ret = scnprintf(buf, PAGE_SIZE -1, "PM mode is not set\n");
655 } else {
656 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", pmmode_val);
657 }
658 return ret;
659}
660
661static ssize_t
662set_pm_info(struct dhd_info *dev, const char *buf, size_t count)
663{
664 unsigned long pm_val;
665
666 pm_val = bcm_strtoul(buf, NULL, 10);
667 sscanf(buf, "%lu", &pm_val);
668
669 if (pm_val > 2) {
670 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
671 __FUNCTION__, pm_val));
672 return -EINVAL;
673 }
674
675 if (!pm_val) {
676 g_pm_control = TRUE;
677 } else {
678 g_pm_control = FALSE;
679 }
680
681 pmmode_val = (uint32)pm_val;
682 DHD_ERROR(("[WIFI_SEC] %s: Set pminfo val = %u\n", __FUNCTION__, pmmode_val));
683 return count;
684}
685
686static struct dhd_attr dhd_attr_cntl_pminfo =
687 __ATTR(pm, 0660, show_pm_info, set_pm_info);
688#endif /* DHD_PM_CONTROL_FROM_FILE */
689
690#ifdef LOGTRACE_FROM_FILE
691unsigned long logtrace_val = 1;
692
693static ssize_t
694show_logtrace_info(struct dhd_info *dev, char *buf)
695{
696 ssize_t ret = 0;
697
698 ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", logtrace_val);
699 return ret;
700}
701
702static ssize_t
703set_logtrace_info(struct dhd_info *dev, const char *buf, size_t count)
704{
705 unsigned long onoff;
706
707 onoff = bcm_strtoul(buf, NULL, 10);
708 sscanf(buf, "%lu", &onoff);
709
710 if (onoff > 2) {
711 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
712 __FUNCTION__, onoff));
713 return -EINVAL;
714 }
715
716 logtrace_val = onoff;
717 DHD_ERROR(("[WIFI_SEC] %s: LOGTRACE On/Off from sysfs = %lu\n",
718 __FUNCTION__, logtrace_val));
719 return count;
720}
721
722static struct dhd_attr dhd_attr_cntl_logtraceinfo =
723 __ATTR(logtrace, 0660, show_logtrace_info, set_logtrace_info);
724#endif /* LOGTRACE_FROM_FILE */
725
726#ifdef USE_WFA_CERT_CONF
727#ifdef BCMSDIO
728uint32 bus_txglom = VALUENOTSET;
729
730static ssize_t
731show_bustxglom(struct dhd_info *dev, char *buf)
732{
733 ssize_t ret = 0;
734
735 if (bus_txglom == VALUENOTSET) {
736 ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", "bustxglom not set from sysfs");
737 } else {
738 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", bus_txglom);
739 }
740 return ret;
741}
742
743static ssize_t
744set_bustxglom(struct dhd_info *dev, const char *buf, size_t count)
745{
746 uint32 onoff;
747
748 onoff = (uint32)bcm_atoi(buf);
749 sscanf(buf, "%u", &onoff);
750
751 if (onoff > 2) {
752 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
753 __FUNCTION__, onoff));
754 return -EINVAL;
755 }
756
757 bus_txglom = onoff;
758 DHD_ERROR(("[WIFI_SEC] %s: BUS TXGLOM On/Off from sysfs = %u\n",
759 __FUNCTION__, bus_txglom));
760 return count;
761}
762
763static struct dhd_attr dhd_attr_cntl_bustxglom =
764 __ATTR(bustxglom, 0660, show_bustxglom, set_bustxglom);
765#endif /* BCMSDIO */
766
767#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
768uint32 roam_off = VALUENOTSET;
769
770static ssize_t
771show_roamoff(struct dhd_info *dev, char *buf)
772{
773 ssize_t ret = 0;
774
775 if (roam_off == VALUENOTSET) {
776 ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "roam_off not set from sysfs");
777 } else {
778 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", roam_off);
779 }
780 return ret;
781}
782
783static ssize_t
784set_roamoff(struct dhd_info *dev, const char *buf, size_t count)
785{
786 uint32 onoff;
787
788 onoff = bcm_atoi(buf);
789 sscanf(buf, "%u", &onoff);
790
791 if (onoff > 2) {
792 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
793 __FUNCTION__, onoff));
794 return -EINVAL;
795 }
796
797 roam_off = onoff;
798 DHD_ERROR(("[WIFI_SEC] %s: ROAM On/Off from sysfs = %u\n",
799 __FUNCTION__, roam_off));
800 return count;
801}
802
803static struct dhd_attr dhd_attr_cntl_roamoff =
804 __ATTR(roamoff, 0660, show_roamoff, set_roamoff);
805#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
806
807#ifdef USE_WL_FRAMEBURST
808uint32 frameburst = VALUENOTSET;
809
810static ssize_t
811show_frameburst(struct dhd_info *dev, char *buf)
812{
813 ssize_t ret = 0;
814
815 if (frameburst == VALUENOTSET) {
816 ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "frameburst not set from sysfs");
817 } else {
818 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", frameburst);
819 }
820 return ret;
821}
822
823static ssize_t
824set_frameburst(struct dhd_info *dev, const char *buf, size_t count)
825{
826 uint32 onoff;
827
828 onoff = bcm_atoi(buf);
829 sscanf(buf, "%u", &onoff);
830
831 if (onoff > 2) {
832 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
833 __FUNCTION__, onoff));
834 return -EINVAL;
835 }
836
837 frameburst = onoff;
838 DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
839 __FUNCTION__, frameburst));
840 return count;
841}
842
843static struct dhd_attr dhd_attr_cntl_frameburst =
844 __ATTR(frameburst, 0660, show_frameburst, set_frameburst);
845#endif /* USE_WL_FRAMEBURST */
846
847#ifdef USE_WL_TXBF
848uint32 txbf = VALUENOTSET;
849
850static ssize_t
851show_txbf(struct dhd_info *dev, char *buf)
852{
853 ssize_t ret = 0;
854
855 if (txbf == VALUENOTSET) {
856 ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "txbf not set from sysfs");
857 } else {
858 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", txbf);
859 }
860 return ret;
861}
862
863static ssize_t
864set_txbf(struct dhd_info *dev, const char *buf, size_t count)
865{
866 uint32 onoff;
867
868 onoff = bcm_atoi(buf);
869 sscanf(buf, "%u", &onoff);
870
871 if (onoff > 2) {
872 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
873 __FUNCTION__, onoff));
874 return -EINVAL;
875 }
876
877 txbf = onoff;
878 DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
879 __FUNCTION__, txbf));
880 return count;
881}
882
883static struct dhd_attr dhd_attr_cntl_txbf =
884 __ATTR(txbf, 0660, show_txbf, set_txbf);
885#endif /* USE_WL_TXBF */
886
887#ifdef PROP_TXSTATUS
888uint32 proptx = VALUENOTSET;
889
890static ssize_t
891show_proptx(struct dhd_info *dev, char *buf)
892{
893 ssize_t ret = 0;
894
895 if (proptx == VALUENOTSET) {
896 ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "proptx not set from sysfs");
897 } else {
898 ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", proptx);
899 }
900 return ret;
901}
902
903static ssize_t
904set_proptx(struct dhd_info *dev, const char *buf, size_t count)
905{
906 uint32 onoff;
907
908 onoff = bcm_strtoul(buf, NULL, 10);
909 sscanf(buf, "%u", &onoff);
910
911 if (onoff > 2) {
912 DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
913 __FUNCTION__, onoff));
914 return -EINVAL;
915 }
916
917 proptx = onoff;
918 DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
5a068558 919 __FUNCTION__, proptx));
1cac41cb
MB
920 return count;
921}
922
923static struct dhd_attr dhd_attr_cntl_proptx =
924 __ATTR(proptx, 0660, show_proptx, set_proptx);
925
926#endif /* PROP_TXSTATUS */
927#endif /* USE_WFA_CERT_CONF */
928#endif /* DHD_EXPORT_CNTL_FILE */
929
930#if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
931#define BAD_AP_MAC_ADDR_ELEMENT_NUM 6
932wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL;
933
934static ssize_t
935show_adps_bam_list(struct dhd_info *dev, char *buf)
936{
937 int offset = 0;
938 ssize_t ret = 0;
939
940 wl_bad_ap_info_t *bad_ap;
941 wl_bad_ap_info_entry_t *entry;
942
943 if (g_bad_ap_mngr == NULL)
944 return ret;
945
946#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
947#pragma GCC diagnostic push
948#pragma GCC diagnostic ignored "-Wcast-qual"
949#endif // endif
950 list_for_each_entry(entry, &g_bad_ap_mngr->list, list) {
951 bad_ap = &entry->bad_ap;
952
953 ret = scnprintf(buf + offset, PAGE_SIZE - 1, MACF"\n",
954 bad_ap->bssid.octet[0], bad_ap->bssid.octet[1],
955 bad_ap->bssid.octet[2], bad_ap->bssid.octet[3],
956 bad_ap->bssid.octet[4], bad_ap->bssid.octet[5]);
957
958 offset += ret;
959 }
960#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
961#pragma GCC diagnostic pop
962#endif // endif
963
964 return offset;
965}
966
967static ssize_t
968store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count)
969{
970 int ret;
971 size_t len;
972 int offset;
973 char tmp[128];
974 wl_bad_ap_info_t bad_ap;
975
976 if (g_bad_ap_mngr == NULL)
977 return count;
978
979 len = count;
980 offset = 0;
981 do {
982 ret = sscanf(buf + offset, MACF"\n",
983 (uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1],
984 (uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3],
985 (uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5]);
986 if (ret != BAD_AP_MAC_ADDR_ELEMENT_NUM) {
987 DHD_ERROR(("%s - fail to parse bad ap data\n", __FUNCTION__));
988 return -EINVAL;
989 }
990
991 ret = wl_bad_ap_mngr_add(g_bad_ap_mngr, &bad_ap);
992 if (ret < 0)
993 return ret;
994
995 ret = snprintf(tmp, ARRAYSIZE(tmp), MACF"\n",
996 bad_ap.bssid.octet[0], bad_ap.bssid.octet[1],
997 bad_ap.bssid.octet[2], bad_ap.bssid.octet[3],
998 bad_ap.bssid.octet[4], bad_ap.bssid.octet[5]);
999 if (ret < 0) {
1000 DHD_ERROR(("%s - fail to get bad ap data length(%d)\n", __FUNCTION__, ret));
1001 return ret;
1002 }
1003
1004 len -= ret;
1005 offset += ret;
1006 } while (len > 0);
1007
1008 return count;
1009}
1010
1011static struct dhd_attr dhd_attr_adps_bam =
1012 __ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list);
1013#endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */
1014
5a068558
MB
1015#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1016uint32 report_hang_privcmd_err = 1;
1017
1018static ssize_t
1019show_hang_privcmd_err(struct dhd_info *dev, char *buf)
1020{
1021 ssize_t ret = 0;
1022
1023 ret = scnprintf(buf, PAGE_SIZE - 1, "%u\n", report_hang_privcmd_err);
1024 return ret;
1025}
1026
1027static ssize_t
1028set_hang_privcmd_err(struct dhd_info *dev, const char *buf, size_t count)
1029{
1030 uint32 val;
1031
1032 val = bcm_atoi(buf);
1033 sscanf(buf, "%u", &val);
1034
1035 report_hang_privcmd_err = val ? 1 : 0;
1036 DHD_INFO(("%s: Set report HANG for private cmd error: %d\n",
1037 __FUNCTION__, report_hang_privcmd_err));
1038 return count;
1039}
1040
1041static struct dhd_attr dhd_attr_hang_privcmd_err =
1042 __ATTR(hang_privcmd_err, 0660, show_hang_privcmd_err, set_hang_privcmd_err);
1043#endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1044
1cac41cb
MB
1045/* Attribute object that gets registered with "wifi" kobject tree */
1046static struct attribute *control_file_attrs[] = {
1047#ifdef DHD_MAC_ADDR_EXPORT
1048 &dhd_attr_cntl_macaddr.attr,
1049#endif /* DHD_MAC_ADDR_EXPORT */
1050#ifdef DHD_EXPORT_CNTL_FILE
1051#ifdef DHD_FW_COREDUMP
1052 &dhd_attr_cntl_memdump.attr,
1053#endif /* DHD_FW_COREDUMP */
1054#ifdef BCMASSERT_LOG
1055 &dhd_attr_cntl_assert.attr,
1056#endif /* BCMASSERT_LOG */
1057#ifdef WRITE_WLANINFO
1058 &dhd_attr_cntl_wifiver.attr,
1059#endif /* WRITE_WLANINFO */
1060#ifdef USE_CID_CHECK
1061 &dhd_attr_cntl_cidinfo.attr,
1062#endif /* USE_CID_CHECK */
1063#ifdef GEN_SOFTAP_INFO_FILE
1064 &dhd_attr_cntl_softapinfo.attr,
1065#endif /* GEN_SOFTAP_INFO_FILE */
1066#ifdef MIMO_ANT_SETTING
1067 &dhd_attr_cntl_antinfo.attr,
1068#endif /* MIMO_ANT_SETTING */
1069#ifdef DHD_PM_CONTROL_FROM_FILE
1070 &dhd_attr_cntl_pminfo.attr,
1071#endif /* DHD_PM_CONTROL_FROM_FILE */
1072#ifdef LOGTRACE_FROM_FILE
1073 &dhd_attr_cntl_logtraceinfo.attr,
1074#endif /* LOGTRACE_FROM_FILE */
1075#ifdef USE_WFA_CERT_CONF
1076#ifdef BCMSDIO
1077 &dhd_attr_cntl_bustxglom.attr,
1078#endif /* BCMSDIO */
1079 &dhd_attr_cntl_roamoff.attr,
1080#ifdef USE_WL_FRAMEBURST
1081 &dhd_attr_cntl_frameburst.attr,
1082#endif /* USE_WL_FRAMEBURST */
1083#ifdef USE_WL_TXBF
1084 &dhd_attr_cntl_txbf.attr,
1085#endif /* USE_WL_TXBF */
1086#ifdef PROP_TXSTATUS
1087 &dhd_attr_cntl_proptx.attr,
1088#endif /* PROP_TXSTATUS */
1089#endif /* USE_WFA_CERT_CONF */
1090#endif /* DHD_EXPORT_CNTL_FILE */
1091#ifdef DHD_ADPS_BAM_EXPORT
1092 &dhd_attr_adps_bam.attr,
1093#endif /* DHD_ADPS_BAM_EXPORT */
5a068558
MB
1094#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1095 &dhd_attr_hang_privcmd_err.attr,
1096#endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1cac41cb
MB
1097 NULL
1098};
1099
1100#define to_cntl_dhd(k) container_of(k, struct dhd_info, dhd_conf_file_kobj)
1101
1102/*
1103 * wifi kobject show function, the "attr" attribute specifices to which
1104 * node under "sys/wifi" the show function is called.
1105 */
1106static ssize_t dhd_cntl_show(struct kobject *kobj, struct attribute *attr, char *buf)
1107{
1108#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1109#pragma GCC diagnostic push
1110#pragma GCC diagnostic ignored "-Wcast-qual"
1111#endif // endif
1112 dhd_info_t *dhd = to_cntl_dhd(kobj);
1113 struct dhd_attr *d_attr = to_attr(attr);
1114#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1115#pragma GCC diagnostic pop
1116#endif // endif
1117 int ret;
1118
1119 if (d_attr->show)
1120 ret = d_attr->show(dhd, buf);
1121 else
1122 ret = -EIO;
1123
1124 return ret;
1125}
1126
1127/*
1128 * wifi kobject show function, the "attr" attribute specifices to which
1129 * node under "sys/wifi" the store function is called.
1130 */
1131static ssize_t dhd_cntl_store(struct kobject *kobj, struct attribute *attr,
1132 const char *buf, size_t count)
1133{
1134#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1135#pragma GCC diagnostic push
1136#pragma GCC diagnostic ignored "-Wcast-qual"
1137#endif // endif
1138 dhd_info_t *dhd = to_cntl_dhd(kobj);
1139 struct dhd_attr *d_attr = to_attr(attr);
1140#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1141#pragma GCC diagnostic pop
1142#endif // endif
1143 int ret;
1144
1145 if (d_attr->store)
1146 ret = d_attr->store(dhd, buf, count);
1147 else
1148 ret = -EIO;
1149
1150 return ret;
1151
1152}
1153
1154static struct sysfs_ops dhd_sysfs_cntl_ops = {
1155 .show = dhd_cntl_show,
1156 .store = dhd_cntl_store,
1157};
1158
1159static struct kobj_type dhd_cntl_file_ktype = {
1160 .sysfs_ops = &dhd_sysfs_cntl_ops,
1161 .default_attrs = control_file_attrs,
1162};
1163
1164/* Create a kobject and attach to sysfs interface */
1165int dhd_sysfs_init(dhd_info_t *dhd)
1166{
1167 int ret = -1;
1168
1169 if (dhd == NULL) {
1170 DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1171 return ret;
1172 }
1173
1174 /* Initialize the kobject */
1175 ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, "bcm-dhd");
1176 if (ret) {
1177 kobject_put(&dhd->dhd_kobj);
1178 DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1179 return ret;
1180 }
1181 ret = kobject_init_and_add(&dhd->dhd_conf_file_kobj, &dhd_cntl_file_ktype, NULL, "wifi");
1182 if (ret) {
1183 kobject_put(&dhd->dhd_conf_file_kobj);
1184 DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1185 return ret;
1186 }
1187
1188 /*
1189 * We are always responsible for sending the uevent that the kobject
1190 * was added to the system.
1191 */
1192 kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD);
1193 kobject_uevent(&dhd->dhd_conf_file_kobj, KOBJ_ADD);
1194
1195 return ret;
1196}
1197
1198/* Done with the kobject and detach the sysfs interface */
1199void dhd_sysfs_exit(dhd_info_t *dhd)
1200{
1201 if (dhd == NULL) {
1202 DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1203 return;
1204 }
1205
1206 /* Releae the kobject */
1207 kobject_put(&dhd->dhd_kobj);
1208 kobject_put(&dhd->dhd_conf_file_kobj);
1209}