diff options
author | Holger Schurig <hs4233@mail.mn-solutions.de> | 2007-11-26 04:07:14 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:04:55 -0500 |
commit | 3a1886491710c196656a005fcc693172f5bb4c8a (patch) | |
tree | c33009fb8cacd0fdea6fe7b7fdb7b5269c3063e4 | |
parent | 69f9032d9dfeb763b467fdbe8cf5938f5457083a (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.c | 50 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/debugfs.c | 1071 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/hostcmd.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/types.h | 19 |
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 | ||
249 | static 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 | |||
267 | static 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 | |||
249 | static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, | 295 | static 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 | ||
557 | static 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 | |||
557 | static inline int handle_cmd_response(u16 respcmd, | 577 | static 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 | ||
387 | static 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; | 404 | static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size) |
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static 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 | */ | ||
483 | static u16 lbs_get_events_bitmap(struct lbs_private *priv) | 429 | static 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 | ||
528 | static 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))) { | 449 | static 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; | ||
604 | out_unlock: | ||
605 | free_page(addr); | ||
606 | return res; | ||
607 | } | ||
608 | |||
609 | static 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 | |||
681 | static 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 | ||
757 | out_unlock: | ||
758 | free_page(addr); | 488 | free_page(addr); |
759 | return res; | 489 | return res; |
760 | } | 490 | } |
761 | 491 | ||
762 | static 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); | 493 | static 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 | |||
833 | static 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 | ||
913 | static 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); | 552 | static 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 | |||
984 | static 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; | ||
1058 | out_unlock: | ||
1059 | free_page(addr); | ||
1060 | return res; | ||
1061 | } | 558 | } |
1062 | 559 | ||
1063 | static 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); | 561 | static 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 */ | 570 | static 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) { | 579 | static 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); | 588 | static 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); | 597 | static 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 | ||
1135 | static ssize_t lbs_highrssi_write(struct file *file, | 605 | |
1136 | const char __user *userbuf, | 606 | static 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); | 615 | static 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; | 624 | static 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; | 633 | static ssize_t lbs_highsnr_write( |
1208 | out_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 | ||
1213 | static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, | 641 | static 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); | 650 | static 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 | ||
1285 | static 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; | ||
1360 | out_unlock: | ||
1361 | free_page(addr); | ||
1362 | return res; | ||
1363 | } | ||
1364 | 664 | ||
1365 | static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, | 665 | static 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 { | |||
151 | struct cmd_ds_802_11_subscribe_event { | 151 | struct 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 | ||
204 | struct mrvlietypes_rssithreshold { | 204 | /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ |
205 | struct 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 | |||
210 | struct mrvlietypes_snrthreshold { | ||
211 | struct mrvlietypesheader header; | ||
212 | u8 snrvalue; | ||
213 | u8 snrfreq; | ||
214 | } __attribute__ ((packed)); | ||
215 | |||
216 | struct mrvlietypes_failurecount { | ||
217 | struct mrvlietypesheader header; | ||
218 | u8 failvalue; | ||
219 | u8 Failfreq; | ||
220 | } __attribute__ ((packed)); | 209 | } __attribute__ ((packed)); |
221 | 210 | ||
222 | struct mrvlietypes_beaconsmissed { | 211 | struct mrvlietypes_beaconsmissed { |