xref: /openbmc/linux/drivers/net/wireless/marvell/libertas/debugfs.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
1  // SPDX-License-Identifier: GPL-2.0
2  #include <linux/dcache.h>
3  #include <linux/debugfs.h>
4  #include <linux/delay.h>
5  #include <linux/hardirq.h>
6  #include <linux/mm.h>
7  #include <linux/string.h>
8  #include <linux/slab.h>
9  #include <linux/export.h>
10  
11  #include "decl.h"
12  #include "cmd.h"
13  #include "debugfs.h"
14  
15  static struct dentry *lbs_dir;
16  static char *szStates[] = {
17  	"Connected",
18  	"Disconnected"
19  };
20  
21  #ifdef PROC_DEBUG
22  static void lbs_debug_init(struct lbs_private *priv);
23  #endif
24  
write_file_dummy(struct file * file,const char __user * buf,size_t count,loff_t * ppos)25  static ssize_t write_file_dummy(struct file *file, const char __user *buf,
26                                  size_t count, loff_t *ppos)
27  {
28          return -EINVAL;
29  }
30  
31  static const size_t len = PAGE_SIZE;
32  
lbs_dev_info(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)33  static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
34  				  size_t count, loff_t *ppos)
35  {
36  	struct lbs_private *priv = file->private_data;
37  	size_t pos = 0;
38  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
39  	char *buf = (char *)addr;
40  	ssize_t res;
41  	if (!buf)
42  		return -ENOMEM;
43  
44  	pos += snprintf(buf+pos, len-pos, "state = %s\n",
45  				szStates[priv->connect_status]);
46  	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
47  				(u32) priv->regioncode);
48  
49  	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
50  
51  	free_page(addr);
52  	return res;
53  }
54  
lbs_sleepparams_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)55  static ssize_t lbs_sleepparams_write(struct file *file,
56  				const char __user *user_buf, size_t count,
57  				loff_t *ppos)
58  {
59  	struct lbs_private *priv = file->private_data;
60  	ssize_t ret;
61  	struct sleep_params sp;
62  	int p1, p2, p3, p4, p5, p6;
63  	char *buf;
64  
65  	buf = memdup_user_nul(user_buf, min(count, len - 1));
66  	if (IS_ERR(buf))
67  		return PTR_ERR(buf);
68  
69  	ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
70  	if (ret != 6) {
71  		ret = -EINVAL;
72  		goto out_unlock;
73  	}
74  	sp.sp_error = p1;
75  	sp.sp_offset = p2;
76  	sp.sp_stabletime = p3;
77  	sp.sp_calcontrol = p4;
78  	sp.sp_extsleepclk = p5;
79  	sp.sp_reserved = p6;
80  
81  	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
82  	if (!ret)
83  		ret = count;
84  	else if (ret > 0)
85  		ret = -EINVAL;
86  
87  out_unlock:
88  	kfree(buf);
89  	return ret;
90  }
91  
lbs_sleepparams_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)92  static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
93  				  size_t count, loff_t *ppos)
94  {
95  	struct lbs_private *priv = file->private_data;
96  	ssize_t ret;
97  	size_t pos = 0;
98  	struct sleep_params sp;
99  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
100  	char *buf = (char *)addr;
101  	if (!buf)
102  		return -ENOMEM;
103  
104  	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
105  	if (ret)
106  		goto out_unlock;
107  
108  	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
109  			sp.sp_offset, sp.sp_stabletime,
110  			sp.sp_calcontrol, sp.sp_extsleepclk,
111  			sp.sp_reserved);
112  
113  	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
114  
115  out_unlock:
116  	free_page(addr);
117  	return ret;
118  }
119  
lbs_host_sleep_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)120  static ssize_t lbs_host_sleep_write(struct file *file,
121  				const char __user *user_buf, size_t count,
122  				loff_t *ppos)
123  {
124  	struct lbs_private *priv = file->private_data;
125  	ssize_t ret;
126  	int host_sleep;
127  	char *buf;
128  
129  	buf = memdup_user_nul(user_buf, min(count, len - 1));
130  	if (IS_ERR(buf))
131  		return PTR_ERR(buf);
132  
133  	ret = sscanf(buf, "%d", &host_sleep);
134  	if (ret != 1) {
135  		ret = -EINVAL;
136  		goto out_unlock;
137  	}
138  
139  	if (host_sleep == 0)
140  		ret = lbs_set_host_sleep(priv, 0);
141  	else if (host_sleep == 1) {
142  		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
143  			netdev_info(priv->dev,
144  				    "wake parameters not configured\n");
145  			ret = -EINVAL;
146  			goto out_unlock;
147  		}
148  		ret = lbs_set_host_sleep(priv, 1);
149  	} else {
150  		netdev_err(priv->dev, "invalid option\n");
151  		ret = -EINVAL;
152  	}
153  
154  	if (!ret)
155  		ret = count;
156  
157  out_unlock:
158  	kfree(buf);
159  	return ret;
160  }
161  
lbs_host_sleep_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)162  static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
163  				  size_t count, loff_t *ppos)
164  {
165  	struct lbs_private *priv = file->private_data;
166  	ssize_t ret;
167  	size_t pos = 0;
168  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
169  	char *buf = (char *)addr;
170  	if (!buf)
171  		return -ENOMEM;
172  
173  	pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
174  
175  	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
176  
177  	free_page(addr);
178  	return ret;
179  }
180  
181  /*
182   * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
183   * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
184   * firmware. Here's an example:
185   *	04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
186   *	00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
187   *	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
188   *
189   * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
190   * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
191   * defined in mrvlietypes_thresholds
192   *
193   * This function searches in this TLV data chunk for a given TLV type
194   * and returns a pointer to the first data byte of the TLV, or to NULL
195   * if the TLV hasn't been found.
196   */
lbs_tlv_find(uint16_t tlv_type,const uint8_t * tlv,uint16_t size)197  static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
198  {
199  	struct mrvl_ie_header *tlv_h;
200  	uint16_t length;
201  	ssize_t pos = 0;
202  
203  	while (pos < size) {
204  		tlv_h = (struct mrvl_ie_header *) tlv;
205  		if (!tlv_h->len)
206  			return NULL;
207  		if (tlv_h->type == cpu_to_le16(tlv_type))
208  			return tlv_h;
209  		length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
210  		pos += length;
211  		tlv += length;
212  	}
213  	return NULL;
214  }
215  
216  
lbs_threshold_read(uint16_t tlv_type,uint16_t event_mask,struct file * file,char __user * userbuf,size_t count,loff_t * ppos)217  static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
218  				  struct file *file, char __user *userbuf,
219  				  size_t count, loff_t *ppos)
220  {
221  	struct cmd_ds_802_11_subscribe_event *subscribed;
222  	struct mrvl_ie_thresholds *got;
223  	struct lbs_private *priv = file->private_data;
224  	ssize_t ret = 0;
225  	size_t pos = 0;
226  	char *buf;
227  	u8 value;
228  	u8 freq;
229  	int events = 0;
230  
231  	buf = (char *)get_zeroed_page(GFP_KERNEL);
232  	if (!buf)
233  		return -ENOMEM;
234  
235  	subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
236  	if (!subscribed) {
237  		ret = -ENOMEM;
238  		goto out_page;
239  	}
240  
241  	subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
242  	subscribed->action = cpu_to_le16(CMD_ACT_GET);
243  
244  	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
245  	if (ret)
246  		goto out_cmd;
247  
248  	got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
249  	if (got) {
250  		value = got->value;
251  		freq  = got->freq;
252  		events = le16_to_cpu(subscribed->events);
253  
254  		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
255  				!!(events & event_mask));
256  	}
257  
258  	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
259  
260   out_cmd:
261  	kfree(subscribed);
262  
263   out_page:
264  	free_page((unsigned long)buf);
265  	return ret;
266  }
267  
268  
lbs_threshold_write(uint16_t tlv_type,uint16_t event_mask,struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)269  static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
270  				   struct file *file,
271  				   const char __user *userbuf, size_t count,
272  				   loff_t *ppos)
273  {
274  	struct cmd_ds_802_11_subscribe_event *events;
275  	struct mrvl_ie_thresholds *tlv;
276  	struct lbs_private *priv = file->private_data;
277  	int value, freq, new_mask;
278  	uint16_t curr_mask;
279  	char *buf;
280  	int ret;
281  
282  	buf = memdup_user_nul(userbuf, min(count, len - 1));
283  	if (IS_ERR(buf))
284  		return PTR_ERR(buf);
285  
286  	ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
287  	if (ret != 3) {
288  		ret = -EINVAL;
289  		goto out_page;
290  	}
291  	events = kzalloc(sizeof(*events), GFP_KERNEL);
292  	if (!events) {
293  		ret = -ENOMEM;
294  		goto out_page;
295  	}
296  
297  	events->hdr.size = cpu_to_le16(sizeof(*events));
298  	events->action = cpu_to_le16(CMD_ACT_GET);
299  
300  	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
301  	if (ret)
302  		goto out_events;
303  
304  	curr_mask = le16_to_cpu(events->events);
305  
306  	if (new_mask)
307  		new_mask = curr_mask | event_mask;
308  	else
309  		new_mask = curr_mask & ~event_mask;
310  
311  	/* Now everything is set and we can send stuff down to the firmware */
312  
313  	tlv = (void *)events->tlv;
314  
315  	events->action = cpu_to_le16(CMD_ACT_SET);
316  	events->events = cpu_to_le16(new_mask);
317  	tlv->header.type = cpu_to_le16(tlv_type);
318  	tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
319  	tlv->value = value;
320  	if (tlv_type != TLV_TYPE_BCNMISS)
321  		tlv->freq = freq;
322  
323  	/* The command header, the action, the event mask, and one TLV */
324  	events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
325  
326  	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
327  
328  	if (!ret)
329  		ret = count;
330   out_events:
331  	kfree(events);
332   out_page:
333  	kfree(buf);
334  	return ret;
335  }
336  
337  
lbs_lowrssi_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)338  static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
339  				size_t count, loff_t *ppos)
340  {
341  	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
342  				  file, userbuf, count, ppos);
343  }
344  
345  
lbs_lowrssi_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)346  static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
347  				 size_t count, loff_t *ppos)
348  {
349  	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
350  				   file, userbuf, count, ppos);
351  }
352  
353  
lbs_lowsnr_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)354  static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
355  			       size_t count, loff_t *ppos)
356  {
357  	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
358  				  file, userbuf, count, ppos);
359  }
360  
361  
lbs_lowsnr_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)362  static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
363  				size_t count, loff_t *ppos)
364  {
365  	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
366  				   file, userbuf, count, ppos);
367  }
368  
369  
lbs_failcount_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)370  static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
371  				  size_t count, loff_t *ppos)
372  {
373  	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
374  				  file, userbuf, count, ppos);
375  }
376  
377  
lbs_failcount_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)378  static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
379  				   size_t count, loff_t *ppos)
380  {
381  	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
382  				   file, userbuf, count, ppos);
383  }
384  
385  
lbs_highrssi_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)386  static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
387  				 size_t count, loff_t *ppos)
388  {
389  	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
390  				  file, userbuf, count, ppos);
391  }
392  
393  
lbs_highrssi_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)394  static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
395  				  size_t count, loff_t *ppos)
396  {
397  	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
398  				   file, userbuf, count, ppos);
399  }
400  
401  
lbs_highsnr_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)402  static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
403  				size_t count, loff_t *ppos)
404  {
405  	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
406  				  file, userbuf, count, ppos);
407  }
408  
409  
lbs_highsnr_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)410  static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
411  				 size_t count, loff_t *ppos)
412  {
413  	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
414  				   file, userbuf, count, ppos);
415  }
416  
lbs_bcnmiss_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)417  static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
418  				size_t count, loff_t *ppos)
419  {
420  	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
421  				  file, userbuf, count, ppos);
422  }
423  
424  
lbs_bcnmiss_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)425  static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
426  				 size_t count, loff_t *ppos)
427  {
428  	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
429  				   file, userbuf, count, ppos);
430  }
431  
432  
lbs_rdmac_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)433  static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
434  				  size_t count, loff_t *ppos)
435  {
436  	struct lbs_private *priv = file->private_data;
437  	ssize_t pos = 0;
438  	int ret;
439  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
440  	char *buf = (char *)addr;
441  	u32 val = 0;
442  
443  	if (!buf)
444  		return -ENOMEM;
445  
446  	ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
447  	mdelay(10);
448  	if (!ret) {
449  		pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
450  				priv->mac_offset, val);
451  		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
452  	}
453  	free_page(addr);
454  	return ret;
455  }
456  
lbs_rdmac_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)457  static ssize_t lbs_rdmac_write(struct file *file,
458  				    const char __user *userbuf,
459  				    size_t count, loff_t *ppos)
460  {
461  	struct lbs_private *priv = file->private_data;
462  	char *buf;
463  
464  	buf = memdup_user_nul(userbuf, min(count, len - 1));
465  	if (IS_ERR(buf))
466  		return PTR_ERR(buf);
467  
468  	priv->mac_offset = simple_strtoul(buf, NULL, 16);
469  	kfree(buf);
470  	return count;
471  }
472  
lbs_wrmac_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)473  static ssize_t lbs_wrmac_write(struct file *file,
474  				    const char __user *userbuf,
475  				    size_t count, loff_t *ppos)
476  {
477  
478  	struct lbs_private *priv = file->private_data;
479  	ssize_t res;
480  	u32 offset, value;
481  	char *buf;
482  
483  	buf = memdup_user_nul(userbuf, min(count, len - 1));
484  	if (IS_ERR(buf))
485  		return PTR_ERR(buf);
486  
487  	res = sscanf(buf, "%x %x", &offset, &value);
488  	if (res != 2) {
489  		res = -EFAULT;
490  		goto out_unlock;
491  	}
492  
493  	res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
494  	mdelay(10);
495  
496  	if (!res)
497  		res = count;
498  out_unlock:
499  	kfree(buf);
500  	return res;
501  }
502  
lbs_rdbbp_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)503  static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
504  				  size_t count, loff_t *ppos)
505  {
506  	struct lbs_private *priv = file->private_data;
507  	ssize_t pos = 0;
508  	int ret;
509  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
510  	char *buf = (char *)addr;
511  	u32 val;
512  
513  	if (!buf)
514  		return -ENOMEM;
515  
516  	ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
517  	mdelay(10);
518  	if (!ret) {
519  		pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
520  				priv->bbp_offset, val);
521  		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
522  	}
523  	free_page(addr);
524  
525  	return ret;
526  }
527  
lbs_rdbbp_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)528  static ssize_t lbs_rdbbp_write(struct file *file,
529  				    const char __user *userbuf,
530  				    size_t count, loff_t *ppos)
531  {
532  	struct lbs_private *priv = file->private_data;
533  	char *buf;
534  
535  	buf = memdup_user_nul(userbuf, min(count, len - 1));
536  	if (IS_ERR(buf))
537  		return PTR_ERR(buf);
538  
539  	priv->bbp_offset = simple_strtoul(buf, NULL, 16);
540  	kfree(buf);
541  
542  	return count;
543  }
544  
lbs_wrbbp_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)545  static ssize_t lbs_wrbbp_write(struct file *file,
546  				    const char __user *userbuf,
547  				    size_t count, loff_t *ppos)
548  {
549  
550  	struct lbs_private *priv = file->private_data;
551  	ssize_t res;
552  	u32 offset, value;
553  	char *buf;
554  
555  	buf = memdup_user_nul(userbuf, min(count, len - 1));
556  	if (IS_ERR(buf))
557  		return PTR_ERR(buf);
558  
559  	res = sscanf(buf, "%x %x", &offset, &value);
560  	if (res != 2) {
561  		res = -EFAULT;
562  		goto out_unlock;
563  	}
564  
565  	res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
566  	mdelay(10);
567  
568  	if (!res)
569  		res = count;
570  out_unlock:
571  	kfree(buf);
572  	return res;
573  }
574  
lbs_rdrf_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)575  static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
576  				  size_t count, loff_t *ppos)
577  {
578  	struct lbs_private *priv = file->private_data;
579  	ssize_t pos = 0;
580  	int ret;
581  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
582  	char *buf = (char *)addr;
583  	u32 val;
584  
585  	if (!buf)
586  		return -ENOMEM;
587  
588  	ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
589  	mdelay(10);
590  	if (!ret) {
591  		pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
592  				priv->rf_offset, val);
593  		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
594  	}
595  	free_page(addr);
596  
597  	return ret;
598  }
599  
lbs_rdrf_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)600  static ssize_t lbs_rdrf_write(struct file *file,
601  				    const char __user *userbuf,
602  				    size_t count, loff_t *ppos)
603  {
604  	struct lbs_private *priv = file->private_data;
605  	char *buf;
606  
607  	buf = memdup_user_nul(userbuf, min(count, len - 1));
608  	if (IS_ERR(buf))
609  		return PTR_ERR(buf);
610  
611  	priv->rf_offset = simple_strtoul(buf, NULL, 16);
612  	kfree(buf);
613  	return count;
614  }
615  
lbs_wrrf_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)616  static ssize_t lbs_wrrf_write(struct file *file,
617  				    const char __user *userbuf,
618  				    size_t count, loff_t *ppos)
619  {
620  
621  	struct lbs_private *priv = file->private_data;
622  	ssize_t res;
623  	u32 offset, value;
624  	char *buf;
625  
626  	buf = memdup_user_nul(userbuf, min(count, len - 1));
627  	if (IS_ERR(buf))
628  		return PTR_ERR(buf);
629  
630  	res = sscanf(buf, "%x %x", &offset, &value);
631  	if (res != 2) {
632  		res = -EFAULT;
633  		goto out_unlock;
634  	}
635  
636  	res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
637  	mdelay(10);
638  
639  	if (!res)
640  		res = count;
641  out_unlock:
642  	kfree(buf);
643  	return res;
644  }
645  
646  #define FOPS(fread, fwrite) { \
647  	.owner = THIS_MODULE, \
648  	.open = simple_open, \
649  	.read = (fread), \
650  	.write = (fwrite), \
651  	.llseek = generic_file_llseek, \
652  }
653  
654  struct lbs_debugfs_files {
655  	const char *name;
656  	umode_t perm;
657  	struct file_operations fops;
658  };
659  
660  static const struct lbs_debugfs_files debugfs_files[] = {
661  	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
662  	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
663  				lbs_sleepparams_write), },
664  	{ "hostsleep", 0644, FOPS(lbs_host_sleep_read,
665  				lbs_host_sleep_write), },
666  };
667  
668  static const struct lbs_debugfs_files debugfs_events_files[] = {
669  	{"low_rssi", 0644, FOPS(lbs_lowrssi_read,
670  				lbs_lowrssi_write), },
671  	{"low_snr", 0644, FOPS(lbs_lowsnr_read,
672  				lbs_lowsnr_write), },
673  	{"failure_count", 0644, FOPS(lbs_failcount_read,
674  				lbs_failcount_write), },
675  	{"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
676  				lbs_bcnmiss_write), },
677  	{"high_rssi", 0644, FOPS(lbs_highrssi_read,
678  				lbs_highrssi_write), },
679  	{"high_snr", 0644, FOPS(lbs_highsnr_read,
680  				lbs_highsnr_write), },
681  };
682  
683  static const struct lbs_debugfs_files debugfs_regs_files[] = {
684  	{"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
685  	{"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
686  	{"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
687  	{"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
688  	{"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
689  	{"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
690  };
691  
lbs_debugfs_init(void)692  void lbs_debugfs_init(void)
693  {
694  	if (!lbs_dir)
695  		lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
696  }
697  
lbs_debugfs_remove(void)698  void lbs_debugfs_remove(void)
699  {
700  	debugfs_remove(lbs_dir);
701  }
702  
lbs_debugfs_init_one(struct lbs_private * priv,struct net_device * dev)703  void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
704  {
705  	int i;
706  	const struct lbs_debugfs_files *files;
707  	if (!lbs_dir)
708  		goto exit;
709  
710  	priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
711  
712  	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
713  		files = &debugfs_files[i];
714  		priv->debugfs_files[i] = debugfs_create_file(files->name,
715  							     files->perm,
716  							     priv->debugfs_dir,
717  							     priv,
718  							     &files->fops);
719  	}
720  
721  	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
722  
723  	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
724  		files = &debugfs_events_files[i];
725  		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
726  							     files->perm,
727  							     priv->events_dir,
728  							     priv,
729  							     &files->fops);
730  	}
731  
732  	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
733  
734  	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
735  		files = &debugfs_regs_files[i];
736  		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
737  							     files->perm,
738  							     priv->regs_dir,
739  							     priv,
740  							     &files->fops);
741  	}
742  
743  #ifdef PROC_DEBUG
744  	lbs_debug_init(priv);
745  #endif
746  exit:
747  	return;
748  }
749  
lbs_debugfs_remove_one(struct lbs_private * priv)750  void lbs_debugfs_remove_one(struct lbs_private *priv)
751  {
752  	int i;
753  
754  	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
755  		debugfs_remove(priv->debugfs_regs_files[i]);
756  
757  	debugfs_remove(priv->regs_dir);
758  
759  	for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
760  		debugfs_remove(priv->debugfs_events_files[i]);
761  
762  	debugfs_remove(priv->events_dir);
763  #ifdef PROC_DEBUG
764  	debugfs_remove(priv->debugfs_debug);
765  #endif
766  	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
767  		debugfs_remove(priv->debugfs_files[i]);
768  	debugfs_remove(priv->debugfs_dir);
769  }
770  
771  
772  
773  /* debug entry */
774  
775  #ifdef PROC_DEBUG
776  
777  #define item_size(n)	(sizeof_field(struct lbs_private, n))
778  #define item_addr(n)	(offsetof(struct lbs_private, n))
779  
780  
781  struct debug_data {
782  	char name[32];
783  	u32 size;
784  	size_t addr;
785  };
786  
787  /* To debug any member of struct lbs_private, simply add one line here.
788   */
789  static struct debug_data items[] = {
790  	{"psmode", item_size(psmode), item_addr(psmode)},
791  	{"psstate", item_size(psstate), item_addr(psstate)},
792  };
793  
794  static int num_of_items = ARRAY_SIZE(items);
795  
796  /**
797   * lbs_debugfs_read - proc read function
798   *
799   * @file:	file to read
800   * @userbuf:	pointer to buffer
801   * @count:	number of bytes to read
802   * @ppos:	read data starting position
803   *
804   * returns:	amount of data read or negative error code
805   */
lbs_debugfs_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)806  static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
807  			size_t count, loff_t *ppos)
808  {
809  	int val = 0;
810  	size_t pos = 0;
811  	ssize_t res;
812  	char *p;
813  	int i;
814  	struct debug_data *d;
815  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
816  	char *buf = (char *)addr;
817  	if (!buf)
818  		return -ENOMEM;
819  
820  	p = buf;
821  
822  	d = file->private_data;
823  
824  	for (i = 0; i < num_of_items; i++) {
825  		if (d[i].size == 1)
826  			val = *((u8 *) d[i].addr);
827  		else if (d[i].size == 2)
828  			val = *((u16 *) d[i].addr);
829  		else if (d[i].size == 4)
830  			val = *((u32 *) d[i].addr);
831  		else if (d[i].size == 8)
832  			val = *((u64 *) d[i].addr);
833  
834  		pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
835  	}
836  
837  	res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
838  
839  	free_page(addr);
840  	return res;
841  }
842  
843  /**
844   * lbs_debugfs_write - proc write function
845   *
846   * @f:		file pointer
847   * @buf:	pointer to data buffer
848   * @cnt:	data number to write
849   * @ppos:	file position
850   *
851   * returns:	amount of data written
852   */
lbs_debugfs_write(struct file * f,const char __user * buf,size_t cnt,loff_t * ppos)853  static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
854  			    size_t cnt, loff_t *ppos)
855  {
856  	int r, i;
857  	char *pdata;
858  	char *p;
859  	char *p0;
860  	char *p1;
861  	char *p2;
862  	struct debug_data *d = f->private_data;
863  
864  	if (cnt == 0)
865  		return 0;
866  
867  	pdata = memdup_user_nul(buf, cnt);
868  	if (IS_ERR(pdata))
869  		return PTR_ERR(pdata);
870  
871  	p0 = pdata;
872  	for (i = 0; i < num_of_items; i++) {
873  		do {
874  			p = strstr(p0, d[i].name);
875  			if (p == NULL)
876  				break;
877  			p1 = strchr(p, '\n');
878  			if (p1 == NULL)
879  				break;
880  			p0 = p1++;
881  			p2 = strchr(p, '=');
882  			if (!p2)
883  				break;
884  			p2++;
885  			r = simple_strtoul(p2, NULL, 0);
886  			if (d[i].size == 1)
887  				*((u8 *) d[i].addr) = (u8) r;
888  			else if (d[i].size == 2)
889  				*((u16 *) d[i].addr) = (u16) r;
890  			else if (d[i].size == 4)
891  				*((u32 *) d[i].addr) = (u32) r;
892  			else if (d[i].size == 8)
893  				*((u64 *) d[i].addr) = (u64) r;
894  			break;
895  		} while (1);
896  	}
897  	kfree(pdata);
898  
899  	return (ssize_t)cnt;
900  }
901  
902  static const struct file_operations lbs_debug_fops = {
903  	.owner = THIS_MODULE,
904  	.open = simple_open,
905  	.write = lbs_debugfs_write,
906  	.read = lbs_debugfs_read,
907  	.llseek = default_llseek,
908  };
909  
910  /**
911   * lbs_debug_init - create debug proc file
912   *
913   * @priv:	pointer to &struct lbs_private
914   *
915   * returns:	N/A
916   */
lbs_debug_init(struct lbs_private * priv)917  static void lbs_debug_init(struct lbs_private *priv)
918  {
919  	int i;
920  
921  	if (!priv->debugfs_dir)
922  		return;
923  
924  	for (i = 0; i < num_of_items; i++)
925  		items[i].addr += (size_t) priv;
926  
927  	priv->debugfs_debug = debugfs_create_file("debug", 0644,
928  						  priv->debugfs_dir, &items[0],
929  						  &lbs_debug_fops);
930  }
931  #endif
932