xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_proc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /**  @file moal_proc.c
2  *
3  * @brief This file contains functions for proc file.
4  *
5  *
6  * Copyright 2008-2022 NXP
7  *
8  * This software file (the File) is distributed by NXP
9  * under the terms of the GNU General Public License Version 2, June 1991
10  * (the License).  You may use, redistribute and/or modify the File in
11  * accordance with the terms and conditions of the License, a copy of which
12  * is available by writing to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  * this warranty disclaimer.
20  *
21  */
22 
23 /********************************************************
24 Change log:
25     10/21/2008: initial version
26 ********************************************************/
27 
28 #include "moal_main.h"
29 #ifdef UAP_SUPPORT
30 #include "moal_uap.h"
31 #endif
32 #ifdef SDIO
33 #include "moal_sdio.h"
34 #endif
35 
36 /********************************************************
37 		Local Variables
38 ********************************************************/
39 #ifdef CONFIG_PROC_FS
40 #define STATUS_PROC "wifi_status"
41 #define MWLAN_PROC "mwlan"
42 #define WLAN_PROC "adapter%d"
43 /** Proc mwlan directory entry */
44 static struct proc_dir_entry *proc_mwlan;
45 
46 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
47 #define PROC_DIR NULL
48 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
49 #define PROC_DIR (&proc_root)
50 #else
51 #define PROC_DIR proc_net
52 #endif
53 
54 #ifdef STA_SUPPORT
55 static char *szModes[] = {
56 	"Unknown",
57 	"Managed",
58 	"Ad-hoc",
59 	"Auto",
60 };
61 #endif
62 
63 /********************************************************
64 		Global Variables
65 ********************************************************/
66 int wifi_status;
67 
68 /********************************************************
69 		Local Functions
70 ********************************************************/
71 /**
72  *  @brief Proc read function for info
73  *
74  *  @param sfp      pointer to seq_file structure
75  *  @param data
76  *
77  *  @return         Number of output data
78  */
woal_info_proc_read(struct seq_file * sfp,void * data)79 static int woal_info_proc_read(struct seq_file *sfp, void *data)
80 {
81 	struct net_device *netdev = (struct net_device *)sfp->private;
82 	char fmt[MLAN_MAX_VER_STR_LEN];
83 	moal_private *priv = (moal_private *)netdev_priv(netdev);
84 	mlan_fw_info fw_info;
85 #ifdef STA_SUPPORT
86 	int i = 0;
87 	moal_handle *handle = NULL;
88 	mlan_bss_info info;
89 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
90 	struct dev_mc_list *mcptr = netdev->mc_list;
91 	int mc_count = netdev->mc_count;
92 #else
93 	struct netdev_hw_addr *mcptr = NULL;
94 	int mc_count = netdev_mc_count(netdev);
95 #endif /* < 2.6.35 */
96 #else
97 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
98 	int i = 0;
99 #endif /* >= 2.6.29 */
100 #endif
101 #ifdef UAP_SUPPORT
102 	mlan_ds_uap_stats ustats;
103 #endif
104 	union {
105 		t_u32 l;
106 		t_u8 c[4];
107 	} ver;
108 
109 	fw_info.uuid_lo = fw_info.uuid_hi = 0x0ULL;
110 
111 	ENTER();
112 
113 	if (priv == NULL)
114 		goto exit;
115 #ifdef STA_SUPPORT
116 	handle = priv->phandle;
117 	if (handle == NULL)
118 		goto exit;
119 #endif
120 
121 	if (!MODULE_GET) {
122 		LEAVE();
123 		return 0;
124 	}
125 
126 	memset(fmt, 0, sizeof(fmt));
127 #ifdef UAP_SUPPORT
128 	memset(&ustats, 0, sizeof(ustats));
129 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
130 		seq_printf(sfp, "driver_name = "
131 				"\"uap\"\n");
132 		woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
133 		if (MLAN_STATUS_SUCCESS !=
134 		    woal_uap_get_stats(priv, MOAL_IOCTL_WAIT, &ustats)) {
135 			MODULE_PUT;
136 			LEAVE();
137 			return -EFAULT;
138 		}
139 	}
140 #endif /* UAP_SUPPORT*/
141 #ifdef STA_SUPPORT
142 	memset(&info, 0, sizeof(info));
143 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
144 		woal_get_version(handle, fmt, sizeof(fmt) - 1);
145 		if (MLAN_STATUS_SUCCESS !=
146 		    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &info)) {
147 			MODULE_PUT;
148 			LEAVE();
149 			return -EFAULT;
150 		}
151 		seq_printf(sfp, "driver_name = "
152 				"\"wlan\"\n");
153 	}
154 #endif
155 	seq_printf(sfp, "driver_version = %s", fmt);
156 	seq_printf(sfp, "\ninterface_name=\"%s\"\n", netdev->name);
157 	ver.l = handle->fw_release_number;
158 	seq_printf(sfp, "firmware_major_version=%u.%u.%u\n", ver.c[2], ver.c[1],
159 		   ver.c[0]);
160 
161 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
162 	if (fw_info.uuid_lo || fw_info.uuid_hi)
163 		seq_printf(sfp, "uuid = %llx%llx\n", fw_info.uuid_lo,
164 			   fw_info.uuid_hi);
165 #ifdef WIFI_DIRECT_SUPPORT
166 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
167 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
168 			seq_printf(sfp, "bss_mode = \"WIFIDIRECT-Client\"\n");
169 		else
170 			seq_printf(sfp, "bss_mode = \"WIFIDIRECT-GO\"\n");
171 	}
172 #endif
173 #ifdef STA_SUPPORT
174 	if (priv->bss_type == MLAN_BSS_TYPE_STA)
175 		seq_printf(sfp, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
176 #endif
177 	seq_printf(sfp, "media_state=\"%s\"\n",
178 		   ((priv->media_connected == MFALSE) ? "Disconnected" :
179 							"Connected"));
180 	seq_printf(sfp, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
181 		   netdev->dev_addr[0], netdev->dev_addr[1],
182 		   netdev->dev_addr[2], netdev->dev_addr[3],
183 		   netdev->dev_addr[4], netdev->dev_addr[5]);
184 #ifdef STA_SUPPORT
185 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
186 		seq_printf(sfp, "multicast_count=\"%d\"\n", mc_count);
187 		seq_printf(sfp, "essid=\"%s\"\n", info.ssid.ssid);
188 		seq_printf(sfp, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
189 			   info.bssid[0], info.bssid[1], info.bssid[2],
190 			   info.bssid[3], info.bssid[4], info.bssid[5]);
191 		seq_printf(sfp, "channel=\"%d\"\n", (int)info.bss_chan);
192 		seq_printf(sfp, "region_code = \"%02x\"\n",
193 			   (t_u8)info.region_code);
194 
195 		/*
196 		 * Put out the multicast list
197 		 */
198 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
199 		for (i = 0; i < netdev->mc_count; i++) {
200 			seq_printf(
201 				sfp,
202 				"multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
203 				i, mcptr->dmi_addr[0], mcptr->dmi_addr[1],
204 				mcptr->dmi_addr[2], mcptr->dmi_addr[3],
205 				mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
206 
207 			mcptr = mcptr->next;
208 		}
209 #else
210 		netdev_for_each_mc_addr (mcptr, netdev)
211 			seq_printf(
212 				sfp,
213 				"multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
214 				i++, mcptr->addr[0], mcptr->addr[1],
215 				mcptr->addr[2], mcptr->addr[3], mcptr->addr[4],
216 				mcptr->addr[5]);
217 #endif /* < 2.6.35 */
218 	}
219 #endif
220 	seq_printf(sfp, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
221 	seq_printf(sfp, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
222 	seq_printf(sfp, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
223 	seq_printf(sfp, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
224 	seq_printf(sfp, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
225 	seq_printf(sfp, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
226 	seq_printf(sfp, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
227 	seq_printf(sfp, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
228 	seq_printf(sfp, "carrier %s\n",
229 		   ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
230 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
231 	for (i = 0; i < (int)netdev->num_tx_queues; i++) {
232 		seq_printf(sfp, "tx queue %d:  %s\n", i,
233 			   ((netif_tx_queue_stopped(
234 				    netdev_get_tx_queue(netdev, 0))) ?
235 				    "stopped" :
236 				    "started"));
237 	}
238 #else
239 	seq_printf(sfp, "tx queue %s\n",
240 		   ((netif_queue_stopped(priv->netdev)) ? "stopped" :
241 							  "started"));
242 #endif
243 #ifdef UAP_SUPPORT
244 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
245 		seq_printf(sfp, "tkip_mic_failures = %u\n",
246 			   ustats.tkip_mic_failures);
247 		seq_printf(sfp, "ccmp_decrypt_errors = %u\n",
248 			   ustats.ccmp_decrypt_errors);
249 		seq_printf(sfp, "wep_undecryptable_count = %u\n",
250 			   ustats.wep_undecryptable_count);
251 		seq_printf(sfp, "wep_icv_error_count = %u\n",
252 			   ustats.wep_icv_error_count);
253 		seq_printf(sfp, "decrypt_failure_count = %u\n",
254 			   ustats.decrypt_failure_count);
255 		seq_printf(sfp, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
256 		seq_printf(sfp, "failed_count = %u\n", ustats.failed_count);
257 		seq_printf(sfp, "retry_count = %u\n", ustats.retry_count);
258 		seq_printf(sfp, "multiple_retry_count = %u\n",
259 			   ustats.multi_retry_count);
260 		seq_printf(sfp, "frame_duplicate_count = %u\n",
261 			   ustats.frame_dup_count);
262 		seq_printf(sfp, "rts_success_count = %u\n",
263 			   ustats.rts_success_count);
264 		seq_printf(sfp, "rts_failure_count = %u\n",
265 			   ustats.rts_failure_count);
266 		seq_printf(sfp, "ack_failure_count = %u\n",
267 			   ustats.ack_failure_count);
268 		seq_printf(sfp, "rx_fragment_count = %u\n",
269 			   ustats.rx_fragment_count);
270 		seq_printf(sfp, "mcast_rx_frame_count = %u\n",
271 			   ustats.mcast_rx_frame_count);
272 		seq_printf(sfp, "fcs_error_count = %u\n",
273 			   ustats.fcs_error_count);
274 		seq_printf(sfp, "tx_frame_count = %u\n", ustats.tx_frame_count);
275 		seq_printf(sfp, "rsna_tkip_cm_invoked = %u\n",
276 			   ustats.rsna_tkip_cm_invoked);
277 		seq_printf(sfp, "rsna_4way_hshk_failures = %u\n",
278 			   ustats.rsna_4way_hshk_failures);
279 	}
280 #endif /* UAP_SUPPORT */
281 	seq_printf(sfp, "=== tp_acnt.on:%d drop_point:%d ===\n",
282 		   handle->tp_acnt.on, handle->tp_acnt.drop_point);
283 	seq_printf(sfp, "====Tx accounting====\n");
284 	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
285 		seq_printf(sfp, "[%d] Tx packets     : %lu\n", i,
286 			   handle->tp_acnt.tx_packets[i]);
287 		seq_printf(sfp, "[%d] Tx packets last: %lu\n", i,
288 			   handle->tp_acnt.tx_packets_last[i]);
289 		seq_printf(sfp, "[%d] Tx packets rate: %lu\n", i,
290 			   handle->tp_acnt.tx_packets_rate[i]);
291 		seq_printf(sfp, "[%d] Tx bytes       : %lu\n", i,
292 			   handle->tp_acnt.tx_bytes[i]);
293 		seq_printf(sfp, "[%d] Tx bytes last  : %lu\n", i,
294 			   handle->tp_acnt.tx_bytes_last[i]);
295 		seq_printf(sfp, "[%d] Tx bytes rate  : %luMbps\n", i,
296 			   handle->tp_acnt.tx_bytes_rate[i] * 8 / 1024 / 1024);
297 	}
298 	seq_printf(sfp, "Tx amsdu cnt		: %lu\n",
299 		   handle->tp_acnt.tx_amsdu_cnt);
300 	seq_printf(sfp, "Tx amsdu cnt last	: %lu\n",
301 		   handle->tp_acnt.tx_amsdu_cnt_last);
302 	seq_printf(sfp, "Tx amsdu cnt rate	: %lu\n",
303 		   handle->tp_acnt.tx_amsdu_cnt_rate);
304 	seq_printf(sfp, "Tx amsdu pkt cnt	: %lu\n",
305 		   handle->tp_acnt.tx_amsdu_pkt_cnt);
306 	seq_printf(sfp, "Tx amsdu pkt cnt last : %lu\n",
307 		   handle->tp_acnt.tx_amsdu_pkt_cnt_last);
308 	seq_printf(sfp, "Tx amsdu pkt cnt rate : %lu\n",
309 		   handle->tp_acnt.tx_amsdu_pkt_cnt_rate);
310 	seq_printf(sfp, "Tx intr cnt    		: %lu\n",
311 		   handle->tp_acnt.tx_intr_cnt);
312 	seq_printf(sfp, "Tx intr last        : %lu\n",
313 		   handle->tp_acnt.tx_intr_last);
314 	seq_printf(sfp, "Tx intr rate        : %lu\n",
315 		   handle->tp_acnt.tx_intr_rate);
316 	seq_printf(sfp, "Tx pending          : %lu\n",
317 		   handle->tp_acnt.tx_pending);
318 	seq_printf(sfp, "Tx xmit skb realloc : %lu\n",
319 		   handle->tp_acnt.tx_xmit_skb_realloc_cnt);
320 	seq_printf(sfp, "Tx stop queue cnt : %lu\n",
321 		   handle->tp_acnt.tx_stop_queue_cnt);
322 	seq_printf(sfp, "====Rx accounting====\n");
323 	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
324 		seq_printf(sfp, "[%d] Rx packets     : %lu\n", i,
325 			   handle->tp_acnt.rx_packets[i]);
326 		seq_printf(sfp, "[%d] Rx packets last: %lu\n", i,
327 			   handle->tp_acnt.rx_packets_last[i]);
328 		seq_printf(sfp, "[%d] Rx packets rate: %lu\n", i,
329 			   handle->tp_acnt.rx_packets_rate[i]);
330 		seq_printf(sfp, "[%d] Rx bytes       : %lu\n", i,
331 			   handle->tp_acnt.rx_bytes[i]);
332 		seq_printf(sfp, "[%d] Rx bytes last  : %lu\n", i,
333 			   handle->tp_acnt.rx_bytes_last[i]);
334 		seq_printf(sfp, "[%d] Rx bytes rate  : %luMbps\n", i,
335 			   handle->tp_acnt.rx_bytes_rate[i] * 8 / 1024 / 1024);
336 	}
337 	seq_printf(sfp, "Rx amsdu cnt		 : %lu\n",
338 		   handle->tp_acnt.rx_amsdu_cnt);
339 	seq_printf(sfp, "Rx amsdu cnt last	 : %lu\n",
340 		   handle->tp_acnt.rx_amsdu_cnt_last);
341 	seq_printf(sfp, "Rx amsdu cnt rate	 : %lu\n",
342 		   handle->tp_acnt.rx_amsdu_cnt_rate);
343 	seq_printf(sfp, "Rx amsdu pkt cnt	 : %lu\n",
344 		   handle->tp_acnt.rx_amsdu_pkt_cnt);
345 	seq_printf(sfp, "Rx amsdu pkt cnt last : %lu\n",
346 		   handle->tp_acnt.rx_amsdu_pkt_cnt_last);
347 	seq_printf(sfp, "Rx amsdu pkt cnt rate : %lu\n",
348 		   handle->tp_acnt.rx_amsdu_pkt_cnt_rate);
349 	seq_printf(sfp, "Rx intr cnt    	 : %lu\n",
350 		   handle->tp_acnt.rx_intr_cnt);
351 	seq_printf(sfp, "Rx intr last        : %lu\n",
352 		   handle->tp_acnt.rx_intr_last);
353 	seq_printf(sfp, "Rx intr rate        : %lu\n",
354 		   handle->tp_acnt.rx_intr_rate);
355 	seq_printf(sfp, "Rx pending          : %lu\n",
356 		   handle->tp_acnt.rx_pending);
357 	seq_printf(sfp, "Rx pause            : %lu\n",
358 		   handle->tp_acnt.rx_paused_cnt);
359 	seq_printf(sfp, "Rx rdptr full cnt   : %lu\n",
360 		   handle->tp_acnt.rx_rdptr_full_cnt);
361 exit:
362 	LEAVE();
363 	MODULE_PUT;
364 	return 0;
365 }
366 
woal_info_proc_open(struct inode * inode,struct file * file)367 static int woal_info_proc_open(struct inode *inode, struct file *file)
368 {
369 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
370 	return single_open(file, woal_info_proc_read, pde_data(inode));
371 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
372 	return single_open(file, woal_info_proc_read, PDE_DATA(inode));
373 #else
374 	return single_open(file, woal_info_proc_read, PDE(inode)->data);
375 #endif
376 }
377 
378 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
379 static const struct proc_ops info_proc_fops = {
380 	.proc_open = woal_info_proc_open,
381 	.proc_read = seq_read,
382 	.proc_lseek = seq_lseek,
383 	.proc_release = single_release,
384 };
385 #else
386 static const struct file_operations info_proc_fops = {
387 	.owner = THIS_MODULE,
388 	.open = woal_info_proc_open,
389 	.read = seq_read,
390 	.llseek = seq_lseek,
391 	.release = single_release,
392 };
393 #endif
394 
395 #ifdef SDIO
396 #define CMD52_STR_LEN 50
397 /*
398  *  @brief Parse cmd52 string
399  *
400  *  @param buffer   A pointer user buffer
401  *  @param len      Length user buffer
402  *  @param func     Parsed func number
403  *  @param reg      Parsed reg value
404  *  @param val      Parsed value to set
405  *  @return         BT_STATUS_SUCCESS
406  */
parse_cmd52_string(const char * buffer,size_t len,int * func,int * reg,int * val)407 static int parse_cmd52_string(const char *buffer, size_t len, int *func,
408 			      int *reg, int *val)
409 {
410 	int ret = MLAN_STATUS_SUCCESS;
411 	char *string = NULL;
412 	char *pos = NULL;
413 	gfp_t flag;
414 
415 	ENTER();
416 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
417 	string = kzalloc(CMD52_STR_LEN, flag);
418 	if (string == NULL)
419 		return -ENOMEM;
420 
421 	moal_memcpy_ext(NULL, string, buffer + strlen("sdcmd52rw="),
422 			len - strlen("sdcmd52rw="), CMD52_STR_LEN - 1);
423 	string = strstrip(string);
424 
425 	*func = -1;
426 	*reg = -1;
427 	*val = -1;
428 
429 	/* Get func */
430 	pos = strsep(&string, " \t");
431 	if (pos)
432 		*func = woal_string_to_number(pos);
433 
434 	/* Get reg */
435 	pos = strsep(&string, " \t");
436 	if (pos)
437 		*reg = woal_string_to_number(pos);
438 
439 	/* Get val (optional) */
440 	pos = strsep(&string, " \t");
441 	if (pos)
442 		*val = woal_string_to_number(pos);
443 	kfree(string);
444 	LEAVE();
445 	return ret;
446 }
447 #endif
448 
449 /**
450  *  @brief config proc write function
451  *
452  *  @param f        file pointer
453  *  @param buf      pointer to data buffer
454  *  @param count    data number to write
455  *  @param off      Offset
456  *
457  *  @return         number of data
458  */
woal_config_write(struct file * f,const char __user * buf,size_t count,loff_t * off)459 static ssize_t woal_config_write(struct file *f, const char __user *buf,
460 				 size_t count, loff_t *off)
461 {
462 	char databuf[200];
463 	char *line = NULL;
464 	t_u32 config_data = 0;
465 	struct seq_file *sfp = f->private_data;
466 	moal_handle *handle = (moal_handle *)sfp->private;
467 
468 #ifdef SDIO
469 	int func = 0, reg = 0, val = 0;
470 #endif
471 	moal_handle *ref_handle = NULL;
472 	t_u32 cmd = 0;
473 	int copy_len;
474 	moal_private *priv = NULL;
475 
476 	ENTER();
477 	if (!MODULE_GET) {
478 		LEAVE();
479 		return 0;
480 	}
481 
482 	if (count >= sizeof(databuf)) {
483 		MODULE_PUT;
484 		LEAVE();
485 		return (int)count;
486 	}
487 	memset(databuf, 0, sizeof(databuf));
488 	copy_len = MIN((sizeof(databuf) - 1), count);
489 	if (copy_from_user(databuf, buf, copy_len)) {
490 		MODULE_PUT;
491 		LEAVE();
492 		return 0;
493 	}
494 	line = databuf;
495 	if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
496 		line += strlen("soft_reset") + 1;
497 		config_data = (t_u32)woal_string_to_number(line);
498 		PRINTM(MINFO, "soft_reset: %d\n", (int)config_data);
499 		if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS)
500 			handle->hardware_status = HardwareStatusReset;
501 		else
502 			PRINTM(MERROR, "Could not perform soft reset\n");
503 	}
504 	if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
505 		line += strlen("drv_mode") + 1;
506 		config_data = (t_u32)woal_string_to_number(line);
507 		PRINTM(MINFO, "drv_mode: %d\n", (int)config_data);
508 		if (config_data != (t_u32)handle->params.drv_mode)
509 			if (woal_switch_drv_mode(handle, config_data) !=
510 			    MLAN_STATUS_SUCCESS) {
511 				PRINTM(MERROR, "Could not switch drv mode\n");
512 			}
513 	}
514 #ifdef SDIO
515 	if (IS_SD(handle->card_type)) {
516 		if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw=")) &&
517 		    count > strlen("sdcmd52rw=")) {
518 			parse_cmd52_string((const char *)databuf, (size_t)count,
519 					   &func, &reg, &val);
520 			woal_sdio_read_write_cmd52(handle, func, reg, val);
521 		}
522 	}
523 #endif /* SD */
524 	if (!strncmp(databuf, "debug_dump", strlen("debug_dump"))) {
525 		PRINTM(MERROR, "Recevie debug_dump command\n");
526 #ifdef USB
527 		if (!IS_USB(handle->card_type))
528 #endif
529 			handle->driver_status = MTRUE;
530 		ref_handle = (moal_handle *)handle->pref_mac;
531 		if (ref_handle) {
532 			priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
533 			if (priv) {
534 				handle->fw_dump_status = MTRUE;
535 				woal_mlan_debug_info(priv);
536 				woal_moal_debug_info(priv, NULL, MFALSE);
537 			}
538 		}
539 		priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
540 		if (priv) {
541 			handle->fw_dump_status = MTRUE;
542 			woal_mlan_debug_info(priv);
543 			woal_moal_debug_info(priv, NULL, MFALSE);
544 			handle->ops.dump_fw_info(handle);
545 		}
546 	}
547 
548 	if (!strncmp(databuf, "fwdump_file=", strlen("fwdump_file="))) {
549 		int len = copy_len - strlen("fwdump_file=");
550 		gfp_t flag;
551 		if (len) {
552 			kfree(handle->fwdump_fname);
553 			flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC :
554 								  GFP_KERNEL;
555 			handle->fwdump_fname = kzalloc(len, flag);
556 			if (handle->fwdump_fname)
557 				moal_memcpy_ext(handle, handle->fwdump_fname,
558 						databuf +
559 							strlen("fwdump_file="),
560 						len - 1, len - 1);
561 		}
562 	}
563 	if (!strncmp(databuf, "fw_reload", strlen("fw_reload"))) {
564 		if (!strncmp(databuf, "fw_reload=", strlen("fw_reload="))) {
565 			line += strlen("fw_reload") + 1;
566 			config_data = (t_u32)woal_string_to_number(line);
567 		}
568 #ifdef SDIO_MMC
569 		else if (IS_SD(handle->card_type))
570 			config_data = FW_RELOAD_SDIO_INBAND_RESET;
571 #endif
572 		PRINTM(MMSG, "Request fw_reload=%d\n", config_data);
573 		woal_request_fw_reload(handle, config_data);
574 	}
575 	if (!strncmp(databuf, "drop_point=", strlen("drop_point="))) {
576 		line += strlen("drop_point") + 1;
577 		config_data = (t_u32)woal_string_to_number(line);
578 		if (config_data) {
579 			handle->tp_acnt.on = 1;
580 			handle->tp_acnt.drop_point = config_data;
581 			if (handle->is_tp_acnt_timer_set == MFALSE) {
582 				woal_initialize_timer(&handle->tp_acnt.timer,
583 						      woal_tp_acnt_timer_func,
584 						      handle);
585 				handle->is_tp_acnt_timer_set = MTRUE;
586 				woal_mod_timer(&handle->tp_acnt.timer, 1000);
587 			}
588 		} else {
589 			if (handle->is_tp_acnt_timer_set) {
590 				woal_cancel_timer(&handle->tp_acnt.timer);
591 				handle->is_tp_acnt_timer_set = MFALSE;
592 			}
593 			memset((void *)&handle->tp_acnt, 0,
594 			       sizeof(moal_tp_acnt_t));
595 		}
596 		priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
597 		if (priv)
598 			woal_set_tp_state(priv);
599 		PRINTM(MMSG, "on=%d drop_point=%d\n", handle->tp_acnt.on,
600 		       handle->tp_acnt.drop_point);
601 	}
602 	if (!strncmp(databuf, "hssetpara=", strlen("hssetpara="))) {
603 		line += strlen("hssetpara") + 1;
604 		PRINTM(MCMND, "hssetpara=%s\n", line);
605 		woal_process_proc_hssetpara(handle, line);
606 	}
607 	if (!strncmp(databuf, "rf_test_mode", strlen("rf_test_mode"))) {
608 		line += strlen("rf_test_mode") + 1;
609 		config_data = (t_u32)woal_string_to_number(line);
610 		PRINTM(MINFO, "RF test mode: %d\n", (int)config_data);
611 		if (config_data != (t_u32)handle->rf_test_mode)
612 			if (woal_process_rf_test_mode(handle, config_data) !=
613 			    MLAN_STATUS_SUCCESS)
614 				PRINTM(MERROR, "Could not set RF test mode\n");
615 	}
616 	if (!strncmp(databuf, "tx_antenna", strlen("tx_antenna"))) {
617 		line += strlen("tx_antenna") + 1;
618 		config_data = (t_u32)woal_string_to_number(line);
619 		cmd = MFG_CMD_TX_ANT;
620 	}
621 	if (!strncmp(databuf, "rx_antenna", strlen("rx_antenna"))) {
622 		line += strlen("rx_antenna") + 1;
623 		config_data = (t_u32)woal_string_to_number(line);
624 		cmd = MFG_CMD_RX_ANT;
625 	}
626 	if (!strncmp(databuf, "radio_mode", strlen("radio_mode"))) {
627 		line += strlen("radio_mode") + 1;
628 		config_data = (t_u32)woal_string_to_number(line);
629 		cmd = MFG_CMD_RADIO_MODE_CFG;
630 	}
631 	if (!strncmp(databuf, "channel", strlen("channel"))) {
632 		line += strlen("channel") + 1;
633 		config_data = (t_u32)woal_string_to_number(line);
634 		cmd = MFG_CMD_RF_CHAN;
635 	}
636 	if (!strncmp(databuf, "band", strlen("band"))) {
637 		line += strlen("band") + 1;
638 		config_data = (t_u32)woal_string_to_number(line);
639 		cmd = MFG_CMD_RF_BAND_AG;
640 	}
641 	if (!strncmp(databuf, "bw", strlen("bw"))) {
642 		line += strlen("bw") + 1;
643 		config_data = (t_u32)woal_string_to_number(line);
644 		cmd = MFG_CMD_RF_CHANNELBW;
645 	}
646 	if (!strncmp(databuf, "get_and_reset_per", strlen("get_and_reset_per")))
647 		cmd = MFG_CMD_CLR_RX_ERR;
648 	if (!strncmp(databuf, "tx_power=", strlen("tx_power=")) &&
649 	    count > strlen("tx_power="))
650 		cmd = MFG_CMD_RFPWR;
651 	if (!strncmp(databuf, "tx_frame=", strlen("tx_frame=")) &&
652 	    count > strlen("tx_frame="))
653 		cmd = MFG_CMD_TX_FRAME;
654 	if (!strncmp(databuf, "tx_continuous=", strlen("tx_continuous=")) &&
655 	    count > strlen("tx_continuous="))
656 		cmd = MFG_CMD_TX_CONT;
657 	if (!strncmp(databuf, "he_tb_tx=", strlen("he_tb_tx=")) &&
658 	    count > strlen("he_tb_tx="))
659 		cmd = MFG_CMD_CONFIG_MAC_HE_TB_TX;
660 
661 	if (cmd && handle->rf_test_mode &&
662 	    (woal_process_rf_test_mode_cmd(
663 		     handle, cmd, (const char *)databuf, (size_t)count,
664 		     MLAN_ACT_SET, config_data) != MLAN_STATUS_SUCCESS)) {
665 		PRINTM(MERROR, "RF test mode cmd error\n");
666 	}
667 	if (cmd && !handle->rf_test_mode)
668 		PRINTM(MERROR, "RF test mode is disabled\n");
669 	MODULE_PUT;
670 	LEAVE();
671 	return (int)count;
672 }
673 
674 /**
675  *  @brief config proc read function
676  *
677  *  @param sfp      pointer to seq_file structure
678  *  @param data
679  *
680  *  @return         number of output data
681  */
woal_config_read(struct seq_file * sfp,void * data)682 static int woal_config_read(struct seq_file *sfp, void *data)
683 {
684 	moal_handle *handle = (moal_handle *)sfp->private;
685 	int i;
686 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
687 	mlan_ds_hs_cfg hscfg;
688 
689 	ENTER();
690 
691 	if (!MODULE_GET) {
692 		LEAVE();
693 		return 0;
694 	}
695 
696 	seq_printf(sfp, "hardware_status=%d\n", (int)handle->hardware_status);
697 	seq_printf(sfp, "netlink_num=%d\n", (int)handle->netlink_num);
698 	seq_printf(sfp, "drv_mode=%d\n", (int)handle->params.drv_mode);
699 	if (priv) {
700 		memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
701 		woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
702 				       &hscfg);
703 		seq_printf(sfp, "hssetpara=%d,0x%x,%d,%d\n", hscfg.conditions,
704 			   hscfg.gpio, hscfg.gap, hscfg.hs_wake_interval);
705 	}
706 #ifdef SDIO
707 	if (IS_SD(handle->card_type)) {
708 		seq_printf(sfp, "sdcmd52rw=%d 0x%0x 0x%02X\n",
709 			   handle->cmd52_func, handle->cmd52_reg,
710 			   handle->cmd52_val);
711 	}
712 #endif /* SD */
713 	seq_printf(sfp, "rf_test_mode=%u\n", handle->rf_test_mode);
714 	if (handle->rf_test_mode && handle->rf_data) {
715 		seq_printf(sfp, "tx_antenna=%u\n", handle->rf_data->tx_antenna);
716 		seq_printf(sfp, "rx_antenna=%u\n", handle->rf_data->rx_antenna);
717 		seq_printf(sfp, "band=%u\n", handle->rf_data->band);
718 		seq_printf(sfp, "bw=%u\n", handle->rf_data->bandwidth);
719 		if (handle->rf_data->channel)
720 			seq_printf(sfp, "channel=%u\n",
721 				   handle->rf_data->channel);
722 		else
723 			seq_printf(sfp, "channel=\n");
724 		if (handle->rf_data->radio_mode[0])
725 			seq_printf(sfp, "radio_mode[0]=%u\n",
726 				   handle->rf_data->radio_mode[0]);
727 		else
728 			seq_printf(sfp, "radio_mode[0]=\n");
729 		if (handle->rf_data->radio_mode[1])
730 			seq_printf(sfp, "radio_mode[1]=%u\n",
731 				   handle->rf_data->radio_mode[1]);
732 		else
733 			seq_printf(sfp, "radio_mode[1]=\n");
734 		seq_printf(sfp, "total rx pkt count=%u\n",
735 			   handle->rf_data->rx_tot_pkt_count);
736 		seq_printf(sfp, "rx multicast/broadcast pkt count=%u\n",
737 			   handle->rf_data->rx_mcast_bcast_pkt_count);
738 		seq_printf(sfp, "rx fcs error pkt count=%u\n",
739 			   handle->rf_data->rx_pkt_fcs_err_count);
740 		if (handle->rf_data->tx_power_data[0]) {
741 			seq_printf(sfp, "tx_power=%u",
742 				   handle->rf_data->tx_power_data[0]);
743 			seq_printf(sfp, " %u",
744 				   handle->rf_data->tx_power_data[1]);
745 			seq_printf(sfp, " %u\n",
746 				   handle->rf_data->tx_power_data[2]);
747 		} else
748 			seq_printf(sfp, "tx_power=\n");
749 		seq_printf(sfp, "tx_continuous=%u",
750 			   handle->rf_data->tx_cont_data[0]);
751 		if (handle->rf_data->tx_cont_data[0] == MTRUE) {
752 			seq_printf(sfp, " %u",
753 				   handle->rf_data->tx_cont_data[1]);
754 			seq_printf(sfp, " 0x%x",
755 				   handle->rf_data->tx_cont_data[2]);
756 			for (i = 3; i < 6; i++)
757 				seq_printf(sfp, " %u",
758 					   handle->rf_data->tx_cont_data[i]);
759 		}
760 		seq_printf(sfp, "\n");
761 		seq_printf(sfp, "tx_frame=%u",
762 			   handle->rf_data->tx_frame_data[0]);
763 		if (handle->rf_data->tx_frame_data[0] == MTRUE) {
764 			seq_printf(sfp, " %u",
765 				   handle->rf_data->tx_frame_data[1]);
766 			seq_printf(sfp, " 0x%x",
767 				   handle->rf_data->tx_frame_data[2]);
768 			for (i = 3; i < 13; i++)
769 				seq_printf(sfp, " %u",
770 					   handle->rf_data->tx_frame_data[i]);
771 			for (i = 13; i < 20; i++)
772 				seq_printf(sfp, " %d",
773 					   handle->rf_data->tx_frame_data[i]);
774 			seq_printf(sfp, " %02x:%02x:%02x:%02x:%02x:%02x",
775 				   handle->rf_data->bssid[0],
776 				   handle->rf_data->bssid[1],
777 				   handle->rf_data->bssid[2],
778 				   handle->rf_data->bssid[3],
779 				   handle->rf_data->bssid[4],
780 				   handle->rf_data->bssid[5]);
781 		}
782 		seq_printf(sfp, "\n");
783 		seq_printf(sfp, "he_tb_tx=%u", handle->rf_data->he_tb_tx[0]);
784 		if (handle->rf_data->he_tb_tx[0] == MTRUE) {
785 			seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[1]);
786 			seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[2]);
787 			seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[3]);
788 			seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[4]);
789 		}
790 		seq_printf(sfp, "\n");
791 	}
792 	MODULE_PUT;
793 	LEAVE();
794 	return 0;
795 }
796 
woal_config_proc_open(struct inode * inode,struct file * file)797 static int woal_config_proc_open(struct inode *inode, struct file *file)
798 {
799 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
800 	return single_open(file, woal_config_read, pde_data(inode));
801 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
802 	return single_open(file, woal_config_read, PDE_DATA(inode));
803 #else
804 	return single_open(file, woal_config_read, PDE(inode)->data);
805 #endif
806 }
807 
808 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
809 static const struct proc_ops config_proc_fops = {
810 	.proc_open = woal_config_proc_open,
811 	.proc_read = seq_read,
812 	.proc_lseek = seq_lseek,
813 	.proc_release = single_release,
814 	.proc_write = woal_config_write,
815 };
816 #else
817 static const struct file_operations config_proc_fops = {
818 	.owner = THIS_MODULE,
819 	.open = woal_config_proc_open,
820 	.read = seq_read,
821 	.llseek = seq_lseek,
822 	.release = single_release,
823 	.write = woal_config_write,
824 };
825 #endif
826 
woal_drv_dump_read(struct seq_file * sfp,void * data)827 static int woal_drv_dump_read(struct seq_file *sfp, void *data)
828 {
829 	moal_handle *handle = (moal_handle *)sfp->private;
830 	int ret = 0;
831 
832 	ENTER();
833 
834 	if (MODULE_GET == 0) {
835 		LEAVE();
836 		return 0;
837 	}
838 
839 	if (!handle) {
840 		PRINTM(MERROR, "handle is NULL!\n");
841 		LEAVE();
842 		return 0;
843 	}
844 	if (!handle->drv_dump_buf || !handle->drv_dump_len)
845 		handle->drv_dump_buf =
846 			woal_dump_drv_info(handle, &handle->drv_dump_len);
847 	if (!handle->drv_dump_buf || !handle->drv_dump_len) {
848 		PRINTM(MERROR,
849 		       "driver dump buffer is NULL or total length is zero\n");
850 		goto done;
851 	}
852 	if (sfp->size < handle->drv_dump_len) {
853 		PRINTM(MERROR,
854 		       "drv dump size too big, size=%d, drv_dump_len=%d\n",
855 		       (int)sfp->size, handle->drv_dump_len);
856 		sfp->count = sfp->size;
857 		ret = 0;
858 		MODULE_PUT;
859 		return ret;
860 	}
861 	memset(sfp->buf, 0x00, sfp->size);
862 	sfp->count = handle->drv_dump_len;
863 	moal_memcpy_ext(handle, sfp->buf, handle->drv_dump_buf,
864 			handle->drv_dump_len, sfp->size);
865 done:
866 	moal_vfree(handle, handle->drv_dump_buf);
867 	handle->drv_dump_len = 0;
868 	handle->drv_dump_buf = NULL;
869 	MODULE_PUT;
870 	LEAVE();
871 	return 0;
872 }
873 
woal_drv_dump_proc_open(struct inode * inode,struct file * file)874 static int woal_drv_dump_proc_open(struct inode *inode, struct file *file)
875 {
876 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
877 	return single_open(file, woal_drv_dump_read, pde_data(inode));
878 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
879 	return single_open(file, woal_drv_dump_read, PDE_DATA(inode));
880 #else
881 	return single_open(file, woal_drv_dump_read, PDE(inode)->data);
882 #endif
883 }
884 
885 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
886 static const struct proc_ops drv_dump_fops = {
887 	.proc_open = woal_drv_dump_proc_open,
888 	.proc_read = seq_read,
889 	.proc_lseek = seq_lseek,
890 	.proc_release = single_release,
891 };
892 #else
893 static const struct file_operations drv_dump_fops = {
894 	.owner = THIS_MODULE,
895 	.open = woal_drv_dump_proc_open,
896 	.read = seq_read,
897 	.llseek = seq_lseek,
898 	.release = single_release,
899 };
900 #endif
901 
woal_fw_dump_read(struct seq_file * sfp,void * data)902 static int woal_fw_dump_read(struct seq_file *sfp, void *data)
903 {
904 	moal_handle *handle = (moal_handle *)sfp->private;
905 	int ret = 0;
906 
907 	ENTER();
908 
909 	if (MODULE_GET == 0) {
910 		LEAVE();
911 		return 0;
912 	}
913 
914 	if (!handle) {
915 		PRINTM(MERROR, "handle is null!\n");
916 		goto done;
917 	}
918 
919 	if (handle->fw_dump == MTRUE) {
920 		PRINTM(MERROR, "fw dump is in progress\n");
921 		goto done;
922 	}
923 
924 	if (!handle->fw_dump_buf || !handle->fw_dump_len) {
925 		PRINTM(MERROR,
926 		       "fw dump buffer is NULL or total length is zero\n");
927 		goto done;
928 	}
929 
930 	if (sfp->size < handle->fw_dump_len) {
931 		PRINTM(MERROR,
932 		       "fw dump size too big, size=%d, fw_dump_len=%ld\n",
933 		       (int)sfp->size, (long int)handle->fw_dump_len);
934 		sfp->count = sfp->size;
935 		ret = 0;
936 		MODULE_PUT;
937 		return ret;
938 	}
939 
940 	sfp->count = handle->fw_dump_len;
941 	moal_memcpy_ext(handle, sfp->buf, handle->fw_dump_buf,
942 			handle->fw_dump_len, sfp->size);
943 	moal_vfree(handle, handle->fw_dump_buf);
944 	handle->fw_dump_buf = NULL;
945 	handle->fw_dump_len = 0;
946 
947 done:
948 	MODULE_PUT;
949 	LEAVE();
950 	return 0;
951 }
952 
woal_fw_dump_proc_open(struct inode * inode,struct file * file)953 static int woal_fw_dump_proc_open(struct inode *inode, struct file *file)
954 {
955 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
956 	return single_open(file, woal_fw_dump_read, pde_data(inode));
957 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
958 	return single_open(file, woal_fw_dump_read, PDE_DATA(inode));
959 #else
960 	return single_open(file, woal_fw_dump_read, PDE(inode)->data);
961 #endif
962 }
963 
964 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
965 static const struct proc_ops fw_dump_fops = {
966 	.proc_open = woal_fw_dump_proc_open,
967 	.proc_read = seq_read,
968 	.proc_lseek = seq_lseek,
969 	.proc_release = single_release,
970 };
971 #else
972 static const struct file_operations fw_dump_fops = {
973 	.owner = THIS_MODULE,
974 	.open = woal_fw_dump_proc_open,
975 	.read = seq_read,
976 	.llseek = seq_lseek,
977 	.release = single_release,
978 };
979 #endif
980 
981 /**
982  *  @brief wifi status proc read function
983  *
984  *  @param sfp      pointer to seq_file structure
985  *  @param data
986  *
987  *  @return         number of output data
988  */
woal_wifi_status_read(struct seq_file * sfp,void * data)989 static int woal_wifi_status_read(struct seq_file *sfp, void *data)
990 {
991 	ENTER();
992 
993 	if (!MODULE_GET) {
994 		LEAVE();
995 		return 0;
996 	}
997 
998 	seq_printf(sfp, "%d\n", wifi_status);
999 
1000 	MODULE_PUT;
1001 	LEAVE();
1002 	return 0;
1003 }
1004 
woal_wifi_status_proc_open(struct inode * inode,struct file * file)1005 static int woal_wifi_status_proc_open(struct inode *inode, struct file *file)
1006 {
1007 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
1008 	return single_open(file, woal_wifi_status_read, pde_data(inode));
1009 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1010 	return single_open(file, woal_wifi_status_read, PDE_DATA(inode));
1011 #else
1012 	return single_open(file, woal_wifi_status_read, PDE(inode)->data);
1013 #endif
1014 }
1015 
1016 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
1017 static const struct proc_ops wifi_status_proc_fops = {
1018 	.proc_open = woal_wifi_status_proc_open,
1019 	.proc_read = seq_read,
1020 	.proc_lseek = seq_lseek,
1021 	.proc_release = single_release,
1022 };
1023 #else
1024 static const struct file_operations wifi_status_proc_fops = {
1025 	.owner = THIS_MODULE,
1026 	.open = woal_wifi_status_proc_open,
1027 	.read = seq_read,
1028 	.llseek = seq_lseek,
1029 	.release = single_release,
1030 };
1031 #endif
1032 
1033 /********************************************************
1034 		Global Functions
1035 ********************************************************/
1036 /**
1037  *  @brief Convert string to number
1038  *
1039  *  @param s        Pointer to numbered string
1040  *
1041  *  @return         Converted number from string s
1042  */
woal_string_to_number(char * s)1043 int woal_string_to_number(char *s)
1044 {
1045 	int r = 0;
1046 	int base = 0;
1047 	int pn = 1;
1048 
1049 	if (!strncmp(s, "-", 1)) {
1050 		pn = -1;
1051 		s++;
1052 	}
1053 	if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
1054 		base = 16;
1055 		s += 2;
1056 	} else
1057 		base = 10;
1058 
1059 	for (; *s; s++) {
1060 		if ((*s >= '0') && (*s <= '9'))
1061 			r = (r * base) + (*s - '0');
1062 		else if ((*s >= 'A') && (*s <= 'F'))
1063 			r = (r * base) + (*s - 'A' + 10);
1064 		else if ((*s >= 'a') && (*s <= 'f'))
1065 			r = (r * base) + (*s - 'a' + 10);
1066 		else
1067 			break;
1068 	}
1069 
1070 	return r * pn;
1071 }
1072 
1073 /**
1074  *  @brief This function creates proc mwlan directory
1075  *  directory structure
1076  *
1077  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1078  */
woal_root_proc_init(void)1079 mlan_status woal_root_proc_init(void)
1080 {
1081 	ENTER();
1082 
1083 	PRINTM(MINFO, "Create /proc/mwlan directory\n");
1084 
1085 	proc_mwlan = proc_mkdir(MWLAN_PROC, PROC_DIR);
1086 	if (!proc_mwlan) {
1087 		PRINTM(MERROR,
1088 		       "woal_root_proc_init: Cannot create /proc/mwlan\n");
1089 		LEAVE();
1090 		return MLAN_STATUS_FAILURE;
1091 	}
1092 
1093 	/* create /proc/mwlan/wifi_status */
1094 	proc_create_data(STATUS_PROC, 0666, proc_mwlan, &wifi_status_proc_fops,
1095 			 NULL);
1096 
1097 	LEAVE();
1098 	return MLAN_STATUS_SUCCESS;
1099 }
1100 
1101 /**
1102  *  @brief This function removes proc mwlan directory
1103  *  directory structure
1104  *
1105  *  @return         N/A
1106  */
woal_root_proc_remove(void)1107 void woal_root_proc_remove(void)
1108 {
1109 	ENTER();
1110 
1111 	remove_proc_entry(STATUS_PROC, proc_mwlan);
1112 
1113 	remove_proc_entry(MWLAN_PROC, PROC_DIR);
1114 	proc_mwlan = NULL;
1115 
1116 	LEAVE();
1117 }
1118 
1119 /**
1120  *  @brief Create the top level proc directory
1121  *
1122  *  @param handle   Pointer to woal_handle
1123  *
1124  *  @return         N/A
1125  */
woal_proc_init(moal_handle * handle)1126 void woal_proc_init(moal_handle *handle)
1127 {
1128 	struct proc_dir_entry *r;
1129 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
1130 	struct proc_dir_entry *pde = proc_mwlan;
1131 #endif
1132 	char config_proc_dir[20];
1133 	char drv_dump_dir[20];
1134 	char fw_dump_dir[20];
1135 
1136 	ENTER();
1137 
1138 	if (handle->proc_wlan) {
1139 		PRINTM(MMSG, "woal_proc_init: proc_wlan is already exist %s\n",
1140 		       handle->proc_wlan_name);
1141 		goto done;
1142 	}
1143 
1144 	snprintf(handle->proc_wlan_name, sizeof(handle->proc_wlan_name),
1145 		 WLAN_PROC, handle->handle_idx);
1146 	PRINTM(MINFO, "Create Proc Interface %s\n", handle->proc_wlan_name);
1147 
1148 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
1149 	/* Check if directory already exists */
1150 	for (pde = pde->subdir; pde; pde = pde->next) {
1151 		if (pde->namelen &&
1152 		    !strcmp(handle->proc_wlan_name, pde->name)) {
1153 			/* Directory exists */
1154 			PRINTM(MWARN, "proc interface already exists!\n");
1155 			handle->proc_wlan = pde;
1156 			break;
1157 		}
1158 	}
1159 	if (pde == NULL) {
1160 		handle->proc_wlan =
1161 			proc_mkdir(handle->proc_wlan_name, proc_mwlan);
1162 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1163 		if (handle->proc_wlan)
1164 			atomic_set(&handle->proc_wlan->count, 1);
1165 #endif
1166 	}
1167 #else
1168 	handle->proc_wlan = proc_mkdir(handle->proc_wlan_name, proc_mwlan);
1169 #endif
1170 	if (!handle->proc_wlan) {
1171 		PRINTM(MERROR, "Cannot create proc interface %s!\n",
1172 		       handle->proc_wlan_name);
1173 		goto done;
1174 	}
1175 
1176 	strcpy(config_proc_dir, "config");
1177 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1178 	r = proc_create_data(config_proc_dir, 0666, handle->proc_wlan,
1179 			     &config_proc_fops, handle);
1180 #else
1181 	r = create_proc_entry(config_proc_dir, 0644, handle->proc_wlan);
1182 	if (r) {
1183 		r->data = handle;
1184 		r->proc_fops = &config_proc_fops;
1185 	}
1186 #endif
1187 	if (!r)
1188 		PRINTM(MERROR, "Fail to create proc config\n");
1189 
1190 	strcpy(drv_dump_dir, "drv_dump");
1191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1192 	r = proc_create_data(drv_dump_dir, 0644, handle->proc_wlan,
1193 			     &drv_dump_fops, handle);
1194 #else
1195 	r = create_proc_entry(drv_dump_dir, 0644, handle->proc_wlan);
1196 	if (r) {
1197 		r->data = handle;
1198 		r->proc_fops = &drv_dump_fops;
1199 	}
1200 #endif
1201 	if (!r)
1202 		PRINTM(MERROR, "Failed to create proc drv dump\n");
1203 
1204 	strcpy(fw_dump_dir, "fw_dump");
1205 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1206 	r = proc_create_data(fw_dump_dir, 0644, handle->proc_wlan,
1207 			     &fw_dump_fops, handle);
1208 #else
1209 	r = create_proc_entry(fw_dump_dir, 0644, handle->proc_wlan);
1210 	if (r) {
1211 		r->data = handle;
1212 		r->proc_fops = &fw_dump_fops;
1213 	}
1214 #endif
1215 	if (!r)
1216 		PRINTM(MERROR, "Failed to create proc fw dump\n");
1217 
1218 done:
1219 	LEAVE();
1220 }
1221 
1222 /**
1223  *  @brief Remove the top level proc directory
1224  *
1225  *  @param handle   pointer moal_handle
1226  *
1227  *  @return         N/A
1228  */
woal_proc_exit(moal_handle * handle)1229 void woal_proc_exit(moal_handle *handle)
1230 {
1231 	char config_proc_dir[20];
1232 	char drv_dump_dir[20];
1233 	char fw_dump_dir[20];
1234 
1235 	ENTER();
1236 
1237 	PRINTM(MINFO, "Remove Proc Interface %s\n", handle->proc_wlan_name);
1238 	if (handle->proc_wlan) {
1239 		strcpy(config_proc_dir, "config");
1240 		remove_proc_entry(config_proc_dir, handle->proc_wlan);
1241 		strcpy(drv_dump_dir, "drv_dump");
1242 		remove_proc_entry(drv_dump_dir, handle->proc_wlan);
1243 		strcpy(fw_dump_dir, "fw_dump");
1244 		remove_proc_entry(fw_dump_dir, handle->proc_wlan);
1245 
1246 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1247 		/* Remove only if we are the only instance using this */
1248 		if (atomic_read(&(handle->proc_wlan->count)) > 1) {
1249 			PRINTM(MWARN, "More than one interface using proc!\n");
1250 		} else {
1251 #endif
1252 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1253 			atomic_dec(&(handle->proc_wlan->count));
1254 #endif
1255 			remove_proc_entry(handle->proc_wlan_name, proc_mwlan);
1256 
1257 			handle->proc_wlan = NULL;
1258 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1259 		}
1260 #endif
1261 	}
1262 	if (handle->fw_dump_buf) {
1263 		moal_vfree(handle, handle->fw_dump_buf);
1264 		handle->fw_dump_buf = NULL;
1265 		handle->fw_dump_len = 0;
1266 	}
1267 	if (handle->drv_dump_buf) {
1268 		moal_vfree(handle, handle->drv_dump_buf);
1269 		handle->drv_dump_len = 0;
1270 		handle->drv_dump_buf = NULL;
1271 	}
1272 	LEAVE();
1273 }
1274 
1275 /**
1276  *  @brief Create proc file for interface
1277  *
1278  *  @param priv     pointer moal_private
1279  *
1280  *  @return         N/A
1281  */
woal_create_proc_entry(moal_private * priv)1282 void woal_create_proc_entry(moal_private *priv)
1283 {
1284 	struct proc_dir_entry *r;
1285 	struct net_device *dev = priv->netdev;
1286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1287 	char proc_dir_name[22];
1288 #endif
1289 
1290 	ENTER();
1291 
1292 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1293 	if (!priv->proc_entry) {
1294 		memset(proc_dir_name, 0, sizeof(proc_dir_name));
1295 		memcpy(proc_dir_name, priv->phandle->proc_wlan_name,
1296 		       sizeof(proc_dir_name) - 2);
1297 		proc_dir_name[strlen(proc_dir_name)] = '/';
1298 
1299 		if (strlen(dev->name) >
1300 		    ((sizeof(proc_dir_name) - 1) - (strlen(proc_dir_name)))) {
1301 			PRINTM(MERROR,
1302 			       "Failed to create proc entry, device name is too long\n");
1303 			LEAVE();
1304 			return;
1305 		}
1306 		strcat(proc_dir_name, dev->name);
1307 		/* Try to create adapterX/dev_name directory first under
1308 		 * /proc/mwlan/ */
1309 		priv->proc_entry = proc_mkdir(proc_dir_name, proc_mwlan);
1310 		if (priv->proc_entry) {
1311 			/* Success. Continue normally */
1312 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1313 			if (!priv->phandle->proc_wlan) {
1314 				priv->phandle->proc_wlan =
1315 					priv->proc_entry->parent;
1316 			}
1317 			atomic_inc(&(priv->phandle->proc_wlan->count));
1318 #endif
1319 		} else {
1320 			/* Failure. adapterX/ may not exist. Try to create that
1321 			 * first */
1322 			priv->phandle->proc_wlan = proc_mkdir(
1323 				priv->phandle->proc_wlan_name, proc_mwlan);
1324 			if (!priv->phandle->proc_wlan) {
1325 				/* Failure. Something broken */
1326 				LEAVE();
1327 				return;
1328 			} else {
1329 				/* Success. Now retry creating mlanX */
1330 				priv->proc_entry =
1331 					proc_mkdir(proc_dir_name, proc_mwlan);
1332 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1333 				atomic_inc(&(priv->phandle->proc_wlan->count));
1334 #endif
1335 			}
1336 		}
1337 #else
1338 	if (priv->phandle->proc_wlan && !priv->proc_entry) {
1339 		priv->proc_entry =
1340 			proc_mkdir(dev->name, priv->phandle->proc_wlan);
1341 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1342 		atomic_inc(&(priv->phandle->proc_wlan->count));
1343 #endif /* < 3.10.0 */
1344 #endif /* < 2.6.26 */
1345 		strcpy(priv->proc_entry_name, dev->name);
1346 		if (priv->proc_entry) {
1347 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1348 			r = proc_create_data("info", 0, priv->proc_entry,
1349 					     &info_proc_fops, dev);
1350 #else
1351 			r = create_proc_entry("info", 0, priv->proc_entry);
1352 			if (r) {
1353 				r->data = dev;
1354 				r->proc_fops = &info_proc_fops;
1355 			}
1356 #endif
1357 			if (!r)
1358 				PRINTM(MMSG, "Fail to create proc info\n");
1359 		}
1360 	}
1361 
1362 	LEAVE();
1363 }
1364 
1365 /**
1366  *  @brief Remove proc file
1367  *
1368  *  @param priv     Pointer moal_private
1369  *
1370  *  @return         N/A
1371  */
1372 void woal_proc_remove(moal_private *priv)
1373 {
1374 	ENTER();
1375 	if (priv->phandle->proc_wlan && priv->proc_entry) {
1376 		remove_proc_entry("info", priv->proc_entry);
1377 		remove_proc_entry(priv->proc_entry_name,
1378 				  priv->phandle->proc_wlan);
1379 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1380 		atomic_dec(&(priv->phandle->proc_wlan->count));
1381 #endif
1382 		priv->proc_entry = NULL;
1383 	}
1384 	LEAVE();
1385 }
1386 #endif
1387