diff options
author | Oliver Neukum <oliver@neukum.name> | 2006-10-03 04:30:52 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-10-17 17:46:30 -0400 |
commit | 1a2ea1dfc4ee078841cd6406ebf6bf0c5a3d25e9 (patch) | |
tree | cba3ced71bc8573e283fe5cd85c2eb532f3e3438 /drivers/usb/net/kaweth.c | |
parent | fbe2bafcb00b25265c2c869ba4615d6a5324b7f1 (diff) |
USB: suspend/resume support for kaweth
this adds support for suspend and resume to the kaweth driver.
Signed-off-by: Oliver Neukum <oliver@neukum.name>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/net/kaweth.c')
-rw-r--r-- | drivers/usb/net/kaweth.c | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 9ef9075a1680..7c906a43e497 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c | |||
@@ -76,6 +76,9 @@ | |||
76 | 76 | ||
77 | #define KAWETH_STATUS_BROKEN 0x0000001 | 77 | #define KAWETH_STATUS_BROKEN 0x0000001 |
78 | #define KAWETH_STATUS_CLOSING 0x0000002 | 78 | #define KAWETH_STATUS_CLOSING 0x0000002 |
79 | #define KAWETH_STATUS_SUSPENDING 0x0000004 | ||
80 | |||
81 | #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) | ||
79 | 82 | ||
80 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 | 83 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 |
81 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 | 84 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 |
@@ -102,6 +105,8 @@ | |||
102 | #define STATE_MASK 0x40 | 105 | #define STATE_MASK 0x40 |
103 | #define STATE_SHIFT 5 | 106 | #define STATE_SHIFT 5 |
104 | 107 | ||
108 | #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) | ||
109 | |||
105 | 110 | ||
106 | MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); | 111 | MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); |
107 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); | 112 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); |
@@ -118,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |||
118 | unsigned int pipe, | 123 | unsigned int pipe, |
119 | struct usb_ctrlrequest *cmd, void *data, | 124 | struct usb_ctrlrequest *cmd, void *data, |
120 | int len, int timeout); | 125 | int len, int timeout); |
126 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); | ||
127 | static int kaweth_resume(struct usb_interface *intf); | ||
121 | 128 | ||
122 | /**************************************************************** | 129 | /**************************************************************** |
123 | * usb_device_id | 130 | * usb_device_id |
@@ -169,6 +176,8 @@ static struct usb_driver kaweth_driver = { | |||
169 | .name = driver_name, | 176 | .name = driver_name, |
170 | .probe = kaweth_probe, | 177 | .probe = kaweth_probe, |
171 | .disconnect = kaweth_disconnect, | 178 | .disconnect = kaweth_disconnect, |
179 | .suspend = kaweth_suspend, | ||
180 | .resume = kaweth_resume, | ||
172 | .id_table = usb_klsi_table, | 181 | .id_table = usb_klsi_table, |
173 | }; | 182 | }; |
174 | 183 | ||
@@ -212,6 +221,7 @@ struct kaweth_device | |||
212 | int suspend_lowmem_rx; | 221 | int suspend_lowmem_rx; |
213 | int suspend_lowmem_ctrl; | 222 | int suspend_lowmem_ctrl; |
214 | int linkstate; | 223 | int linkstate; |
224 | int opened; | ||
215 | struct work_struct lowmem_work; | 225 | struct work_struct lowmem_work; |
216 | 226 | ||
217 | struct usb_device *dev; | 227 | struct usb_device *dev; |
@@ -524,7 +534,7 @@ static void kaweth_resubmit_tl(void *d) | |||
524 | { | 534 | { |
525 | struct kaweth_device *kaweth = (struct kaweth_device *)d; | 535 | struct kaweth_device *kaweth = (struct kaweth_device *)d; |
526 | 536 | ||
527 | if (kaweth->status | KAWETH_STATUS_CLOSING) | 537 | if (IS_BLOCKED(kaweth->status)) |
528 | return; | 538 | return; |
529 | 539 | ||
530 | if (kaweth->suspend_lowmem_rx) | 540 | if (kaweth->suspend_lowmem_rx) |
@@ -591,8 +601,12 @@ static void kaweth_usb_receive(struct urb *urb) | |||
591 | return; | 601 | return; |
592 | } | 602 | } |
593 | 603 | ||
594 | if (kaweth->status & KAWETH_STATUS_CLOSING) | 604 | spin_lock(&kaweth->device_lock); |
605 | if (IS_BLOCKED(kaweth->status)) { | ||
606 | spin_unlock(&kaweth->device_lock); | ||
595 | return; | 607 | return; |
608 | } | ||
609 | spin_unlock(&kaweth->device_lock); | ||
596 | 610 | ||
597 | if(urb->status && urb->status != -EREMOTEIO && count != 1) { | 611 | if(urb->status && urb->status != -EREMOTEIO && count != 1) { |
598 | err("%s RX status: %d count: %d packet_len: %d", | 612 | err("%s RX status: %d count: %d packet_len: %d", |
@@ -668,6 +682,7 @@ static int kaweth_open(struct net_device *net) | |||
668 | usb_kill_urb(kaweth->rx_urb); | 682 | usb_kill_urb(kaweth->rx_urb); |
669 | return -EIO; | 683 | return -EIO; |
670 | } | 684 | } |
685 | kaweth->opened = 1; | ||
671 | 686 | ||
672 | netif_start_queue(net); | 687 | netif_start_queue(net); |
673 | 688 | ||
@@ -678,14 +693,8 @@ static int kaweth_open(struct net_device *net) | |||
678 | /**************************************************************** | 693 | /**************************************************************** |
679 | * kaweth_close | 694 | * kaweth_close |
680 | ****************************************************************/ | 695 | ****************************************************************/ |
681 | static int kaweth_close(struct net_device *net) | 696 | static void kaweth_kill_urbs(struct kaweth_device *kaweth) |
682 | { | 697 | { |
683 | struct kaweth_device *kaweth = netdev_priv(net); | ||
684 | |||
685 | netif_stop_queue(net); | ||
686 | |||
687 | kaweth->status |= KAWETH_STATUS_CLOSING; | ||
688 | |||
689 | usb_kill_urb(kaweth->irq_urb); | 698 | usb_kill_urb(kaweth->irq_urb); |
690 | usb_kill_urb(kaweth->rx_urb); | 699 | usb_kill_urb(kaweth->rx_urb); |
691 | usb_kill_urb(kaweth->tx_urb); | 700 | usb_kill_urb(kaweth->tx_urb); |
@@ -696,6 +705,21 @@ static int kaweth_close(struct net_device *net) | |||
696 | we hit them again */ | 705 | we hit them again */ |
697 | usb_kill_urb(kaweth->irq_urb); | 706 | usb_kill_urb(kaweth->irq_urb); |
698 | usb_kill_urb(kaweth->rx_urb); | 707 | usb_kill_urb(kaweth->rx_urb); |
708 | } | ||
709 | |||
710 | /**************************************************************** | ||
711 | * kaweth_close | ||
712 | ****************************************************************/ | ||
713 | static int kaweth_close(struct net_device *net) | ||
714 | { | ||
715 | struct kaweth_device *kaweth = netdev_priv(net); | ||
716 | |||
717 | netif_stop_queue(net); | ||
718 | kaweth->opened = 0; | ||
719 | |||
720 | kaweth->status |= KAWETH_STATUS_CLOSING; | ||
721 | |||
722 | kaweth_kill_urbs(kaweth); | ||
699 | 723 | ||
700 | kaweth->status &= ~KAWETH_STATUS_CLOSING; | 724 | kaweth->status &= ~KAWETH_STATUS_CLOSING; |
701 | 725 | ||
@@ -742,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
742 | 766 | ||
743 | kaweth_async_set_rx_mode(kaweth); | 767 | kaweth_async_set_rx_mode(kaweth); |
744 | netif_stop_queue(net); | 768 | netif_stop_queue(net); |
769 | if (IS_BLOCKED(kaweth->status)) { | ||
770 | goto skip; | ||
771 | } | ||
745 | 772 | ||
746 | /* We now decide whether we can put our special header into the sk_buff */ | 773 | /* We now decide whether we can put our special header into the sk_buff */ |
747 | if (skb_cloned(skb) || skb_headroom(skb) < 2) { | 774 | if (skb_cloned(skb) || skb_headroom(skb) < 2) { |
@@ -774,6 +801,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
774 | if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) | 801 | if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) |
775 | { | 802 | { |
776 | warn("kaweth failed tx_urb %d", res); | 803 | warn("kaweth failed tx_urb %d", res); |
804 | skip: | ||
777 | kaweth->stats.tx_errors++; | 805 | kaweth->stats.tx_errors++; |
778 | 806 | ||
779 | netif_start_queue(net); | 807 | netif_start_queue(net); |
@@ -872,6 +900,42 @@ static void kaweth_tx_timeout(struct net_device *net) | |||
872 | } | 900 | } |
873 | 901 | ||
874 | /**************************************************************** | 902 | /**************************************************************** |
903 | * kaweth_suspend | ||
904 | ****************************************************************/ | ||
905 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) | ||
906 | { | ||
907 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
908 | unsigned long flags; | ||
909 | |||
910 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
911 | kaweth->status |= KAWETH_STATUS_SUSPENDING; | ||
912 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
913 | |||
914 | kaweth_kill_urbs(kaweth); | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | /**************************************************************** | ||
919 | * kaweth_resume | ||
920 | ****************************************************************/ | ||
921 | static int kaweth_resume(struct usb_interface *intf) | ||
922 | { | ||
923 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
924 | unsigned long flags; | ||
925 | |||
926 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
927 | kaweth->status &= ~KAWETH_STATUS_SUSPENDING; | ||
928 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
929 | |||
930 | if (!kaweth->opened) | ||
931 | return 0; | ||
932 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | ||
933 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | ||
934 | |||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | /**************************************************************** | ||
875 | * kaweth_probe | 939 | * kaweth_probe |
876 | ****************************************************************/ | 940 | ****************************************************************/ |
877 | static int kaweth_probe( | 941 | static int kaweth_probe( |