aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Schurig <hs4233@mail.mn-solutions.de>2007-11-26 04:07:14 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:04:55 -0500
commit3a1886491710c196656a005fcc693172f5bb4c8a (patch)
treec33009fb8cacd0fdea6fe7b7fdb7b5269c3063e4
parent69f9032d9dfeb763b467fdbe8cf5938f5457083a (diff)
libertas: rework event subscription
This patch moves re-works the implementation of event subscription via debugfs. For this: * it tells cmd.c and cmdresp.c about CMD_802_11_SUBSCRIBE_EVENT * removes lots of low-level cmd stuff from debugfs.c * create unified functions to read/write snr, rssi, bcnmiss and failcount * introduces #define's for subscription event bitmask values * add a function to search for a specific element in an IE (a.k.a. TLV) * add a function to find out the size of the TLV. This is needed because lbs_prepare_and_send_command() has an argument for a data buffer, but not for it's lengths and TLVs can be, by definition, vary in size. * fix a bug where it was not possible to disable an event Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/cmd.c50
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c24
-rw-r--r--drivers/net/wireless/libertas/debugfs.c1071
-rw-r--r--drivers/net/wireless/libertas/host.h8
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h7
-rw-r--r--drivers/net/wireless/libertas/types.h19
6 files changed, 278 insertions, 901 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index dde17c65bccd..d98bec92474b 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -246,6 +246,52 @@ static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
246} 246}
247 247
248 248
249static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
250{
251 ssize_t pos = 0;
252 struct mrvlietypesheader *tlv_h;
253 while (pos < size) {
254 u16 length;
255 tlv_h = (struct mrvlietypesheader *) tlv;
256 if (tlv_h->len == 0)
257 return pos;
258 length = le16_to_cpu(tlv_h->len) +
259 sizeof(struct mrvlietypesheader);
260 pos += length;
261 tlv += length;
262 }
263 return pos;
264}
265
266
267static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
268 struct cmd_ds_command *cmd, u16 cmd_action,
269 void *pdata_buf)
270{
271 struct cmd_ds_802_11_subscribe_event *events =
272 (struct cmd_ds_802_11_subscribe_event *) pdata_buf;
273
274 /* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
275 * for various Marvell TLVs */
276
277 lbs_deb_enter(LBS_DEB_CMD);
278
279 cmd->size = cpu_to_le16(sizeof(*events)
280 - sizeof(events->tlv)
281 + S_DS_GEN);
282 cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
283 if (cmd_action == CMD_ACT_GET) {
284 cmd->params.subscribe_event.events = 0;
285 } else {
286 ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
287 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
288 cmd->params.subscribe_event.events = events->events;
289 memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
290 }
291
292 lbs_deb_leave(LBS_DEB_CMD);
293}
294
249static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, 295static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
250 struct enc_key * pkey) 296 struct enc_key * pkey)
251{ 297{
@@ -1394,6 +1440,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
1394 ret = 0; 1440 ret = 0;
1395 break; 1441 break;
1396 } 1442 }
1443 case CMD_802_11_SUBSCRIBE_EVENT:
1444 lbs_cmd_802_11_subscribe_event(priv, cmdptr,
1445 cmd_action, pdata_buf);
1446 break;
1397 case CMD_802_11_PWR_CFG: 1447 case CMD_802_11_PWR_CFG:
1398 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); 1448 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1399 cmdptr->size = 1449 cmdptr->size =
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 3596957f1d5a..87b5bd2988e7 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -554,6 +554,26 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
554 return 0; 554 return 0;
555} 555}
556 556
557static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
558 struct cmd_ds_command *resp)
559{
560 struct lbs_adapter *adapter = priv->adapter;
561 struct cmd_ds_802_11_subscribe_event *cmd_event =
562 &resp->params.subscribe_event;
563 struct cmd_ds_802_11_subscribe_event *dst_event =
564 adapter->cur_cmd->pdata_buf;
565
566 lbs_deb_enter(LBS_DEB_CMD);
567
568 if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
569 dst_event->events = le16_to_cpu(cmd_event->events);
570 memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
571 }
572
573 lbs_deb_leave(LBS_DEB_CMD);
574 return 0;
575}
576
557static inline int handle_cmd_response(u16 respcmd, 577static inline int handle_cmd_response(u16 respcmd,
558 struct cmd_ds_command *resp, 578 struct cmd_ds_command *resp,
559 struct lbs_private *priv) 579 struct lbs_private *priv)
@@ -689,6 +709,10 @@ static inline int handle_cmd_response(u16 respcmd,
689 sizeof(struct cmd_ds_802_11_led_ctrl)); 709 sizeof(struct cmd_ds_802_11_led_ctrl));
690 spin_unlock_irqrestore(&adapter->driver_lock, flags); 710 spin_unlock_irqrestore(&adapter->driver_lock, flags);
691 break; 711 break;
712 case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
713 ret = lbs_ret_802_11_subscribe_event(priv, resp);
714 break;
715
692 case CMD_RET(CMD_802_11_PWR_CFG): 716 case CMD_RET(CMD_802_11_PWR_CFG):
693 spin_lock_irqsave(&adapter->driver_lock, flags); 717 spin_lock_irqsave(&adapter->driver_lock, flags);
694 memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, 718 memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 2e1842474f8e..de768de45848 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -384,524 +384,162 @@ out_unlock:
384 return count; 384 return count;
385} 385}
386 386
387static int lbs_event_initcmd(struct lbs_private *priv, void **response_buf,
388 struct cmd_ctrl_node **cmdnode,
389 struct cmd_ds_command **cmd)
390{
391 u16 wait_option = CMD_OPTION_WAITFORRSP;
392 387
393 if (!(*cmdnode = lbs_get_free_cmd_ctrl_node(priv))) { 388/*
394 lbs_deb_debugfs("failed lbs_get_free_cmd_ctrl_node\n"); 389 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
395 return -ENOMEM; 390 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
396 } 391 * firmware. Here's an example:
397 if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) { 392 * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
398 lbs_deb_debugfs("failed to allocate response buffer!\n"); 393 * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
399 return -ENOMEM; 394 * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
400 } 395 *
401 lbs_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL); 396 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
402 init_waitqueue_head(&(*cmdnode)->cmdwait_q); 397 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
403 (*cmdnode)->pdata_buf = *response_buf; 398 * defined in mrvlietypes_thresholds
404 (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; 399 *
405 (*cmdnode)->cmdwaitqwoken = 0; 400 * This function searches in this TLV data chunk for a given TLV type
406 *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; 401 * and returns a pointer to the first data byte of the TLV, or to NULL
407 (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT); 402 * if the TLV hasn't been found.
408 (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum); 403 */
409 (*cmd)->result = 0; 404static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
410 return 0;
411}
412
413static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
414 size_t count, loff_t *ppos)
415{ 405{
416 struct lbs_private *priv = file->private_data; 406 __le16 le_type = cpu_to_le16(tlv_type);
417 struct lbs_adapter *adapter = priv->adapter;
418 struct cmd_ctrl_node *pcmdnode;
419 struct cmd_ds_command *pcmdptr;
420 struct cmd_ds_802_11_subscribe_event *event;
421 void *response_buf;
422 int res, cmd_len;
423 ssize_t pos = 0; 407 ssize_t pos = 0;
424 unsigned long addr = get_zeroed_page(GFP_KERNEL); 408 struct mrvlietypesheader *tlv_h;
425 char *buf = (char *)addr; 409 while (pos < size) {
426 410 u16 length;
427 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); 411 tlv_h = (struct mrvlietypesheader *) tlv;
428 if (res < 0) { 412 if (tlv_h->type == le_type)
429 free_page(addr); 413 return tlv_h;
430 return res; 414 if (tlv_h->len == 0)
431 } 415 return NULL;
432 416 length = le16_to_cpu(tlv_h->len) +
433 event = &pcmdptr->params.subscribe_event; 417 sizeof(struct mrvlietypesheader);
434 event->action = cpu_to_le16(CMD_ACT_GET); 418 pos += length;
435 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); 419 tlv += length;
436 lbs_queue_cmd(adapter, pcmdnode, 1); 420 }
437 wake_up_interruptible(&priv->waitq); 421 return NULL;
438
439 /* Sleep until response is generated by FW */
440 wait_event_interruptible(pcmdnode->cmdwait_q,
441 pcmdnode->cmdwaitqwoken);
442
443 pcmdptr = response_buf;
444 if (pcmdptr->result) {
445 lbs_pr_err("%s: fail, result=%d\n", __func__,
446 le16_to_cpu(pcmdptr->result));
447 kfree(response_buf);
448 free_page(addr);
449 return 0;
450 }
451
452 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
453 lbs_pr_err("command response incorrect!\n");
454 kfree(response_buf);
455 free_page(addr);
456 return 0;
457 }
458
459 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
460 event = (void *)(response_buf + S_DS_GEN);
461 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
462 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
463 switch (header->type) {
464 struct mrvlietypes_rssithreshold *Lowrssi;
465 case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
466 Lowrssi = (void *)(response_buf + cmd_len);
467 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
468 Lowrssi->rssivalue,
469 Lowrssi->rssifreq,
470 (event->events & cpu_to_le16(0x0001))?1:0);
471 default:
472 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
473 break;
474 }
475 }
476
477 kfree(response_buf);
478 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
479 free_page(addr);
480 return res;
481} 422}
482 423
424
425/*
426 * This just gets the bitmap of currently subscribed events. Used when
427 * adding an additonal event subscription.
428 */
483static u16 lbs_get_events_bitmap(struct lbs_private *priv) 429static u16 lbs_get_events_bitmap(struct lbs_private *priv)
484{ 430{
485 struct lbs_adapter *adapter = priv->adapter; 431 ssize_t res;
486 struct cmd_ctrl_node *pcmdnode;
487 struct cmd_ds_command *pcmdptr;
488 struct cmd_ds_802_11_subscribe_event *event;
489 void *response_buf;
490 int res;
491 u16 event_bitmap;
492
493 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
494 if (res < 0)
495 return res;
496
497 event = &pcmdptr->params.subscribe_event;
498 event->action = cpu_to_le16(CMD_ACT_GET);
499 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
500 lbs_queue_cmd(adapter, pcmdnode, 1);
501 wake_up_interruptible(&priv->waitq);
502
503 /* Sleep until response is generated by FW */
504 wait_event_interruptible(pcmdnode->cmdwait_q,
505 pcmdnode->cmdwaitqwoken);
506 432
507 pcmdptr = response_buf; 433 struct cmd_ds_802_11_subscribe_event *events = kzalloc(
434 sizeof(struct cmd_ds_802_11_subscribe_event),
435 GFP_KERNEL);
508 436
509 if (pcmdptr->result) { 437 res = lbs_prepare_and_send_command(priv,
510 lbs_pr_err("%s: fail, result=%d\n", __func__, 438 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
511 le16_to_cpu(pcmdptr->result)); 439 CMD_OPTION_WAITFORRSP, 0, events);
512 kfree(response_buf);
513 return 0;
514 }
515 440
516 if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { 441 if (res) {
517 lbs_pr_err("command response incorrect!\n"); 442 kfree(events);
518 kfree(response_buf);
519 return 0; 443 return 0;
520 } 444 }
521 445 return le16_to_cpu(events->events);
522 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
523 event_bitmap = le16_to_cpu(event->events);
524 kfree(response_buf);
525 return event_bitmap;
526} 446}
527 447
528static ssize_t lbs_lowrssi_write(struct file *file,
529 const char __user *userbuf,
530 size_t count, loff_t *ppos)
531{
532 struct lbs_private *priv = file->private_data;
533 struct lbs_adapter *adapter = priv->adapter;
534 ssize_t res, buf_size;
535 int value, freq, subscribed, cmd_len;
536 struct cmd_ctrl_node *pcmdnode;
537 struct cmd_ds_command *pcmdptr;
538 struct cmd_ds_802_11_subscribe_event *event;
539 struct mrvlietypes_rssithreshold *rssi_threshold;
540 void *response_buf;
541 u16 event_bitmap;
542 u8 *ptr;
543 unsigned long addr = get_zeroed_page(GFP_KERNEL);
544 char *buf = (char *)addr;
545
546 buf_size = min(count, len - 1);
547 if (copy_from_user(buf, userbuf, buf_size)) {
548 res = -EFAULT;
549 goto out_unlock;
550 }
551 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
552 if (res != 3) {
553 res = -EFAULT;
554 goto out_unlock;
555 }
556
557 event_bitmap = lbs_get_events_bitmap(priv);
558
559 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
560 if (res < 0)
561 goto out_unlock;
562
563 event = &pcmdptr->params.subscribe_event;
564 event->action = cpu_to_le16(CMD_ACT_SET);
565 pcmdptr->size = cpu_to_le16(S_DS_GEN +
566 sizeof(struct cmd_ds_802_11_subscribe_event) +
567 sizeof(struct mrvlietypes_rssithreshold));
568
569 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
570 ptr = (u8*) pcmdptr+cmd_len;
571 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
572 rssi_threshold->header.type = cpu_to_le16(0x0104);
573 rssi_threshold->header.len = cpu_to_le16(2);
574 rssi_threshold->rssivalue = value;
575 rssi_threshold->rssifreq = freq;
576 event_bitmap |= subscribed ? 0x0001 : 0x0;
577 event->events = cpu_to_le16(event_bitmap);
578
579 lbs_queue_cmd(adapter, pcmdnode, 1);
580 wake_up_interruptible(&priv->waitq);
581
582 /* Sleep until response is generated by FW */
583 wait_event_interruptible(pcmdnode->cmdwait_q,
584 pcmdnode->cmdwaitqwoken);
585
586 pcmdptr = response_buf;
587
588 if (pcmdptr->result) {
589 lbs_pr_err("%s: fail, result=%d\n", __func__,
590 le16_to_cpu(pcmdptr->result));
591 kfree(response_buf);
592 free_page(addr);
593 return 0;
594 }
595 448
596 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { 449static ssize_t lbs_threshold_read(
597 lbs_pr_err("command response incorrect!\n"); 450 u16 tlv_type, u16 event_mask,
598 kfree(response_buf); 451 struct file *file, char __user *userbuf,
599 free_page(addr); 452 size_t count, loff_t *ppos)
600 return 0;
601 }
602
603 res = count;
604out_unlock:
605 free_page(addr);
606 return res;
607}
608
609static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
610 size_t count, loff_t *ppos)
611{ 453{
612 struct lbs_private *priv = file->private_data; 454 struct lbs_private *priv = file->private_data;
613 struct lbs_adapter *adapter = priv->adapter; 455 ssize_t res = 0;
614 struct cmd_ctrl_node *pcmdnode; 456 size_t pos = 0;
615 struct cmd_ds_command *pcmdptr;
616 struct cmd_ds_802_11_subscribe_event *event;
617 void *response_buf;
618 int res, cmd_len;
619 ssize_t pos = 0;
620 unsigned long addr = get_zeroed_page(GFP_KERNEL); 457 unsigned long addr = get_zeroed_page(GFP_KERNEL);
621 char *buf = (char *)addr; 458 char *buf = (char *)addr;
459 u8 value;
460 u8 freq;
622 461
623 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); 462 struct cmd_ds_802_11_subscribe_event *events = kzalloc(
624 if (res < 0) { 463 sizeof(struct cmd_ds_802_11_subscribe_event),
625 free_page(addr); 464 GFP_KERNEL);
626 return res; 465 struct mrvlietypes_thresholds *got;
627 }
628
629 event = &pcmdptr->params.subscribe_event;
630 event->action = cpu_to_le16(CMD_ACT_GET);
631 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
632 lbs_queue_cmd(adapter, pcmdnode, 1);
633 wake_up_interruptible(&priv->waitq);
634
635 /* Sleep until response is generated by FW */
636 wait_event_interruptible(pcmdnode->cmdwait_q,
637 pcmdnode->cmdwaitqwoken);
638 466
639 pcmdptr = response_buf; 467 res = lbs_prepare_and_send_command(priv,
640 468 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
641 if (pcmdptr->result) { 469 CMD_OPTION_WAITFORRSP, 0, events);
642 lbs_pr_err("%s: fail, result=%d\n", __func__, 470 if (res) {
643 le16_to_cpu(pcmdptr->result)); 471 kfree(events);
644 kfree(response_buf); 472 return res;
645 free_page(addr);
646 return 0;
647 }
648
649 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
650 lbs_pr_err("command response incorrect!\n");
651 kfree(response_buf);
652 free_page(addr);
653 return 0;
654 } 473 }
655 474
656 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); 475 got = lbs_tlv_find(tlv_type, events->tlv, sizeof(events->tlv));
657 event = (void *)(response_buf + S_DS_GEN); 476 if (got) {
658 while (cmd_len < le16_to_cpu(pcmdptr->size)) { 477 value = got->value;
659 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); 478 freq = got->freq;
660 switch (header->type) {
661 struct mrvlietypes_snrthreshold *LowSnr;
662 case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
663 LowSnr = (void *)(response_buf + cmd_len);
664 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
665 LowSnr->snrvalue,
666 LowSnr->snrfreq,
667 (event->events & cpu_to_le16(0x0002))?1:0);
668 default:
669 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
670 break;
671 }
672 } 479 }
480 kfree(events);
673 481
674 kfree(response_buf); 482 if (got)
483 pos += snprintf(buf, len, "%d %d %d\n", value, freq,
484 !!(le16_to_cpu(events->events) & event_mask));
675 485
676 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 486 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
677 free_page(addr);
678 return res;
679}
680
681static ssize_t lbs_lowsnr_write(struct file *file,
682 const char __user *userbuf,
683 size_t count, loff_t *ppos)
684{
685 struct lbs_private *priv = file->private_data;
686 struct lbs_adapter *adapter = priv->adapter;
687 ssize_t res, buf_size;
688 int value, freq, subscribed, cmd_len;
689 struct cmd_ctrl_node *pcmdnode;
690 struct cmd_ds_command *pcmdptr;
691 struct cmd_ds_802_11_subscribe_event *event;
692 struct mrvlietypes_snrthreshold *snr_threshold;
693 void *response_buf;
694 u16 event_bitmap;
695 u8 *ptr;
696 unsigned long addr = get_zeroed_page(GFP_KERNEL);
697 char *buf = (char *)addr;
698
699 buf_size = min(count, len - 1);
700 if (copy_from_user(buf, userbuf, buf_size)) {
701 res = -EFAULT;
702 goto out_unlock;
703 }
704 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
705 if (res != 3) {
706 res = -EFAULT;
707 goto out_unlock;
708 }
709
710 event_bitmap = lbs_get_events_bitmap(priv);
711
712 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
713 if (res < 0)
714 goto out_unlock;
715
716 event = &pcmdptr->params.subscribe_event;
717 event->action = cpu_to_le16(CMD_ACT_SET);
718 pcmdptr->size = cpu_to_le16(S_DS_GEN +
719 sizeof(struct cmd_ds_802_11_subscribe_event) +
720 sizeof(struct mrvlietypes_snrthreshold));
721 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
722 ptr = (u8*) pcmdptr+cmd_len;
723 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
724 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
725 snr_threshold->header.len = cpu_to_le16(2);
726 snr_threshold->snrvalue = value;
727 snr_threshold->snrfreq = freq;
728 event_bitmap |= subscribed ? 0x0002 : 0x0;
729 event->events = cpu_to_le16(event_bitmap);
730
731 lbs_queue_cmd(adapter, pcmdnode, 1);
732 wake_up_interruptible(&priv->waitq);
733
734 /* Sleep until response is generated by FW */
735 wait_event_interruptible(pcmdnode->cmdwait_q,
736 pcmdnode->cmdwaitqwoken);
737
738 pcmdptr = response_buf;
739
740 if (pcmdptr->result) {
741 lbs_pr_err("%s: fail, result=%d\n", __func__,
742 le16_to_cpu(pcmdptr->result));
743 kfree(response_buf);
744 free_page(addr);
745 return 0;
746 }
747
748 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
749 lbs_pr_err("command response incorrect!\n");
750 kfree(response_buf);
751 free_page(addr);
752 return 0;
753 }
754
755 res = count;
756 487
757out_unlock:
758 free_page(addr); 488 free_page(addr);
759 return res; 489 return res;
760} 490}
761 491
762static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
763 size_t count, loff_t *ppos)
764{
765 struct lbs_private *priv = file->private_data;
766 struct lbs_adapter *adapter = priv->adapter;
767 struct cmd_ctrl_node *pcmdnode;
768 struct cmd_ds_command *pcmdptr;
769 struct cmd_ds_802_11_subscribe_event *event;
770 void *response_buf;
771 int res, cmd_len;
772 ssize_t pos = 0;
773 unsigned long addr = get_zeroed_page(GFP_KERNEL);
774 char *buf = (char *)addr;
775
776 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
777 if (res < 0) {
778 free_page(addr);
779 return res;
780 }
781
782 event = &pcmdptr->params.subscribe_event;
783 event->action = cpu_to_le16(CMD_ACT_GET);
784 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
785 lbs_queue_cmd(adapter, pcmdnode, 1);
786 wake_up_interruptible(&priv->waitq);
787
788 /* Sleep until response is generated by FW */
789 wait_event_interruptible(pcmdnode->cmdwait_q,
790 pcmdnode->cmdwaitqwoken);
791
792 pcmdptr = response_buf;
793
794 if (pcmdptr->result) {
795 lbs_pr_err("%s: fail, result=%d\n", __func__,
796 le16_to_cpu(pcmdptr->result));
797 kfree(response_buf);
798 free_page(addr);
799 return 0;
800 }
801
802 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
803 lbs_pr_err("command response incorrect!\n");
804 kfree(response_buf);
805 free_page(addr);
806 return 0;
807 }
808
809 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
810 event = (void *)(response_buf + S_DS_GEN);
811 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
812 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
813 switch (header->type) {
814 struct mrvlietypes_failurecount *failcount;
815 case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
816 failcount = (void *)(response_buf + cmd_len);
817 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
818 failcount->failvalue,
819 failcount->Failfreq,
820 (event->events & cpu_to_le16(0x0004))?1:0);
821 default:
822 cmd_len += sizeof(struct mrvlietypes_failurecount);
823 break;
824 }
825 }
826 492
827 kfree(response_buf); 493static ssize_t lbs_threshold_write(
828 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 494 u16 tlv_type, u16 event_mask,
829 free_page(addr); 495 struct file *file,
830 return res; 496 const char __user *userbuf,
831} 497 size_t count, loff_t *ppos)
832
833static ssize_t lbs_failcount_write(struct file *file,
834 const char __user *userbuf,
835 size_t count, loff_t *ppos)
836{ 498{
837 struct lbs_private *priv = file->private_data; 499 struct lbs_private *priv = file->private_data;
838 struct lbs_adapter *adapter = priv->adapter;
839 ssize_t res, buf_size; 500 ssize_t res, buf_size;
840 int value, freq, subscribed, cmd_len; 501 int value, freq, curr_mask, new_mask;
841 struct cmd_ctrl_node *pcmdnode;
842 struct cmd_ds_command *pcmdptr;
843 struct cmd_ds_802_11_subscribe_event *event;
844 struct mrvlietypes_failurecount *failcount;
845 void *response_buf;
846 u16 event_bitmap;
847 u8 *ptr;
848 unsigned long addr = get_zeroed_page(GFP_KERNEL); 502 unsigned long addr = get_zeroed_page(GFP_KERNEL);
849 char *buf = (char *)addr; 503 char *buf = (char *)addr;
504 struct cmd_ds_802_11_subscribe_event *events;
850 505
851 buf_size = min(count, len - 1); 506 buf_size = min(count, len - 1);
852 if (copy_from_user(buf, userbuf, buf_size)) { 507 if (copy_from_user(buf, userbuf, buf_size)) {
853 res = -EFAULT; 508 res = -EFAULT;
854 goto out_unlock; 509 goto out_unlock;
855 } 510 }
856 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); 511 res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
857 if (res != 3) { 512 if (res != 3) {
858 res = -EFAULT; 513 res = -EFAULT;
859 goto out_unlock; 514 goto out_unlock;
860 } 515 }
516 curr_mask = lbs_get_events_bitmap(priv);
861 517
862 event_bitmap = lbs_get_events_bitmap(priv); 518 if (new_mask)
863 519 new_mask = curr_mask | event_mask;
864 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); 520 else
865 if (res < 0) 521 new_mask = curr_mask & ~event_mask;
866 goto out_unlock; 522
867 523 /* Now everything is set and we can send stuff down to the firmware */
868 event = &pcmdptr->params.subscribe_event; 524 events = kzalloc(
869 event->action = cpu_to_le16(CMD_ACT_SET); 525 sizeof(struct cmd_ds_802_11_subscribe_event),
870 pcmdptr->size = cpu_to_le16(S_DS_GEN + 526 GFP_KERNEL);
871 sizeof(struct cmd_ds_802_11_subscribe_event) + 527 if (events) {
872 sizeof(struct mrvlietypes_failurecount)); 528 struct mrvlietypes_thresholds *tlv =
873 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); 529 (struct mrvlietypes_thresholds *) events->tlv;
874 ptr = (u8*) pcmdptr+cmd_len; 530 events->action = cpu_to_le16(CMD_ACT_SET);
875 failcount = (struct mrvlietypes_failurecount *)(ptr); 531 events->events = cpu_to_le16(new_mask);
876 failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); 532 tlv->header.type = cpu_to_le16(tlv_type);
877 failcount->header.len = cpu_to_le16(2); 533 tlv->header.len = cpu_to_le16(
878 failcount->failvalue = value; 534 sizeof(struct mrvlietypes_thresholds) -
879 failcount->Failfreq = freq; 535 sizeof(struct mrvlietypesheader));
880 event_bitmap |= subscribed ? 0x0004 : 0x0; 536 tlv->value = value;
881 event->events = cpu_to_le16(event_bitmap); 537 if (tlv_type != TLV_TYPE_BCNMISS)
882 538 tlv->freq = freq;
883 lbs_queue_cmd(adapter, pcmdnode, 1); 539 lbs_prepare_and_send_command(priv,
884 wake_up_interruptible(&priv->waitq); 540 CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
885 541 CMD_OPTION_WAITFORRSP, 0, events);
886 /* Sleep until response is generated by FW */ 542 kfree(events);
887 wait_event_interruptible(pcmdnode->cmdwait_q,
888 pcmdnode->cmdwaitqwoken);
889
890 pcmdptr = (struct cmd_ds_command *)response_buf;
891
892 if (pcmdptr->result) {
893 lbs_pr_err("%s: fail, result=%d\n", __func__,
894 le16_to_cpu(pcmdptr->result));
895 kfree(response_buf);
896 free_page(addr);
897 return 0;
898 }
899
900 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
901 lbs_pr_err("command response incorrect!\n");
902 kfree(response_buf);
903 free_page(addr);
904 return 0;
905 } 543 }
906 544
907 res = count; 545 res = count;
@@ -910,457 +548,119 @@ out_unlock:
910 return res; 548 return res;
911} 549}
912 550
913static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
914 size_t count, loff_t *ppos)
915{
916 struct lbs_private *priv = file->private_data;
917 struct lbs_adapter *adapter = priv->adapter;
918 struct cmd_ctrl_node *pcmdnode;
919 struct cmd_ds_command *pcmdptr;
920 struct cmd_ds_802_11_subscribe_event *event;
921 void *response_buf;
922 int res, cmd_len;
923 ssize_t pos = 0;
924 unsigned long addr = get_zeroed_page(GFP_KERNEL);
925 char *buf = (char *)addr;
926
927 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
928 if (res < 0) {
929 free_page(addr);
930 return res;
931 }
932
933 event = &pcmdptr->params.subscribe_event;
934 event->action = cpu_to_le16(CMD_ACT_GET);
935 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
936 lbs_queue_cmd(adapter, pcmdnode, 1);
937 wake_up_interruptible(&priv->waitq);
938
939 /* Sleep until response is generated by FW */
940 wait_event_interruptible(pcmdnode->cmdwait_q,
941 pcmdnode->cmdwaitqwoken);
942
943 pcmdptr = response_buf;
944
945 if (pcmdptr->result) {
946 lbs_pr_err("%s: fail, result=%d\n", __func__,
947 le16_to_cpu(pcmdptr->result));
948 free_page(addr);
949 kfree(response_buf);
950 return 0;
951 }
952
953 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
954 lbs_pr_err("command response incorrect!\n");
955 free_page(addr);
956 kfree(response_buf);
957 return 0;
958 }
959 551
960 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); 552static ssize_t lbs_lowrssi_read(
961 event = (void *)(response_buf + S_DS_GEN); 553 struct file *file, char __user *userbuf,
962 while (cmd_len < le16_to_cpu(pcmdptr->size)) { 554 size_t count, loff_t *ppos)
963 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
964 switch (header->type) {
965 struct mrvlietypes_beaconsmissed *bcnmiss;
966 case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
967 bcnmiss = (void *)(response_buf + cmd_len);
968 pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
969 bcnmiss->beaconmissed,
970 (event->events & cpu_to_le16(0x0008))?1:0);
971 default:
972 cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
973 break;
974 }
975 }
976
977 kfree(response_buf);
978
979 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
980 free_page(addr);
981 return res;
982}
983
984static ssize_t lbs_bcnmiss_write(struct file *file,
985 const char __user *userbuf,
986 size_t count, loff_t *ppos)
987{ 555{
988 struct lbs_private *priv = file->private_data; 556 return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
989 struct lbs_adapter *adapter = priv->adapter; 557 file, userbuf, count, ppos);
990 ssize_t res, buf_size;
991 int value, freq, subscribed, cmd_len;
992 struct cmd_ctrl_node *pcmdnode;
993 struct cmd_ds_command *pcmdptr;
994 struct cmd_ds_802_11_subscribe_event *event;
995 struct mrvlietypes_beaconsmissed *bcnmiss;
996 void *response_buf;
997 u16 event_bitmap;
998 u8 *ptr;
999 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1000 char *buf = (char *)addr;
1001
1002 buf_size = min(count, len - 1);
1003 if (copy_from_user(buf, userbuf, buf_size)) {
1004 res = -EFAULT;
1005 goto out_unlock;
1006 }
1007 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1008 if (res != 3) {
1009 res = -EFAULT;
1010 goto out_unlock;
1011 }
1012
1013 event_bitmap = lbs_get_events_bitmap(priv);
1014
1015 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1016 if (res < 0)
1017 goto out_unlock;
1018
1019 event = &pcmdptr->params.subscribe_event;
1020 event->action = cpu_to_le16(CMD_ACT_SET);
1021 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1022 sizeof(struct cmd_ds_802_11_subscribe_event) +
1023 sizeof(struct mrvlietypes_beaconsmissed));
1024 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1025 ptr = (u8*) pcmdptr+cmd_len;
1026 bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
1027 bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
1028 bcnmiss->header.len = cpu_to_le16(2);
1029 bcnmiss->beaconmissed = value;
1030 event_bitmap |= subscribed ? 0x0008 : 0x0;
1031 event->events = cpu_to_le16(event_bitmap);
1032
1033 lbs_queue_cmd(adapter, pcmdnode, 1);
1034 wake_up_interruptible(&priv->waitq);
1035
1036 /* Sleep until response is generated by FW */
1037 wait_event_interruptible(pcmdnode->cmdwait_q,
1038 pcmdnode->cmdwaitqwoken);
1039
1040 pcmdptr = response_buf;
1041
1042 if (pcmdptr->result) {
1043 lbs_pr_err("%s: fail, result=%d\n", __func__,
1044 le16_to_cpu(pcmdptr->result));
1045 kfree(response_buf);
1046 free_page(addr);
1047 return 0;
1048 }
1049
1050 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
1051 lbs_pr_err("command response incorrect!\n");
1052 free_page(addr);
1053 kfree(response_buf);
1054 return 0;
1055 }
1056
1057 res = count;
1058out_unlock:
1059 free_page(addr);
1060 return res;
1061} 558}
1062 559
1063static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
1064 size_t count, loff_t *ppos)
1065{
1066 struct lbs_private *priv = file->private_data;
1067 struct lbs_adapter *adapter = priv->adapter;
1068 struct cmd_ctrl_node *pcmdnode;
1069 struct cmd_ds_command *pcmdptr;
1070 struct cmd_ds_802_11_subscribe_event *event;
1071 void *response_buf;
1072 int res, cmd_len;
1073 ssize_t pos = 0;
1074 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1075 char *buf = (char *)addr;
1076 560
1077 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); 561static ssize_t lbs_lowrssi_write(
1078 if (res < 0) { 562 struct file *file, const char __user *userbuf,
1079 free_page(addr); 563 size_t count, loff_t *ppos)
1080 return res; 564{
1081 } 565 return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
566 file, userbuf, count, ppos);
567}
1082 568
1083 event = &pcmdptr->params.subscribe_event;
1084 event->action = cpu_to_le16(CMD_ACT_GET);
1085 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
1086 lbs_queue_cmd(adapter, pcmdnode, 1);
1087 wake_up_interruptible(&priv->waitq);
1088 569
1089 /* Sleep until response is generated by FW */ 570static ssize_t lbs_lowsnr_read(
1090 wait_event_interruptible(pcmdnode->cmdwait_q, 571 struct file *file, char __user *userbuf,
1091 pcmdnode->cmdwaitqwoken); 572 size_t count, loff_t *ppos)
573{
574 return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
575 file, userbuf, count, ppos);
576}
1092 577
1093 pcmdptr = response_buf;
1094 578
1095 if (pcmdptr->result) { 579static ssize_t lbs_lowsnr_write(
1096 lbs_pr_err("%s: fail, result=%d\n", __func__, 580 struct file *file, const char __user *userbuf,
1097 le16_to_cpu(pcmdptr->result)); 581 size_t count, loff_t *ppos)
1098 kfree(response_buf); 582{
1099 free_page(addr); 583 return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
1100 return 0; 584 file, userbuf, count, ppos);
1101 } 585}
1102 586
1103 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
1104 lbs_pr_err("command response incorrect!\n");
1105 kfree(response_buf);
1106 free_page(addr);
1107 return 0;
1108 }
1109 587
1110 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); 588static ssize_t lbs_failcount_read(
1111 event = (void *)(response_buf + S_DS_GEN); 589 struct file *file, char __user *userbuf,
1112 while (cmd_len < le16_to_cpu(pcmdptr->size)) { 590 size_t count, loff_t *ppos)
1113 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); 591{
1114 switch (header->type) { 592 return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
1115 struct mrvlietypes_rssithreshold *Highrssi; 593 file, userbuf, count, ppos);
1116 case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH): 594}
1117 Highrssi = (void *)(response_buf + cmd_len);
1118 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1119 Highrssi->rssivalue,
1120 Highrssi->rssifreq,
1121 (event->events & cpu_to_le16(0x0010))?1:0);
1122 default:
1123 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1124 break;
1125 }
1126 }
1127 595
1128 kfree(response_buf);
1129 596
1130 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 597static ssize_t lbs_failcount_write(
1131 free_page(addr); 598 struct file *file, const char __user *userbuf,
1132 return res; 599 size_t count, loff_t *ppos)
600{
601 return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
602 file, userbuf, count, ppos);
1133} 603}
1134 604
1135static ssize_t lbs_highrssi_write(struct file *file, 605
1136 const char __user *userbuf, 606static ssize_t lbs_highrssi_read(
1137 size_t count, loff_t *ppos) 607 struct file *file, char __user *userbuf,
608 size_t count, loff_t *ppos)
1138{ 609{
1139 struct lbs_private *priv = file->private_data; 610 return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
1140 struct lbs_adapter *adapter = priv->adapter; 611 file, userbuf, count, ppos);
1141 ssize_t res, buf_size; 612}
1142 int value, freq, subscribed, cmd_len;
1143 struct cmd_ctrl_node *pcmdnode;
1144 struct cmd_ds_command *pcmdptr;
1145 struct cmd_ds_802_11_subscribe_event *event;
1146 struct mrvlietypes_rssithreshold *rssi_threshold;
1147 void *response_buf;
1148 u16 event_bitmap;
1149 u8 *ptr;
1150 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1151 char *buf = (char *)addr;
1152 613
1153 buf_size = min(count, len - 1);
1154 if (copy_from_user(buf, userbuf, buf_size)) {
1155 res = -EFAULT;
1156 goto out_unlock;
1157 }
1158 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1159 if (res != 3) {
1160 res = -EFAULT;
1161 goto out_unlock;
1162 }
1163 614
1164 event_bitmap = lbs_get_events_bitmap(priv); 615static ssize_t lbs_highrssi_write(
616 struct file *file, const char __user *userbuf,
617 size_t count, loff_t *ppos)
618{
619 return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
620 file, userbuf, count, ppos);
621}
1165 622
1166 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1167 if (res < 0)
1168 goto out_unlock;
1169 623
1170 event = &pcmdptr->params.subscribe_event; 624static ssize_t lbs_highsnr_read(
1171 event->action = cpu_to_le16(CMD_ACT_SET); 625 struct file *file, char __user *userbuf,
1172 pcmdptr->size = cpu_to_le16(S_DS_GEN + 626 size_t count, loff_t *ppos)
1173 sizeof(struct cmd_ds_802_11_subscribe_event) + 627{
1174 sizeof(struct mrvlietypes_rssithreshold)); 628 return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
1175 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); 629 file, userbuf, count, ppos);
1176 ptr = (u8*) pcmdptr+cmd_len; 630}
1177 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
1178 rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
1179 rssi_threshold->header.len = cpu_to_le16(2);
1180 rssi_threshold->rssivalue = value;
1181 rssi_threshold->rssifreq = freq;
1182 event_bitmap |= subscribed ? 0x0010 : 0x0;
1183 event->events = cpu_to_le16(event_bitmap);
1184
1185 lbs_queue_cmd(adapter, pcmdnode, 1);
1186 wake_up_interruptible(&priv->waitq);
1187
1188 /* Sleep until response is generated by FW */
1189 wait_event_interruptible(pcmdnode->cmdwait_q,
1190 pcmdnode->cmdwaitqwoken);
1191
1192 pcmdptr = response_buf;
1193
1194 if (pcmdptr->result) {
1195 lbs_pr_err("%s: fail, result=%d\n", __func__,
1196 le16_to_cpu(pcmdptr->result));
1197 kfree(response_buf);
1198 return 0;
1199 }
1200 631
1201 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
1202 lbs_pr_err("command response incorrect!\n");
1203 kfree(response_buf);
1204 return 0;
1205 }
1206 632
1207 res = count; 633static ssize_t lbs_highsnr_write(
1208out_unlock: 634 struct file *file, const char __user *userbuf,
1209 free_page(addr); 635 size_t count, loff_t *ppos)
1210 return res; 636{
637 return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
638 file, userbuf, count, ppos);
1211} 639}
1212 640
1213static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, 641static ssize_t lbs_bcnmiss_read(
1214 size_t count, loff_t *ppos) 642 struct file *file, char __user *userbuf,
643 size_t count, loff_t *ppos)
1215{ 644{
1216 struct lbs_private *priv = file->private_data; 645 return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
1217 struct lbs_adapter *adapter = priv->adapter; 646 file, userbuf, count, ppos);
1218 struct cmd_ctrl_node *pcmdnode; 647}
1219 struct cmd_ds_command *pcmdptr;
1220 struct cmd_ds_802_11_subscribe_event *event;
1221 void *response_buf;
1222 int res, cmd_len;
1223 ssize_t pos = 0;
1224 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1225 char *buf = (char *)addr;
1226
1227 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1228 if (res < 0) {
1229 free_page(addr);
1230 return res;
1231 }
1232
1233 event = &pcmdptr->params.subscribe_event;
1234 event->action = cpu_to_le16(CMD_ACT_GET);
1235 pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
1236 lbs_queue_cmd(adapter, pcmdnode, 1);
1237 wake_up_interruptible(&priv->waitq);
1238
1239 /* Sleep until response is generated by FW */
1240 wait_event_interruptible(pcmdnode->cmdwait_q,
1241 pcmdnode->cmdwaitqwoken);
1242
1243 pcmdptr = response_buf;
1244
1245 if (pcmdptr->result) {
1246 lbs_pr_err("%s: fail, result=%d\n", __func__,
1247 le16_to_cpu(pcmdptr->result));
1248 kfree(response_buf);
1249 free_page(addr);
1250 return 0;
1251 }
1252
1253 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
1254 lbs_pr_err("command response incorrect!\n");
1255 kfree(response_buf);
1256 free_page(addr);
1257 return 0;
1258 }
1259
1260 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1261 event = (void *)(response_buf + S_DS_GEN);
1262 while (cmd_len < le16_to_cpu(pcmdptr->size)) {
1263 struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
1264 switch (header->type) {
1265 struct mrvlietypes_snrthreshold *HighSnr;
1266 case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
1267 HighSnr = (void *)(response_buf + cmd_len);
1268 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1269 HighSnr->snrvalue,
1270 HighSnr->snrfreq,
1271 (event->events & cpu_to_le16(0x0020))?1:0);
1272 default:
1273 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1274 break;
1275 }
1276 }
1277 648
1278 kfree(response_buf);
1279 649
1280 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 650static ssize_t lbs_bcnmiss_write(
1281 free_page(addr); 651 struct file *file, const char __user *userbuf,
1282 return res; 652 size_t count, loff_t *ppos)
653{
654 return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
655 file, userbuf, count, ppos);
1283} 656}
1284 657
1285static ssize_t lbs_highsnr_write(struct file *file,
1286 const char __user *userbuf,
1287 size_t count, loff_t *ppos)
1288{
1289 struct lbs_private *priv = file->private_data;
1290 struct lbs_adapter *adapter = priv->adapter;
1291 ssize_t res, buf_size;
1292 int value, freq, subscribed, cmd_len;
1293 struct cmd_ctrl_node *pcmdnode;
1294 struct cmd_ds_command *pcmdptr;
1295 struct cmd_ds_802_11_subscribe_event *event;
1296 struct mrvlietypes_snrthreshold *snr_threshold;
1297 void *response_buf;
1298 u16 event_bitmap;
1299 u8 *ptr;
1300 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1301 char *buf = (char *)addr;
1302 658
1303 buf_size = min(count, len - 1);
1304 if (copy_from_user(buf, userbuf, buf_size)) {
1305 res = -EFAULT;
1306 goto out_unlock;
1307 }
1308 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1309 if (res != 3) {
1310 res = -EFAULT;
1311 goto out_unlock;
1312 }
1313 659
1314 event_bitmap = lbs_get_events_bitmap(priv);
1315 660
1316 res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1317 if (res < 0)
1318 goto out_unlock;
1319 661
1320 event = &pcmdptr->params.subscribe_event;
1321 event->action = cpu_to_le16(CMD_ACT_SET);
1322 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1323 sizeof(struct cmd_ds_802_11_subscribe_event) +
1324 sizeof(struct mrvlietypes_snrthreshold));
1325 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1326 ptr = (u8*) pcmdptr+cmd_len;
1327 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
1328 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
1329 snr_threshold->header.len = cpu_to_le16(2);
1330 snr_threshold->snrvalue = value;
1331 snr_threshold->snrfreq = freq;
1332 event_bitmap |= subscribed ? 0x0020 : 0x0;
1333 event->events = cpu_to_le16(event_bitmap);
1334
1335 lbs_queue_cmd(adapter, pcmdnode, 1);
1336 wake_up_interruptible(&priv->waitq);
1337
1338 /* Sleep until response is generated by FW */
1339 wait_event_interruptible(pcmdnode->cmdwait_q,
1340 pcmdnode->cmdwaitqwoken);
1341
1342 pcmdptr = response_buf;
1343
1344 if (pcmdptr->result) {
1345 lbs_pr_err("%s: fail, result=%d\n", __func__,
1346 le16_to_cpu(pcmdptr->result));
1347 kfree(response_buf);
1348 free_page(addr);
1349 return 0;
1350 }
1351 662
1352 if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
1353 lbs_pr_err("command response incorrect!\n");
1354 kfree(response_buf);
1355 free_page(addr);
1356 return 0;
1357 }
1358 663
1359 res = count;
1360out_unlock:
1361 free_page(addr);
1362 return res;
1363}
1364 664
1365static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, 665static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
1366 size_t count, loff_t *ppos) 666 size_t count, loff_t *ppos)
@@ -1911,4 +1211,3 @@ static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
1911 &lbs_debug_fops); 1211 &lbs_debug_fops);
1912} 1212}
1913#endif 1213#endif
1914
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 256cac2050cc..6b8932a003ab 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -180,6 +180,14 @@
180#define CMD_TYPE_SHORT_PREAMBLE 0x0002 180#define CMD_TYPE_SHORT_PREAMBLE 0x0002
181#define CMD_TYPE_LONG_PREAMBLE 0x0003 181#define CMD_TYPE_LONG_PREAMBLE 0x0003
182 182
183/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
184#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
185#define CMD_SUBSCRIBE_SNR_LOW 0x0002
186#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
187#define CMD_SUBSCRIBE_BCNMISS 0x0008
188#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
189#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
190
183#define TURN_ON_RF 0x01 191#define TURN_ON_RF 0x01
184#define RADIO_ON 0x01 192#define RADIO_ON 0x01
185#define RADIO_OFF 0x00 193#define RADIO_OFF 0x00
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index f4a265daff2c..614db6c74576 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -151,6 +151,13 @@ struct cmd_ds_802_11_reset {
151struct cmd_ds_802_11_subscribe_event { 151struct cmd_ds_802_11_subscribe_event {
152 __le16 action; 152 __le16 action;
153 __le16 events; 153 __le16 events;
154
155 /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
156 * number of TLVs. From the v5.1 manual, those TLVs would add up to
157 * 40 bytes. However, future firmware might add additional TLVs, so I
158 * bump this up a bit.
159 */
160 u8 tlv[128];
154}; 161};
155 162
156/* 163/*
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 8a454454e2a9..f0d57958b34b 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -201,22 +201,11 @@ struct mrvlietypes_powercapability {
201 s8 maxpower; 201 s8 maxpower;
202} __attribute__ ((packed)); 202} __attribute__ ((packed));
203 203
204struct mrvlietypes_rssithreshold { 204/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
205struct mrvlietypes_thresholds {
205 struct mrvlietypesheader header; 206 struct mrvlietypesheader header;
206 u8 rssivalue; 207 u8 value;
207 u8 rssifreq; 208 u8 freq;
208} __attribute__ ((packed));
209
210struct mrvlietypes_snrthreshold {
211 struct mrvlietypesheader header;
212 u8 snrvalue;
213 u8 snrfreq;
214} __attribute__ ((packed));
215
216struct mrvlietypes_failurecount {
217 struct mrvlietypesheader header;
218 u8 failvalue;
219 u8 Failfreq;
220} __attribute__ ((packed)); 209} __attribute__ ((packed));
221 210
222struct mrvlietypes_beaconsmissed { 211struct mrvlietypes_beaconsmissed {