1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3*4882a593Smuzhiyun * Basically selected code segments from usb-cdc.c and usb-rndis.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 1999-2017, Broadcom Corporation
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Unless you and Broadcom execute a separate written software license
10*4882a593Smuzhiyun * agreement governing use of this software, this software is licensed to you
11*4882a593Smuzhiyun * under the terms of the GNU General Public License version 2 (the "GPL"),
12*4882a593Smuzhiyun * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13*4882a593Smuzhiyun * following added to such license:
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * As a special exception, the copyright holders of this software give you
16*4882a593Smuzhiyun * permission to link this software with independent modules, and to copy and
17*4882a593Smuzhiyun * distribute the resulting executable under terms of your choice, provided that
18*4882a593Smuzhiyun * you also meet, for each linked independent module, the terms and conditions of
19*4882a593Smuzhiyun * the license of that module. An independent module is a module which is not
20*4882a593Smuzhiyun * derived from this software. The special exception does not apply to any
21*4882a593Smuzhiyun * modifications of the software.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Notwithstanding the above, under no circumstances may you combine this
24*4882a593Smuzhiyun * software in any way with any other Broadcom software provided under a license
25*4882a593Smuzhiyun * other than the GPL, without Broadcom's express prior written consent.
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * <<Broadcom-WL-IPTag/Open:>>
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * $Id$
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun #include <linux/kobject.h>
33*4882a593Smuzhiyun #include <linux/proc_fs.h>
34*4882a593Smuzhiyun #include <linux/sysfs.h>
35*4882a593Smuzhiyun #include <osl.h>
36*4882a593Smuzhiyun #include <dhd_dbg.h>
37*4882a593Smuzhiyun #include <dhd_linux_priv.h>
38*4882a593Smuzhiyun #ifdef DHD_ADPS_BAM_EXPORT
39*4882a593Smuzhiyun #include <wl_bam.h>
40*4882a593Smuzhiyun #endif // endif
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #ifndef BCMDHDX
43*4882a593Smuzhiyun #define SYSFS_DIR_BCMDHD "bcmdhd"
44*4882a593Smuzhiyun #define SYSFS_DIR_WIFI "wifi0"
45*4882a593Smuzhiyun #define PROCFS_DIR_TRACE "dhd_trace"
46*4882a593Smuzhiyun #define PROCFS_DIR_ENCOUNTERS "dhd_ecounters"
47*4882a593Smuzhiyun #define PROCFS_DIR_RTT "dhd_rtt"
48*4882a593Smuzhiyun #else
49*4882a593Smuzhiyun #define SYSFS_DIR_BCMDHD "bcmdhdx"
50*4882a593Smuzhiyun #define SYSFS_DIR_WIFI "wifi1"
51*4882a593Smuzhiyun #define PROCFS_DIR_WIFI "dhdx_trace"
52*4882a593Smuzhiyun #define PROCFS_DIR_ENCOUNTERS "dhdx_ecounters"
53*4882a593Smuzhiyun #define PROCFS_DIR_RTT "dhdx_rtt"
54*4882a593Smuzhiyun #endif /* BCMDHDX */
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #ifdef SHOW_LOGTRACE
57*4882a593Smuzhiyun extern dhd_pub_t* g_dhd_pub;
58*4882a593Smuzhiyun static int dhd_ring_proc_open(struct inode *inode, struct file *file);
59*4882a593Smuzhiyun ssize_t dhd_ring_proc_read(struct file *file, char *buffer, size_t tt, loff_t *loff);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static const struct file_operations dhd_ring_proc_fops = {
62*4882a593Smuzhiyun .open = dhd_ring_proc_open,
63*4882a593Smuzhiyun .read = dhd_ring_proc_read,
64*4882a593Smuzhiyun .release = single_release,
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static int
dhd_ring_proc_open(struct inode * inode,struct file * file)68*4882a593Smuzhiyun dhd_ring_proc_open(struct inode *inode, struct file *file)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun int ret = BCME_ERROR;
71*4882a593Smuzhiyun if (inode) {
72*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
73*4882a593Smuzhiyun ret = single_open(file, 0, PDE_DATA(inode));
74*4882a593Smuzhiyun #else
75*4882a593Smuzhiyun /* This feature is not supported for lower kernel versions */
76*4882a593Smuzhiyun ret = single_open(file, 0, NULL);
77*4882a593Smuzhiyun #endif // endif
78*4882a593Smuzhiyun } else {
79*4882a593Smuzhiyun DHD_ERROR(("%s: inode is NULL\n", __FUNCTION__));
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun return ret;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun ssize_t
dhd_ring_proc_read(struct file * file,char __user * buffer,size_t tt,loff_t * loff)85*4882a593Smuzhiyun dhd_ring_proc_read(struct file *file, char __user *buffer, size_t tt, loff_t *loff)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun trace_buf_info_t *trace_buf_info;
88*4882a593Smuzhiyun int ret = BCME_ERROR;
89*4882a593Smuzhiyun dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)((struct seq_file *)(file->private_data))->private;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (ring == NULL) {
92*4882a593Smuzhiyun DHD_ERROR(("%s: ring is NULL\n", __FUNCTION__));
93*4882a593Smuzhiyun return ret;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun ASSERT(g_dhd_pub);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun trace_buf_info = (trace_buf_info_t *)MALLOCZ(g_dhd_pub->osh, sizeof(trace_buf_info_t));
99*4882a593Smuzhiyun if (trace_buf_info) {
100*4882a593Smuzhiyun dhd_dbg_read_ring_into_trace_buf(ring, trace_buf_info);
101*4882a593Smuzhiyun if (copy_to_user(buffer, (void*)trace_buf_info->buf, MIN(trace_buf_info->size, tt)))
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun ret = -EFAULT;
104*4882a593Smuzhiyun goto exit;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun if (trace_buf_info->availability == BUF_NOT_AVAILABLE)
107*4882a593Smuzhiyun ret = BUF_NOT_AVAILABLE;
108*4882a593Smuzhiyun else
109*4882a593Smuzhiyun ret = trace_buf_info->size;
110*4882a593Smuzhiyun } else
111*4882a593Smuzhiyun DHD_ERROR(("Memory allocation Failed\n"));
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun exit:
114*4882a593Smuzhiyun if (trace_buf_info) {
115*4882a593Smuzhiyun MFREE(g_dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t));
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun return ret;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun void
dhd_dbg_ring_proc_create(dhd_pub_t * dhdp)121*4882a593Smuzhiyun dhd_dbg_ring_proc_create(dhd_pub_t *dhdp)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun #ifdef DEBUGABILITY
124*4882a593Smuzhiyun dhd_dbg_ring_t *dbg_verbose_ring = NULL;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun dbg_verbose_ring = dhd_dbg_get_ring_from_ring_id(dhdp, FW_VERBOSE_RING_ID);
127*4882a593Smuzhiyun if (dbg_verbose_ring) {
128*4882a593Smuzhiyun if (!proc_create_data(PROCFS_DIR_TRACE, S_IRUSR, NULL, &dhd_ring_proc_fops,
129*4882a593Smuzhiyun dbg_verbose_ring)) {
130*4882a593Smuzhiyun DHD_ERROR(("Failed to create /proc/dhd_trace procfs interface\n"));
131*4882a593Smuzhiyun } else {
132*4882a593Smuzhiyun DHD_ERROR(("Created /proc/dhd_trace procfs interface\n"));
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun } else {
135*4882a593Smuzhiyun DHD_ERROR(("dbg_verbose_ring is NULL, /proc/dhd_trace not created\n"));
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun #endif /* DEBUGABILITY */
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #ifdef EWP_ECNTRS_LOGGING
140*4882a593Smuzhiyun if (!proc_create_data(PROCFS_DIR_ENCOUNTERS, S_IRUSR, NULL, &dhd_ring_proc_fops,
141*4882a593Smuzhiyun dhdp->ecntr_dbg_ring)) {
142*4882a593Smuzhiyun DHD_ERROR(("Failed to create /proc/dhd_ecounters procfs interface\n"));
143*4882a593Smuzhiyun } else {
144*4882a593Smuzhiyun DHD_ERROR(("Created /proc/dhd_ecounters procfs interface\n"));
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun #endif /* EWP_ECNTRS_LOGGING */
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun #ifdef EWP_RTT_LOGGING
149*4882a593Smuzhiyun if (!proc_create_data(PROCFS_DIR_RTT, S_IRUSR, NULL, &dhd_ring_proc_fops,
150*4882a593Smuzhiyun dhdp->rtt_dbg_ring)) {
151*4882a593Smuzhiyun DHD_ERROR(("Failed to create /proc/dhd_rtt procfs interface\n"));
152*4882a593Smuzhiyun } else {
153*4882a593Smuzhiyun DHD_ERROR(("Created /proc/dhd_rtt procfs interface\n"));
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun #endif /* EWP_RTT_LOGGING */
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun void
dhd_dbg_ring_proc_destroy(dhd_pub_t * dhdp)159*4882a593Smuzhiyun dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun #ifdef DEBUGABILITY
162*4882a593Smuzhiyun remove_proc_entry(PROCFS_DIR_TRACE, NULL);
163*4882a593Smuzhiyun #endif /* DEBUGABILITY */
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun #ifdef EWP_ECNTRS_LOGGING
166*4882a593Smuzhiyun remove_proc_entry(PROCFS_DIR_ENCOUNTERS, NULL);
167*4882a593Smuzhiyun #endif /* EWP_ECNTRS_LOGGING */
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun #ifdef EWP_RTT_LOGGING
170*4882a593Smuzhiyun remove_proc_entry(PROCFS_DIR_RTT, NULL);
171*4882a593Smuzhiyun #endif /* EWP_RTT_LOGGING */
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun #endif /* SHOW_LOGTRACE */
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* ----------------------------------------------------------------------------
177*4882a593Smuzhiyun * Infrastructure code for sysfs interface support for DHD
178*4882a593Smuzhiyun *
179*4882a593Smuzhiyun * What is sysfs interface?
180*4882a593Smuzhiyun * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * Why sysfs interface?
183*4882a593Smuzhiyun * This is the Linux standard way of changing/configuring Run Time parameters
184*4882a593Smuzhiyun * for a driver. We can use this interface to control "linux" specific driver
185*4882a593Smuzhiyun * parameters.
186*4882a593Smuzhiyun *
187*4882a593Smuzhiyun * -----------------------------------------------------------------------------
188*4882a593Smuzhiyun */
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #if defined(DHD_TRACE_WAKE_LOCK)
191*4882a593Smuzhiyun extern atomic_t trace_wklock_onoff;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Function to show the history buffer */
194*4882a593Smuzhiyun static ssize_t
show_wklock_trace(struct dhd_info * dev,char * buf)195*4882a593Smuzhiyun show_wklock_trace(struct dhd_info *dev, char *buf)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun ssize_t ret = 0;
198*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun buf[ret] = '\n';
201*4882a593Smuzhiyun buf[ret+1] = 0;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun dhd_wk_lock_stats_dump(&dhd->pub);
204*4882a593Smuzhiyun return ret+1;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Function to enable/disable wakelock trace */
208*4882a593Smuzhiyun static ssize_t
wklock_trace_onoff(struct dhd_info * dev,const char * buf,size_t count)209*4882a593Smuzhiyun wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun unsigned long onoff;
212*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
213*4882a593Smuzhiyun BCM_REFERENCE(dhd);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
216*4882a593Smuzhiyun if (onoff != 0 && onoff != 1) {
217*4882a593Smuzhiyun return -EINVAL;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun atomic_set(&trace_wklock_onoff, onoff);
221*4882a593Smuzhiyun if (atomic_read(&trace_wklock_onoff)) {
222*4882a593Smuzhiyun printk("ENABLE WAKLOCK TRACE\n");
223*4882a593Smuzhiyun } else {
224*4882a593Smuzhiyun printk("DISABLE WAKELOCK TRACE\n");
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return (ssize_t)(onoff+1);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun #endif /* DHD_TRACE_WAKE_LOCK */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun #if defined(DHD_LB_TXP)
232*4882a593Smuzhiyun static ssize_t
show_lbtxp(struct dhd_info * dev,char * buf)233*4882a593Smuzhiyun show_lbtxp(struct dhd_info *dev, char *buf)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun ssize_t ret = 0;
236*4882a593Smuzhiyun unsigned long onoff;
237*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun onoff = atomic_read(&dhd->lb_txp_active);
240*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
241*4882a593Smuzhiyun onoff);
242*4882a593Smuzhiyun return ret;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun static ssize_t
lbtxp_onoff(struct dhd_info * dev,const char * buf,size_t count)246*4882a593Smuzhiyun lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun unsigned long onoff;
249*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
250*4882a593Smuzhiyun int i;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun sscanf(buf, "%lu", &onoff);
255*4882a593Smuzhiyun if (onoff != 0 && onoff != 1) {
256*4882a593Smuzhiyun return -EINVAL;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun atomic_set(&dhd->lb_txp_active, onoff);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* Since the scheme is changed clear the counters */
261*4882a593Smuzhiyun for (i = 0; i < NR_CPUS; i++) {
262*4882a593Smuzhiyun DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]);
263*4882a593Smuzhiyun DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return count;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun #endif /* DHD_LB_TXP */
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun #if defined(DHD_LB_RXP)
272*4882a593Smuzhiyun static ssize_t
show_lbrxp(struct dhd_info * dev,char * buf)273*4882a593Smuzhiyun show_lbrxp(struct dhd_info *dev, char *buf)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun ssize_t ret = 0;
276*4882a593Smuzhiyun unsigned long onoff;
277*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun onoff = atomic_read(&dhd->lb_rxp_active);
280*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
281*4882a593Smuzhiyun onoff);
282*4882a593Smuzhiyun return ret;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun static ssize_t
lbrxp_onoff(struct dhd_info * dev,const char * buf,size_t count)286*4882a593Smuzhiyun lbrxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun unsigned long onoff;
289*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
290*4882a593Smuzhiyun int i, j;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun sscanf(buf, "%lu", &onoff);
295*4882a593Smuzhiyun if (onoff != 0 && onoff != 1) {
296*4882a593Smuzhiyun return -EINVAL;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun atomic_set(&dhd->lb_rxp_active, onoff);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Since the scheme is changed clear the counters */
301*4882a593Smuzhiyun for (i = 0; i < NR_CPUS; i++) {
302*4882a593Smuzhiyun DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]);
303*4882a593Smuzhiyun for (j = 0; j < HIST_BIN_SIZE; j++) {
304*4882a593Smuzhiyun DHD_LB_STATS_CLR(dhd->napi_rx_hist[j][i]);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return count;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun #endif /* DHD_LB_RXP */
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
313*4882a593Smuzhiyun extern int logdump_periodic_flush;
314*4882a593Smuzhiyun extern int logdump_ecntr_enable;
315*4882a593Smuzhiyun static ssize_t
show_logdump_periodic_flush(struct dhd_info * dev,char * buf)316*4882a593Smuzhiyun show_logdump_periodic_flush(struct dhd_info *dev, char *buf)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun ssize_t ret = 0;
319*4882a593Smuzhiyun unsigned long val;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun val = logdump_periodic_flush;
322*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
323*4882a593Smuzhiyun return ret;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun static ssize_t
logdump_periodic_flush_onoff(struct dhd_info * dev,const char * buf,size_t count)327*4882a593Smuzhiyun logdump_periodic_flush_onoff(struct dhd_info *dev, const char *buf, size_t count)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun unsigned long val;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun val = bcm_strtoul(buf, NULL, 10);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun sscanf(buf, "%lu", &val);
334*4882a593Smuzhiyun if (val != 0 && val != 1) {
335*4882a593Smuzhiyun return -EINVAL;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun logdump_periodic_flush = val;
338*4882a593Smuzhiyun return count;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun static ssize_t
show_logdump_ecntr(struct dhd_info * dev,char * buf)342*4882a593Smuzhiyun show_logdump_ecntr(struct dhd_info *dev, char *buf)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun ssize_t ret = 0;
345*4882a593Smuzhiyun unsigned long val;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun val = logdump_ecntr_enable;
348*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
349*4882a593Smuzhiyun return ret;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun static ssize_t
logdump_ecntr_onoff(struct dhd_info * dev,const char * buf,size_t count)353*4882a593Smuzhiyun logdump_ecntr_onoff(struct dhd_info *dev, const char *buf, size_t count)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun unsigned long val;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun val = bcm_strtoul(buf, NULL, 10);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun sscanf(buf, "%lu", &val);
360*4882a593Smuzhiyun if (val != 0 && val != 1) {
361*4882a593Smuzhiyun return -EINVAL;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun logdump_ecntr_enable = val;
364*4882a593Smuzhiyun return count;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun extern uint enable_ecounter;
370*4882a593Smuzhiyun static ssize_t
show_enable_ecounter(struct dhd_info * dev,char * buf)371*4882a593Smuzhiyun show_enable_ecounter(struct dhd_info *dev, char *buf)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun ssize_t ret = 0;
374*4882a593Smuzhiyun unsigned long onoff;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun onoff = enable_ecounter;
377*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
378*4882a593Smuzhiyun onoff);
379*4882a593Smuzhiyun return ret;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun static ssize_t
ecounter_onoff(struct dhd_info * dev,const char * buf,size_t count)383*4882a593Smuzhiyun ecounter_onoff(struct dhd_info *dev, const char *buf, size_t count)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun unsigned long onoff;
386*4882a593Smuzhiyun dhd_info_t *dhd = (dhd_info_t *)dev;
387*4882a593Smuzhiyun dhd_pub_t *dhdp;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (!dhd) {
390*4882a593Smuzhiyun DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
391*4882a593Smuzhiyun return count;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun dhdp = &dhd->pub;
394*4882a593Smuzhiyun if (!FW_SUPPORTED(dhdp, ecounters)) {
395*4882a593Smuzhiyun DHD_ERROR(("%s: ecounters not supported by FW\n", __FUNCTION__));
396*4882a593Smuzhiyun return count;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun sscanf(buf, "%lu", &onoff);
402*4882a593Smuzhiyun if (onoff != 0 && onoff != 1) {
403*4882a593Smuzhiyun return -EINVAL;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if (enable_ecounter == onoff) {
407*4882a593Smuzhiyun DHD_ERROR(("%s: ecounters already %d\n", __FUNCTION__, enable_ecounter));
408*4882a593Smuzhiyun return count;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun enable_ecounter = onoff;
412*4882a593Smuzhiyun dhd_ecounter_configure(dhdp, enable_ecounter);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return count;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun * Generic Attribute Structure for DHD.
419*4882a593Smuzhiyun * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have
420*4882a593Smuzhiyun * to instantiate an object of type dhd_attr, populate it with
421*4882a593Smuzhiyun * the required show/store functions (ex:- dhd_attr_cpumask_primary)
422*4882a593Smuzhiyun * and add the object to default_attrs[] array, that gets registered
423*4882a593Smuzhiyun * to the kobject of dhd (named bcm-dhd).
424*4882a593Smuzhiyun */
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun struct dhd_attr {
427*4882a593Smuzhiyun struct attribute attr;
428*4882a593Smuzhiyun ssize_t(*show)(struct dhd_info *, char *);
429*4882a593Smuzhiyun ssize_t(*store)(struct dhd_info *, const char *, size_t count);
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun #if defined(DHD_TRACE_WAKE_LOCK)
433*4882a593Smuzhiyun static struct dhd_attr dhd_attr_wklock =
434*4882a593Smuzhiyun __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff);
435*4882a593Smuzhiyun #endif /* defined(DHD_TRACE_WAKE_LOCK */
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun #if defined(DHD_LB_TXP)
438*4882a593Smuzhiyun static struct dhd_attr dhd_attr_lbtxp =
439*4882a593Smuzhiyun __ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff);
440*4882a593Smuzhiyun #endif /* DHD_LB_TXP */
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun #if defined(DHD_LB_RXP)
443*4882a593Smuzhiyun static struct dhd_attr dhd_attr_lbrxp =
444*4882a593Smuzhiyun __ATTR(lbrxp, 0660, show_lbrxp, lbrxp_onoff);
445*4882a593Smuzhiyun #endif /* DHD_LB_RXP */
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
448*4882a593Smuzhiyun static struct dhd_attr dhd_attr_logdump_periodic_flush =
449*4882a593Smuzhiyun __ATTR(logdump_periodic_flush, 0660, show_logdump_periodic_flush,
450*4882a593Smuzhiyun logdump_periodic_flush_onoff);
451*4882a593Smuzhiyun static struct dhd_attr dhd_attr_logdump_ecntr =
452*4882a593Smuzhiyun __ATTR(logdump_ecntr_enable, 0660, show_logdump_ecntr,
453*4882a593Smuzhiyun logdump_ecntr_onoff);
454*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun static struct dhd_attr dhd_attr_ecounters =
457*4882a593Smuzhiyun __ATTR(ecounters, 0660, show_enable_ecounter, ecounter_onoff);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* Attribute object that gets registered with "bcm-dhd" kobject tree */
460*4882a593Smuzhiyun static struct attribute *default_attrs[] = {
461*4882a593Smuzhiyun #if defined(DHD_TRACE_WAKE_LOCK)
462*4882a593Smuzhiyun &dhd_attr_wklock.attr,
463*4882a593Smuzhiyun #endif // endif
464*4882a593Smuzhiyun #if defined(DHD_LB_TXP)
465*4882a593Smuzhiyun &dhd_attr_lbtxp.attr,
466*4882a593Smuzhiyun #endif /* DHD_LB_TXP */
467*4882a593Smuzhiyun #if defined(DHD_LB_RXP)
468*4882a593Smuzhiyun &dhd_attr_lbrxp.attr,
469*4882a593Smuzhiyun #endif /* DHD_LB_RXP */
470*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
471*4882a593Smuzhiyun &dhd_attr_logdump_periodic_flush.attr,
472*4882a593Smuzhiyun &dhd_attr_logdump_ecntr.attr,
473*4882a593Smuzhiyun #endif // endif
474*4882a593Smuzhiyun &dhd_attr_ecounters.attr,
475*4882a593Smuzhiyun NULL
476*4882a593Smuzhiyun };
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj)
479*4882a593Smuzhiyun #define to_attr(a) container_of(a, struct dhd_attr, attr)
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /*
482*4882a593Smuzhiyun * bcm-dhd kobject show function, the "attr" attribute specifices to which
483*4882a593Smuzhiyun * node under "bcm-dhd" the show function is called.
484*4882a593Smuzhiyun */
dhd_show(struct kobject * kobj,struct attribute * attr,char * buf)485*4882a593Smuzhiyun static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
488*4882a593Smuzhiyun #pragma GCC diagnostic push
489*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
490*4882a593Smuzhiyun #endif // endif
491*4882a593Smuzhiyun dhd_info_t *dhd = to_dhd(kobj);
492*4882a593Smuzhiyun struct dhd_attr *d_attr = to_attr(attr);
493*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
494*4882a593Smuzhiyun #pragma GCC diagnostic pop
495*4882a593Smuzhiyun #endif // endif
496*4882a593Smuzhiyun int ret;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun if (d_attr->show)
499*4882a593Smuzhiyun ret = d_attr->show(dhd, buf);
500*4882a593Smuzhiyun else
501*4882a593Smuzhiyun ret = -EIO;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun return ret;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun * bcm-dhd kobject show function, the "attr" attribute specifices to which
508*4882a593Smuzhiyun * node under "bcm-dhd" the store function is called.
509*4882a593Smuzhiyun */
dhd_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)510*4882a593Smuzhiyun static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr,
511*4882a593Smuzhiyun const char *buf, size_t count)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
514*4882a593Smuzhiyun #pragma GCC diagnostic push
515*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
516*4882a593Smuzhiyun #endif // endif
517*4882a593Smuzhiyun dhd_info_t *dhd = to_dhd(kobj);
518*4882a593Smuzhiyun struct dhd_attr *d_attr = to_attr(attr);
519*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
520*4882a593Smuzhiyun #pragma GCC diagnostic pop
521*4882a593Smuzhiyun #endif // endif
522*4882a593Smuzhiyun int ret;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (d_attr->store)
525*4882a593Smuzhiyun ret = d_attr->store(dhd, buf, count);
526*4882a593Smuzhiyun else
527*4882a593Smuzhiyun ret = -EIO;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return ret;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun static struct sysfs_ops dhd_sysfs_ops = {
534*4882a593Smuzhiyun .show = dhd_show,
535*4882a593Smuzhiyun .store = dhd_store,
536*4882a593Smuzhiyun };
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun static struct kobj_type dhd_ktype = {
539*4882a593Smuzhiyun .sysfs_ops = &dhd_sysfs_ops,
540*4882a593Smuzhiyun .default_attrs = default_attrs,
541*4882a593Smuzhiyun };
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun #ifdef DHD_MAC_ADDR_EXPORT
544*4882a593Smuzhiyun struct ether_addr sysfs_mac_addr;
545*4882a593Smuzhiyun static ssize_t
show_mac_addr(struct dhd_info * dev,char * buf)546*4882a593Smuzhiyun show_mac_addr(struct dhd_info *dev, char *buf)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun ssize_t ret = 0;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, MACF,
551*4882a593Smuzhiyun (uint32)sysfs_mac_addr.octet[0], (uint32)sysfs_mac_addr.octet[1],
552*4882a593Smuzhiyun (uint32)sysfs_mac_addr.octet[2], (uint32)sysfs_mac_addr.octet[3],
553*4882a593Smuzhiyun (uint32)sysfs_mac_addr.octet[4], (uint32)sysfs_mac_addr.octet[5]);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun return ret;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun static ssize_t
set_mac_addr(struct dhd_info * dev,const char * buf,size_t count)559*4882a593Smuzhiyun set_mac_addr(struct dhd_info *dev, const char *buf, size_t count)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun if (!bcm_ether_atoe(buf, &sysfs_mac_addr)) {
562*4882a593Smuzhiyun DHD_ERROR(("Invalid Mac Address \n"));
563*4882a593Smuzhiyun return -EINVAL;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun DHD_ERROR(("Mac Address set with "MACDBG"\n", MAC2STRDBG(&sysfs_mac_addr)));
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun return count;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_macaddr =
572*4882a593Smuzhiyun __ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr);
573*4882a593Smuzhiyun #endif /* DHD_MAC_ADDR_EXPORT */
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun #ifdef DHD_FW_COREDUMP
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun #ifdef CUSTOMER_HW4_DEBUG
578*4882a593Smuzhiyun #define MEMDUMPINFO PLATFORM_PATH".memdump.info"
579*4882a593Smuzhiyun #elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)
580*4882a593Smuzhiyun #define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
581*4882a593Smuzhiyun #elif defined(OEM_ANDROID) && defined(CONFIG_DHD_PLAT_ROCKCHIP)
582*4882a593Smuzhiyun #define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
583*4882a593Smuzhiyun #elif defined(OEM_ANDROID) && (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__))
584*4882a593Smuzhiyun #define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
585*4882a593Smuzhiyun #elif defined(OEM_ANDROID) && defined(DHD_FW_COREDUMP)
586*4882a593Smuzhiyun #define MEMDUMPINFO_LIVE "/installmedia/.memdump.info"
587*4882a593Smuzhiyun #define MEMDUMPINFO_INST "/data/.memdump.info"
588*4882a593Smuzhiyun #define MEMDUMPINFO MEMDUMPINFO_LIVE
589*4882a593Smuzhiyun #else /* FC19 and Others */
590*4882a593Smuzhiyun #define MEMDUMPINFO "/root/.memdump.info"
591*4882a593Smuzhiyun #endif /* CUSTOMER_HW4_DEBUG */
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun uint32
get_mem_val_from_file(void)594*4882a593Smuzhiyun get_mem_val_from_file(void)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun struct file *fp = NULL;
597*4882a593Smuzhiyun uint32 mem_val = DUMP_MEMFILE_MAX;
598*4882a593Smuzhiyun char *p_mem_val = NULL;
599*4882a593Smuzhiyun char *filepath = MEMDUMPINFO;
600*4882a593Smuzhiyun int ret = 0;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /* Read memdump info from the file */
603*4882a593Smuzhiyun fp = filp_open(filepath, O_RDONLY, 0);
604*4882a593Smuzhiyun if (IS_ERR(fp)) {
605*4882a593Smuzhiyun DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
606*4882a593Smuzhiyun #if defined(CONFIG_X86) && defined(OEM_ANDROID) && defined(DHD_FW_COREDUMP)
607*4882a593Smuzhiyun /* Check if it is Live Brix Image */
608*4882a593Smuzhiyun if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) {
609*4882a593Smuzhiyun goto done;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun /* Try if it is Installed Brix Image */
612*4882a593Smuzhiyun filepath = MEMDUMPINFO_INST;
613*4882a593Smuzhiyun DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
614*4882a593Smuzhiyun fp = filp_open(filepath, O_RDONLY, 0);
615*4882a593Smuzhiyun if (IS_ERR(fp)) {
616*4882a593Smuzhiyun DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
617*4882a593Smuzhiyun goto done;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun #else /* Non Brix Android platform */
620*4882a593Smuzhiyun goto done;
621*4882a593Smuzhiyun #endif /* CONFIG_X86 && OEM_ANDROID */
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* Handle success case */
625*4882a593Smuzhiyun ret = compat_kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
626*4882a593Smuzhiyun if (ret < 0) {
627*4882a593Smuzhiyun DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
628*4882a593Smuzhiyun filp_close(fp, NULL);
629*4882a593Smuzhiyun goto done;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun p_mem_val = (char*)&mem_val;
633*4882a593Smuzhiyun p_mem_val[sizeof(uint32) - 1] = '\0';
634*4882a593Smuzhiyun mem_val = bcm_atoi(p_mem_val);
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun filp_close(fp, NULL);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun done:
639*4882a593Smuzhiyun return mem_val;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
dhd_get_memdump_info(dhd_pub_t * dhd)642*4882a593Smuzhiyun void dhd_get_memdump_info(dhd_pub_t *dhd)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun #ifndef DHD_EXPORT_CNTL_FILE
645*4882a593Smuzhiyun uint32 mem_val = DUMP_MEMFILE_MAX;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun mem_val = get_mem_val_from_file();
648*4882a593Smuzhiyun if (mem_val != DUMP_MEMFILE_MAX)
649*4882a593Smuzhiyun dhd->memdump_enabled = mem_val;
650*4882a593Smuzhiyun #ifdef DHD_INIT_DEFAULT_MEMDUMP
651*4882a593Smuzhiyun if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX)
652*4882a593Smuzhiyun mem_val = DUMP_MEMFILE_BUGON;
653*4882a593Smuzhiyun #endif /* DHD_INIT_DEFAULT_MEMDUMP */
654*4882a593Smuzhiyun #else
655*4882a593Smuzhiyun #ifdef DHD_INIT_DEFAULT_MEMDUMP
656*4882a593Smuzhiyun if (dhd->memdump_enabled == 0 || dhd->memdump_enabled == DUMP_MEMFILE_MAX)
657*4882a593Smuzhiyun dhd->memdump_enabled = DUMP_MEMFILE_BUGON;
658*4882a593Smuzhiyun #endif /* DHD_INIT_DEFAULT_MEMDUMP */
659*4882a593Smuzhiyun #endif /* !DHD_EXPORT_CNTL_FILE */
660*4882a593Smuzhiyun #ifdef BCMQT
661*4882a593Smuzhiyun /* In QT environment collecting memdump on FW TRAP, IOVAR timeouts,
662*4882a593Smuzhiyun * is taking more time and makes system unresponsive so disabling it.
663*4882a593Smuzhiyun * if needed memdump can be collected through 'dhd upload' command.
664*4882a593Smuzhiyun */
665*4882a593Smuzhiyun dhd->memdump_enabled = DUMP_DISABLED;
666*4882a593Smuzhiyun #endif // endif
667*4882a593Smuzhiyun DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, dhd->memdump_enabled));
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun #ifdef DHD_EXPORT_CNTL_FILE
671*4882a593Smuzhiyun static ssize_t
show_memdump_info(struct dhd_info * dev,char * buf)672*4882a593Smuzhiyun show_memdump_info(struct dhd_info *dev, char *buf)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun ssize_t ret = 0;
675*4882a593Smuzhiyun dhd_pub_t *dhdp;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (!dev) {
678*4882a593Smuzhiyun DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
679*4882a593Smuzhiyun return ret;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun dhdp = &dev->pub;
683*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", dhdp->memdump_enabled);
684*4882a593Smuzhiyun return ret;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun static ssize_t
set_memdump_info(struct dhd_info * dev,const char * buf,size_t count)688*4882a593Smuzhiyun set_memdump_info(struct dhd_info *dev, const char *buf, size_t count)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun unsigned long memval;
691*4882a593Smuzhiyun dhd_pub_t *dhdp;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun if (!dev) {
694*4882a593Smuzhiyun DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
695*4882a593Smuzhiyun return count;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun dhdp = &dev->pub;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun memval = bcm_strtoul(buf, NULL, 10);
700*4882a593Smuzhiyun sscanf(buf, "%lu", &memval);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun dhdp->memdump_enabled = (uint32)memval;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun DHD_ERROR(("%s: MEMDUMP ENABLED = %iu\n", __FUNCTION__, dhdp->memdump_enabled));
705*4882a593Smuzhiyun return count;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_memdump =
709*4882a593Smuzhiyun __ATTR(memdump, 0660, show_memdump_info, set_memdump_info);
710*4882a593Smuzhiyun #endif /* DHD_EXPORT_CNTL_FILE */
711*4882a593Smuzhiyun #endif /* DHD_FW_COREDUMP */
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun #ifdef BCMASSERT_LOG
714*4882a593Smuzhiyun #ifdef CUSTOMER_HW4_DEBUG
715*4882a593Smuzhiyun #define ASSERTINFO PLATFORM_PATH".assert.info"
716*4882a593Smuzhiyun #elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)
717*4882a593Smuzhiyun #define ASSERTINFO "/data/misc/wifi/.assert.info"
718*4882a593Smuzhiyun #elif defined(OEM_ANDROID) && defined(CONFIG_DHD_PLAT_ROCKCHIP)
719*4882a593Smuzhiyun #define ASSERTINFO "/data/misc/wifi/.assert.info"
720*4882a593Smuzhiyun #elif defined(OEM_ANDROID)
721*4882a593Smuzhiyun #define ASSERTINFO "/installmedia/.assert.info"
722*4882a593Smuzhiyun #else
723*4882a593Smuzhiyun #define ASSERTINFO "/root/.assert.info"
724*4882a593Smuzhiyun #endif /* CUSTOMER_HW4_DEBUG */
725*4882a593Smuzhiyun int
get_assert_val_from_file(void)726*4882a593Smuzhiyun get_assert_val_from_file(void)
727*4882a593Smuzhiyun {
728*4882a593Smuzhiyun struct file *fp = NULL;
729*4882a593Smuzhiyun char *filepath = ASSERTINFO;
730*4882a593Smuzhiyun char *p_mem_val = NULL;
731*4882a593Smuzhiyun int mem_val = -1;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun /*
734*4882a593Smuzhiyun * Read assert info from the file
735*4882a593Smuzhiyun * 0: Trigger Kernel crash by panic()
736*4882a593Smuzhiyun * 1: Print out the logs and don't trigger Kernel panic. (default)
737*4882a593Smuzhiyun * 2: Trigger Kernel crash by BUG()
738*4882a593Smuzhiyun * File doesn't exist: Keep default value (1).
739*4882a593Smuzhiyun */
740*4882a593Smuzhiyun fp = filp_open(filepath, O_RDONLY, 0);
741*4882a593Smuzhiyun if (IS_ERR(fp)) {
742*4882a593Smuzhiyun DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
743*4882a593Smuzhiyun } else {
744*4882a593Smuzhiyun int ret = compat_kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
745*4882a593Smuzhiyun if (ret < 0) {
746*4882a593Smuzhiyun DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
747*4882a593Smuzhiyun } else {
748*4882a593Smuzhiyun p_mem_val = (char *)&mem_val;
749*4882a593Smuzhiyun p_mem_val[sizeof(uint32) - 1] = '\0';
750*4882a593Smuzhiyun mem_val = bcm_atoi(p_mem_val);
751*4882a593Smuzhiyun DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val));
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun filp_close(fp, NULL);
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun #ifdef CUSTOMER_HW4_DEBUG
757*4882a593Smuzhiyun mem_val = (mem_val >= 0) ? mem_val : 1;
758*4882a593Smuzhiyun #else
759*4882a593Smuzhiyun mem_val = (mem_val >= 0) ? mem_val : 0;
760*4882a593Smuzhiyun #endif /* CUSTOMER_HW4_DEBUG */
761*4882a593Smuzhiyun return mem_val;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
dhd_get_assert_info(dhd_pub_t * dhd)764*4882a593Smuzhiyun void dhd_get_assert_info(dhd_pub_t *dhd)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun #ifndef DHD_EXPORT_CNTL_FILE
767*4882a593Smuzhiyun int mem_val = -1;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun mem_val = get_assert_val_from_file();
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun g_assert_type = mem_val;
772*4882a593Smuzhiyun #endif /* !DHD_EXPORT_CNTL_FILE */
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun #ifdef DHD_EXPORT_CNTL_FILE
776*4882a593Smuzhiyun static ssize_t
show_assert_info(struct dhd_info * dev,char * buf)777*4882a593Smuzhiyun show_assert_info(struct dhd_info *dev, char *buf)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun ssize_t ret = 0;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (!dev) {
782*4882a593Smuzhiyun DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
783*4882a593Smuzhiyun return ret;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%d\n", g_assert_type);
787*4882a593Smuzhiyun return ret;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun static ssize_t
set_assert_info(struct dhd_info * dev,const char * buf,size_t count)792*4882a593Smuzhiyun set_assert_info(struct dhd_info *dev, const char *buf, size_t count)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun unsigned long assert_val;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun assert_val = bcm_strtoul(buf, NULL, 10);
797*4882a593Smuzhiyun sscanf(buf, "%lu", &assert_val);
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun g_assert_type = (uint32)assert_val;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun DHD_ERROR(("%s: ASSERT ENABLED = %lu\n", __FUNCTION__, assert_val));
802*4882a593Smuzhiyun return count;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_assert =
807*4882a593Smuzhiyun __ATTR(assert, 0660, show_assert_info, set_assert_info);
808*4882a593Smuzhiyun #endif /* DHD_EXPORT_CNTL_FILE */
809*4882a593Smuzhiyun #endif /* BCMASSERT_LOG */
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun #ifdef DHD_EXPORT_CNTL_FILE
812*4882a593Smuzhiyun #if defined(WRITE_WLANINFO)
813*4882a593Smuzhiyun static ssize_t
show_wifiver_info(struct dhd_info * dev,char * buf)814*4882a593Smuzhiyun show_wifiver_info(struct dhd_info *dev, char *buf)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun ssize_t ret = 0;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s", version_info);
819*4882a593Smuzhiyun return ret;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun static ssize_t
set_wifiver_info(struct dhd_info * dev,const char * buf,size_t count)823*4882a593Smuzhiyun set_wifiver_info(struct dhd_info *dev, const char *buf, size_t count)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun DHD_ERROR(("Do not set version info\n"));
826*4882a593Smuzhiyun return -EINVAL;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_wifiver =
830*4882a593Smuzhiyun __ATTR(wifiver, 0660, show_wifiver_info, set_wifiver_info);
831*4882a593Smuzhiyun #endif /* WRITE_WLANINFO */
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun #if defined(USE_CID_CHECK)
834*4882a593Smuzhiyun char cidinfostr[MAX_VNAME_LEN];
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun static ssize_t
show_cid_info(struct dhd_info * dev,char * buf)837*4882a593Smuzhiyun show_cid_info(struct dhd_info *dev, char *buf)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun ssize_t ret = 0;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s", cidinfostr);
842*4882a593Smuzhiyun return ret;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun static ssize_t
set_cid_info(struct dhd_info * dev,const char * buf,size_t count)846*4882a593Smuzhiyun set_cid_info(struct dhd_info *dev, const char *buf, size_t count)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun int len = strlen(buf) + 1;
849*4882a593Smuzhiyun int maxstrsz;
850*4882a593Smuzhiyun maxstrsz = MAX_VNAME_LEN;
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun scnprintf(cidinfostr, ((len > maxstrsz) ? maxstrsz : len), "%s", buf);
853*4882a593Smuzhiyun DHD_INFO(("%s : CID info string\n", cidinfostr));
854*4882a593Smuzhiyun return count;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_cidinfo =
858*4882a593Smuzhiyun __ATTR(cid, 0660, show_cid_info, set_cid_info);
859*4882a593Smuzhiyun #endif /* USE_CID_CHECK */
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun #if defined(GEN_SOFTAP_INFO_FILE)
862*4882a593Smuzhiyun char softapinfostr[SOFTAP_INFO_BUF_SZ];
863*4882a593Smuzhiyun static ssize_t
show_softap_info(struct dhd_info * dev,char * buf)864*4882a593Smuzhiyun show_softap_info(struct dhd_info *dev, char *buf)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun ssize_t ret = 0;
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s", softapinfostr);
869*4882a593Smuzhiyun return ret;
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun static ssize_t
set_softap_info(struct dhd_info * dev,const char * buf,size_t count)873*4882a593Smuzhiyun set_softap_info(struct dhd_info *dev, const char *buf, size_t count)
874*4882a593Smuzhiyun {
875*4882a593Smuzhiyun DHD_ERROR(("Do not set sofap related info\n"));
876*4882a593Smuzhiyun return -EINVAL;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_softapinfo =
880*4882a593Smuzhiyun __ATTR(softap, 0660, show_softap_info, set_softap_info);
881*4882a593Smuzhiyun #endif /* GEN_SOFTAP_INFO_FILE */
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun #if defined(MIMO_ANT_SETTING)
884*4882a593Smuzhiyun unsigned long antsel;
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun static ssize_t
show_ant_info(struct dhd_info * dev,char * buf)887*4882a593Smuzhiyun show_ant_info(struct dhd_info *dev, char *buf)
888*4882a593Smuzhiyun {
889*4882a593Smuzhiyun ssize_t ret = 0;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", antsel);
892*4882a593Smuzhiyun return ret;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun static ssize_t
set_ant_info(struct dhd_info * dev,const char * buf,size_t count)896*4882a593Smuzhiyun set_ant_info(struct dhd_info *dev, const char *buf, size_t count)
897*4882a593Smuzhiyun {
898*4882a593Smuzhiyun unsigned long ant_val;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun ant_val = bcm_strtoul(buf, NULL, 10);
901*4882a593Smuzhiyun sscanf(buf, "%lu", &ant_val);
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /*
904*4882a593Smuzhiyun * Check value
905*4882a593Smuzhiyun * 0 - Not set, handle same as file not exist
906*4882a593Smuzhiyun */
907*4882a593Smuzhiyun if (ant_val > 3) {
908*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
909*4882a593Smuzhiyun __FUNCTION__, ant_val));
910*4882a593Smuzhiyun return -EINVAL;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun antsel = ant_val;
914*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Antinfo val = %lu \n", __FUNCTION__, antsel));
915*4882a593Smuzhiyun return count;
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_antinfo =
919*4882a593Smuzhiyun __ATTR(ant, 0660, show_ant_info, set_ant_info);
920*4882a593Smuzhiyun #endif /* MIMO_ANT_SETTING */
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun #ifdef DHD_PM_CONTROL_FROM_FILE
923*4882a593Smuzhiyun extern bool g_pm_control;
924*4882a593Smuzhiyun extern uint32 pmmode_val;
925*4882a593Smuzhiyun static ssize_t
show_pm_info(struct dhd_info * dev,char * buf)926*4882a593Smuzhiyun show_pm_info(struct dhd_info *dev, char *buf)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun ssize_t ret = 0;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun if (!g_pm_control) {
931*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "PM mode is not set\n");
932*4882a593Smuzhiyun } else {
933*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", pmmode_val);
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun return ret;
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun static ssize_t
set_pm_info(struct dhd_info * dev,const char * buf,size_t count)939*4882a593Smuzhiyun set_pm_info(struct dhd_info *dev, const char *buf, size_t count)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun unsigned long pm_val;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun pm_val = bcm_strtoul(buf, NULL, 10);
944*4882a593Smuzhiyun sscanf(buf, "%lu", &pm_val);
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun if (pm_val > 2) {
947*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
948*4882a593Smuzhiyun __FUNCTION__, pm_val));
949*4882a593Smuzhiyun return -EINVAL;
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun if (!pm_val) {
953*4882a593Smuzhiyun g_pm_control = TRUE;
954*4882a593Smuzhiyun } else {
955*4882a593Smuzhiyun g_pm_control = FALSE;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun pmmode_val = (uint32)pm_val;
959*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set pminfo val = %u\n", __FUNCTION__, pmmode_val));
960*4882a593Smuzhiyun return count;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_pminfo =
964*4882a593Smuzhiyun __ATTR(pm, 0660, show_pm_info, set_pm_info);
965*4882a593Smuzhiyun #endif /* DHD_PM_CONTROL_FROM_FILE */
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun #ifdef LOGTRACE_FROM_FILE
968*4882a593Smuzhiyun unsigned long logtrace_val = 1;
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun static ssize_t
show_logtrace_info(struct dhd_info * dev,char * buf)971*4882a593Smuzhiyun show_logtrace_info(struct dhd_info *dev, char *buf)
972*4882a593Smuzhiyun {
973*4882a593Smuzhiyun ssize_t ret = 0;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", logtrace_val);
976*4882a593Smuzhiyun return ret;
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun static ssize_t
set_logtrace_info(struct dhd_info * dev,const char * buf,size_t count)980*4882a593Smuzhiyun set_logtrace_info(struct dhd_info *dev, const char *buf, size_t count)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun unsigned long onoff;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
985*4882a593Smuzhiyun sscanf(buf, "%lu", &onoff);
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun if (onoff > 2) {
988*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
989*4882a593Smuzhiyun __FUNCTION__, onoff));
990*4882a593Smuzhiyun return -EINVAL;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun logtrace_val = onoff;
994*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: LOGTRACE On/Off from sysfs = %lu\n",
995*4882a593Smuzhiyun __FUNCTION__, logtrace_val));
996*4882a593Smuzhiyun return count;
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_logtraceinfo =
1000*4882a593Smuzhiyun __ATTR(logtrace, 0660, show_logtrace_info, set_logtrace_info);
1001*4882a593Smuzhiyun #endif /* LOGTRACE_FROM_FILE */
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun #ifdef USE_WFA_CERT_CONF
1004*4882a593Smuzhiyun #ifdef BCMSDIO
1005*4882a593Smuzhiyun uint32 bus_txglom = VALUENOTSET;
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun static ssize_t
show_bustxglom(struct dhd_info * dev,char * buf)1008*4882a593Smuzhiyun show_bustxglom(struct dhd_info *dev, char *buf)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun ssize_t ret = 0;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun if (bus_txglom == VALUENOTSET) {
1013*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", "bustxglom not set from sysfs");
1014*4882a593Smuzhiyun } else {
1015*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", bus_txglom);
1016*4882a593Smuzhiyun }
1017*4882a593Smuzhiyun return ret;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun static ssize_t
set_bustxglom(struct dhd_info * dev,const char * buf,size_t count)1021*4882a593Smuzhiyun set_bustxglom(struct dhd_info *dev, const char *buf, size_t count)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun uint32 onoff;
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun onoff = (uint32)bcm_atoi(buf);
1026*4882a593Smuzhiyun sscanf(buf, "%u", &onoff);
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun if (onoff > 2) {
1029*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1030*4882a593Smuzhiyun __FUNCTION__, onoff));
1031*4882a593Smuzhiyun return -EINVAL;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun bus_txglom = onoff;
1035*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: BUS TXGLOM On/Off from sysfs = %u\n",
1036*4882a593Smuzhiyun __FUNCTION__, bus_txglom));
1037*4882a593Smuzhiyun return count;
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_bustxglom =
1041*4882a593Smuzhiyun __ATTR(bustxglom, 0660, show_bustxglom, set_bustxglom);
1042*4882a593Smuzhiyun #endif /* BCMSDIO */
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
1045*4882a593Smuzhiyun uint32 roam_off = VALUENOTSET;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun static ssize_t
show_roamoff(struct dhd_info * dev,char * buf)1048*4882a593Smuzhiyun show_roamoff(struct dhd_info *dev, char *buf)
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun ssize_t ret = 0;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun if (roam_off == VALUENOTSET) {
1053*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "roam_off not set from sysfs");
1054*4882a593Smuzhiyun } else {
1055*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", roam_off);
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun return ret;
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun static ssize_t
set_roamoff(struct dhd_info * dev,const char * buf,size_t count)1061*4882a593Smuzhiyun set_roamoff(struct dhd_info *dev, const char *buf, size_t count)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun uint32 onoff;
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun onoff = bcm_atoi(buf);
1066*4882a593Smuzhiyun sscanf(buf, "%u", &onoff);
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun if (onoff > 2) {
1069*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1070*4882a593Smuzhiyun __FUNCTION__, onoff));
1071*4882a593Smuzhiyun return -EINVAL;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun roam_off = onoff;
1075*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: ROAM On/Off from sysfs = %u\n",
1076*4882a593Smuzhiyun __FUNCTION__, roam_off));
1077*4882a593Smuzhiyun return count;
1078*4882a593Smuzhiyun }
1079*4882a593Smuzhiyun
1080*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_roamoff =
1081*4882a593Smuzhiyun __ATTR(roamoff, 0660, show_roamoff, set_roamoff);
1082*4882a593Smuzhiyun #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun #ifdef USE_WL_FRAMEBURST
1085*4882a593Smuzhiyun uint32 frameburst = VALUENOTSET;
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun static ssize_t
show_frameburst(struct dhd_info * dev,char * buf)1088*4882a593Smuzhiyun show_frameburst(struct dhd_info *dev, char *buf)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun ssize_t ret = 0;
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun if (frameburst == VALUENOTSET) {
1093*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "frameburst not set from sysfs");
1094*4882a593Smuzhiyun } else {
1095*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", frameburst);
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun return ret;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun static ssize_t
set_frameburst(struct dhd_info * dev,const char * buf,size_t count)1101*4882a593Smuzhiyun set_frameburst(struct dhd_info *dev, const char *buf, size_t count)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun uint32 onoff;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun onoff = bcm_atoi(buf);
1106*4882a593Smuzhiyun sscanf(buf, "%u", &onoff);
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun if (onoff > 2) {
1109*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1110*4882a593Smuzhiyun __FUNCTION__, onoff));
1111*4882a593Smuzhiyun return -EINVAL;
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun frameburst = onoff;
1115*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1116*4882a593Smuzhiyun __FUNCTION__, frameburst));
1117*4882a593Smuzhiyun return count;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_frameburst =
1121*4882a593Smuzhiyun __ATTR(frameburst, 0660, show_frameburst, set_frameburst);
1122*4882a593Smuzhiyun #endif /* USE_WL_FRAMEBURST */
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun #ifdef USE_WL_TXBF
1125*4882a593Smuzhiyun uint32 txbf = VALUENOTSET;
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun static ssize_t
show_txbf(struct dhd_info * dev,char * buf)1128*4882a593Smuzhiyun show_txbf(struct dhd_info *dev, char *buf)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun ssize_t ret = 0;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun if (txbf == VALUENOTSET) {
1133*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "txbf not set from sysfs");
1134*4882a593Smuzhiyun } else {
1135*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", txbf);
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun return ret;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun static ssize_t
set_txbf(struct dhd_info * dev,const char * buf,size_t count)1141*4882a593Smuzhiyun set_txbf(struct dhd_info *dev, const char *buf, size_t count)
1142*4882a593Smuzhiyun {
1143*4882a593Smuzhiyun uint32 onoff;
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun onoff = bcm_atoi(buf);
1146*4882a593Smuzhiyun sscanf(buf, "%u", &onoff);
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun if (onoff > 2) {
1149*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1150*4882a593Smuzhiyun __FUNCTION__, onoff));
1151*4882a593Smuzhiyun return -EINVAL;
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun txbf = onoff;
1155*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1156*4882a593Smuzhiyun __FUNCTION__, txbf));
1157*4882a593Smuzhiyun return count;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_txbf =
1161*4882a593Smuzhiyun __ATTR(txbf, 0660, show_txbf, set_txbf);
1162*4882a593Smuzhiyun #endif /* USE_WL_TXBF */
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun #ifdef PROP_TXSTATUS
1165*4882a593Smuzhiyun uint32 proptx = VALUENOTSET;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun static ssize_t
show_proptx(struct dhd_info * dev,char * buf)1168*4882a593Smuzhiyun show_proptx(struct dhd_info *dev, char *buf)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun ssize_t ret = 0;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun if (proptx == VALUENOTSET) {
1173*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "proptx not set from sysfs");
1174*4882a593Smuzhiyun } else {
1175*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", proptx);
1176*4882a593Smuzhiyun }
1177*4882a593Smuzhiyun return ret;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun static ssize_t
set_proptx(struct dhd_info * dev,const char * buf,size_t count)1181*4882a593Smuzhiyun set_proptx(struct dhd_info *dev, const char *buf, size_t count)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun uint32 onoff;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun onoff = bcm_strtoul(buf, NULL, 10);
1186*4882a593Smuzhiyun sscanf(buf, "%u", &onoff);
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun if (onoff > 2) {
1189*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1190*4882a593Smuzhiyun __FUNCTION__, onoff));
1191*4882a593Smuzhiyun return -EINVAL;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun proptx = onoff;
1195*4882a593Smuzhiyun DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1196*4882a593Smuzhiyun __FUNCTION__, txbf));
1197*4882a593Smuzhiyun return count;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun static struct dhd_attr dhd_attr_cntl_proptx =
1201*4882a593Smuzhiyun __ATTR(proptx, 0660, show_proptx, set_proptx);
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun #endif /* PROP_TXSTATUS */
1204*4882a593Smuzhiyun #endif /* USE_WFA_CERT_CONF */
1205*4882a593Smuzhiyun #endif /* DHD_EXPORT_CNTL_FILE */
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun #if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
1208*4882a593Smuzhiyun #define BAD_AP_MAC_ADDR_ELEMENT_NUM 6
1209*4882a593Smuzhiyun wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL;
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun static ssize_t
show_adps_bam_list(struct dhd_info * dev,char * buf)1212*4882a593Smuzhiyun show_adps_bam_list(struct dhd_info *dev, char *buf)
1213*4882a593Smuzhiyun {
1214*4882a593Smuzhiyun int offset = 0;
1215*4882a593Smuzhiyun ssize_t ret = 0;
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun wl_bad_ap_info_t *bad_ap;
1218*4882a593Smuzhiyun wl_bad_ap_info_entry_t *entry;
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun if (g_bad_ap_mngr == NULL)
1221*4882a593Smuzhiyun return ret;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1224*4882a593Smuzhiyun #pragma GCC diagnostic push
1225*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
1226*4882a593Smuzhiyun #endif // endif
1227*4882a593Smuzhiyun list_for_each_entry(entry, &g_bad_ap_mngr->list, list) {
1228*4882a593Smuzhiyun bad_ap = &entry->bad_ap;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun ret = scnprintf(buf + offset, PAGE_SIZE - 1, MACF"\n",
1231*4882a593Smuzhiyun bad_ap->bssid.octet[0], bad_ap->bssid.octet[1],
1232*4882a593Smuzhiyun bad_ap->bssid.octet[2], bad_ap->bssid.octet[3],
1233*4882a593Smuzhiyun bad_ap->bssid.octet[4], bad_ap->bssid.octet[5]);
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun offset += ret;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1238*4882a593Smuzhiyun #pragma GCC diagnostic pop
1239*4882a593Smuzhiyun #endif // endif
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun return offset;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun static ssize_t
store_adps_bam_list(struct dhd_info * dev,const char * buf,size_t count)1245*4882a593Smuzhiyun store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun int ret;
1248*4882a593Smuzhiyun size_t len;
1249*4882a593Smuzhiyun int offset;
1250*4882a593Smuzhiyun char tmp[128];
1251*4882a593Smuzhiyun wl_bad_ap_info_t bad_ap;
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun if (g_bad_ap_mngr == NULL)
1254*4882a593Smuzhiyun return count;
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun len = count;
1257*4882a593Smuzhiyun offset = 0;
1258*4882a593Smuzhiyun do {
1259*4882a593Smuzhiyun ret = sscanf(buf + offset, MACF"\n",
1260*4882a593Smuzhiyun (uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1],
1261*4882a593Smuzhiyun (uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3],
1262*4882a593Smuzhiyun (uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5]);
1263*4882a593Smuzhiyun if (ret != BAD_AP_MAC_ADDR_ELEMENT_NUM) {
1264*4882a593Smuzhiyun DHD_ERROR(("%s - fail to parse bad ap data\n", __FUNCTION__));
1265*4882a593Smuzhiyun return -EINVAL;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun ret = wl_bad_ap_mngr_add(g_bad_ap_mngr, &bad_ap);
1269*4882a593Smuzhiyun if (ret < 0)
1270*4882a593Smuzhiyun return ret;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun ret = snprintf(tmp, ARRAYSIZE(tmp), MACF"\n",
1273*4882a593Smuzhiyun bad_ap.bssid.octet[0], bad_ap.bssid.octet[1],
1274*4882a593Smuzhiyun bad_ap.bssid.octet[2], bad_ap.bssid.octet[3],
1275*4882a593Smuzhiyun bad_ap.bssid.octet[4], bad_ap.bssid.octet[5]);
1276*4882a593Smuzhiyun if (ret < 0) {
1277*4882a593Smuzhiyun DHD_ERROR(("%s - fail to get bad ap data length(%d)\n", __FUNCTION__, ret));
1278*4882a593Smuzhiyun return ret;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun len -= ret;
1282*4882a593Smuzhiyun offset += ret;
1283*4882a593Smuzhiyun } while (len > 0);
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun return count;
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun static struct dhd_attr dhd_attr_adps_bam =
1289*4882a593Smuzhiyun __ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list);
1290*4882a593Smuzhiyun #endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1293*4882a593Smuzhiyun uint32 report_hang_privcmd_err = 1;
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun static ssize_t
show_hang_privcmd_err(struct dhd_info * dev,char * buf)1296*4882a593Smuzhiyun show_hang_privcmd_err(struct dhd_info *dev, char *buf)
1297*4882a593Smuzhiyun {
1298*4882a593Smuzhiyun ssize_t ret = 0;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%u\n", report_hang_privcmd_err);
1301*4882a593Smuzhiyun return ret;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun static ssize_t
set_hang_privcmd_err(struct dhd_info * dev,const char * buf,size_t count)1305*4882a593Smuzhiyun set_hang_privcmd_err(struct dhd_info *dev, const char *buf, size_t count)
1306*4882a593Smuzhiyun {
1307*4882a593Smuzhiyun uint32 val;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun val = bcm_atoi(buf);
1310*4882a593Smuzhiyun sscanf(buf, "%u", &val);
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun report_hang_privcmd_err = val ? 1 : 0;
1313*4882a593Smuzhiyun DHD_INFO(("%s: Set report HANG for private cmd error: %d\n",
1314*4882a593Smuzhiyun __FUNCTION__, report_hang_privcmd_err));
1315*4882a593Smuzhiyun return count;
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun static struct dhd_attr dhd_attr_hang_privcmd_err =
1319*4882a593Smuzhiyun __ATTR(hang_privcmd_err, 0660, show_hang_privcmd_err, set_hang_privcmd_err);
1320*4882a593Smuzhiyun #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB)
1323*4882a593Smuzhiyun uint8 control_he_enab = 1;
1324*4882a593Smuzhiyun #endif /* DISABLE_HE_ENAB || CUSTOM_CONTROL_HE_ENAB */
1325*4882a593Smuzhiyun
1326*4882a593Smuzhiyun #if defined(CUSTOM_CONTROL_HE_ENAB)
1327*4882a593Smuzhiyun static ssize_t
show_control_he_enab(struct dhd_info * dev,char * buf)1328*4882a593Smuzhiyun show_control_he_enab(struct dhd_info *dev, char *buf)
1329*4882a593Smuzhiyun {
1330*4882a593Smuzhiyun ssize_t ret = 0;
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", control_he_enab);
1333*4882a593Smuzhiyun return ret;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun static ssize_t
set_control_he_enab(struct dhd_info * dev,const char * buf,size_t count)1337*4882a593Smuzhiyun set_control_he_enab(struct dhd_info *dev, const char *buf, size_t count)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun uint32 val;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun val = bcm_atoi(buf);
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun control_he_enab = val ? 1 : 0;
1344*4882a593Smuzhiyun DHD_ERROR(("%s: Set control he enab: %d\n", __FUNCTION__, control_he_enab));
1345*4882a593Smuzhiyun return count;
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun static struct dhd_attr dhd_attr_control_he_enab=
1349*4882a593Smuzhiyun __ATTR(control_he_enab, 0660, show_control_he_enab, set_control_he_enab);
1350*4882a593Smuzhiyun #endif /* CUSTOM_CONTROL_HE_ENAB */
1351*4882a593Smuzhiyun /* Attribute object that gets registered with "wifi" kobject tree */
1352*4882a593Smuzhiyun static struct attribute *control_file_attrs[] = {
1353*4882a593Smuzhiyun #ifdef DHD_MAC_ADDR_EXPORT
1354*4882a593Smuzhiyun &dhd_attr_cntl_macaddr.attr,
1355*4882a593Smuzhiyun #endif /* DHD_MAC_ADDR_EXPORT */
1356*4882a593Smuzhiyun #ifdef DHD_EXPORT_CNTL_FILE
1357*4882a593Smuzhiyun #ifdef DHD_FW_COREDUMP
1358*4882a593Smuzhiyun &dhd_attr_cntl_memdump.attr,
1359*4882a593Smuzhiyun #endif /* DHD_FW_COREDUMP */
1360*4882a593Smuzhiyun #ifdef BCMASSERT_LOG
1361*4882a593Smuzhiyun &dhd_attr_cntl_assert.attr,
1362*4882a593Smuzhiyun #endif /* BCMASSERT_LOG */
1363*4882a593Smuzhiyun #ifdef WRITE_WLANINFO
1364*4882a593Smuzhiyun &dhd_attr_cntl_wifiver.attr,
1365*4882a593Smuzhiyun #endif /* WRITE_WLANINFO */
1366*4882a593Smuzhiyun #ifdef USE_CID_CHECK
1367*4882a593Smuzhiyun &dhd_attr_cntl_cidinfo.attr,
1368*4882a593Smuzhiyun #endif /* USE_CID_CHECK */
1369*4882a593Smuzhiyun #ifdef GEN_SOFTAP_INFO_FILE
1370*4882a593Smuzhiyun &dhd_attr_cntl_softapinfo.attr,
1371*4882a593Smuzhiyun #endif /* GEN_SOFTAP_INFO_FILE */
1372*4882a593Smuzhiyun #ifdef MIMO_ANT_SETTING
1373*4882a593Smuzhiyun &dhd_attr_cntl_antinfo.attr,
1374*4882a593Smuzhiyun #endif /* MIMO_ANT_SETTING */
1375*4882a593Smuzhiyun #ifdef DHD_PM_CONTROL_FROM_FILE
1376*4882a593Smuzhiyun &dhd_attr_cntl_pminfo.attr,
1377*4882a593Smuzhiyun #endif /* DHD_PM_CONTROL_FROM_FILE */
1378*4882a593Smuzhiyun #ifdef LOGTRACE_FROM_FILE
1379*4882a593Smuzhiyun &dhd_attr_cntl_logtraceinfo.attr,
1380*4882a593Smuzhiyun #endif /* LOGTRACE_FROM_FILE */
1381*4882a593Smuzhiyun #ifdef USE_WFA_CERT_CONF
1382*4882a593Smuzhiyun #ifdef BCMSDIO
1383*4882a593Smuzhiyun &dhd_attr_cntl_bustxglom.attr,
1384*4882a593Smuzhiyun #endif /* BCMSDIO */
1385*4882a593Smuzhiyun &dhd_attr_cntl_roamoff.attr,
1386*4882a593Smuzhiyun #ifdef USE_WL_FRAMEBURST
1387*4882a593Smuzhiyun &dhd_attr_cntl_frameburst.attr,
1388*4882a593Smuzhiyun #endif /* USE_WL_FRAMEBURST */
1389*4882a593Smuzhiyun #ifdef USE_WL_TXBF
1390*4882a593Smuzhiyun &dhd_attr_cntl_txbf.attr,
1391*4882a593Smuzhiyun #endif /* USE_WL_TXBF */
1392*4882a593Smuzhiyun #ifdef PROP_TXSTATUS
1393*4882a593Smuzhiyun &dhd_attr_cntl_proptx.attr,
1394*4882a593Smuzhiyun #endif /* PROP_TXSTATUS */
1395*4882a593Smuzhiyun #endif /* USE_WFA_CERT_CONF */
1396*4882a593Smuzhiyun #endif /* DHD_EXPORT_CNTL_FILE */
1397*4882a593Smuzhiyun #ifdef DHD_ADPS_BAM_EXPORT
1398*4882a593Smuzhiyun &dhd_attr_adps_bam.attr,
1399*4882a593Smuzhiyun #endif /* DHD_ADPS_BAM_EXPORT */
1400*4882a593Smuzhiyun #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1401*4882a593Smuzhiyun &dhd_attr_hang_privcmd_err.attr,
1402*4882a593Smuzhiyun #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1403*4882a593Smuzhiyun #if defined(CUSTOM_CONTROL_HE_ENAB)
1404*4882a593Smuzhiyun &dhd_attr_control_he_enab.attr,
1405*4882a593Smuzhiyun #endif /* CUSTOM_CONTROL_HE_ENAB */
1406*4882a593Smuzhiyun NULL
1407*4882a593Smuzhiyun };
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun #define to_cntl_dhd(k) container_of(k, struct dhd_info, dhd_conf_file_kobj)
1410*4882a593Smuzhiyun
1411*4882a593Smuzhiyun /*
1412*4882a593Smuzhiyun * wifi kobject show function, the "attr" attribute specifices to which
1413*4882a593Smuzhiyun * node under "sys/wifi" the show function is called.
1414*4882a593Smuzhiyun */
dhd_cntl_show(struct kobject * kobj,struct attribute * attr,char * buf)1415*4882a593Smuzhiyun static ssize_t dhd_cntl_show(struct kobject *kobj, struct attribute *attr, char *buf)
1416*4882a593Smuzhiyun {
1417*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1418*4882a593Smuzhiyun #pragma GCC diagnostic push
1419*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
1420*4882a593Smuzhiyun #endif // endif
1421*4882a593Smuzhiyun dhd_info_t *dhd = to_cntl_dhd(kobj);
1422*4882a593Smuzhiyun struct dhd_attr *d_attr = to_attr(attr);
1423*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1424*4882a593Smuzhiyun #pragma GCC diagnostic pop
1425*4882a593Smuzhiyun #endif // endif
1426*4882a593Smuzhiyun int ret;
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun if (d_attr->show)
1429*4882a593Smuzhiyun ret = d_attr->show(dhd, buf);
1430*4882a593Smuzhiyun else
1431*4882a593Smuzhiyun ret = -EIO;
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun return ret;
1434*4882a593Smuzhiyun }
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun /*
1437*4882a593Smuzhiyun * wifi kobject show function, the "attr" attribute specifices to which
1438*4882a593Smuzhiyun * node under "sys/wifi" the store function is called.
1439*4882a593Smuzhiyun */
dhd_cntl_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)1440*4882a593Smuzhiyun static ssize_t dhd_cntl_store(struct kobject *kobj, struct attribute *attr,
1441*4882a593Smuzhiyun const char *buf, size_t count)
1442*4882a593Smuzhiyun {
1443*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1444*4882a593Smuzhiyun #pragma GCC diagnostic push
1445*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
1446*4882a593Smuzhiyun #endif // endif
1447*4882a593Smuzhiyun dhd_info_t *dhd = to_cntl_dhd(kobj);
1448*4882a593Smuzhiyun struct dhd_attr *d_attr = to_attr(attr);
1449*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1450*4882a593Smuzhiyun #pragma GCC diagnostic pop
1451*4882a593Smuzhiyun #endif // endif
1452*4882a593Smuzhiyun int ret;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun if (d_attr->store)
1455*4882a593Smuzhiyun ret = d_attr->store(dhd, buf, count);
1456*4882a593Smuzhiyun else
1457*4882a593Smuzhiyun ret = -EIO;
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun return ret;
1460*4882a593Smuzhiyun
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun static struct sysfs_ops dhd_sysfs_cntl_ops = {
1464*4882a593Smuzhiyun .show = dhd_cntl_show,
1465*4882a593Smuzhiyun .store = dhd_cntl_store,
1466*4882a593Smuzhiyun };
1467*4882a593Smuzhiyun
1468*4882a593Smuzhiyun static struct kobj_type dhd_cntl_file_ktype = {
1469*4882a593Smuzhiyun .sysfs_ops = &dhd_sysfs_cntl_ops,
1470*4882a593Smuzhiyun .default_attrs = control_file_attrs,
1471*4882a593Smuzhiyun };
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun /* Create a kobject and attach to sysfs interface */
dhd_sysfs_init(dhd_info_t * dhd)1474*4882a593Smuzhiyun int dhd_sysfs_init(dhd_info_t *dhd)
1475*4882a593Smuzhiyun {
1476*4882a593Smuzhiyun int ret = -1;
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun if (dhd == NULL) {
1479*4882a593Smuzhiyun DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1480*4882a593Smuzhiyun return ret;
1481*4882a593Smuzhiyun }
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun /* Initialize the kobject */
1484*4882a593Smuzhiyun ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, SYSFS_DIR_BCMDHD);
1485*4882a593Smuzhiyun if (ret) {
1486*4882a593Smuzhiyun kobject_put(&dhd->dhd_kobj);
1487*4882a593Smuzhiyun DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1488*4882a593Smuzhiyun return ret;
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun ret = kobject_init_and_add(&dhd->dhd_conf_file_kobj,
1491*4882a593Smuzhiyun &dhd_cntl_file_ktype, NULL, SYSFS_DIR_WIFI);
1492*4882a593Smuzhiyun if (ret) {
1493*4882a593Smuzhiyun kobject_put(&dhd->dhd_conf_file_kobj);
1494*4882a593Smuzhiyun DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1495*4882a593Smuzhiyun return ret;
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun /*
1499*4882a593Smuzhiyun * We are always responsible for sending the uevent that the kobject
1500*4882a593Smuzhiyun * was added to the system.
1501*4882a593Smuzhiyun */
1502*4882a593Smuzhiyun kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD);
1503*4882a593Smuzhiyun kobject_uevent(&dhd->dhd_conf_file_kobj, KOBJ_ADD);
1504*4882a593Smuzhiyun
1505*4882a593Smuzhiyun return ret;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun /* Done with the kobject and detach the sysfs interface */
dhd_sysfs_exit(dhd_info_t * dhd)1509*4882a593Smuzhiyun void dhd_sysfs_exit(dhd_info_t *dhd)
1510*4882a593Smuzhiyun {
1511*4882a593Smuzhiyun if (dhd == NULL) {
1512*4882a593Smuzhiyun DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1513*4882a593Smuzhiyun return;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun /* Releae the kobject */
1517*4882a593Smuzhiyun kobject_put(&dhd->dhd_kobj);
1518*4882a593Smuzhiyun kobject_put(&dhd->dhd_conf_file_kobj);
1519*4882a593Smuzhiyun }
1520