|
@@ -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 */
|
|
|
};
|
|
@@ -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 :
|
|
@@ -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.
|
|
|
*/
|
|
@@ -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);
|
|
@@ -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) );
|
|
|
|
|
@@ -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)
|
|
@@ -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);
|
|
@@ -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) },
|
|
@@ -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,
|
|
|
};
|
|
|
|