blob: 816f42e4f5b49d484a1af11139313e1aa47ac7b9 [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>
6#include <net/iw_handler.h>
Holger Schurig46868202007-05-25 00:37:28 -04007
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02008#include "dev.h"
9#include "decl.h"
10#include "host.h"
Dan Williams5bdb3ef2007-05-10 23:08:05 -040011#include "debugfs.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020012
13static struct dentry *libertas_dir = NULL;
14static char *szStates[] = {
15 "Connected",
16 "Disconnected"
17};
18
Holger Schurig46868202007-05-25 00:37:28 -040019#ifdef PROC_DEBUG
20static void libertas_debug_init(wlan_private * priv, struct net_device *dev);
21#endif
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020022
23static int open_file_generic(struct inode *inode, struct file *file)
24{
25 file->private_data = inode->i_private;
26 return 0;
27}
28
29static ssize_t write_file_dummy(struct file *file, const char __user *buf,
30 size_t count, loff_t *ppos)
31{
32 return -EINVAL;
33}
34
35static const size_t len = PAGE_SIZE;
36
37static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
38 size_t count, loff_t *ppos)
39{
40 wlan_private *priv = file->private_data;
41 size_t pos = 0;
42 unsigned long addr = get_zeroed_page(GFP_KERNEL);
43 char *buf = (char *)addr;
44 ssize_t res;
45
46 pos += snprintf(buf+pos, len-pos, "state = %s\n",
47 szStates[priv->adapter->connect_status]);
48 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
49 (u32) priv->adapter->regioncode);
50
51 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
52
53 free_page(addr);
54 return res;
55}
56
57
58static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
59 size_t count, loff_t *ppos)
60{
61 wlan_private *priv = file->private_data;
62 size_t pos = 0;
63 int numscansdone = 0, res;
64 unsigned long addr = get_zeroed_page(GFP_KERNEL);
65 char *buf = (char *)addr;
Dan Williamsfcdb53d2007-05-25 16:15:56 -040066 struct bss_descriptor * iter_bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020067
68 pos += snprintf(buf+pos, len-pos,
Holger Schuriga2235ed2007-08-02 13:12:45 -040069 "# | ch | rssi | bssid | cap | Qual | SSID \n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020070
Dan Williamsfcdb53d2007-05-25 16:15:56 -040071 mutex_lock(&priv->adapter->lock);
72 list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
Dan Williams0c9ca6902007-08-02 10:43:44 -040073 u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
74 u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
75 u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020076
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020077 pos += snprintf(buf+pos, len-pos,
Holger Schuriga2235ed2007-08-02 13:12:45 -040078 "%02u| %03d | %04ld | " MAC_FMT " |",
Dan Williamsfcdb53d2007-05-25 16:15:56 -040079 numscansdone, iter_bss->channel, iter_bss->rssi,
Dan Williams02eb2292007-05-25 17:27:31 -040080 MAC_ARG(iter_bss->bssid));
Dan Williams0c9ca6902007-08-02 10:43:44 -040081 pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020082 pos += snprintf(buf+pos, len-pos, "%c%c%c |",
Dan Williams0c9ca6902007-08-02 10:43:44 -040083 ibss ? 'A' : 'I', privacy ? 'P' : ' ',
84 spectrum_mgmt ? 'S' : ' ');
Holger Schuriga2235ed2007-08-02 13:12:45 -040085 pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
Dan Williamsd8efea22007-05-28 23:54:55 -040086 pos += snprintf(buf+pos, len-pos, " %s\n",
87 escape_essid(iter_bss->ssid, iter_bss->ssid_len));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020088
89 numscansdone++;
90 }
Dan Williamsfcdb53d2007-05-25 16:15:56 -040091 mutex_unlock(&priv->adapter->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020092
93 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
94
95 free_page(addr);
96 return res;
97}
98
99static ssize_t libertas_sleepparams_write(struct file *file,
100 const char __user *user_buf, size_t count,
101 loff_t *ppos)
102{
103 wlan_private *priv = file->private_data;
104 ssize_t buf_size, res;
105 int p1, p2, p3, p4, p5, p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200106 unsigned long addr = get_zeroed_page(GFP_KERNEL);
107 char *buf = (char *)addr;
108
109 buf_size = min(count, len - 1);
110 if (copy_from_user(buf, user_buf, buf_size)) {
111 res = -EFAULT;
112 goto out_unlock;
113 }
114 res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
115 if (res != 6) {
116 res = -EFAULT;
117 goto out_unlock;
118 }
David Woodhouse981f1872007-05-25 23:36:54 -0400119 priv->adapter->sp.sp_error = p1;
120 priv->adapter->sp.sp_offset = p2;
121 priv->adapter->sp.sp_stabletime = p3;
122 priv->adapter->sp.sp_calcontrol = p4;
123 priv->adapter->sp.sp_extsleepclk = p5;
124 priv->adapter->sp.sp_reserved = p6;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200125
126 res = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400127 CMD_802_11_SLEEP_PARAMS,
128 CMD_ACT_SET,
129 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200130
131 if (!res)
132 res = count;
133 else
134 res = -EINVAL;
135
136out_unlock:
137 free_page(addr);
138 return res;
139}
140
141static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
142 size_t count, loff_t *ppos)
143{
144 wlan_private *priv = file->private_data;
145 wlan_adapter *adapter = priv->adapter;
146 ssize_t res;
147 size_t pos = 0;
148 unsigned long addr = get_zeroed_page(GFP_KERNEL);
149 char *buf = (char *)addr;
150
151 res = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400152 CMD_802_11_SLEEP_PARAMS,
153 CMD_ACT_GET,
154 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200155 if (res) {
156 res = -EFAULT;
157 goto out_unlock;
158 }
159
160 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
161 adapter->sp.sp_offset, adapter->sp.sp_stabletime,
162 adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
163 adapter->sp.sp_reserved);
164
165 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
166
167out_unlock:
168 free_page(addr);
169 return res;
170}
171
172static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
173 size_t count, loff_t *ppos)
174{
175 wlan_private *priv = file->private_data;
176 ssize_t res, buf_size;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200177 union iwreq_data wrqu;
178 unsigned long addr = get_zeroed_page(GFP_KERNEL);
179 char *buf = (char *)addr;
180
181 buf_size = min(count, len - 1);
182 if (copy_from_user(buf, userbuf, buf_size)) {
183 res = -EFAULT;
184 goto out_unlock;
185 }
186
Dan Williams717c9332007-05-29 00:03:31 -0400187 libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200188
189 memset(&wrqu, 0, sizeof(union iwreq_data));
Holger Schurig634b8f42007-05-25 13:05:16 -0400190 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200191
192out_unlock:
193 free_page(addr);
194 return count;
195}
196
197static int libertas_parse_chan(char *buf, size_t count,
198 struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
199{
200 char *start, *end, *hold, *str;
201 int i = 0;
202
203 start = strstr(buf, "chan=");
204 if (!start)
205 return -EINVAL;
206 start += 5;
207 end = strstr(start, " ");
208 if (!end)
209 end = buf + count;
210 hold = kzalloc((end - start)+1, GFP_KERNEL);
211 if (!hold)
212 return -ENOMEM;
213 strncpy(hold, start, end - start);
214 hold[(end-start)+1] = '\0';
215 while(hold && (str = strsep(&hold, ","))) {
216 int chan;
217 char band, passive = 0;
218 sscanf(str, "%d%c%c", &chan, &band, &passive);
219 scan_cfg->chanlist[i].channumber = chan;
220 scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
221 if (band == 'b' || band == 'g')
222 scan_cfg->chanlist[i].radiotype = 0;
223 else if (band == 'a')
224 scan_cfg->chanlist[i].radiotype = 1;
225
226 scan_cfg->chanlist[i].scantime = dur;
227 i++;
228 }
229
230 kfree(hold);
231 return i;
232}
233
234static void libertas_parse_bssid(char *buf, size_t count,
235 struct wlan_ioctl_user_scan_cfg *scan_cfg)
236{
237 char *hold;
238 unsigned int mac[ETH_ALEN];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200239
240 hold = strstr(buf, "bssid=");
241 if (!hold)
242 return;
243 hold += 6;
Dan Williamseb8f7332007-05-25 16:25:21 -0400244 sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
245 memcpy(scan_cfg->bssid, mac, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200246}
247
248static void libertas_parse_ssid(char *buf, size_t count,
249 struct wlan_ioctl_user_scan_cfg *scan_cfg)
250{
251 char *hold, *end;
252 ssize_t size;
253
254 hold = strstr(buf, "ssid=");
255 if (!hold)
256 return;
257 hold += 5;
258 end = strstr(hold, " ");
259 if (!end)
260 end = buf + count - 1;
261
Dan Williams4269e2a2007-05-10 23:10:18 -0400262 size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
Dan Williamseb8f7332007-05-25 16:25:21 -0400263 strncpy(scan_cfg->ssid, hold, size);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200264
265 return;
266}
267
Dan Williamseb8f7332007-05-25 16:25:21 -0400268static int libertas_parse_clear(char *buf, size_t count, const char *tag)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200269{
270 char *hold;
271 int val;
272
Dan Williamseb8f7332007-05-25 16:25:21 -0400273 hold = strstr(buf, tag);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200274 if (!hold)
Dan Williamseb8f7332007-05-25 16:25:21 -0400275 return 0;
276 hold += strlen(tag);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200277 sscanf(hold, "%d", &val);
278
279 if (val != 0)
280 val = 1;
281
Dan Williamseb8f7332007-05-25 16:25:21 -0400282 return val;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200283}
284
285static int libertas_parse_dur(char *buf, size_t count,
286 struct wlan_ioctl_user_scan_cfg *scan_cfg)
287{
288 char *hold;
289 int val;
290
291 hold = strstr(buf, "dur=");
292 if (!hold)
293 return 0;
294 hold += 4;
295 sscanf(hold, "%d", &val);
296
297 return val;
298}
299
300static void libertas_parse_probes(char *buf, size_t count,
301 struct wlan_ioctl_user_scan_cfg *scan_cfg)
302{
303 char *hold;
304 int val;
305
306 hold = strstr(buf, "probes=");
307 if (!hold)
308 return;
309 hold += 7;
310 sscanf(hold, "%d", &val);
311
312 scan_cfg->numprobes = val;
313
314 return;
315}
316
317static void libertas_parse_type(char *buf, size_t count,
318 struct wlan_ioctl_user_scan_cfg *scan_cfg)
319{
320 char *hold;
321 int val;
322
323 hold = strstr(buf, "type=");
324 if (!hold)
325 return;
326 hold += 5;
327 sscanf(hold, "%d", &val);
328
329 /* type=1,2 or 3 */
330 if (val < 1 || val > 3)
331 return;
332
333 scan_cfg->bsstype = val;
334
335 return;
336}
337
338static ssize_t libertas_setuserscan(struct file *file,
339 const char __user *userbuf,
340 size_t count, loff_t *ppos)
341{
342 wlan_private *priv = file->private_data;
343 ssize_t res, buf_size;
344 struct wlan_ioctl_user_scan_cfg *scan_cfg;
345 union iwreq_data wrqu;
346 int dur;
347 unsigned long addr = get_zeroed_page(GFP_KERNEL);
348 char *buf = (char *)addr;
349
350 scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
351 if (!scan_cfg)
352 return -ENOMEM;
353
354 buf_size = min(count, len - 1);
355 if (copy_from_user(buf, userbuf, buf_size)) {
356 res = -EFAULT;
357 goto out_unlock;
358 }
359
360 scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
361
362 dur = libertas_parse_dur(buf, count, scan_cfg);
363 libertas_parse_chan(buf, count, scan_cfg, dur);
364 libertas_parse_bssid(buf, count, scan_cfg);
Dan Williamseb8f7332007-05-25 16:25:21 -0400365 scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200366 libertas_parse_ssid(buf, count, scan_cfg);
Dan Williamseb8f7332007-05-25 16:25:21 -0400367 scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200368 libertas_parse_probes(buf, count, scan_cfg);
369 libertas_parse_type(buf, count, scan_cfg);
370
Marcelo Tosatti2be92192007-05-25 00:33:28 -0400371 wlan_scan_networks(priv, scan_cfg, 1);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200372 wait_event_interruptible(priv->adapter->cmd_pending,
373 !priv->adapter->nr_cmd_pending);
374
375 memset(&wrqu, 0x00, sizeof(union iwreq_data));
Holger Schurig634b8f42007-05-25 13:05:16 -0400376 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200377
378out_unlock:
379 free_page(addr);
380 kfree(scan_cfg);
381 return count;
382}
383
384static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
385 struct cmd_ctrl_node **cmdnode,
386 struct cmd_ds_command **cmd)
387{
Dan Williams0aef64d2007-08-02 11:31:18 -0400388 u16 wait_option = CMD_OPTION_WAITFORRSP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389
390 if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
Holger Schurig9012b282007-05-25 11:27:16 -0400391 lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200392 return -ENOMEM;
393 }
394 if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
Holger Schurig9012b282007-05-25 11:27:16 -0400395 lbs_deb_debugfs("failed to allocate response buffer!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200396 return -ENOMEM;
397 }
398 libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
399 init_waitqueue_head(&(*cmdnode)->cmdwait_q);
400 (*cmdnode)->pdata_buf = *response_buf;
401 (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
402 (*cmdnode)->cmdwaitqwoken = 0;
403 *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
Dan Williams0aef64d2007-08-02 11:31:18 -0400404 (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
David Woodhouse981f1872007-05-25 23:36:54 -0400405 (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200406 (*cmd)->result = 0;
407 return 0;
408}
409
410static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
411 size_t count, loff_t *ppos)
412{
413 wlan_private *priv = file->private_data;
414 wlan_adapter *adapter = priv->adapter;
415 struct cmd_ctrl_node *pcmdnode;
416 struct cmd_ds_command *pcmdptr;
417 struct cmd_ds_802_11_subscribe_event *event;
418 void *response_buf;
419 int res, cmd_len;
420 ssize_t pos = 0;
421 unsigned long addr = get_zeroed_page(GFP_KERNEL);
422 char *buf = (char *)addr;
423
424 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
425 if (res < 0) {
426 free_page(addr);
427 return res;
428 }
429
430 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400431 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -0400432 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200433 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400434 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200435
436 /* Sleep until response is generated by FW */
437 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400438 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439
440 pcmdptr = response_buf;
441 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400442 lbs_pr_err("%s: fail, result=%d\n", __func__,
443 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200444 kfree(response_buf);
445 free_page(addr);
446 return 0;
447 }
448
Holger Schurig6b63cd02007-08-02 11:53:36 -0400449 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200450 lbs_pr_err("command response incorrect!\n");
451 kfree(response_buf);
452 free_page(addr);
453 return 0;
454 }
455
456 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -0400457 event = (void *)(response_buf + S_DS_GEN);
458 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
459 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
460 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200461 struct mrvlietypes_rssithreshold *Lowrssi;
David Woodhouse981f1872007-05-25 23:36:54 -0400462 case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
463 Lowrssi = (void *)(response_buf + cmd_len);
464 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
465 Lowrssi->rssivalue,
466 Lowrssi->rssifreq,
467 (event->events & cpu_to_le16(0x0001))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468 default:
469 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
470 break;
471 }
472 }
473
474 kfree(response_buf);
475 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
476 free_page(addr);
477 return res;
478}
479
480static u16 libertas_get_events_bitmap(wlan_private *priv)
481{
482 wlan_adapter *adapter = priv->adapter;
483 struct cmd_ctrl_node *pcmdnode;
484 struct cmd_ds_command *pcmdptr;
485 struct cmd_ds_802_11_subscribe_event *event;
486 void *response_buf;
487 int res;
488 u16 event_bitmap;
489
490 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
491 if (res < 0)
492 return res;
493
494 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400495 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -0400496 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200497 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400498 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200499
500 /* Sleep until response is generated by FW */
501 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400502 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200503
504 pcmdptr = response_buf;
505
506 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400507 lbs_pr_err("%s: fail, result=%d\n", __func__,
508 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509 kfree(response_buf);
510 return 0;
511 }
512
Dan Williams8362cd42007-08-03 09:40:55 -0400513 if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200514 lbs_pr_err("command response incorrect!\n");
515 kfree(response_buf);
516 return 0;
517 }
518
519 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
David Woodhouse981f1872007-05-25 23:36:54 -0400520 event_bitmap = le16_to_cpu(event->events);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200521 kfree(response_buf);
522 return event_bitmap;
523}
524
525static ssize_t libertas_lowrssi_write(struct file *file,
526 const char __user *userbuf,
527 size_t count, loff_t *ppos)
528{
529 wlan_private *priv = file->private_data;
530 wlan_adapter *adapter = priv->adapter;
531 ssize_t res, buf_size;
532 int value, freq, subscribed, cmd_len;
533 struct cmd_ctrl_node *pcmdnode;
534 struct cmd_ds_command *pcmdptr;
535 struct cmd_ds_802_11_subscribe_event *event;
536 struct mrvlietypes_rssithreshold *rssi_threshold;
537 void *response_buf;
538 u16 event_bitmap;
539 u8 *ptr;
540 unsigned long addr = get_zeroed_page(GFP_KERNEL);
541 char *buf = (char *)addr;
542
543 buf_size = min(count, len - 1);
544 if (copy_from_user(buf, userbuf, buf_size)) {
545 res = -EFAULT;
546 goto out_unlock;
547 }
548 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
549 if (res != 3) {
550 res = -EFAULT;
551 goto out_unlock;
552 }
553
554 event_bitmap = libertas_get_events_bitmap(priv);
555
556 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
557 if (res < 0)
558 goto out_unlock;
559
560 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400561 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200562 pcmdptr->size = cpu_to_le16(S_DS_GEN +
563 sizeof(struct cmd_ds_802_11_subscribe_event) +
564 sizeof(struct mrvlietypes_rssithreshold));
565
566 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
567 ptr = (u8*) pcmdptr+cmd_len;
568 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
569 rssi_threshold->header.type = cpu_to_le16(0x0104);
David Woodhouse981f1872007-05-25 23:36:54 -0400570 rssi_threshold->header.len = cpu_to_le16(2);
571 rssi_threshold->rssivalue = value;
572 rssi_threshold->rssifreq = freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200573 event_bitmap |= subscribed ? 0x0001 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -0400574 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200575
576 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400577 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200578
579 /* Sleep until response is generated by FW */
580 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400581 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200582
583 pcmdptr = response_buf;
584
585 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400586 lbs_pr_err("%s: fail, result=%d\n", __func__,
587 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588 kfree(response_buf);
589 free_page(addr);
590 return 0;
591 }
592
Holger Schurig6b63cd02007-08-02 11:53:36 -0400593 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200594 lbs_pr_err("command response incorrect!\n");
595 kfree(response_buf);
596 free_page(addr);
597 return 0;
598 }
599
600 res = count;
601out_unlock:
602 free_page(addr);
603 return res;
604}
605
606static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
607 size_t count, loff_t *ppos)
608{
609 wlan_private *priv = file->private_data;
610 wlan_adapter *adapter = priv->adapter;
611 struct cmd_ctrl_node *pcmdnode;
612 struct cmd_ds_command *pcmdptr;
613 struct cmd_ds_802_11_subscribe_event *event;
614 void *response_buf;
615 int res, cmd_len;
616 ssize_t pos = 0;
617 unsigned long addr = get_zeroed_page(GFP_KERNEL);
618 char *buf = (char *)addr;
619
620 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
621 if (res < 0) {
622 free_page(addr);
623 return res;
624 }
625
626 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400627 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -0400628 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200629 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400630 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200631
632 /* Sleep until response is generated by FW */
633 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400634 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200635
636 pcmdptr = response_buf;
637
638 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400639 lbs_pr_err("%s: fail, result=%d\n", __func__,
640 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200641 kfree(response_buf);
642 free_page(addr);
643 return 0;
644 }
645
Holger Schurig6b63cd02007-08-02 11:53:36 -0400646 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200647 lbs_pr_err("command response incorrect!\n");
648 kfree(response_buf);
649 free_page(addr);
650 return 0;
651 }
652
653 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -0400654 event = (void *)(response_buf + S_DS_GEN);
655 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
656 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
657 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200658 struct mrvlietypes_snrthreshold *LowSnr;
David Woodhouse981f1872007-05-25 23:36:54 -0400659 case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
660 LowSnr = (void *)(response_buf + cmd_len);
661 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
662 LowSnr->snrvalue,
663 LowSnr->snrfreq,
664 (event->events & cpu_to_le16(0x0002))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200665 default:
666 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
667 break;
668 }
669 }
670
671 kfree(response_buf);
672
673 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
674 free_page(addr);
675 return res;
676}
677
678static ssize_t libertas_lowsnr_write(struct file *file,
679 const char __user *userbuf,
680 size_t count, loff_t *ppos)
681{
682 wlan_private *priv = file->private_data;
683 wlan_adapter *adapter = priv->adapter;
684 ssize_t res, buf_size;
685 int value, freq, subscribed, cmd_len;
686 struct cmd_ctrl_node *pcmdnode;
687 struct cmd_ds_command *pcmdptr;
688 struct cmd_ds_802_11_subscribe_event *event;
689 struct mrvlietypes_snrthreshold *snr_threshold;
690 void *response_buf;
691 u16 event_bitmap;
692 u8 *ptr;
693 unsigned long addr = get_zeroed_page(GFP_KERNEL);
694 char *buf = (char *)addr;
695
696 buf_size = min(count, len - 1);
697 if (copy_from_user(buf, userbuf, buf_size)) {
698 res = -EFAULT;
699 goto out_unlock;
700 }
701 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
702 if (res != 3) {
703 res = -EFAULT;
704 goto out_unlock;
705 }
706
707 event_bitmap = libertas_get_events_bitmap(priv);
708
709 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
710 if (res < 0)
711 goto out_unlock;
712
713 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400714 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200715 pcmdptr->size = cpu_to_le16(S_DS_GEN +
716 sizeof(struct cmd_ds_802_11_subscribe_event) +
717 sizeof(struct mrvlietypes_snrthreshold));
718 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
719 ptr = (u8*) pcmdptr+cmd_len;
720 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
721 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
David Woodhouse981f1872007-05-25 23:36:54 -0400722 snr_threshold->header.len = cpu_to_le16(2);
723 snr_threshold->snrvalue = value;
724 snr_threshold->snrfreq = freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200725 event_bitmap |= subscribed ? 0x0002 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -0400726 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200727
728 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400729 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200730
731 /* Sleep until response is generated by FW */
732 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400733 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200734
735 pcmdptr = response_buf;
736
737 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400738 lbs_pr_err("%s: fail, result=%d\n", __func__,
739 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200740 kfree(response_buf);
741 free_page(addr);
742 return 0;
743 }
744
Holger Schurig6b63cd02007-08-02 11:53:36 -0400745 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200746 lbs_pr_err("command response incorrect!\n");
747 kfree(response_buf);
748 free_page(addr);
749 return 0;
750 }
751
752 res = count;
753
754out_unlock:
755 free_page(addr);
756 return res;
757}
758
759static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
760 size_t count, loff_t *ppos)
761{
762 wlan_private *priv = file->private_data;
763 wlan_adapter *adapter = priv->adapter;
764 struct cmd_ctrl_node *pcmdnode;
765 struct cmd_ds_command *pcmdptr;
766 struct cmd_ds_802_11_subscribe_event *event;
767 void *response_buf;
768 int res, cmd_len;
769 ssize_t pos = 0;
770 unsigned long addr = get_zeroed_page(GFP_KERNEL);
771 char *buf = (char *)addr;
772
773 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
774 if (res < 0) {
775 free_page(addr);
776 return res;
777 }
778
779 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400780 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -0400781 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200782 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400783 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200784
785 /* Sleep until response is generated by FW */
786 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400787 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200788
789 pcmdptr = response_buf;
790
791 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400792 lbs_pr_err("%s: fail, result=%d\n", __func__,
793 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200794 kfree(response_buf);
795 free_page(addr);
796 return 0;
797 }
798
Holger Schurig6b63cd02007-08-02 11:53:36 -0400799 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200800 lbs_pr_err("command response incorrect!\n");
801 kfree(response_buf);
802 free_page(addr);
803 return 0;
804 }
805
806 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -0400807 event = (void *)(response_buf + S_DS_GEN);
808 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
809 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
810 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200811 struct mrvlietypes_failurecount *failcount;
David Woodhouse981f1872007-05-25 23:36:54 -0400812 case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
813 failcount = (void *)(response_buf + cmd_len);
814 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
815 failcount->failvalue,
816 failcount->Failfreq,
817 (event->events & cpu_to_le16(0x0004))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200818 default:
819 cmd_len += sizeof(struct mrvlietypes_failurecount);
820 break;
821 }
822 }
823
824 kfree(response_buf);
825 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
826 free_page(addr);
827 return res;
828}
829
830static ssize_t libertas_failcount_write(struct file *file,
831 const char __user *userbuf,
832 size_t count, loff_t *ppos)
833{
834 wlan_private *priv = file->private_data;
835 wlan_adapter *adapter = priv->adapter;
836 ssize_t res, buf_size;
837 int value, freq, subscribed, cmd_len;
838 struct cmd_ctrl_node *pcmdnode;
839 struct cmd_ds_command *pcmdptr;
840 struct cmd_ds_802_11_subscribe_event *event;
841 struct mrvlietypes_failurecount *failcount;
842 void *response_buf;
843 u16 event_bitmap;
844 u8 *ptr;
845 unsigned long addr = get_zeroed_page(GFP_KERNEL);
846 char *buf = (char *)addr;
847
848 buf_size = min(count, len - 1);
849 if (copy_from_user(buf, userbuf, buf_size)) {
850 res = -EFAULT;
851 goto out_unlock;
852 }
853 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
854 if (res != 3) {
855 res = -EFAULT;
856 goto out_unlock;
857 }
858
859 event_bitmap = libertas_get_events_bitmap(priv);
860
861 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
862 if (res < 0)
863 goto out_unlock;
864
865 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400866 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200867 pcmdptr->size = cpu_to_le16(S_DS_GEN +
868 sizeof(struct cmd_ds_802_11_subscribe_event) +
869 sizeof(struct mrvlietypes_failurecount));
870 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
871 ptr = (u8*) pcmdptr+cmd_len;
872 failcount = (struct mrvlietypes_failurecount *)(ptr);
873 failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
David Woodhouse981f1872007-05-25 23:36:54 -0400874 failcount->header.len = cpu_to_le16(2);
875 failcount->failvalue = value;
876 failcount->Failfreq = freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200877 event_bitmap |= subscribed ? 0x0004 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -0400878 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200879
880 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400881 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200882
883 /* Sleep until response is generated by FW */
884 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400885 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200886
887 pcmdptr = (struct cmd_ds_command *)response_buf;
888
889 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400890 lbs_pr_err("%s: fail, result=%d\n", __func__,
891 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200892 kfree(response_buf);
893 free_page(addr);
894 return 0;
895 }
896
Holger Schurig6b63cd02007-08-02 11:53:36 -0400897 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200898 lbs_pr_err("command response incorrect!\n");
899 kfree(response_buf);
900 free_page(addr);
901 return 0;
902 }
903
904 res = count;
905out_unlock:
906 free_page(addr);
907 return res;
908}
909
910static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
911 size_t count, loff_t *ppos)
912{
913 wlan_private *priv = file->private_data;
914 wlan_adapter *adapter = priv->adapter;
915 struct cmd_ctrl_node *pcmdnode;
916 struct cmd_ds_command *pcmdptr;
917 struct cmd_ds_802_11_subscribe_event *event;
918 void *response_buf;
919 int res, cmd_len;
920 ssize_t pos = 0;
921 unsigned long addr = get_zeroed_page(GFP_KERNEL);
922 char *buf = (char *)addr;
923
924 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
925 if (res < 0) {
926 free_page(addr);
927 return res;
928 }
929
930 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -0400931 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -0400932 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200933 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -0400934 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200935
936 /* Sleep until response is generated by FW */
937 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -0400938 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200939
940 pcmdptr = response_buf;
941
942 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -0400943 lbs_pr_err("%s: fail, result=%d\n", __func__,
944 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200945 free_page(addr);
946 kfree(response_buf);
947 return 0;
948 }
949
Holger Schurig6b63cd02007-08-02 11:53:36 -0400950 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200951 lbs_pr_err("command response incorrect!\n");
952 free_page(addr);
953 kfree(response_buf);
954 return 0;
955 }
956
957 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -0400958 event = (void *)(response_buf + S_DS_GEN);
959 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
960 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
961 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200962 struct mrvlietypes_beaconsmissed *bcnmiss;
David Woodhouse981f1872007-05-25 23:36:54 -0400963 case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
964 bcnmiss = (void *)(response_buf + cmd_len);
965 pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
966 bcnmiss->beaconmissed,
967 (event->events & cpu_to_le16(0x0008))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200968 default:
969 cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
970 break;
971 }
972 }
973
974 kfree(response_buf);
975
976 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
977 free_page(addr);
978 return res;
979}
980
981static ssize_t libertas_bcnmiss_write(struct file *file,
982 const char __user *userbuf,
983 size_t count, loff_t *ppos)
984{
985 wlan_private *priv = file->private_data;
986 wlan_adapter *adapter = priv->adapter;
987 ssize_t res, buf_size;
988 int value, freq, subscribed, cmd_len;
989 struct cmd_ctrl_node *pcmdnode;
990 struct cmd_ds_command *pcmdptr;
991 struct cmd_ds_802_11_subscribe_event *event;
992 struct mrvlietypes_beaconsmissed *bcnmiss;
993 void *response_buf;
994 u16 event_bitmap;
995 u8 *ptr;
996 unsigned long addr = get_zeroed_page(GFP_KERNEL);
997 char *buf = (char *)addr;
998
999 buf_size = min(count, len - 1);
1000 if (copy_from_user(buf, userbuf, buf_size)) {
1001 res = -EFAULT;
1002 goto out_unlock;
1003 }
1004 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1005 if (res != 3) {
1006 res = -EFAULT;
1007 goto out_unlock;
1008 }
1009
1010 event_bitmap = libertas_get_events_bitmap(priv);
1011
1012 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1013 if (res < 0)
1014 goto out_unlock;
1015
1016 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -04001017 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001018 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1019 sizeof(struct cmd_ds_802_11_subscribe_event) +
1020 sizeof(struct mrvlietypes_beaconsmissed));
1021 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1022 ptr = (u8*) pcmdptr+cmd_len;
1023 bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
1024 bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
David Woodhouse981f1872007-05-25 23:36:54 -04001025 bcnmiss->header.len = cpu_to_le16(2);
1026 bcnmiss->beaconmissed = value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001027 event_bitmap |= subscribed ? 0x0008 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -04001028 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001029
1030 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001031 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001032
1033 /* Sleep until response is generated by FW */
1034 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -04001035 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001036
1037 pcmdptr = response_buf;
1038
1039 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -04001040 lbs_pr_err("%s: fail, result=%d\n", __func__,
1041 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001042 kfree(response_buf);
1043 free_page(addr);
1044 return 0;
1045 }
1046
Holger Schurig6b63cd02007-08-02 11:53:36 -04001047 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001048 lbs_pr_err("command response incorrect!\n");
1049 free_page(addr);
1050 kfree(response_buf);
1051 return 0;
1052 }
1053
1054 res = count;
1055out_unlock:
1056 free_page(addr);
1057 return res;
1058}
1059
1060static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
1061 size_t count, loff_t *ppos)
1062{
1063 wlan_private *priv = file->private_data;
1064 wlan_adapter *adapter = priv->adapter;
1065 struct cmd_ctrl_node *pcmdnode;
1066 struct cmd_ds_command *pcmdptr;
1067 struct cmd_ds_802_11_subscribe_event *event;
1068 void *response_buf;
1069 int res, cmd_len;
1070 ssize_t pos = 0;
1071 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1072 char *buf = (char *)addr;
1073
1074 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1075 if (res < 0) {
1076 free_page(addr);
1077 return res;
1078 }
1079
1080 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -04001081 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -04001082 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001083 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001084 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001085
1086 /* Sleep until response is generated by FW */
1087 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -04001088 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001089
1090 pcmdptr = response_buf;
1091
1092 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -04001093 lbs_pr_err("%s: fail, result=%d\n", __func__,
1094 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001095 kfree(response_buf);
1096 free_page(addr);
1097 return 0;
1098 }
1099
Holger Schurig6b63cd02007-08-02 11:53:36 -04001100 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001101 lbs_pr_err("command response incorrect!\n");
1102 kfree(response_buf);
1103 free_page(addr);
1104 return 0;
1105 }
1106
1107 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -04001108 event = (void *)(response_buf + S_DS_GEN);
1109 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
1110 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
1111 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001112 struct mrvlietypes_rssithreshold *Highrssi;
David Woodhouse981f1872007-05-25 23:36:54 -04001113 case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
1114 Highrssi = (void *)(response_buf + cmd_len);
1115 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1116 Highrssi->rssivalue,
1117 Highrssi->rssifreq,
1118 (event->events & cpu_to_le16(0x0010))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001119 default:
1120 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1121 break;
1122 }
1123 }
1124
1125 kfree(response_buf);
1126
1127 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1128 free_page(addr);
1129 return res;
1130}
1131
1132static ssize_t libertas_highrssi_write(struct file *file,
1133 const char __user *userbuf,
1134 size_t count, loff_t *ppos)
1135{
1136 wlan_private *priv = file->private_data;
1137 wlan_adapter *adapter = priv->adapter;
1138 ssize_t res, buf_size;
1139 int value, freq, subscribed, cmd_len;
1140 struct cmd_ctrl_node *pcmdnode;
1141 struct cmd_ds_command *pcmdptr;
1142 struct cmd_ds_802_11_subscribe_event *event;
1143 struct mrvlietypes_rssithreshold *rssi_threshold;
1144 void *response_buf;
1145 u16 event_bitmap;
1146 u8 *ptr;
1147 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1148 char *buf = (char *)addr;
1149
1150 buf_size = min(count, len - 1);
1151 if (copy_from_user(buf, userbuf, buf_size)) {
1152 res = -EFAULT;
1153 goto out_unlock;
1154 }
1155 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1156 if (res != 3) {
1157 res = -EFAULT;
1158 goto out_unlock;
1159 }
1160
1161 event_bitmap = libertas_get_events_bitmap(priv);
1162
1163 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1164 if (res < 0)
1165 goto out_unlock;
1166
1167 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -04001168 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001169 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1170 sizeof(struct cmd_ds_802_11_subscribe_event) +
1171 sizeof(struct mrvlietypes_rssithreshold));
1172 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1173 ptr = (u8*) pcmdptr+cmd_len;
1174 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
1175 rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
David Woodhouse981f1872007-05-25 23:36:54 -04001176 rssi_threshold->header.len = cpu_to_le16(2);
1177 rssi_threshold->rssivalue = value;
1178 rssi_threshold->rssifreq = freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001179 event_bitmap |= subscribed ? 0x0010 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -04001180 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001181
1182 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001183 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001184
1185 /* Sleep until response is generated by FW */
1186 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -04001187 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001188
1189 pcmdptr = response_buf;
1190
1191 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -04001192 lbs_pr_err("%s: fail, result=%d\n", __func__,
1193 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001194 kfree(response_buf);
1195 return 0;
1196 }
1197
Holger Schurig6b63cd02007-08-02 11:53:36 -04001198 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001199 lbs_pr_err("command response incorrect!\n");
1200 kfree(response_buf);
1201 return 0;
1202 }
1203
1204 res = count;
1205out_unlock:
1206 free_page(addr);
1207 return res;
1208}
1209
1210static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
1211 size_t count, loff_t *ppos)
1212{
1213 wlan_private *priv = file->private_data;
1214 wlan_adapter *adapter = priv->adapter;
1215 struct cmd_ctrl_node *pcmdnode;
1216 struct cmd_ds_command *pcmdptr;
1217 struct cmd_ds_802_11_subscribe_event *event;
1218 void *response_buf;
1219 int res, cmd_len;
1220 ssize_t pos = 0;
1221 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1222 char *buf = (char *)addr;
1223
1224 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1225 if (res < 0) {
1226 free_page(addr);
1227 return res;
1228 }
1229
1230 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -04001231 event->action = cpu_to_le16(CMD_ACT_GET);
David Woodhouse981f1872007-05-25 23:36:54 -04001232 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001233 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001234 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001235
1236 /* Sleep until response is generated by FW */
1237 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -04001238 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001239
1240 pcmdptr = response_buf;
1241
1242 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -04001243 lbs_pr_err("%s: fail, result=%d\n", __func__,
1244 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001245 kfree(response_buf);
1246 free_page(addr);
1247 return 0;
1248 }
1249
Holger Schurig6b63cd02007-08-02 11:53:36 -04001250 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001251 lbs_pr_err("command response incorrect!\n");
1252 kfree(response_buf);
1253 free_page(addr);
1254 return 0;
1255 }
1256
1257 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
David Woodhouse981f1872007-05-25 23:36:54 -04001258 event = (void *)(response_buf + S_DS_GEN);
1259 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
1260 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
1261 switch (header->type) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001262 struct mrvlietypes_snrthreshold *HighSnr;
David Woodhouse981f1872007-05-25 23:36:54 -04001263 case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
1264 HighSnr = (void *)(response_buf + cmd_len);
1265 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1266 HighSnr->snrvalue,
1267 HighSnr->snrfreq,
1268 (event->events & cpu_to_le16(0x0020))?1:0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001269 default:
1270 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1271 break;
1272 }
1273 }
1274
1275 kfree(response_buf);
1276
1277 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1278 free_page(addr);
1279 return res;
1280}
1281
1282static ssize_t libertas_highsnr_write(struct file *file,
1283 const char __user *userbuf,
1284 size_t count, loff_t *ppos)
1285{
1286 wlan_private *priv = file->private_data;
1287 wlan_adapter *adapter = priv->adapter;
1288 ssize_t res, buf_size;
1289 int value, freq, subscribed, cmd_len;
1290 struct cmd_ctrl_node *pcmdnode;
1291 struct cmd_ds_command *pcmdptr;
1292 struct cmd_ds_802_11_subscribe_event *event;
1293 struct mrvlietypes_snrthreshold *snr_threshold;
1294 void *response_buf;
1295 u16 event_bitmap;
1296 u8 *ptr;
1297 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1298 char *buf = (char *)addr;
1299
1300 buf_size = min(count, len - 1);
1301 if (copy_from_user(buf, userbuf, buf_size)) {
1302 res = -EFAULT;
1303 goto out_unlock;
1304 }
1305 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1306 if (res != 3) {
1307 res = -EFAULT;
1308 goto out_unlock;
1309 }
1310
1311 event_bitmap = libertas_get_events_bitmap(priv);
1312
1313 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1314 if (res < 0)
1315 goto out_unlock;
1316
1317 event = &pcmdptr->params.subscribe_event;
Dan Williams0aef64d2007-08-02 11:31:18 -04001318 event->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001319 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1320 sizeof(struct cmd_ds_802_11_subscribe_event) +
1321 sizeof(struct mrvlietypes_snrthreshold));
1322 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1323 ptr = (u8*) pcmdptr+cmd_len;
1324 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
1325 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
David Woodhouse981f1872007-05-25 23:36:54 -04001326 snr_threshold->header.len = cpu_to_le16(2);
1327 snr_threshold->snrvalue = value;
1328 snr_threshold->snrfreq = freq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001329 event_bitmap |= subscribed ? 0x0020 : 0x0;
David Woodhouse981f1872007-05-25 23:36:54 -04001330 event->events = cpu_to_le16(event_bitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001331
1332 libertas_queue_cmd(adapter, pcmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001333 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001334
1335 /* Sleep until response is generated by FW */
1336 wait_event_interruptible(pcmdnode->cmdwait_q,
David Woodhouse981f1872007-05-25 23:36:54 -04001337 pcmdnode->cmdwaitqwoken);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001338
1339 pcmdptr = response_buf;
1340
1341 if (pcmdptr->result) {
David Woodhouse981f1872007-05-25 23:36:54 -04001342 lbs_pr_err("%s: fail, result=%d\n", __func__,
1343 le16_to_cpu(pcmdptr->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001344 kfree(response_buf);
1345 free_page(addr);
1346 return 0;
1347 }
1348
Holger Schurig6b63cd02007-08-02 11:53:36 -04001349 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001350 lbs_pr_err("command response incorrect!\n");
1351 kfree(response_buf);
1352 free_page(addr);
1353 return 0;
1354 }
1355
1356 res = count;
1357out_unlock:
1358 free_page(addr);
1359 return res;
1360}
1361
1362static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
1363 size_t count, loff_t *ppos)
1364{
1365 wlan_private *priv = file->private_data;
1366 wlan_adapter *adapter = priv->adapter;
1367 struct wlan_offset_value offval;
1368 ssize_t pos = 0;
1369 int ret;
1370 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1371 char *buf = (char *)addr;
1372
1373 offval.offset = priv->mac_offset;
1374 offval.value = 0;
1375
1376 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001377 CMD_MAC_REG_ACCESS, 0,
1378 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001379 mdelay(10);
1380 pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
1381 priv->mac_offset, adapter->offsetvalue.value);
1382
1383 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1384 free_page(addr);
1385 return ret;
1386}
1387
1388static ssize_t libertas_rdmac_write(struct file *file,
1389 const char __user *userbuf,
1390 size_t count, loff_t *ppos)
1391{
1392 wlan_private *priv = file->private_data;
1393 ssize_t res, buf_size;
1394 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1395 char *buf = (char *)addr;
1396
1397 buf_size = min(count, len - 1);
1398 if (copy_from_user(buf, userbuf, buf_size)) {
1399 res = -EFAULT;
1400 goto out_unlock;
1401 }
1402 priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
1403 res = count;
1404out_unlock:
1405 free_page(addr);
1406 return res;
1407}
1408
1409static ssize_t libertas_wrmac_write(struct file *file,
1410 const char __user *userbuf,
1411 size_t count, loff_t *ppos)
1412{
1413
1414 wlan_private *priv = file->private_data;
1415 ssize_t res, buf_size;
1416 u32 offset, value;
1417 struct wlan_offset_value offval;
1418 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1419 char *buf = (char *)addr;
1420
1421 buf_size = min(count, len - 1);
1422 if (copy_from_user(buf, userbuf, buf_size)) {
1423 res = -EFAULT;
1424 goto out_unlock;
1425 }
1426 res = sscanf(buf, "%x %x", &offset, &value);
1427 if (res != 2) {
1428 res = -EFAULT;
1429 goto out_unlock;
1430 }
1431
1432 offval.offset = offset;
1433 offval.value = value;
1434 res = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001435 CMD_MAC_REG_ACCESS, 1,
1436 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001437 mdelay(10);
1438
1439 res = count;
1440out_unlock:
1441 free_page(addr);
1442 return res;
1443}
1444
1445static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
1446 size_t count, loff_t *ppos)
1447{
1448 wlan_private *priv = file->private_data;
1449 wlan_adapter *adapter = priv->adapter;
1450 struct wlan_offset_value offval;
1451 ssize_t pos = 0;
1452 int ret;
1453 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1454 char *buf = (char *)addr;
1455
1456 offval.offset = priv->bbp_offset;
1457 offval.value = 0;
1458
1459 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001460 CMD_BBP_REG_ACCESS, 0,
1461 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001462 mdelay(10);
1463 pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
1464 priv->bbp_offset, adapter->offsetvalue.value);
1465
1466 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1467 free_page(addr);
1468
1469 return ret;
1470}
1471
1472static ssize_t libertas_rdbbp_write(struct file *file,
1473 const char __user *userbuf,
1474 size_t count, loff_t *ppos)
1475{
1476 wlan_private *priv = file->private_data;
1477 ssize_t res, buf_size;
1478 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1479 char *buf = (char *)addr;
1480
1481 buf_size = min(count, len - 1);
1482 if (copy_from_user(buf, userbuf, buf_size)) {
1483 res = -EFAULT;
1484 goto out_unlock;
1485 }
1486 priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
1487 res = count;
1488out_unlock:
1489 free_page(addr);
1490 return res;
1491}
1492
1493static ssize_t libertas_wrbbp_write(struct file *file,
1494 const char __user *userbuf,
1495 size_t count, loff_t *ppos)
1496{
1497
1498 wlan_private *priv = file->private_data;
1499 ssize_t res, buf_size;
1500 u32 offset, value;
1501 struct wlan_offset_value offval;
1502 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1503 char *buf = (char *)addr;
1504
1505 buf_size = min(count, len - 1);
1506 if (copy_from_user(buf, userbuf, buf_size)) {
1507 res = -EFAULT;
1508 goto out_unlock;
1509 }
1510 res = sscanf(buf, "%x %x", &offset, &value);
1511 if (res != 2) {
1512 res = -EFAULT;
1513 goto out_unlock;
1514 }
1515
1516 offval.offset = offset;
1517 offval.value = value;
1518 res = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001519 CMD_BBP_REG_ACCESS, 1,
1520 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001521 mdelay(10);
1522
1523 res = count;
1524out_unlock:
1525 free_page(addr);
1526 return res;
1527}
1528
1529static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
1530 size_t count, loff_t *ppos)
1531{
1532 wlan_private *priv = file->private_data;
1533 wlan_adapter *adapter = priv->adapter;
1534 struct wlan_offset_value offval;
1535 ssize_t pos = 0;
1536 int ret;
1537 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1538 char *buf = (char *)addr;
1539
1540 offval.offset = priv->rf_offset;
1541 offval.value = 0;
1542
1543 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001544 CMD_RF_REG_ACCESS, 0,
1545 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001546 mdelay(10);
1547 pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
1548 priv->rf_offset, adapter->offsetvalue.value);
1549
1550 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1551 free_page(addr);
1552
1553 return ret;
1554}
1555
1556static ssize_t libertas_rdrf_write(struct file *file,
1557 const char __user *userbuf,
1558 size_t count, loff_t *ppos)
1559{
1560 wlan_private *priv = file->private_data;
1561 ssize_t res, buf_size;
1562 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1563 char *buf = (char *)addr;
1564
1565 buf_size = min(count, len - 1);
1566 if (copy_from_user(buf, userbuf, buf_size)) {
1567 res = -EFAULT;
1568 goto out_unlock;
1569 }
1570 priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
1571 res = count;
1572out_unlock:
1573 free_page(addr);
1574 return res;
1575}
1576
1577static ssize_t libertas_wrrf_write(struct file *file,
1578 const char __user *userbuf,
1579 size_t count, loff_t *ppos)
1580{
1581
1582 wlan_private *priv = file->private_data;
1583 ssize_t res, buf_size;
1584 u32 offset, value;
1585 struct wlan_offset_value offval;
1586 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1587 char *buf = (char *)addr;
1588
1589 buf_size = min(count, len - 1);
1590 if (copy_from_user(buf, userbuf, buf_size)) {
1591 res = -EFAULT;
1592 goto out_unlock;
1593 }
1594 res = sscanf(buf, "%x %x", &offset, &value);
1595 if (res != 2) {
1596 res = -EFAULT;
1597 goto out_unlock;
1598 }
1599
1600 offval.offset = offset;
1601 offval.value = value;
1602 res = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001603 CMD_RF_REG_ACCESS, 1,
1604 CMD_OPTION_WAITFORRSP, 0, &offval);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001605 mdelay(10);
1606
1607 res = count;
1608out_unlock:
1609 free_page(addr);
1610 return res;
1611}
1612
1613#define FOPS(fread, fwrite) { \
1614 .owner = THIS_MODULE, \
1615 .open = open_file_generic, \
1616 .read = (fread), \
1617 .write = (fwrite), \
1618}
1619
1620struct libertas_debugfs_files {
1621 char *name;
1622 int perm;
1623 struct file_operations fops;
1624};
1625
Dan Williams5bdb3ef2007-05-10 23:08:05 -04001626static struct libertas_debugfs_files debugfs_files[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001627 { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
1628 { "getscantable", 0444, FOPS(libertas_getscantable,
1629 write_file_dummy), },
1630 { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
1631 libertas_sleepparams_write), },
1632 { "extscan", 0600, FOPS(NULL, libertas_extscan), },
1633 { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
1634};
1635
Dan Williams5bdb3ef2007-05-10 23:08:05 -04001636static struct libertas_debugfs_files debugfs_events_files[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001637 {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
1638 libertas_lowrssi_write), },
1639 {"low_snr", 0644, FOPS(libertas_lowsnr_read,
1640 libertas_lowsnr_write), },
1641 {"failure_count", 0644, FOPS(libertas_failcount_read,
1642 libertas_failcount_write), },
1643 {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
1644 libertas_bcnmiss_write), },
1645 {"high_rssi", 0644, FOPS(libertas_highrssi_read,
1646 libertas_highrssi_write), },
1647 {"high_snr", 0644, FOPS(libertas_highsnr_read,
1648 libertas_highsnr_write), },
1649};
1650
Dan Williams5bdb3ef2007-05-10 23:08:05 -04001651static struct libertas_debugfs_files debugfs_regs_files[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001652 {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
1653 {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
1654 {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
1655 {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
1656 {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
1657 {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
1658};
1659
1660void libertas_debugfs_init(void)
1661{
1662 if (!libertas_dir)
1663 libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
1664
1665 return;
1666}
1667
1668void libertas_debugfs_remove(void)
1669{
1670 if (libertas_dir)
1671 debugfs_remove(libertas_dir);
1672 return;
1673}
1674
1675void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
1676{
1677 int i;
1678 struct libertas_debugfs_files *files;
1679 if (!libertas_dir)
1680 goto exit;
1681
1682 priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
1683 if (!priv->debugfs_dir)
1684 goto exit;
1685
1686 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
1687 files = &debugfs_files[i];
1688 priv->debugfs_files[i] = debugfs_create_file(files->name,
1689 files->perm,
1690 priv->debugfs_dir,
1691 priv,
1692 &files->fops);
1693 }
1694
1695 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
1696 if (!priv->events_dir)
1697 goto exit;
1698
1699 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
1700 files = &debugfs_events_files[i];
1701 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
1702 files->perm,
1703 priv->events_dir,
1704 priv,
1705 &files->fops);
1706 }
1707
1708 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
1709 if (!priv->regs_dir)
1710 goto exit;
1711
1712 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
1713 files = &debugfs_regs_files[i];
1714 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
1715 files->perm,
1716 priv->regs_dir,
1717 priv,
1718 &files->fops);
1719 }
1720
1721#ifdef PROC_DEBUG
1722 libertas_debug_init(priv, dev);
1723#endif
1724exit:
1725 return;
1726}
1727
1728void libertas_debugfs_remove_one(wlan_private *priv)
1729{
1730 int i;
1731
1732 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
1733 debugfs_remove(priv->debugfs_regs_files[i]);
1734
1735 debugfs_remove(priv->regs_dir);
1736
Holger Schurig0b7db952007-05-24 23:47:34 -04001737 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001738 debugfs_remove(priv->debugfs_events_files[i]);
1739
1740 debugfs_remove(priv->events_dir);
1741#ifdef PROC_DEBUG
1742 debugfs_remove(priv->debugfs_debug);
1743#endif
1744 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
1745 debugfs_remove(priv->debugfs_files[i]);
Holger Schurig0b7db952007-05-24 23:47:34 -04001746 debugfs_remove(priv->debugfs_dir);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001747}
1748
Holger Schurig46868202007-05-25 00:37:28 -04001749
1750
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001751/* debug entry */
1752
Holger Schurig46868202007-05-25 00:37:28 -04001753#ifdef PROC_DEBUG
1754
Tony Breedsd2f11e02007-03-09 13:11:46 +11001755#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n))
1756#define item_addr(n) (offsetof(wlan_adapter, n))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001757
Holger Schurig46868202007-05-25 00:37:28 -04001758
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001759struct debug_data {
1760 char name[32];
1761 u32 size;
Dan Williams4269e2a2007-05-10 23:10:18 -04001762 size_t addr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001763};
1764
1765/* To debug any member of wlan_adapter, simply add one line here.
1766 */
1767static struct debug_data items[] = {
1768 {"intcounter", item_size(intcounter), item_addr(intcounter)},
1769 {"psmode", item_size(psmode), item_addr(psmode)},
1770 {"psstate", item_size(psstate), item_addr(psstate)},
1771};
1772
Tony Breedsd2f11e02007-03-09 13:11:46 +11001773static int num_of_items = ARRAY_SIZE(items);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001774
1775/**
1776 * @brief proc read function
1777 *
1778 * @param page pointer to buffer
1779 * @param s read data starting position
1780 * @param off offset
1781 * @param cnt counter
1782 * @param eof end of file flag
1783 * @param data data to output
1784 * @return number of output data
1785 */
1786static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
1787 size_t count, loff_t *ppos)
1788{
1789 int val = 0;
1790 size_t pos = 0;
1791 ssize_t res;
1792 char *p;
1793 int i;
1794 struct debug_data *d;
1795 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1796 char *buf = (char *)addr;
1797
1798 p = buf;
1799
1800 d = (struct debug_data *)file->private_data;
1801
1802 for (i = 0; i < num_of_items; i++) {
1803 if (d[i].size == 1)
1804 val = *((u8 *) d[i].addr);
1805 else if (d[i].size == 2)
1806 val = *((u16 *) d[i].addr);
1807 else if (d[i].size == 4)
1808 val = *((u32 *) d[i].addr);
Dan Williams4269e2a2007-05-10 23:10:18 -04001809 else if (d[i].size == 8)
1810 val = *((u64 *) d[i].addr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001811
1812 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
1813 }
1814
1815 res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
1816
1817 free_page(addr);
1818 return res;
1819}
1820
1821/**
1822 * @brief proc write function
1823 *
1824 * @param f file pointer
1825 * @param buf pointer to data buffer
1826 * @param cnt data number to write
1827 * @param data data to write
1828 * @return number of data
1829 */
Dan Williams4269e2a2007-05-10 23:10:18 -04001830static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001831 size_t cnt, loff_t *ppos)
1832{
1833 int r, i;
1834 char *pdata;
1835 char *p;
1836 char *p0;
1837 char *p1;
1838 char *p2;
1839 struct debug_data *d = (struct debug_data *)f->private_data;
1840
Jesper Juhl655b4d12007-08-24 11:48:16 -04001841 pdata = kmalloc(cnt, GFP_KERNEL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001842 if (pdata == NULL)
1843 return 0;
1844
1845 if (copy_from_user(pdata, buf, cnt)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001846 lbs_deb_debugfs("Copy from user failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001847 kfree(pdata);
1848 return 0;
1849 }
1850
1851 p0 = pdata;
1852 for (i = 0; i < num_of_items; i++) {
1853 do {
1854 p = strstr(p0, d[i].name);
1855 if (p == NULL)
1856 break;
1857 p1 = strchr(p, '\n');
1858 if (p1 == NULL)
1859 break;
1860 p0 = p1++;
1861 p2 = strchr(p, '=');
1862 if (!p2)
1863 break;
1864 p2++;
Tony Breedsd2f11e02007-03-09 13:11:46 +11001865 r = simple_strtoul(p2, NULL, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001866 if (d[i].size == 1)
1867 *((u8 *) d[i].addr) = (u8) r;
1868 else if (d[i].size == 2)
1869 *((u16 *) d[i].addr) = (u16) r;
1870 else if (d[i].size == 4)
1871 *((u32 *) d[i].addr) = (u32) r;
Dan Williams4269e2a2007-05-10 23:10:18 -04001872 else if (d[i].size == 8)
1873 *((u64 *) d[i].addr) = (u64) r;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001874 break;
1875 } while (1);
1876 }
1877 kfree(pdata);
1878
Dan Williams4269e2a2007-05-10 23:10:18 -04001879 return (ssize_t)cnt;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001880}
1881
1882static struct file_operations libertas_debug_fops = {
1883 .owner = THIS_MODULE,
1884 .open = open_file_generic,
1885 .write = wlan_debugfs_write,
1886 .read = wlan_debugfs_read,
1887};
1888
1889/**
1890 * @brief create debug proc file
1891 *
1892 * @param priv pointer wlan_private
1893 * @param dev pointer net_device
1894 * @return N/A
1895 */
Holger Schurig46868202007-05-25 00:37:28 -04001896static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001897{
1898 int i;
1899
1900 if (!priv->debugfs_dir)
1901 return;
1902
1903 for (i = 0; i < num_of_items; i++)
Dan Williams4269e2a2007-05-10 23:10:18 -04001904 items[i].addr += (size_t) priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001905
1906 priv->debugfs_debug = debugfs_create_file("debug", 0644,
1907 priv->debugfs_dir, &items[0],
1908 &libertas_debug_fops);
1909}
Holger Schurig46868202007-05-25 00:37:28 -04001910#endif
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001911