Commit 1a2ea1df authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: suspend/resume support for kaweth

this adds support for suspend and resume to the kaweth driver.
Signed-off-by: default avatarOliver Neukum <oliver@neukum.name>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent fbe2bafc
...@@ -76,6 +76,9 @@ ...@@ -76,6 +76,9 @@
#define KAWETH_STATUS_BROKEN 0x0000001 #define KAWETH_STATUS_BROKEN 0x0000001
#define KAWETH_STATUS_CLOSING 0x0000002 #define KAWETH_STATUS_CLOSING 0x0000002
#define KAWETH_STATUS_SUSPENDING 0x0000004
#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
...@@ -102,6 +105,8 @@ ...@@ -102,6 +105,8 @@
#define STATE_MASK 0x40 #define STATE_MASK 0x40
#define STATE_SHIFT 5 #define STATE_SHIFT 5
#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
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>"); 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>");
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
...@@ -118,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, ...@@ -118,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe, unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data, struct usb_ctrlrequest *cmd, void *data,
int len, int timeout); int len, int timeout);
static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
static int kaweth_resume(struct usb_interface *intf);
/**************************************************************** /****************************************************************
* usb_device_id * usb_device_id
...@@ -169,6 +176,8 @@ static struct usb_driver kaweth_driver = { ...@@ -169,6 +176,8 @@ static struct usb_driver kaweth_driver = {
.name = driver_name, .name = driver_name,
.probe = kaweth_probe, .probe = kaweth_probe,
.disconnect = kaweth_disconnect, .disconnect = kaweth_disconnect,
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table, .id_table = usb_klsi_table,
}; };
...@@ -212,6 +221,7 @@ struct kaweth_device ...@@ -212,6 +221,7 @@ struct kaweth_device
int suspend_lowmem_rx; int suspend_lowmem_rx;
int suspend_lowmem_ctrl; int suspend_lowmem_ctrl;
int linkstate; int linkstate;
int opened;
struct work_struct lowmem_work; struct work_struct lowmem_work;
struct usb_device *dev; struct usb_device *dev;
...@@ -524,7 +534,7 @@ static void kaweth_resubmit_tl(void *d) ...@@ -524,7 +534,7 @@ static void kaweth_resubmit_tl(void *d)
{ {
struct kaweth_device *kaweth = (struct kaweth_device *)d; struct kaweth_device *kaweth = (struct kaweth_device *)d;
if (kaweth->status | KAWETH_STATUS_CLOSING) if (IS_BLOCKED(kaweth->status))
return; return;
if (kaweth->suspend_lowmem_rx) if (kaweth->suspend_lowmem_rx)
...@@ -591,8 +601,12 @@ static void kaweth_usb_receive(struct urb *urb) ...@@ -591,8 +601,12 @@ static void kaweth_usb_receive(struct urb *urb)
return; return;
} }
if (kaweth->status & KAWETH_STATUS_CLOSING) spin_lock(&kaweth->device_lock);
if (IS_BLOCKED(kaweth->status)) {
spin_unlock(&kaweth->device_lock);
return; return;
}
spin_unlock(&kaweth->device_lock);
if(urb->status && urb->status != -EREMOTEIO && count != 1) { if(urb->status && urb->status != -EREMOTEIO && count != 1) {
err("%s RX status: %d count: %d packet_len: %d", err("%s RX status: %d count: %d packet_len: %d",
...@@ -668,6 +682,7 @@ static int kaweth_open(struct net_device *net) ...@@ -668,6 +682,7 @@ static int kaweth_open(struct net_device *net)
usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->rx_urb);
return -EIO; return -EIO;
} }
kaweth->opened = 1;
netif_start_queue(net); netif_start_queue(net);
...@@ -678,14 +693,8 @@ static int kaweth_open(struct net_device *net) ...@@ -678,14 +693,8 @@ static int kaweth_open(struct net_device *net)
/**************************************************************** /****************************************************************
* kaweth_close * kaweth_close
****************************************************************/ ****************************************************************/
static int kaweth_close(struct net_device *net) static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{ {
struct kaweth_device *kaweth = netdev_priv(net);
netif_stop_queue(net);
kaweth->status |= KAWETH_STATUS_CLOSING;
usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->rx_urb);
usb_kill_urb(kaweth->tx_urb); usb_kill_urb(kaweth->tx_urb);
...@@ -696,6 +705,21 @@ static int kaweth_close(struct net_device *net) ...@@ -696,6 +705,21 @@ static int kaweth_close(struct net_device *net)
we hit them again */ we hit them again */
usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->rx_urb);
}
/****************************************************************
* kaweth_close
****************************************************************/
static int kaweth_close(struct net_device *net)
{
struct kaweth_device *kaweth = netdev_priv(net);
netif_stop_queue(net);
kaweth->opened = 0;
kaweth->status |= KAWETH_STATUS_CLOSING;
kaweth_kill_urbs(kaweth);
kaweth->status &= ~KAWETH_STATUS_CLOSING; kaweth->status &= ~KAWETH_STATUS_CLOSING;
...@@ -742,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -742,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth_async_set_rx_mode(kaweth); kaweth_async_set_rx_mode(kaweth);
netif_stop_queue(net); netif_stop_queue(net);
if (IS_BLOCKED(kaweth->status)) {
goto skip;
}
/* We now decide whether we can put our special header into the sk_buff */ /* We now decide whether we can put our special header into the sk_buff */
if (skb_cloned(skb) || skb_headroom(skb) < 2) { 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,6 +801,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{ {
warn("kaweth failed tx_urb %d", res); warn("kaweth failed tx_urb %d", res);
skip:
kaweth->stats.tx_errors++; kaweth->stats.tx_errors++;
netif_start_queue(net); netif_start_queue(net);
...@@ -871,6 +899,42 @@ static void kaweth_tx_timeout(struct net_device *net) ...@@ -871,6 +899,42 @@ static void kaweth_tx_timeout(struct net_device *net)
usb_unlink_urb(kaweth->tx_urb); usb_unlink_urb(kaweth->tx_urb);
} }
/****************************************************************
* kaweth_suspend
****************************************************************/
static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
{
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
kaweth_kill_urbs(kaweth);
return 0;
}
/****************************************************************
* kaweth_resume
****************************************************************/
static int kaweth_resume(struct usb_interface *intf)
{
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
if (!kaweth->opened)
return 0;
kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
return 0;
}
/**************************************************************** /****************************************************************
* kaweth_probe * kaweth_probe
****************************************************************/ ****************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment