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