Commit 516077c1 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: fix suspend support for usblp

this implements suspend support for usblp. According to the CUPS people
ENODEV will make CUPS retry the job. Thus it is returned in the runtime
case. My printer survives suspend/resume cycles with it.
Signed-off-by: default avatarOliver Neukum <oliver@neukum.name>
Signed-off-by: default avatarVojtech Pavlik <vojtech@suse.cz>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 44960af1
...@@ -154,6 +154,7 @@ struct usblp { ...@@ -154,6 +154,7 @@ struct usblp {
unsigned char used; /* True if open */ unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */ unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */ unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */ /* first 2 bytes are (big-endian) length */
}; };
...@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) { ...@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks); dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used); dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir); dbg("bidir=%d", usblp->bidir);
dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"", dbg("device_id_string=\"%s\"",
usblp->device_id_string ? usblp->device_id_string ?
usblp->device_id_string + 2 : usblp->device_id_string + 2 :
...@@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err) ...@@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err)
return newerr; return newerr;
} }
static int handle_bidir (struct usblp *usblp)
{
if (usblp->bidir && usblp->used && !usblp->sleeping) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
usblp->used = 0;
return -EIO;
}
}
return 0;
}
/* /*
* File op functions. * File op functions.
*/ */
...@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file) ...@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->status = 0; usblp->writeurb->status = 0;
usblp->readurb->status = 0; usblp->readurb->status = 0;
if (usblp->bidir) { if (handle_bidir(usblp) < 0) {
usblp->readcount = 0; file->private_data = NULL;
usblp->readurb->dev = usblp->dev; retval = -EIO;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
retval = -EIO;
usblp->used = 0;
file->private_data = NULL;
}
} }
out: out:
mutex_unlock (&usblp_mutex); mutex_unlock (&usblp_mutex);
...@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done; goto done;
} }
if (usblp->sleeping) {
retval = -ENODEV;
goto done;
}
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
...@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t ...@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
return -ENODEV; return -ENODEV;
} }
if (usblp->sleeping) {
up (&usblp->sem);
return writecount ? writecount : -ENODEV;
}
if (usblp->writeurb->status != 0) { if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete) if (!usblp->wcomplete)
...@@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, ...@@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
goto done; goto done;
} }
if (usblp->sleeping) {
count = -ENODEV;
goto done;
}
if (usblp->readurb->status) { if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer", err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb->status); usblp->minor, usblp->readurb->status);
...@@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf) ...@@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_unlock (&usblp_mutex); mutex_unlock (&usblp_mutex);
} }
static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
/* this races against normal access and open */
mutex_lock (&usblp_mutex);
down (&usblp->sem);
/* we take no more IO */
usblp->sleeping = 1;
/* we wait for anything printing */
wait_event (usblp->wait, usblp->wcomplete || !usblp->present);
usblp_unlink_urbs(usblp);
up (&usblp->sem);
mutex_unlock (&usblp_mutex);
return 0;
}
static int usblp_resume (struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
int r;
mutex_lock (&usblp_mutex);
down (&usblp->sem);
usblp->sleeping = 0;
r = handle_bidir (usblp);
up (&usblp->sem);
mutex_unlock (&usblp_mutex);
return r;
}
static struct usb_device_id usblp_ids [] = { static struct usb_device_id usblp_ids [] = {
{ USB_DEVICE_INFO(7, 1, 1) }, { USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) }, { USB_DEVICE_INFO(7, 1, 2) },
...@@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = { ...@@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = {
.name = "usblp", .name = "usblp",
.probe = usblp_probe, .probe = usblp_probe,
.disconnect = usblp_disconnect, .disconnect = usblp_disconnect,
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids, .id_table = usblp_ids,
}; };
......
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