blob: 17367463c8554451c757e78d92d692c2d67a0ec7 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001#include <linux/dcache.h>
2#include <linux/debugfs.h>
3#include <linux/delay.h>
4#include <linux/mm.h>
Geert Uytterhoevend8b0fb52007-10-08 09:43:02 +02005#include <linux/string.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09006#include <linux/slab.h>
Holger Schurig46868202007-05-25 00:37:28 -04007
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02008#include "decl.h"
David Woodhouse3fbe1042007-12-17 23:48:31 -05009#include "cmd.h"
Kiran Divekare86dc1c2010-06-14 22:01:26 +053010#include "debugfs.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020011
Holger Schurig10078322007-11-15 18:05:47 -050012static struct dentry *lbs_dir;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020013static char *szStates[] = {
14 "Connected",
15 "Disconnected"
16};
17
Holger Schurig46868202007-05-25 00:37:28 -040018#ifdef PROC_DEBUG
Holger Schurige98a88d2008-03-19 14:25:58 +010019static void lbs_debug_init(struct lbs_private *priv);
Holger Schurig46868202007-05-25 00:37:28 -040020#endif
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020021
22static int open_file_generic(struct inode *inode, struct file *file)
23{
24 file->private_data = inode->i_private;
25 return 0;
26}
27
28static ssize_t write_file_dummy(struct file *file, const char __user *buf,
29 size_t count, loff_t *ppos)
30{
31 return -EINVAL;
32}
33
34static const size_t len = PAGE_SIZE;
35
Holger Schurig10078322007-11-15 18:05:47 -050036static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020037 size_t count, loff_t *ppos)
38{
Holger Schurig69f90322007-11-23 15:43:44 +010039 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020040 size_t pos = 0;
41 unsigned long addr = get_zeroed_page(GFP_KERNEL);
42 char *buf = (char *)addr;
43 ssize_t res;
Kiran Divekarad43f8b2009-08-28 17:47:59 +053044 if (!buf)
45 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020046
47 pos += snprintf(buf+pos, len-pos, "state = %s\n",
David Woodhouseaa21c002007-12-08 20:04:36 +000048 szStates[priv->connect_status]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020049 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
David Woodhouseaa21c002007-12-08 20:04:36 +000050 (u32) priv->regioncode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020051
52 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
53
54 free_page(addr);
55 return res;
56}
57
Holger Schurig10078322007-11-15 18:05:47 -050058static ssize_t lbs_sleepparams_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020059 const char __user *user_buf, size_t count,
60 loff_t *ppos)
61{
Holger Schurig69f90322007-11-23 15:43:44 +010062 struct lbs_private *priv = file->private_data;
David Woodhouse3fbe1042007-12-17 23:48:31 -050063 ssize_t buf_size, ret;
64 struct sleep_params sp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020065 int p1, p2, p3, p4, p5, p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020066 unsigned long addr = get_zeroed_page(GFP_KERNEL);
67 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +053068 if (!buf)
69 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020070
71 buf_size = min(count, len - 1);
72 if (copy_from_user(buf, user_buf, buf_size)) {
David Woodhouse3fbe1042007-12-17 23:48:31 -050073 ret = -EFAULT;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020074 goto out_unlock;
75 }
David Woodhouse3fbe1042007-12-17 23:48:31 -050076 ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
77 if (ret != 6) {
78 ret = -EINVAL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020079 goto out_unlock;
80 }
David Woodhouse3fbe1042007-12-17 23:48:31 -050081 sp.sp_error = p1;
82 sp.sp_offset = p2;
83 sp.sp_stabletime = p3;
84 sp.sp_calcontrol = p4;
85 sp.sp_extsleepclk = p5;
86 sp.sp_reserved = p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020087
David Woodhouse3fbe1042007-12-17 23:48:31 -050088 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
89 if (!ret)
90 ret = count;
91 else if (ret > 0)
92 ret = -EINVAL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020093
94out_unlock:
95 free_page(addr);
David Woodhouse3fbe1042007-12-17 23:48:31 -050096 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020097}
98
Holger Schurig10078322007-11-15 18:05:47 -050099static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200100 size_t count, loff_t *ppos)
101{
Holger Schurig69f90322007-11-23 15:43:44 +0100102 struct lbs_private *priv = file->private_data;
David Woodhouse3fbe1042007-12-17 23:48:31 -0500103 ssize_t ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200104 size_t pos = 0;
David Woodhouse3fbe1042007-12-17 23:48:31 -0500105 struct sleep_params sp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200106 unsigned long addr = get_zeroed_page(GFP_KERNEL);
107 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530108 if (!buf)
109 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200110
David Woodhouse3fbe1042007-12-17 23:48:31 -0500111 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
112 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200113 goto out_unlock;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200114
David Woodhouse3fbe1042007-12-17 23:48:31 -0500115 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
116 sp.sp_offset, sp.sp_stabletime,
117 sp.sp_calcontrol, sp.sp_extsleepclk,
118 sp.sp_reserved);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200119
David Woodhouse3fbe1042007-12-17 23:48:31 -0500120 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200121
122out_unlock:
123 free_page(addr);
David Woodhouse3fbe1042007-12-17 23:48:31 -0500124 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200125}
126
Holger Schurig3a188642007-11-26 10:07:14 +0100127/*
128 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
129 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
130 * firmware. Here's an example:
131 * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
132 * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
133 * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
134 *
135 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
136 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
137 * defined in mrvlietypes_thresholds
138 *
139 * This function searches in this TLV data chunk for a given TLV type
140 * and returns a pointer to the first data byte of the TLV, or to NULL
141 * if the TLV hasn't been found.
142 */
David Woodhouse5844d122007-12-18 02:01:37 -0500143static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200144{
Dan Williams75b6a612009-05-22 20:03:09 -0400145 struct mrvl_ie_header *tlv_h;
David Woodhouse5844d122007-12-18 02:01:37 -0500146 uint16_t length;
147 ssize_t pos = 0;
148
Holger Schurig3a188642007-11-26 10:07:14 +0100149 while (pos < size) {
Dan Williams75b6a612009-05-22 20:03:09 -0400150 tlv_h = (struct mrvl_ie_header *) tlv;
David Woodhouse5844d122007-12-18 02:01:37 -0500151 if (!tlv_h->len)
Holger Schurig3a188642007-11-26 10:07:14 +0100152 return NULL;
David Woodhouse5844d122007-12-18 02:01:37 -0500153 if (tlv_h->type == cpu_to_le16(tlv_type))
154 return tlv_h;
155 length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
Holger Schurig3a188642007-11-26 10:07:14 +0100156 pos += length;
157 tlv += length;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200158 }
Holger Schurig3a188642007-11-26 10:07:14 +0100159 return NULL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200160}
161
Holger Schurig3a188642007-11-26 10:07:14 +0100162
David Woodhouse5844d122007-12-18 02:01:37 -0500163static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
164 struct file *file, char __user *userbuf,
165 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200166{
David Woodhouse5844d122007-12-18 02:01:37 -0500167 struct cmd_ds_802_11_subscribe_event *subscribed;
Dan Williams75b6a612009-05-22 20:03:09 -0400168 struct mrvl_ie_thresholds *got;
Holger Schurig69f90322007-11-23 15:43:44 +0100169 struct lbs_private *priv = file->private_data;
David Woodhouse5844d122007-12-18 02:01:37 -0500170 ssize_t ret = 0;
Holger Schurig3a188642007-11-26 10:07:14 +0100171 size_t pos = 0;
David Woodhouse5844d122007-12-18 02:01:37 -0500172 char *buf;
Holger Schurig3a188642007-11-26 10:07:14 +0100173 u8 value;
174 u8 freq;
Holger Schurigb6b8abe2007-12-10 12:19:55 +0100175 int events = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200176
David Woodhouse5844d122007-12-18 02:01:37 -0500177 buf = (char *)get_zeroed_page(GFP_KERNEL);
178 if (!buf)
179 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200180
David Woodhouse5844d122007-12-18 02:01:37 -0500181 subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
182 if (!subscribed) {
183 ret = -ENOMEM;
184 goto out_page;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200185 }
186
David Woodhouse5844d122007-12-18 02:01:37 -0500187 subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
188 subscribed->action = cpu_to_le16(CMD_ACT_GET);
189
190 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
191 if (ret)
192 goto out_cmd;
193
Holger Schurigb6b8abe2007-12-10 12:19:55 +0100194 got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
Holger Schurig3a188642007-11-26 10:07:14 +0100195 if (got) {
196 value = got->value;
197 freq = got->freq;
Holger Schurigb6b8abe2007-12-10 12:19:55 +0100198 events = le16_to_cpu(subscribed->events);
David Woodhouse5844d122007-12-18 02:01:37 -0500199
200 pos += snprintf(buf, len, "%d %d %d\n", value, freq,
201 !!(events & event_mask));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200202 }
David Woodhouse5844d122007-12-18 02:01:37 -0500203
204 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
205
206 out_cmd:
Holger Schurigb6b8abe2007-12-10 12:19:55 +0100207 kfree(subscribed);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200208
David Woodhouse5844d122007-12-18 02:01:37 -0500209 out_page:
210 free_page((unsigned long)buf);
211 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200212}
213
Holger Schurig3a188642007-11-26 10:07:14 +0100214
David Woodhouse5844d122007-12-18 02:01:37 -0500215static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
216 struct file *file,
217 const char __user *userbuf, size_t count,
218 loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200219{
Holger Schurig3a188642007-11-26 10:07:14 +0100220 struct cmd_ds_802_11_subscribe_event *events;
Dan Williams75b6a612009-05-22 20:03:09 -0400221 struct mrvl_ie_thresholds *tlv;
David Woodhouse5844d122007-12-18 02:01:37 -0500222 struct lbs_private *priv = file->private_data;
223 ssize_t buf_size;
224 int value, freq, new_mask;
225 uint16_t curr_mask;
226 char *buf;
227 int ret;
228
229 buf = (char *)get_zeroed_page(GFP_KERNEL);
230 if (!buf)
231 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200232
233 buf_size = min(count, len - 1);
234 if (copy_from_user(buf, userbuf, buf_size)) {
David Woodhouse5844d122007-12-18 02:01:37 -0500235 ret = -EFAULT;
236 goto out_page;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200237 }
David Woodhouse5844d122007-12-18 02:01:37 -0500238 ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
239 if (ret != 3) {
240 ret = -EINVAL;
241 goto out_page;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200242 }
David Woodhouse5844d122007-12-18 02:01:37 -0500243 events = kzalloc(sizeof(*events), GFP_KERNEL);
244 if (!events) {
245 ret = -ENOMEM;
246 goto out_page;
247 }
248
249 events->hdr.size = cpu_to_le16(sizeof(*events));
250 events->action = cpu_to_le16(CMD_ACT_GET);
251
252 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
253 if (ret)
254 goto out_events;
255
256 curr_mask = le16_to_cpu(events->events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200257
Holger Schurig3a188642007-11-26 10:07:14 +0100258 if (new_mask)
259 new_mask = curr_mask | event_mask;
260 else
261 new_mask = curr_mask & ~event_mask;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200262
Holger Schurig3a188642007-11-26 10:07:14 +0100263 /* Now everything is set and we can send stuff down to the firmware */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200264
David Woodhouse5844d122007-12-18 02:01:37 -0500265 tlv = (void *)events->tlv;
266
267 events->action = cpu_to_le16(CMD_ACT_SET);
268 events->events = cpu_to_le16(new_mask);
269 tlv->header.type = cpu_to_le16(tlv_type);
270 tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
271 tlv->value = value;
272 if (tlv_type != TLV_TYPE_BCNMISS)
273 tlv->freq = freq;
274
Holger Schuriga75eda42008-05-30 14:53:22 +0200275 /* The command header, the action, the event mask, and one TLV */
276 events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
David Woodhouse5844d122007-12-18 02:01:37 -0500277
278 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
279
280 if (!ret)
281 ret = count;
282 out_events:
283 kfree(events);
284 out_page:
285 free_page((unsigned long)buf);
286 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200287}
288
Holger Schurig3a188642007-11-26 10:07:14 +0100289
David Woodhouse5844d122007-12-18 02:01:37 -0500290static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
291 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200292{
Holger Schurig3a188642007-11-26 10:07:14 +0100293 return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
David Woodhouse5844d122007-12-18 02:01:37 -0500294 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200295}
296
Holger Schurig3a188642007-11-26 10:07:14 +0100297
David Woodhouse5844d122007-12-18 02:01:37 -0500298static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
299 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300{
Holger Schurig3a188642007-11-26 10:07:14 +0100301 return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
David Woodhouse5844d122007-12-18 02:01:37 -0500302 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200303}
304
Holger Schurig3a188642007-11-26 10:07:14 +0100305
David Woodhouse5844d122007-12-18 02:01:37 -0500306static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
307 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200308{
Holger Schurig3a188642007-11-26 10:07:14 +0100309 return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
David Woodhouse5844d122007-12-18 02:01:37 -0500310 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200311}
312
Holger Schurig3a188642007-11-26 10:07:14 +0100313
David Woodhouse5844d122007-12-18 02:01:37 -0500314static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
315 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200316{
Holger Schurig3a188642007-11-26 10:07:14 +0100317 return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
David Woodhouse5844d122007-12-18 02:01:37 -0500318 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200319}
320
Holger Schurig3a188642007-11-26 10:07:14 +0100321
David Woodhouse5844d122007-12-18 02:01:37 -0500322static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
323 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200324{
Holger Schurig3a188642007-11-26 10:07:14 +0100325 return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
David Woodhouse5844d122007-12-18 02:01:37 -0500326 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200327}
328
Holger Schurig3a188642007-11-26 10:07:14 +0100329
David Woodhouse5844d122007-12-18 02:01:37 -0500330static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
331 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200332{
Holger Schurig3a188642007-11-26 10:07:14 +0100333 return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
David Woodhouse5844d122007-12-18 02:01:37 -0500334 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200335}
336
Holger Schurig3a188642007-11-26 10:07:14 +0100337
David Woodhouse5844d122007-12-18 02:01:37 -0500338static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
339 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100340{
341 return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
David Woodhouse5844d122007-12-18 02:01:37 -0500342 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100343}
344
345
David Woodhouse5844d122007-12-18 02:01:37 -0500346static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
347 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100348{
349 return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
David Woodhouse5844d122007-12-18 02:01:37 -0500350 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100351}
352
353
David Woodhouse5844d122007-12-18 02:01:37 -0500354static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
355 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100356{
357 return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
David Woodhouse5844d122007-12-18 02:01:37 -0500358 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100359}
360
361
David Woodhouse5844d122007-12-18 02:01:37 -0500362static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
363 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100364{
365 return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
David Woodhouse5844d122007-12-18 02:01:37 -0500366 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100367}
368
David Woodhouse5844d122007-12-18 02:01:37 -0500369static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
370 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100371{
372 return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
David Woodhouse5844d122007-12-18 02:01:37 -0500373 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100374}
375
376
David Woodhouse5844d122007-12-18 02:01:37 -0500377static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
378 size_t count, loff_t *ppos)
Holger Schurig3a188642007-11-26 10:07:14 +0100379{
380 return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
David Woodhouse5844d122007-12-18 02:01:37 -0500381 file, userbuf, count, ppos);
Holger Schurig3a188642007-11-26 10:07:14 +0100382}
383
384
385
Holger Schurig10078322007-11-15 18:05:47 -0500386static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200387 size_t count, loff_t *ppos)
388{
Holger Schurig69f90322007-11-23 15:43:44 +0100389 struct lbs_private *priv = file->private_data;
Holger Schurig10078322007-11-15 18:05:47 -0500390 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200391 ssize_t pos = 0;
392 int ret;
393 unsigned long addr = get_zeroed_page(GFP_KERNEL);
394 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530395 if (!buf)
396 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200397
398 offval.offset = priv->mac_offset;
399 offval.value = 0;
400
Holger Schurig10078322007-11-15 18:05:47 -0500401 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400402 CMD_MAC_REG_ACCESS, 0,
403 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200404 mdelay(10);
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700405 if (!ret) {
406 pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000407 priv->mac_offset, priv->offsetvalue.value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200408
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700409 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
410 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200411 free_page(addr);
412 return ret;
413}
414
Holger Schurig10078322007-11-15 18:05:47 -0500415static ssize_t lbs_rdmac_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200416 const char __user *userbuf,
417 size_t count, loff_t *ppos)
418{
Holger Schurig69f90322007-11-23 15:43:44 +0100419 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200420 ssize_t res, buf_size;
421 unsigned long addr = get_zeroed_page(GFP_KERNEL);
422 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530423 if (!buf)
424 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200425
426 buf_size = min(count, len - 1);
427 if (copy_from_user(buf, userbuf, buf_size)) {
428 res = -EFAULT;
429 goto out_unlock;
430 }
431 priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
432 res = count;
433out_unlock:
434 free_page(addr);
435 return res;
436}
437
Holger Schurig10078322007-11-15 18:05:47 -0500438static ssize_t lbs_wrmac_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439 const char __user *userbuf,
440 size_t count, loff_t *ppos)
441{
442
Holger Schurig69f90322007-11-23 15:43:44 +0100443 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200444 ssize_t res, buf_size;
445 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500446 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200447 unsigned long addr = get_zeroed_page(GFP_KERNEL);
448 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530449 if (!buf)
450 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200451
452 buf_size = min(count, len - 1);
453 if (copy_from_user(buf, userbuf, buf_size)) {
454 res = -EFAULT;
455 goto out_unlock;
456 }
457 res = sscanf(buf, "%x %x", &offset, &value);
458 if (res != 2) {
459 res = -EFAULT;
460 goto out_unlock;
461 }
462
463 offval.offset = offset;
464 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500465 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400466 CMD_MAC_REG_ACCESS, 1,
467 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468 mdelay(10);
469
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700470 if (!res)
471 res = count;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200472out_unlock:
473 free_page(addr);
474 return res;
475}
476
Holger Schurig10078322007-11-15 18:05:47 -0500477static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200478 size_t count, loff_t *ppos)
479{
Holger Schurig69f90322007-11-23 15:43:44 +0100480 struct lbs_private *priv = file->private_data;
Holger Schurig10078322007-11-15 18:05:47 -0500481 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 ssize_t pos = 0;
483 int ret;
484 unsigned long addr = get_zeroed_page(GFP_KERNEL);
485 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530486 if (!buf)
487 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200488
489 offval.offset = priv->bbp_offset;
490 offval.value = 0;
491
Holger Schurig10078322007-11-15 18:05:47 -0500492 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400493 CMD_BBP_REG_ACCESS, 0,
494 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200495 mdelay(10);
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700496 if (!ret) {
497 pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000498 priv->bbp_offset, priv->offsetvalue.value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200499
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700500 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
501 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200502 free_page(addr);
503
504 return ret;
505}
506
Holger Schurig10078322007-11-15 18:05:47 -0500507static ssize_t lbs_rdbbp_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200508 const char __user *userbuf,
509 size_t count, loff_t *ppos)
510{
Holger Schurig69f90322007-11-23 15:43:44 +0100511 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200512 ssize_t res, buf_size;
513 unsigned long addr = get_zeroed_page(GFP_KERNEL);
514 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530515 if (!buf)
516 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200517
518 buf_size = min(count, len - 1);
519 if (copy_from_user(buf, userbuf, buf_size)) {
520 res = -EFAULT;
521 goto out_unlock;
522 }
523 priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
524 res = count;
525out_unlock:
526 free_page(addr);
527 return res;
528}
529
Holger Schurig10078322007-11-15 18:05:47 -0500530static ssize_t lbs_wrbbp_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200531 const char __user *userbuf,
532 size_t count, loff_t *ppos)
533{
534
Holger Schurig69f90322007-11-23 15:43:44 +0100535 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200536 ssize_t res, buf_size;
537 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500538 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200539 unsigned long addr = get_zeroed_page(GFP_KERNEL);
540 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530541 if (!buf)
542 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200543
544 buf_size = min(count, len - 1);
545 if (copy_from_user(buf, userbuf, buf_size)) {
546 res = -EFAULT;
547 goto out_unlock;
548 }
549 res = sscanf(buf, "%x %x", &offset, &value);
550 if (res != 2) {
551 res = -EFAULT;
552 goto out_unlock;
553 }
554
555 offval.offset = offset;
556 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500557 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400558 CMD_BBP_REG_ACCESS, 1,
559 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200560 mdelay(10);
561
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700562 if (!res)
563 res = count;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200564out_unlock:
565 free_page(addr);
566 return res;
567}
568
Holger Schurig10078322007-11-15 18:05:47 -0500569static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200570 size_t count, loff_t *ppos)
571{
Holger Schurig69f90322007-11-23 15:43:44 +0100572 struct lbs_private *priv = file->private_data;
Holger Schurig10078322007-11-15 18:05:47 -0500573 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200574 ssize_t pos = 0;
575 int ret;
576 unsigned long addr = get_zeroed_page(GFP_KERNEL);
577 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530578 if (!buf)
579 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200580
581 offval.offset = priv->rf_offset;
582 offval.value = 0;
583
Holger Schurig10078322007-11-15 18:05:47 -0500584 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400585 CMD_RF_REG_ACCESS, 0,
586 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200587 mdelay(10);
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700588 if (!ret) {
589 pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000590 priv->rf_offset, priv->offsetvalue.value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200591
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700592 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
593 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200594 free_page(addr);
595
596 return ret;
597}
598
Holger Schurig10078322007-11-15 18:05:47 -0500599static ssize_t lbs_rdrf_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200600 const char __user *userbuf,
601 size_t count, loff_t *ppos)
602{
Holger Schurig69f90322007-11-23 15:43:44 +0100603 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 ssize_t res, buf_size;
605 unsigned long addr = get_zeroed_page(GFP_KERNEL);
606 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530607 if (!buf)
608 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200609
610 buf_size = min(count, len - 1);
611 if (copy_from_user(buf, userbuf, buf_size)) {
612 res = -EFAULT;
613 goto out_unlock;
614 }
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800615 priv->rf_offset = simple_strtoul(buf, NULL, 16);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200616 res = count;
617out_unlock:
618 free_page(addr);
619 return res;
620}
621
Holger Schurig10078322007-11-15 18:05:47 -0500622static ssize_t lbs_wrrf_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200623 const char __user *userbuf,
624 size_t count, loff_t *ppos)
625{
626
Holger Schurig69f90322007-11-23 15:43:44 +0100627 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200628 ssize_t res, buf_size;
629 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500630 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200631 unsigned long addr = get_zeroed_page(GFP_KERNEL);
632 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530633 if (!buf)
634 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200635
636 buf_size = min(count, len - 1);
637 if (copy_from_user(buf, userbuf, buf_size)) {
638 res = -EFAULT;
639 goto out_unlock;
640 }
641 res = sscanf(buf, "%x %x", &offset, &value);
642 if (res != 2) {
643 res = -EFAULT;
644 goto out_unlock;
645 }
646
647 offval.offset = offset;
648 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500649 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400650 CMD_RF_REG_ACCESS, 1,
651 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200652 mdelay(10);
653
Amitkumar Karwarc0bbd572009-10-08 19:38:45 -0700654 if (!res)
655 res = count;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200656out_unlock:
657 free_page(addr);
658 return res;
659}
660
661#define FOPS(fread, fwrite) { \
662 .owner = THIS_MODULE, \
663 .open = open_file_generic, \
664 .read = (fread), \
665 .write = (fwrite), \
666}
667
Holger Schurig10078322007-11-15 18:05:47 -0500668struct lbs_debugfs_files {
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800669 const char *name;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200670 int perm;
671 struct file_operations fops;
672};
673
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800674static const struct lbs_debugfs_files debugfs_files[] = {
Holger Schurig10078322007-11-15 18:05:47 -0500675 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
Holger Schurig10078322007-11-15 18:05:47 -0500676 { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
677 lbs_sleepparams_write), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200678};
679
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800680static const struct lbs_debugfs_files debugfs_events_files[] = {
Holger Schurig10078322007-11-15 18:05:47 -0500681 {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
682 lbs_lowrssi_write), },
683 {"low_snr", 0644, FOPS(lbs_lowsnr_read,
684 lbs_lowsnr_write), },
685 {"failure_count", 0644, FOPS(lbs_failcount_read,
686 lbs_failcount_write), },
687 {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
688 lbs_bcnmiss_write), },
689 {"high_rssi", 0644, FOPS(lbs_highrssi_read,
690 lbs_highrssi_write), },
691 {"high_snr", 0644, FOPS(lbs_highsnr_read,
692 lbs_highsnr_write), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200693};
694
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800695static const struct lbs_debugfs_files debugfs_regs_files[] = {
Holger Schurig10078322007-11-15 18:05:47 -0500696 {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
697 {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
698 {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
699 {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
700 {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
701 {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200702};
703
Holger Schurig10078322007-11-15 18:05:47 -0500704void lbs_debugfs_init(void)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200705{
Holger Schurig10078322007-11-15 18:05:47 -0500706 if (!lbs_dir)
707 lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200708}
709
Holger Schurig10078322007-11-15 18:05:47 -0500710void lbs_debugfs_remove(void)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200711{
Holger Schurig10078322007-11-15 18:05:47 -0500712 if (lbs_dir)
713 debugfs_remove(lbs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200714}
715
Holger Schurig69f90322007-11-23 15:43:44 +0100716void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200717{
718 int i;
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800719 const struct lbs_debugfs_files *files;
Holger Schurig10078322007-11-15 18:05:47 -0500720 if (!lbs_dir)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200721 goto exit;
722
Holger Schurig10078322007-11-15 18:05:47 -0500723 priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200724 if (!priv->debugfs_dir)
725 goto exit;
726
727 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
728 files = &debugfs_files[i];
729 priv->debugfs_files[i] = debugfs_create_file(files->name,
730 files->perm,
731 priv->debugfs_dir,
732 priv,
733 &files->fops);
734 }
735
736 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
737 if (!priv->events_dir)
738 goto exit;
739
740 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
741 files = &debugfs_events_files[i];
742 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
743 files->perm,
744 priv->events_dir,
745 priv,
746 &files->fops);
747 }
748
749 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
750 if (!priv->regs_dir)
751 goto exit;
752
753 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
754 files = &debugfs_regs_files[i];
755 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
756 files->perm,
757 priv->regs_dir,
758 priv,
759 &files->fops);
760 }
761
762#ifdef PROC_DEBUG
Holger Schurige98a88d2008-03-19 14:25:58 +0100763 lbs_debug_init(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200764#endif
765exit:
766 return;
767}
768
Holger Schurig69f90322007-11-23 15:43:44 +0100769void lbs_debugfs_remove_one(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200770{
771 int i;
772
773 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
774 debugfs_remove(priv->debugfs_regs_files[i]);
775
776 debugfs_remove(priv->regs_dir);
777
Holger Schurig0b7db952007-05-24 23:47:34 -0400778 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200779 debugfs_remove(priv->debugfs_events_files[i]);
780
781 debugfs_remove(priv->events_dir);
782#ifdef PROC_DEBUG
783 debugfs_remove(priv->debugfs_debug);
784#endif
785 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
786 debugfs_remove(priv->debugfs_files[i]);
Holger Schurig0b7db952007-05-24 23:47:34 -0400787 debugfs_remove(priv->debugfs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200788}
789
Holger Schurig46868202007-05-25 00:37:28 -0400790
791
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200792/* debug entry */
793
Holger Schurig46868202007-05-25 00:37:28 -0400794#ifdef PROC_DEBUG
795
David Woodhouseaa21c002007-12-08 20:04:36 +0000796#define item_size(n) (FIELD_SIZEOF(struct lbs_private, n))
797#define item_addr(n) (offsetof(struct lbs_private, n))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200798
Holger Schurig46868202007-05-25 00:37:28 -0400799
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200800struct debug_data {
801 char name[32];
802 u32 size;
Dan Williams4269e2a2007-05-10 23:10:18 -0400803 size_t addr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200804};
805
David Woodhouseaa21c002007-12-08 20:04:36 +0000806/* To debug any member of struct lbs_private, simply add one line here.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200807 */
808static struct debug_data items[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200809 {"psmode", item_size(psmode), item_addr(psmode)},
810 {"psstate", item_size(psstate), item_addr(psstate)},
811};
812
Tony Breedsd2f11e02007-03-09 13:11:46 +1100813static int num_of_items = ARRAY_SIZE(items);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200814
815/**
816 * @brief proc read function
817 *
818 * @param page pointer to buffer
819 * @param s read data starting position
820 * @param off offset
821 * @param cnt counter
822 * @param eof end of file flag
823 * @param data data to output
824 * @return number of output data
825 */
Holger Schurig10078322007-11-15 18:05:47 -0500826static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200827 size_t count, loff_t *ppos)
828{
829 int val = 0;
830 size_t pos = 0;
831 ssize_t res;
832 char *p;
833 int i;
834 struct debug_data *d;
835 unsigned long addr = get_zeroed_page(GFP_KERNEL);
836 char *buf = (char *)addr;
Kiran Divekarad43f8b2009-08-28 17:47:59 +0530837 if (!buf)
838 return -ENOMEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200839
840 p = buf;
841
842 d = (struct debug_data *)file->private_data;
843
844 for (i = 0; i < num_of_items; i++) {
845 if (d[i].size == 1)
846 val = *((u8 *) d[i].addr);
847 else if (d[i].size == 2)
848 val = *((u16 *) d[i].addr);
849 else if (d[i].size == 4)
850 val = *((u32 *) d[i].addr);
Dan Williams4269e2a2007-05-10 23:10:18 -0400851 else if (d[i].size == 8)
852 val = *((u64 *) d[i].addr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200853
854 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
855 }
856
857 res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
858
859 free_page(addr);
860 return res;
861}
862
863/**
864 * @brief proc write function
865 *
866 * @param f file pointer
867 * @param buf pointer to data buffer
868 * @param cnt data number to write
869 * @param data data to write
870 * @return number of data
871 */
Holger Schurig10078322007-11-15 18:05:47 -0500872static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200873 size_t cnt, loff_t *ppos)
874{
875 int r, i;
876 char *pdata;
877 char *p;
878 char *p0;
879 char *p1;
880 char *p2;
881 struct debug_data *d = (struct debug_data *)f->private_data;
882
Jesper Juhl655b4d12007-08-24 11:48:16 -0400883 pdata = kmalloc(cnt, GFP_KERNEL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200884 if (pdata == NULL)
885 return 0;
886
887 if (copy_from_user(pdata, buf, cnt)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400888 lbs_deb_debugfs("Copy from user failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200889 kfree(pdata);
890 return 0;
891 }
892
893 p0 = pdata;
894 for (i = 0; i < num_of_items; i++) {
895 do {
896 p = strstr(p0, d[i].name);
897 if (p == NULL)
898 break;
899 p1 = strchr(p, '\n');
900 if (p1 == NULL)
901 break;
902 p0 = p1++;
903 p2 = strchr(p, '=');
904 if (!p2)
905 break;
906 p2++;
Tony Breedsd2f11e02007-03-09 13:11:46 +1100907 r = simple_strtoul(p2, NULL, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200908 if (d[i].size == 1)
909 *((u8 *) d[i].addr) = (u8) r;
910 else if (d[i].size == 2)
911 *((u16 *) d[i].addr) = (u16) r;
912 else if (d[i].size == 4)
913 *((u32 *) d[i].addr) = (u32) r;
Dan Williams4269e2a2007-05-10 23:10:18 -0400914 else if (d[i].size == 8)
915 *((u64 *) d[i].addr) = (u64) r;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200916 break;
917 } while (1);
918 }
919 kfree(pdata);
920
Dan Williams4269e2a2007-05-10 23:10:18 -0400921 return (ssize_t)cnt;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200922}
923
Jan Engelhardt4101dec2009-01-14 13:52:18 -0800924static const struct file_operations lbs_debug_fops = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200925 .owner = THIS_MODULE,
926 .open = open_file_generic,
Holger Schurig10078322007-11-15 18:05:47 -0500927 .write = lbs_debugfs_write,
928 .read = lbs_debugfs_read,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200929};
930
931/**
932 * @brief create debug proc file
933 *
Holger Schurig69f90322007-11-23 15:43:44 +0100934 * @param priv pointer struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200935 * @param dev pointer net_device
936 * @return N/A
937 */
Holger Schurige98a88d2008-03-19 14:25:58 +0100938static void lbs_debug_init(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200939{
940 int i;
941
942 if (!priv->debugfs_dir)
943 return;
944
945 for (i = 0; i < num_of_items; i++)
David Woodhouseaa21c002007-12-08 20:04:36 +0000946 items[i].addr += (size_t) priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200947
948 priv->debugfs_debug = debugfs_create_file("debug", 0644,
949 priv->debugfs_dir, &items[0],
Holger Schurig10078322007-11-15 18:05:47 -0500950 &lbs_debug_fops);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200951}
Holger Schurig46868202007-05-25 00:37:28 -0400952#endif