blob: e79236cfdbc17bf281fb80ad1135b61d626bd640 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001#include <linux/module.h>
2#include <linux/dcache.h>
3#include <linux/debugfs.h>
4#include <linux/delay.h>
5#include <linux/mm.h>
Geert Uytterhoevend8b0fb52007-10-08 09:43:02 +02006#include <linux/string.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02007#include <net/iw_handler.h>
Holger Schurig46868202007-05-25 00:37:28 -04008
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02009#include "dev.h"
10#include "decl.h"
11#include "host.h"
Dan Williams5bdb3ef2007-05-10 23:08:05 -040012#include "debugfs.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020013
Holger Schurig10078322007-11-15 18:05:47 -050014static struct dentry *lbs_dir;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020015static char *szStates[] = {
16 "Connected",
17 "Disconnected"
18};
19
Holger Schurig46868202007-05-25 00:37:28 -040020#ifdef PROC_DEBUG
Holger Schurig69f90322007-11-23 15:43:44 +010021static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev);
Holger Schurig46868202007-05-25 00:37:28 -040022#endif
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020023
24static int open_file_generic(struct inode *inode, struct file *file)
25{
26 file->private_data = inode->i_private;
27 return 0;
28}
29
30static ssize_t write_file_dummy(struct file *file, const char __user *buf,
31 size_t count, loff_t *ppos)
32{
33 return -EINVAL;
34}
35
36static const size_t len = PAGE_SIZE;
37
Holger Schurig10078322007-11-15 18:05:47 -050038static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020039 size_t count, loff_t *ppos)
40{
Holger Schurig69f90322007-11-23 15:43:44 +010041 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020042 size_t pos = 0;
43 unsigned long addr = get_zeroed_page(GFP_KERNEL);
44 char *buf = (char *)addr;
45 ssize_t res;
46
47 pos += snprintf(buf+pos, len-pos, "state = %s\n",
48 szStates[priv->adapter->connect_status]);
49 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
50 (u32) priv->adapter->regioncode);
51
52 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
53
54 free_page(addr);
55 return res;
56}
57
58
Holger Schurig10078322007-11-15 18:05:47 -050059static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020060 size_t count, loff_t *ppos)
61{
Holger Schurig69f90322007-11-23 15:43:44 +010062 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020063 size_t pos = 0;
64 int numscansdone = 0, res;
65 unsigned long addr = get_zeroed_page(GFP_KERNEL);
66 char *buf = (char *)addr;
Joe Perches0795af52007-10-03 17:59:30 -070067 DECLARE_MAC_BUF(mac);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040068 struct bss_descriptor * iter_bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020069
70 pos += snprintf(buf+pos, len-pos,
Holger Schuriga2235ed2007-08-02 13:12:45 -040071 "# | ch | rssi | bssid | cap | Qual | SSID \n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020072
Dan Williamsfcdb53d2007-05-25 16:15:56 -040073 mutex_lock(&priv->adapter->lock);
74 list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
Dan Williams0c9ca692007-08-02 10:43:44 -040075 u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
76 u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
77 u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020078
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020079 pos += snprintf(buf+pos, len-pos,
Joe Perches0795af52007-10-03 17:59:30 -070080 "%02u| %03d | %04ld | %s |",
Dan Williamsfcdb53d2007-05-25 16:15:56 -040081 numscansdone, iter_bss->channel, iter_bss->rssi,
Joe Perches0795af52007-10-03 17:59:30 -070082 print_mac(mac, iter_bss->bssid));
Dan Williams0c9ca692007-08-02 10:43:44 -040083 pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020084 pos += snprintf(buf+pos, len-pos, "%c%c%c |",
Dan Williams0c9ca692007-08-02 10:43:44 -040085 ibss ? 'A' : 'I', privacy ? 'P' : ' ',
86 spectrum_mgmt ? 'S' : ' ');
Holger Schuriga2235ed2007-08-02 13:12:45 -040087 pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
Dan Williamsd8efea22007-05-28 23:54:55 -040088 pos += snprintf(buf+pos, len-pos, " %s\n",
89 escape_essid(iter_bss->ssid, iter_bss->ssid_len));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020090
91 numscansdone++;
92 }
Dan Williamsfcdb53d2007-05-25 16:15:56 -040093 mutex_unlock(&priv->adapter->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020094
95 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
96
97 free_page(addr);
98 return res;
99}
100
Holger Schurig10078322007-11-15 18:05:47 -0500101static ssize_t lbs_sleepparams_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200102 const char __user *user_buf, size_t count,
103 loff_t *ppos)
104{
Holger Schurig69f90322007-11-23 15:43:44 +0100105 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200106 ssize_t buf_size, res;
107 int p1, p2, p3, p4, p5, p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200108 unsigned long addr = get_zeroed_page(GFP_KERNEL);
109 char *buf = (char *)addr;
110
111 buf_size = min(count, len - 1);
112 if (copy_from_user(buf, user_buf, buf_size)) {
113 res = -EFAULT;
114 goto out_unlock;
115 }
116 res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
117 if (res != 6) {
118 res = -EFAULT;
119 goto out_unlock;
120 }
David Woodhouse981f1872007-05-25 23:36:54 -0400121 priv->adapter->sp.sp_error = p1;
122 priv->adapter->sp.sp_offset = p2;
123 priv->adapter->sp.sp_stabletime = p3;
124 priv->adapter->sp.sp_calcontrol = p4;
125 priv->adapter->sp.sp_extsleepclk = p5;
126 priv->adapter->sp.sp_reserved = p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200127
Holger Schurig10078322007-11-15 18:05:47 -0500128 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400129 CMD_802_11_SLEEP_PARAMS,
130 CMD_ACT_SET,
131 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200132
133 if (!res)
134 res = count;
135 else
136 res = -EINVAL;
137
138out_unlock:
139 free_page(addr);
140 return res;
141}
142
Holger Schurig10078322007-11-15 18:05:47 -0500143static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200144 size_t count, loff_t *ppos)
145{
Holger Schurig69f90322007-11-23 15:43:44 +0100146 struct lbs_private *priv = file->private_data;
147 struct lbs_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200148 ssize_t res;
149 size_t pos = 0;
150 unsigned long addr = get_zeroed_page(GFP_KERNEL);
151 char *buf = (char *)addr;
152
Holger Schurig10078322007-11-15 18:05:47 -0500153 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400154 CMD_802_11_SLEEP_PARAMS,
155 CMD_ACT_GET,
156 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200157 if (res) {
158 res = -EFAULT;
159 goto out_unlock;
160 }
161
162 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
163 adapter->sp.sp_offset, adapter->sp.sp_stabletime,
164 adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
165 adapter->sp.sp_reserved);
166
167 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
168
169out_unlock:
170 free_page(addr);
171 return res;
172}
173
Holger Schurig10078322007-11-15 18:05:47 -0500174static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200175 size_t count, loff_t *ppos)
176{
Holger Schurig69f90322007-11-23 15:43:44 +0100177 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200178 ssize_t res, buf_size;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200179 union iwreq_data wrqu;
180 unsigned long addr = get_zeroed_page(GFP_KERNEL);
181 char *buf = (char *)addr;
182
183 buf_size = min(count, len - 1);
184 if (copy_from_user(buf, userbuf, buf_size)) {
185 res = -EFAULT;
186 goto out_unlock;
187 }
188
Holger Schurig10078322007-11-15 18:05:47 -0500189 lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200190
191 memset(&wrqu, 0, sizeof(union iwreq_data));
Holger Schurig634b8f42007-05-25 13:05:16 -0400192 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200193
194out_unlock:
195 free_page(addr);
196 return count;
197}
198
Holger Schurig10078322007-11-15 18:05:47 -0500199static int lbs_parse_chan(char *buf, size_t count,
200 struct lbs_ioctl_user_scan_cfg *scan_cfg, int dur)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200201{
202 char *start, *end, *hold, *str;
203 int i = 0;
204
205 start = strstr(buf, "chan=");
206 if (!start)
207 return -EINVAL;
208 start += 5;
Geert Uytterhoevend8b0fb52007-10-08 09:43:02 +0200209 end = strchr(start, ' ');
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200210 if (!end)
211 end = buf + count;
212 hold = kzalloc((end - start)+1, GFP_KERNEL);
213 if (!hold)
214 return -ENOMEM;
215 strncpy(hold, start, end - start);
216 hold[(end-start)+1] = '\0';
217 while(hold && (str = strsep(&hold, ","))) {
218 int chan;
219 char band, passive = 0;
220 sscanf(str, "%d%c%c", &chan, &band, &passive);
221 scan_cfg->chanlist[i].channumber = chan;
222 scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
223 if (band == 'b' || band == 'g')
224 scan_cfg->chanlist[i].radiotype = 0;
225 else if (band == 'a')
226 scan_cfg->chanlist[i].radiotype = 1;
227
228 scan_cfg->chanlist[i].scantime = dur;
229 i++;
230 }
231
232 kfree(hold);
233 return i;
234}
235
Holger Schurig10078322007-11-15 18:05:47 -0500236static void lbs_parse_bssid(char *buf, size_t count,
237 struct lbs_ioctl_user_scan_cfg *scan_cfg)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200238{
239 char *hold;
240 unsigned int mac[ETH_ALEN];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200241
242 hold = strstr(buf, "bssid=");
243 if (!hold)
244 return;
245 hold += 6;
David S. Miller15ca36f2007-12-27 16:43:38 -0800246 sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x",
247 mac, mac+1, mac+2, mac+3, mac+4, mac+5);
Dan Williamseb8f7332007-05-25 16:25:21 -0400248 memcpy(scan_cfg->bssid, mac, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200249}
250
Holger Schurig10078322007-11-15 18:05:47 -0500251static void lbs_parse_ssid(char *buf, size_t count,
252 struct lbs_ioctl_user_scan_cfg *scan_cfg)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200253{
254 char *hold, *end;
255 ssize_t size;
256
257 hold = strstr(buf, "ssid=");
258 if (!hold)
259 return;
260 hold += 5;
Geert Uytterhoevend8b0fb52007-10-08 09:43:02 +0200261 end = strchr(hold, ' ');
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200262 if (!end)
263 end = buf + count - 1;
264
Dan Williams4269e2a2007-05-10 23:10:18 -0400265 size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
Dan Williamseb8f7332007-05-25 16:25:21 -0400266 strncpy(scan_cfg->ssid, hold, size);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200267
268 return;
269}
270
Holger Schurig10078322007-11-15 18:05:47 -0500271static int lbs_parse_clear(char *buf, size_t count, const char *tag)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200272{
273 char *hold;
274 int val;
275
Dan Williamseb8f7332007-05-25 16:25:21 -0400276 hold = strstr(buf, tag);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200277 if (!hold)
Dan Williamseb8f7332007-05-25 16:25:21 -0400278 return 0;
279 hold += strlen(tag);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200280 sscanf(hold, "%d", &val);
281
282 if (val != 0)
283 val = 1;
284
Dan Williamseb8f7332007-05-25 16:25:21 -0400285 return val;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200286}
287
Holger Schurig10078322007-11-15 18:05:47 -0500288static int lbs_parse_dur(char *buf, size_t count,
289 struct lbs_ioctl_user_scan_cfg *scan_cfg)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200290{
291 char *hold;
292 int val;
293
294 hold = strstr(buf, "dur=");
295 if (!hold)
296 return 0;
297 hold += 4;
298 sscanf(hold, "%d", &val);
299
300 return val;
301}
302
Holger Schurig10078322007-11-15 18:05:47 -0500303static void lbs_parse_type(char *buf, size_t count,
304 struct lbs_ioctl_user_scan_cfg *scan_cfg)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200305{
306 char *hold;
307 int val;
308
309 hold = strstr(buf, "type=");
310 if (!hold)
311 return;
312 hold += 5;
313 sscanf(hold, "%d", &val);
314
315 /* type=1,2 or 3 */
316 if (val < 1 || val > 3)
317 return;
318
319 scan_cfg->bsstype = val;
320
321 return;
322}
323
Holger Schurig10078322007-11-15 18:05:47 -0500324static ssize_t lbs_setuserscan(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200325 const char __user *userbuf,
326 size_t count, loff_t *ppos)
327{
Holger Schurig69f90322007-11-23 15:43:44 +0100328 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200329 ssize_t res, buf_size;
Holger Schurig10078322007-11-15 18:05:47 -0500330 struct lbs_ioctl_user_scan_cfg *scan_cfg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200331 union iwreq_data wrqu;
332 int dur;
333 unsigned long addr = get_zeroed_page(GFP_KERNEL);
334 char *buf = (char *)addr;
335
Holger Schurig10078322007-11-15 18:05:47 -0500336 scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200337 if (!scan_cfg)
338 return -ENOMEM;
339
340 buf_size = min(count, len - 1);
341 if (copy_from_user(buf, userbuf, buf_size)) {
342 res = -EFAULT;
343 goto out_unlock;
344 }
345
Holger Schurig10078322007-11-15 18:05:47 -0500346 scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200347
Holger Schurig10078322007-11-15 18:05:47 -0500348 dur = lbs_parse_dur(buf, count, scan_cfg);
349 lbs_parse_chan(buf, count, scan_cfg, dur);
350 lbs_parse_bssid(buf, count, scan_cfg);
351 scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
352 lbs_parse_ssid(buf, count, scan_cfg);
353 scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
Holger Schurig10078322007-11-15 18:05:47 -0500354 lbs_parse_type(buf, count, scan_cfg);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200355
Holger Schurig10078322007-11-15 18:05:47 -0500356 lbs_scan_networks(priv, scan_cfg, 1);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200357 wait_event_interruptible(priv->adapter->cmd_pending,
358 !priv->adapter->nr_cmd_pending);
359
360 memset(&wrqu, 0x00, sizeof(union iwreq_data));
Holger Schurig634b8f42007-05-25 13:05:16 -0400361 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200362
363out_unlock:
364 free_page(addr);
365 kfree(scan_cfg);
366 return count;
367}
368
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200369
Holger Schurig3a188642007-11-26 10:07:14 +0100370/*
371 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
372 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
373 * firmware. Here's an example:
374 * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
375 * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
376 * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
377 *
378 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
379 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
380 * defined in mrvlietypes_thresholds
381 *
382 * This function searches in this TLV data chunk for a given TLV type
383 * and returns a pointer to the first data byte of the TLV, or to NULL
384 * if the TLV hasn't been found.
385 */
386static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200387{
Holger Schurig3a188642007-11-26 10:07:14 +0100388 __le16 le_type = cpu_to_le16(tlv_type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389 ssize_t pos = 0;
Holger Schurig3a188642007-11-26 10:07:14 +0100390 struct mrvlietypesheader *tlv_h;
391 while (pos < size) {
392 u16 length;
393 tlv_h = (struct mrvlietypesheader *) tlv;
394 if (tlv_h->type == le_type)
395 return tlv_h;
396 if (tlv_h->len == 0)
397 return NULL;
398 length = le16_to_cpu(tlv_h->len) +
399 sizeof(struct mrvlietypesheader);
400 pos += length;
401 tlv += length;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200402 }
Holger Schurig3a188642007-11-26 10:07:14 +0100403 return NULL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200404}
405
Holger Schurig3a188642007-11-26 10:07:14 +0100406
407/*
408 * This just gets the bitmap of currently subscribed events. Used when
409 * adding an additonal event subscription.
410 */
Holger Schurig69f90322007-11-23 15:43:44 +0100411static u16 lbs_get_events_bitmap(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200412{
Holger Schurig3a188642007-11-26 10:07:14 +0100413 ssize_t res;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200414
Holger Schurig3a188642007-11-26 10:07:14 +0100415 struct cmd_ds_802_11_subscribe_event *events = kzalloc(
416 sizeof(struct cmd_ds_802_11_subscribe_event),
417 GFP_KERNEL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200418
Holger Schurig3a188642007-11-26 10:07:14 +0100419 res = lbs_prepare_and_send_command(priv,
420 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
421 CMD_OPTION_WAITFORRSP, 0, events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200422
Holger Schurig3a188642007-11-26 10:07:14 +0100423 if (res) {
424 kfree(events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200425 return 0;
426 }
Holger Schurig3a188642007-11-26 10:07:14 +0100427 return le16_to_cpu(events->events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200428}
429
Holger Schurig3a188642007-11-26 10:07:14 +0100430
431static ssize_t lbs_threshold_read(
432 u16 tlv_type, u16 event_mask,
433 struct file *file, char __user *userbuf,
434 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200435{
Holger Schurig69f90322007-11-23 15:43:44 +0100436 struct lbs_private *priv = file->private_data;
Holger Schurig3a188642007-11-26 10:07:14 +0100437 ssize_t res = 0;
438 size_t pos = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439 unsigned long addr = get_zeroed_page(GFP_KERNEL);
440 char *buf = (char *)addr;
Holger Schurig3a188642007-11-26 10:07:14 +0100441 u8 value;
442 u8 freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200443
Holger Schurig3a188642007-11-26 10:07:14 +0100444 struct cmd_ds_802_11_subscribe_event *events = kzalloc(
445 sizeof(struct cmd_ds_802_11_subscribe_event),
446 GFP_KERNEL);
447 struct mrvlietypes_thresholds *got;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200448
Holger Schurig3a188642007-11-26 10:07:14 +0100449 res = lbs_prepare_and_send_command(priv,
450 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
451 CMD_OPTION_WAITFORRSP, 0, events);
452 if (res) {
453 kfree(events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200454 return res;
455 }
456
Holger Schurig3a188642007-11-26 10:07:14 +0100457 got = lbs_tlv_find(tlv_type, events->tlv, sizeof(events->tlv));
458 if (got) {
459 value = got->value;
460 freq = got->freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200461 }
Holger Schurig3a188642007-11-26 10:07:14 +0100462 kfree(events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200463
Holger Schurig3a188642007-11-26 10:07:14 +0100464 if (got)
465 pos += snprintf(buf, len, "%d %d %d\n", value, freq,
466 !!(le16_to_cpu(events->events) & event_mask));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467
468 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
Holger Schurig3a188642007-11-26 10:07:14 +0100469
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200470 free_page(addr);
471 return res;
472}
473
Holger Schurig3a188642007-11-26 10:07:14 +0100474
475static ssize_t lbs_threshold_write(
476 u16 tlv_type, u16 event_mask,
477 struct file *file,
478 const char __user *userbuf,
479 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200480{
Holger Schurig69f90322007-11-23 15:43:44 +0100481 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 ssize_t res, buf_size;
Holger Schurig3a188642007-11-26 10:07:14 +0100483 int value, freq, curr_mask, new_mask;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200484 unsigned long addr = get_zeroed_page(GFP_KERNEL);
485 char *buf = (char *)addr;
Holger Schurig3a188642007-11-26 10:07:14 +0100486 struct cmd_ds_802_11_subscribe_event *events;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200487
488 buf_size = min(count, len - 1);
489 if (copy_from_user(buf, userbuf, buf_size)) {
490 res = -EFAULT;
491 goto out_unlock;
492 }
Holger Schurig3a188642007-11-26 10:07:14 +0100493 res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200494 if (res != 3) {
495 res = -EFAULT;
496 goto out_unlock;
497 }
Holger Schurig3a188642007-11-26 10:07:14 +0100498 curr_mask = lbs_get_events_bitmap(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200499
Holger Schurig3a188642007-11-26 10:07:14 +0100500 if (new_mask)
501 new_mask = curr_mask | event_mask;
502 else
503 new_mask = curr_mask & ~event_mask;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200504
Holger Schurig3a188642007-11-26 10:07:14 +0100505 /* Now everything is set and we can send stuff down to the firmware */
506 events = kzalloc(
507 sizeof(struct cmd_ds_802_11_subscribe_event),
508 GFP_KERNEL);
509 if (events) {
510 struct mrvlietypes_thresholds *tlv =
511 (struct mrvlietypes_thresholds *) events->tlv;
512 events->action = cpu_to_le16(CMD_ACT_SET);
513 events->events = cpu_to_le16(new_mask);
514 tlv->header.type = cpu_to_le16(tlv_type);
515 tlv->header.len = cpu_to_le16(
516 sizeof(struct mrvlietypes_thresholds) -
517 sizeof(struct mrvlietypesheader));
518 tlv->value = value;
519 if (tlv_type != TLV_TYPE_BCNMISS)
520 tlv->freq = freq;
521 lbs_prepare_and_send_command(priv,
522 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
523 CMD_OPTION_WAITFORRSP, 0, events);
524 kfree(events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200525 }
526
527 res = count;
528out_unlock:
529 free_page(addr);
530 return res;
531}
532
Holger Schurig3a188642007-11-26 10:07:14 +0100533
534static ssize_t lbs_lowrssi_read(
535 struct file *file, char __user *userbuf,
536 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200537{
Holger Schurig3a188642007-11-26 10:07:14 +0100538 return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
539 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200540}
541
Holger Schurig3a188642007-11-26 10:07:14 +0100542
543static ssize_t lbs_lowrssi_write(
544 struct file *file, const char __user *userbuf,
545 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200546{
Holger Schurig3a188642007-11-26 10:07:14 +0100547 return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
548 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200549}
550
Holger Schurig3a188642007-11-26 10:07:14 +0100551
552static ssize_t lbs_lowsnr_read(
553 struct file *file, char __user *userbuf,
554 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200555{
Holger Schurig3a188642007-11-26 10:07:14 +0100556 return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
557 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200558}
559
Holger Schurig3a188642007-11-26 10:07:14 +0100560
561static ssize_t lbs_lowsnr_write(
562 struct file *file, const char __user *userbuf,
563 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200564{
Holger Schurig3a188642007-11-26 10:07:14 +0100565 return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
566 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200567}
568
Holger Schurig3a188642007-11-26 10:07:14 +0100569
570static ssize_t lbs_failcount_read(
571 struct file *file, char __user *userbuf,
572 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200573{
Holger Schurig3a188642007-11-26 10:07:14 +0100574 return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
575 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200576}
577
Holger Schurig3a188642007-11-26 10:07:14 +0100578
579static ssize_t lbs_failcount_write(
580 struct file *file, const char __user *userbuf,
581 size_t count, loff_t *ppos)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200582{
Holger Schurig3a188642007-11-26 10:07:14 +0100583 return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
584 file, userbuf, count, ppos);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200585}
586
Holger Schurig3a188642007-11-26 10:07:14 +0100587
588static ssize_t lbs_highrssi_read(
589 struct file *file, char __user *userbuf,
590 size_t count, loff_t *ppos)
591{
592 return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
593 file, userbuf, count, ppos);
594}
595
596
597static ssize_t lbs_highrssi_write(
598 struct file *file, const char __user *userbuf,
599 size_t count, loff_t *ppos)
600{
601 return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
602 file, userbuf, count, ppos);
603}
604
605
606static ssize_t lbs_highsnr_read(
607 struct file *file, char __user *userbuf,
608 size_t count, loff_t *ppos)
609{
610 return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
611 file, userbuf, count, ppos);
612}
613
614
615static ssize_t lbs_highsnr_write(
616 struct file *file, const char __user *userbuf,
617 size_t count, loff_t *ppos)
618{
619 return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
620 file, userbuf, count, ppos);
621}
622
623static ssize_t lbs_bcnmiss_read(
624 struct file *file, char __user *userbuf,
625 size_t count, loff_t *ppos)
626{
627 return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
628 file, userbuf, count, ppos);
629}
630
631
632static ssize_t lbs_bcnmiss_write(
633 struct file *file, const char __user *userbuf,
634 size_t count, loff_t *ppos)
635{
636 return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
637 file, userbuf, count, ppos);
638}
639
640
641
642
643
644
645
646
Holger Schurig10078322007-11-15 18:05:47 -0500647static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200648 size_t count, loff_t *ppos)
649{
Holger Schurig69f90322007-11-23 15:43:44 +0100650 struct lbs_private *priv = file->private_data;
651 struct lbs_adapter *adapter = priv->adapter;
Holger Schurig10078322007-11-15 18:05:47 -0500652 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200653 ssize_t pos = 0;
654 int ret;
655 unsigned long addr = get_zeroed_page(GFP_KERNEL);
656 char *buf = (char *)addr;
657
658 offval.offset = priv->mac_offset;
659 offval.value = 0;
660
Holger Schurig10078322007-11-15 18:05:47 -0500661 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400662 CMD_MAC_REG_ACCESS, 0,
663 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200664 mdelay(10);
665 pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
666 priv->mac_offset, adapter->offsetvalue.value);
667
668 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
669 free_page(addr);
670 return ret;
671}
672
Holger Schurig10078322007-11-15 18:05:47 -0500673static ssize_t lbs_rdmac_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200674 const char __user *userbuf,
675 size_t count, loff_t *ppos)
676{
Holger Schurig69f90322007-11-23 15:43:44 +0100677 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200678 ssize_t res, buf_size;
679 unsigned long addr = get_zeroed_page(GFP_KERNEL);
680 char *buf = (char *)addr;
681
682 buf_size = min(count, len - 1);
683 if (copy_from_user(buf, userbuf, buf_size)) {
684 res = -EFAULT;
685 goto out_unlock;
686 }
687 priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
688 res = count;
689out_unlock:
690 free_page(addr);
691 return res;
692}
693
Holger Schurig10078322007-11-15 18:05:47 -0500694static ssize_t lbs_wrmac_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200695 const char __user *userbuf,
696 size_t count, loff_t *ppos)
697{
698
Holger Schurig69f90322007-11-23 15:43:44 +0100699 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200700 ssize_t res, buf_size;
701 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500702 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200703 unsigned long addr = get_zeroed_page(GFP_KERNEL);
704 char *buf = (char *)addr;
705
706 buf_size = min(count, len - 1);
707 if (copy_from_user(buf, userbuf, buf_size)) {
708 res = -EFAULT;
709 goto out_unlock;
710 }
711 res = sscanf(buf, "%x %x", &offset, &value);
712 if (res != 2) {
713 res = -EFAULT;
714 goto out_unlock;
715 }
716
717 offval.offset = offset;
718 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500719 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400720 CMD_MAC_REG_ACCESS, 1,
721 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200722 mdelay(10);
723
724 res = count;
725out_unlock:
726 free_page(addr);
727 return res;
728}
729
Holger Schurig10078322007-11-15 18:05:47 -0500730static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200731 size_t count, loff_t *ppos)
732{
Holger Schurig69f90322007-11-23 15:43:44 +0100733 struct lbs_private *priv = file->private_data;
734 struct lbs_adapter *adapter = priv->adapter;
Holger Schurig10078322007-11-15 18:05:47 -0500735 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200736 ssize_t pos = 0;
737 int ret;
738 unsigned long addr = get_zeroed_page(GFP_KERNEL);
739 char *buf = (char *)addr;
740
741 offval.offset = priv->bbp_offset;
742 offval.value = 0;
743
Holger Schurig10078322007-11-15 18:05:47 -0500744 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400745 CMD_BBP_REG_ACCESS, 0,
746 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200747 mdelay(10);
748 pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
749 priv->bbp_offset, adapter->offsetvalue.value);
750
751 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
752 free_page(addr);
753
754 return ret;
755}
756
Holger Schurig10078322007-11-15 18:05:47 -0500757static ssize_t lbs_rdbbp_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200758 const char __user *userbuf,
759 size_t count, loff_t *ppos)
760{
Holger Schurig69f90322007-11-23 15:43:44 +0100761 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200762 ssize_t res, buf_size;
763 unsigned long addr = get_zeroed_page(GFP_KERNEL);
764 char *buf = (char *)addr;
765
766 buf_size = min(count, len - 1);
767 if (copy_from_user(buf, userbuf, buf_size)) {
768 res = -EFAULT;
769 goto out_unlock;
770 }
771 priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
772 res = count;
773out_unlock:
774 free_page(addr);
775 return res;
776}
777
Holger Schurig10078322007-11-15 18:05:47 -0500778static ssize_t lbs_wrbbp_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200779 const char __user *userbuf,
780 size_t count, loff_t *ppos)
781{
782
Holger Schurig69f90322007-11-23 15:43:44 +0100783 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200784 ssize_t res, buf_size;
785 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500786 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200787 unsigned long addr = get_zeroed_page(GFP_KERNEL);
788 char *buf = (char *)addr;
789
790 buf_size = min(count, len - 1);
791 if (copy_from_user(buf, userbuf, buf_size)) {
792 res = -EFAULT;
793 goto out_unlock;
794 }
795 res = sscanf(buf, "%x %x", &offset, &value);
796 if (res != 2) {
797 res = -EFAULT;
798 goto out_unlock;
799 }
800
801 offval.offset = offset;
802 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500803 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400804 CMD_BBP_REG_ACCESS, 1,
805 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200806 mdelay(10);
807
808 res = count;
809out_unlock:
810 free_page(addr);
811 return res;
812}
813
Holger Schurig10078322007-11-15 18:05:47 -0500814static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200815 size_t count, loff_t *ppos)
816{
Holger Schurig69f90322007-11-23 15:43:44 +0100817 struct lbs_private *priv = file->private_data;
818 struct lbs_adapter *adapter = priv->adapter;
Holger Schurig10078322007-11-15 18:05:47 -0500819 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200820 ssize_t pos = 0;
821 int ret;
822 unsigned long addr = get_zeroed_page(GFP_KERNEL);
823 char *buf = (char *)addr;
824
825 offval.offset = priv->rf_offset;
826 offval.value = 0;
827
Holger Schurig10078322007-11-15 18:05:47 -0500828 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400829 CMD_RF_REG_ACCESS, 0,
830 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200831 mdelay(10);
832 pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
833 priv->rf_offset, adapter->offsetvalue.value);
834
835 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
836 free_page(addr);
837
838 return ret;
839}
840
Holger Schurig10078322007-11-15 18:05:47 -0500841static ssize_t lbs_rdrf_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200842 const char __user *userbuf,
843 size_t count, loff_t *ppos)
844{
Holger Schurig69f90322007-11-23 15:43:44 +0100845 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200846 ssize_t res, buf_size;
847 unsigned long addr = get_zeroed_page(GFP_KERNEL);
848 char *buf = (char *)addr;
849
850 buf_size = min(count, len - 1);
851 if (copy_from_user(buf, userbuf, buf_size)) {
852 res = -EFAULT;
853 goto out_unlock;
854 }
855 priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
856 res = count;
857out_unlock:
858 free_page(addr);
859 return res;
860}
861
Holger Schurig10078322007-11-15 18:05:47 -0500862static ssize_t lbs_wrrf_write(struct file *file,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200863 const char __user *userbuf,
864 size_t count, loff_t *ppos)
865{
866
Holger Schurig69f90322007-11-23 15:43:44 +0100867 struct lbs_private *priv = file->private_data;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200868 ssize_t res, buf_size;
869 u32 offset, value;
Holger Schurig10078322007-11-15 18:05:47 -0500870 struct lbs_offset_value offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200871 unsigned long addr = get_zeroed_page(GFP_KERNEL);
872 char *buf = (char *)addr;
873
874 buf_size = min(count, len - 1);
875 if (copy_from_user(buf, userbuf, buf_size)) {
876 res = -EFAULT;
877 goto out_unlock;
878 }
879 res = sscanf(buf, "%x %x", &offset, &value);
880 if (res != 2) {
881 res = -EFAULT;
882 goto out_unlock;
883 }
884
885 offval.offset = offset;
886 offval.value = value;
Holger Schurig10078322007-11-15 18:05:47 -0500887 res = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400888 CMD_RF_REG_ACCESS, 1,
889 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200890 mdelay(10);
891
892 res = count;
893out_unlock:
894 free_page(addr);
895 return res;
896}
897
898#define FOPS(fread, fwrite) { \
899 .owner = THIS_MODULE, \
900 .open = open_file_generic, \
901 .read = (fread), \
902 .write = (fwrite), \
903}
904
Holger Schurig10078322007-11-15 18:05:47 -0500905struct lbs_debugfs_files {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200906 char *name;
907 int perm;
908 struct file_operations fops;
909};
910
Holger Schurig10078322007-11-15 18:05:47 -0500911static struct lbs_debugfs_files debugfs_files[] = {
912 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
913 { "getscantable", 0444, FOPS(lbs_getscantable,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200914 write_file_dummy), },
Holger Schurig10078322007-11-15 18:05:47 -0500915 { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
916 lbs_sleepparams_write), },
917 { "extscan", 0600, FOPS(NULL, lbs_extscan), },
918 { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200919};
920
Holger Schurig10078322007-11-15 18:05:47 -0500921static struct lbs_debugfs_files debugfs_events_files[] = {
922 {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
923 lbs_lowrssi_write), },
924 {"low_snr", 0644, FOPS(lbs_lowsnr_read,
925 lbs_lowsnr_write), },
926 {"failure_count", 0644, FOPS(lbs_failcount_read,
927 lbs_failcount_write), },
928 {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
929 lbs_bcnmiss_write), },
930 {"high_rssi", 0644, FOPS(lbs_highrssi_read,
931 lbs_highrssi_write), },
932 {"high_snr", 0644, FOPS(lbs_highsnr_read,
933 lbs_highsnr_write), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200934};
935
Holger Schurig10078322007-11-15 18:05:47 -0500936static struct lbs_debugfs_files debugfs_regs_files[] = {
937 {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
938 {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
939 {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
940 {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
941 {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
942 {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200943};
944
Holger Schurig10078322007-11-15 18:05:47 -0500945void lbs_debugfs_init(void)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200946{
Holger Schurig10078322007-11-15 18:05:47 -0500947 if (!lbs_dir)
948 lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200949
950 return;
951}
952
Holger Schurig10078322007-11-15 18:05:47 -0500953void lbs_debugfs_remove(void)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200954{
Holger Schurig10078322007-11-15 18:05:47 -0500955 if (lbs_dir)
956 debugfs_remove(lbs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200957 return;
958}
959
Holger Schurig69f90322007-11-23 15:43:44 +0100960void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200961{
962 int i;
Holger Schurig10078322007-11-15 18:05:47 -0500963 struct lbs_debugfs_files *files;
964 if (!lbs_dir)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200965 goto exit;
966
Holger Schurig10078322007-11-15 18:05:47 -0500967 priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200968 if (!priv->debugfs_dir)
969 goto exit;
970
971 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
972 files = &debugfs_files[i];
973 priv->debugfs_files[i] = debugfs_create_file(files->name,
974 files->perm,
975 priv->debugfs_dir,
976 priv,
977 &files->fops);
978 }
979
980 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
981 if (!priv->events_dir)
982 goto exit;
983
984 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
985 files = &debugfs_events_files[i];
986 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
987 files->perm,
988 priv->events_dir,
989 priv,
990 &files->fops);
991 }
992
993 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
994 if (!priv->regs_dir)
995 goto exit;
996
997 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
998 files = &debugfs_regs_files[i];
999 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
1000 files->perm,
1001 priv->regs_dir,
1002 priv,
1003 &files->fops);
1004 }
1005
1006#ifdef PROC_DEBUG
Holger Schurig10078322007-11-15 18:05:47 -05001007 lbs_debug_init(priv, dev);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001008#endif
1009exit:
1010 return;
1011}
1012
Holger Schurig69f90322007-11-23 15:43:44 +01001013void lbs_debugfs_remove_one(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001014{
1015 int i;
1016
1017 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
1018 debugfs_remove(priv->debugfs_regs_files[i]);
1019
1020 debugfs_remove(priv->regs_dir);
1021
Holger Schurig0b7db952007-05-24 23:47:34 -04001022 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001023 debugfs_remove(priv->debugfs_events_files[i]);
1024
1025 debugfs_remove(priv->events_dir);
1026#ifdef PROC_DEBUG
1027 debugfs_remove(priv->debugfs_debug);
1028#endif
1029 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
1030 debugfs_remove(priv->debugfs_files[i]);
Holger Schurig0b7db952007-05-24 23:47:34 -04001031 debugfs_remove(priv->debugfs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001032}
1033
Holger Schurig46868202007-05-25 00:37:28 -04001034
1035
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001036/* debug entry */
1037
Holger Schurig46868202007-05-25 00:37:28 -04001038#ifdef PROC_DEBUG
1039
Holger Schurig69f90322007-11-23 15:43:44 +01001040#define item_size(n) (FIELD_SIZEOF(struct lbs_adapter, n))
1041#define item_addr(n) (offsetof(struct lbs_adapter, n))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001042
Holger Schurig46868202007-05-25 00:37:28 -04001043
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001044struct debug_data {
1045 char name[32];
1046 u32 size;
Dan Williams4269e2a2007-05-10 23:10:18 -04001047 size_t addr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001048};
1049
Holger Schurig69f90322007-11-23 15:43:44 +01001050/* To debug any member of struct lbs_adapter, simply add one line here.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001051 */
1052static struct debug_data items[] = {
1053 {"intcounter", item_size(intcounter), item_addr(intcounter)},
1054 {"psmode", item_size(psmode), item_addr(psmode)},
1055 {"psstate", item_size(psstate), item_addr(psstate)},
1056};
1057
Tony Breedsd2f11e02007-03-09 13:11:46 +11001058static int num_of_items = ARRAY_SIZE(items);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001059
1060/**
1061 * @brief proc read function
1062 *
1063 * @param page pointer to buffer
1064 * @param s read data starting position
1065 * @param off offset
1066 * @param cnt counter
1067 * @param eof end of file flag
1068 * @param data data to output
1069 * @return number of output data
1070 */
Holger Schurig10078322007-11-15 18:05:47 -05001071static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001072 size_t count, loff_t *ppos)
1073{
1074 int val = 0;
1075 size_t pos = 0;
1076 ssize_t res;
1077 char *p;
1078 int i;
1079 struct debug_data *d;
1080 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1081 char *buf = (char *)addr;
1082
1083 p = buf;
1084
1085 d = (struct debug_data *)file->private_data;
1086
1087 for (i = 0; i < num_of_items; i++) {
1088 if (d[i].size == 1)
1089 val = *((u8 *) d[i].addr);
1090 else if (d[i].size == 2)
1091 val = *((u16 *) d[i].addr);
1092 else if (d[i].size == 4)
1093 val = *((u32 *) d[i].addr);
Dan Williams4269e2a2007-05-10 23:10:18 -04001094 else if (d[i].size == 8)
1095 val = *((u64 *) d[i].addr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001096
1097 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
1098 }
1099
1100 res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
1101
1102 free_page(addr);
1103 return res;
1104}
1105
1106/**
1107 * @brief proc write function
1108 *
1109 * @param f file pointer
1110 * @param buf pointer to data buffer
1111 * @param cnt data number to write
1112 * @param data data to write
1113 * @return number of data
1114 */
Holger Schurig10078322007-11-15 18:05:47 -05001115static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001116 size_t cnt, loff_t *ppos)
1117{
1118 int r, i;
1119 char *pdata;
1120 char *p;
1121 char *p0;
1122 char *p1;
1123 char *p2;
1124 struct debug_data *d = (struct debug_data *)f->private_data;
1125
Jesper Juhl655b4d12007-08-24 11:48:16 -04001126 pdata = kmalloc(cnt, GFP_KERNEL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001127 if (pdata == NULL)
1128 return 0;
1129
1130 if (copy_from_user(pdata, buf, cnt)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001131 lbs_deb_debugfs("Copy from user failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001132 kfree(pdata);
1133 return 0;
1134 }
1135
1136 p0 = pdata;
1137 for (i = 0; i < num_of_items; i++) {
1138 do {
1139 p = strstr(p0, d[i].name);
1140 if (p == NULL)
1141 break;
1142 p1 = strchr(p, '\n');
1143 if (p1 == NULL)
1144 break;
1145 p0 = p1++;
1146 p2 = strchr(p, '=');
1147 if (!p2)
1148 break;
1149 p2++;
Tony Breedsd2f11e02007-03-09 13:11:46 +11001150 r = simple_strtoul(p2, NULL, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001151 if (d[i].size == 1)
1152 *((u8 *) d[i].addr) = (u8) r;
1153 else if (d[i].size == 2)
1154 *((u16 *) d[i].addr) = (u16) r;
1155 else if (d[i].size == 4)
1156 *((u32 *) d[i].addr) = (u32) r;
Dan Williams4269e2a2007-05-10 23:10:18 -04001157 else if (d[i].size == 8)
1158 *((u64 *) d[i].addr) = (u64) r;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001159 break;
1160 } while (1);
1161 }
1162 kfree(pdata);
1163
Dan Williams4269e2a2007-05-10 23:10:18 -04001164 return (ssize_t)cnt;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001165}
1166
Holger Schurig10078322007-11-15 18:05:47 -05001167static struct file_operations lbs_debug_fops = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001168 .owner = THIS_MODULE,
1169 .open = open_file_generic,
Holger Schurig10078322007-11-15 18:05:47 -05001170 .write = lbs_debugfs_write,
1171 .read = lbs_debugfs_read,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001172};
1173
1174/**
1175 * @brief create debug proc file
1176 *
Holger Schurig69f90322007-11-23 15:43:44 +01001177 * @param priv pointer struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001178 * @param dev pointer net_device
1179 * @return N/A
1180 */
Holger Schurig69f90322007-11-23 15:43:44 +01001181static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001182{
1183 int i;
1184
1185 if (!priv->debugfs_dir)
1186 return;
1187
1188 for (i = 0; i < num_of_items; i++)
Dan Williams4269e2a2007-05-10 23:10:18 -04001189 items[i].addr += (size_t) priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001190
1191 priv->debugfs_debug = debugfs_create_file("debug", 0644,
1192 priv->debugfs_dir, &items[0],
Holger Schurig10078322007-11-15 18:05:47 -05001193 &lbs_debug_fops);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001194}
Holger Schurig46868202007-05-25 00:37:28 -04001195#endif