Skip to content

Commit

Permalink
USB: fix suspend support for usblp
Browse files Browse the repository at this point in the history
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: Oliver Neukum <oliver@neukum.name>
Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Oct 17, 2006
1 parent 44960af commit 516077c
Showing 1 changed file with 71 additions and 8 deletions.
79 changes: 71 additions & 8 deletions drivers/usb/class/usblp.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
Expand Down Expand Up @@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"",
usblp->device_id_string ?
usblp->device_id_string + 2 :
Expand Down Expand Up @@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err)
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.
*/
Expand Down Expand Up @@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->status = 0;
usblp->readurb->status = 0;

if (usblp->bidir) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
retval = -EIO;
usblp->used = 0;
file->private_data = NULL;
}
if (handle_bidir(usblp) < 0) {
file->private_data = NULL;
retval = -EIO;
}
out:
mutex_unlock (&usblp_mutex);
Expand Down Expand Up @@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
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),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );

Expand Down Expand Up @@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
return -ENODEV;
}

if (usblp->sleeping) {
up (&usblp->sem);
return writecount ? writecount : -ENODEV;
}

if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete)
Expand Down Expand Up @@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
goto done;
}

if (usblp->sleeping) {
count = -ENODEV;
goto done;
}

if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb->status);
Expand Down Expand Up @@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf)
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 [] = {
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
Expand All @@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = {
.name = "usblp",
.probe = usblp_probe,
.disconnect = usblp_disconnect,
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
};

Expand Down

0 comments on commit 516077c

Please sign in to comment.