diff options
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 79 |
1 files changed, 55 insertions, 24 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d9b8ee130c45..abfecc4814b4 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -625,16 +625,13 @@ static int lbs_thread(void *data) | |||
625 | return 0; | 625 | return 0; |
626 | } | 626 | } |
627 | 627 | ||
628 | static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy, | 628 | static int lbs_ret_host_sleep_activate(struct lbs_private *priv, |
629 | struct cmd_header *cmd) | 629 | unsigned long dummy, |
630 | struct cmd_header *cmd) | ||
630 | { | 631 | { |
631 | lbs_deb_enter(LBS_DEB_FW); | 632 | lbs_deb_enter(LBS_DEB_FW); |
632 | 633 | priv->is_host_sleep_activated = 1; | |
633 | netif_device_detach(priv->dev); | 634 | wake_up_interruptible(&priv->host_sleep_q); |
634 | if (priv->mesh_dev) | ||
635 | netif_device_detach(priv->mesh_dev); | ||
636 | |||
637 | priv->fw_ready = 0; | ||
638 | lbs_deb_leave(LBS_DEB_FW); | 635 | lbs_deb_leave(LBS_DEB_FW); |
639 | return 0; | 636 | return 0; |
640 | } | 637 | } |
@@ -646,39 +643,65 @@ int lbs_suspend(struct lbs_private *priv) | |||
646 | 643 | ||
647 | lbs_deb_enter(LBS_DEB_FW); | 644 | lbs_deb_enter(LBS_DEB_FW); |
648 | 645 | ||
649 | if (priv->wol_criteria == 0xffffffff) { | 646 | if (priv->is_deep_sleep) { |
650 | lbs_pr_info("Suspend attempt without configuring wake params!\n"); | 647 | ret = lbs_set_deep_sleep(priv, 0); |
651 | return -EINVAL; | 648 | if (ret) { |
649 | lbs_pr_err("deep sleep cancellation failed: %d\n", ret); | ||
650 | return ret; | ||
651 | } | ||
652 | priv->deep_sleep_required = 1; | ||
652 | } | 653 | } |
653 | 654 | ||
654 | memset(&cmd, 0, sizeof(cmd)); | 655 | memset(&cmd, 0, sizeof(cmd)); |
656 | ret = lbs_host_sleep_cfg(priv, priv->wol_criteria, | ||
657 | (struct wol_config *)NULL); | ||
658 | if (ret) { | ||
659 | lbs_pr_info("Host sleep configuration failed: %d\n", ret); | ||
660 | return ret; | ||
661 | } | ||
662 | if (priv->psstate == PS_STATE_FULL_POWER) { | ||
663 | ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd, | ||
664 | sizeof(cmd), lbs_ret_host_sleep_activate, 0); | ||
665 | if (ret) | ||
666 | lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret); | ||
667 | } | ||
655 | 668 | ||
656 | ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd, | 669 | if (!wait_event_interruptible_timeout(priv->host_sleep_q, |
657 | sizeof(cmd), lbs_suspend_callback, 0); | 670 | priv->is_host_sleep_activated, (10 * HZ))) { |
658 | if (ret) | 671 | lbs_pr_err("host_sleep_q: timer expired\n"); |
659 | lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret); | 672 | ret = -1; |
673 | } | ||
674 | netif_device_detach(priv->dev); | ||
675 | if (priv->mesh_dev) | ||
676 | netif_device_detach(priv->mesh_dev); | ||
660 | 677 | ||
661 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | 678 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); |
662 | return ret; | 679 | return ret; |
663 | } | 680 | } |
664 | EXPORT_SYMBOL_GPL(lbs_suspend); | 681 | EXPORT_SYMBOL_GPL(lbs_suspend); |
665 | 682 | ||
666 | void lbs_resume(struct lbs_private *priv) | 683 | int lbs_resume(struct lbs_private *priv) |
667 | { | 684 | { |
668 | lbs_deb_enter(LBS_DEB_FW); | 685 | int ret; |
686 | uint32_t criteria = EHS_REMOVE_WAKEUP; | ||
669 | 687 | ||
670 | priv->fw_ready = 1; | 688 | lbs_deb_enter(LBS_DEB_FW); |
671 | 689 | ||
672 | /* Firmware doesn't seem to give us RX packets any more | 690 | ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); |
673 | until we send it some command. Might as well update */ | ||
674 | lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, | ||
675 | 0, 0, NULL); | ||
676 | 691 | ||
677 | netif_device_attach(priv->dev); | 692 | netif_device_attach(priv->dev); |
678 | if (priv->mesh_dev) | 693 | if (priv->mesh_dev) |
679 | netif_device_attach(priv->mesh_dev); | 694 | netif_device_attach(priv->mesh_dev); |
680 | 695 | ||
681 | lbs_deb_leave(LBS_DEB_FW); | 696 | if (priv->deep_sleep_required) { |
697 | priv->deep_sleep_required = 0; | ||
698 | ret = lbs_set_deep_sleep(priv, 1); | ||
699 | if (ret) | ||
700 | lbs_pr_err("deep sleep activation failed: %d\n", ret); | ||
701 | } | ||
702 | |||
703 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | ||
704 | return ret; | ||
682 | } | 705 | } |
683 | EXPORT_SYMBOL_GPL(lbs_resume); | 706 | EXPORT_SYMBOL_GPL(lbs_resume); |
684 | 707 | ||
@@ -834,10 +857,13 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
834 | priv->psstate = PS_STATE_FULL_POWER; | 857 | priv->psstate = PS_STATE_FULL_POWER; |
835 | priv->is_deep_sleep = 0; | 858 | priv->is_deep_sleep = 0; |
836 | priv->is_auto_deep_sleep_enabled = 0; | 859 | priv->is_auto_deep_sleep_enabled = 0; |
860 | priv->deep_sleep_required = 0; | ||
837 | priv->wakeup_dev_required = 0; | 861 | priv->wakeup_dev_required = 0; |
838 | init_waitqueue_head(&priv->ds_awake_q); | 862 | init_waitqueue_head(&priv->ds_awake_q); |
839 | priv->authtype_auto = 1; | 863 | priv->authtype_auto = 1; |
840 | 864 | priv->is_host_sleep_configured = 0; | |
865 | priv->is_host_sleep_activated = 0; | ||
866 | init_waitqueue_head(&priv->host_sleep_q); | ||
841 | mutex_init(&priv->lock); | 867 | mutex_init(&priv->lock); |
842 | 868 | ||
843 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, | 869 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, |
@@ -976,6 +1002,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
976 | 1002 | ||
977 | priv->wol_criteria = 0xffffffff; | 1003 | priv->wol_criteria = 0xffffffff; |
978 | priv->wol_gpio = 0xff; | 1004 | priv->wol_gpio = 0xff; |
1005 | priv->wol_gap = 20; | ||
979 | 1006 | ||
980 | goto done; | 1007 | goto done; |
981 | 1008 | ||
@@ -1031,6 +1058,10 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1031 | wake_up_interruptible(&priv->ds_awake_q); | 1058 | wake_up_interruptible(&priv->ds_awake_q); |
1032 | } | 1059 | } |
1033 | 1060 | ||
1061 | priv->is_host_sleep_configured = 0; | ||
1062 | priv->is_host_sleep_activated = 0; | ||
1063 | wake_up_interruptible(&priv->host_sleep_q); | ||
1064 | |||
1034 | /* Stop the thread servicing the interrupts */ | 1065 | /* Stop the thread servicing the interrupts */ |
1035 | priv->surpriseremoved = 1; | 1066 | priv->surpriseremoved = 1; |
1036 | kthread_stop(priv->main_thread); | 1067 | kthread_stop(priv->main_thread); |