source: G950FXXS5DSI1
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / dhd_linux_exportfs.c
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 *
28 * $Id: dhd_linux_exportfs.c 808910 2019-03-11 10:44:36Z $
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)
55 extern atomic_t trace_wklock_onoff;
56
57 /* Function to show the history buffer */
58 static ssize_t
59 show_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 */
72 static ssize_t
73 wklock_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)
96 static ssize_t
97 show_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
109 static ssize_t
110 lbtxp_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)
136 static ssize_t
137 show_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
149 static ssize_t
150 lbrxp_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
185 struct 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)
192 static 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)
197 static 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)
202 static 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 */
207 static 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 */
227 static 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 */
252 static 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
275 static struct sysfs_ops dhd_sysfs_ops = {
276 .show = dhd_show,
277 .store = dhd_store,
278 };
279
280 static struct kobj_type dhd_ktype = {
281 .sysfs_ops = &dhd_sysfs_ops,
282 .default_attrs = default_attrs,
283 };
284
285 #ifdef DHD_MAC_ADDR_EXPORT
286 struct ether_addr sysfs_mac_addr;
287 static ssize_t
288 show_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
300 static ssize_t
301 set_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
313 static 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
329 uint32
330 get_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
374 done:
375 return mem_val;
376 }
377
378 void 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
400 static ssize_t
401 show_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
416 static ssize_t
417 set_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
437 static 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 */
448 int
449 get_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
487 void 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
499 static ssize_t
500 show_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
514 static ssize_t
515 set_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
529 static 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)
536 static ssize_t
537 show_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
545 static ssize_t
546 set_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
552 static 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)
557 char cidinfostr[MAX_VNAME_LEN];
558
559 static ssize_t
560 show_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
568 static ssize_t
569 set_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
580 static 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)
585 char softapinfostr[SOFTAP_INFO_BUF_SZ];
586 static ssize_t
587 show_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
595 static ssize_t
596 set_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
602 static 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)
607 unsigned long antsel;
608
609 static ssize_t
610 show_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
618 static ssize_t
619 set_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
641 static 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
646 extern bool g_pm_control;
647 extern uint32 pmmode_val;
648 static ssize_t
649 show_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
661 static ssize_t
662 set_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
686 static 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
691 unsigned long logtrace_val = 1;
692
693 static ssize_t
694 show_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
702 static ssize_t
703 set_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
722 static 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
728 uint32 bus_txglom = VALUENOTSET;
729
730 static ssize_t
731 show_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
743 static ssize_t
744 set_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
763 static 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)
768 uint32 roam_off = VALUENOTSET;
769
770 static ssize_t
771 show_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
783 static ssize_t
784 set_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
803 static 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
808 uint32 frameburst = VALUENOTSET;
809
810 static ssize_t
811 show_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
823 static ssize_t
824 set_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
843 static 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
848 uint32 txbf = VALUENOTSET;
849
850 static ssize_t
851 show_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
863 static ssize_t
864 set_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
883 static 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
888 uint32 proptx = VALUENOTSET;
889
890 static ssize_t
891 show_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
903 static ssize_t
904 set_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",
919 __FUNCTION__, proptx));
920 return count;
921 }
922
923 static 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
932 wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL;
933
934 static ssize_t
935 show_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
967 static ssize_t
968 store_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
1011 static 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
1015 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1016 uint32 report_hang_privcmd_err = 1;
1017
1018 static ssize_t
1019 show_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
1027 static ssize_t
1028 set_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
1041 static 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
1045 /* Attribute object that gets registered with "wifi" kobject tree */
1046 static 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 */
1094 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1095 &dhd_attr_hang_privcmd_err.attr,
1096 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
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 */
1106 static 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 */
1131 static 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
1154 static struct sysfs_ops dhd_sysfs_cntl_ops = {
1155 .show = dhd_cntl_show,
1156 .store = dhd_cntl_store,
1157 };
1158
1159 static 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 */
1165 int 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 */
1199 void 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 }