patch-2.4.0-test2 linux/drivers/usb/printer.c
Next file: linux/drivers/usb/scanner.c
Previous file: linux/drivers/usb/pegasus.c
Back to the patch index
Back to the overall index
- Lines: 268
- Date:
Mon Jun 19 13:42:42 2000
- Orig file:
v2.4.0-test1/linux/drivers/usb/printer.c
- Orig date:
Tue May 23 15:31:35 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
@@ -1,9 +1,10 @@
/*
- * printer.c Version 0.4
+ * printer.c Version 0.5
*
- * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
- * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com>
*
* USB Printer Device Class driver for USB printers and printer cables
*
@@ -14,6 +15,7 @@
* v0.2 - some more cleanups
* v0.3 - cleaner again, waitqueue fixes
* v0.4 - fixes in unidirectional mode
+ * v0.5 - add DEVICE_ID string support
*/
/*
@@ -44,6 +46,18 @@
#include <linux/usb.h>
#define USBLP_BUF_SIZE 8192
+#define DEVICE_ID_SIZE 1024
+
+#define IOCNR_GET_DEVICE_ID 1
+#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */
+
+/*
+ * A DEVICE_ID string may include the printer's serial number.
+ * It should end with a semi-colon (';').
+ * An example from an HP 970C DeskJet printer is (this is one long string,
+ * with the serial number changed):
+MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ: ;
+ */
/*
* USB Printer Requests
@@ -67,6 +81,8 @@
int minor; /* minor number of device */
unsigned char used; /* True if open */
unsigned char bidir; /* interface is bidirectional */
+ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
+ /* first 2 bytes are (big-endian) length */
};
static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
@@ -75,21 +91,22 @@
* Functions for usblp control messages.
*/
-static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, void *buf, int len)
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len)
{
int retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
- request, USB_TYPE_CLASS | dir | recip, 0, usblp->ifnum, buf, len, HZ * 5);
- dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d len: %#x result: %d", request, !!dir, recip, len, retval);
+ request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5);
+ dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
+ request, !!dir, recip, value, len, retval);
return retval < 0 ? retval : 0;
}
#define usblp_read_status(usblp, status)\
- usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, status, 1)
-#define usblp_get_id(usblp, id, maxlen)\
- usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, id, maxlen)
+ usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
+#define usblp_get_id(usblp, config, id, maxlen)\
+ usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
#define usblp_reset(usblp)\
- usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, NULL, 0)
+ usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
/*
* URB callback.
@@ -121,8 +138,7 @@
return -EIO;
}
- if (status & LP_PERRORP) {
-
+ if (~status & LP_PERRORP) {
if (status & LP_POUTPA) {
info("usblp%d: out of paper", usblp->minor);
return -ENOSPC;
@@ -161,10 +177,7 @@
if (usblp->used)
return -EBUSY;
- MOD_INC_USE_COUNT;
-
if ((retval = usblp_check_status(usblp))) {
- MOD_DEC_USE_COUNT;
return retval;
}
@@ -187,18 +200,17 @@
struct usblp *usblp = file->private_data;
usblp->used = 0;
-
+
if (usblp->dev) {
if (usblp->bidir)
- usb_unlink_urb(&usblp->readurb);
- usb_unlink_urb(&usblp->writeurb);
- MOD_DEC_USE_COUNT;
+ usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(&usblp->writeurb);
return 0;
}
usblp_table[usblp->minor] = NULL;
+ kfree(usblp->device_id_string);
kfree(usblp);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -212,6 +224,34 @@
| (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
}
+static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int length;
+ struct usblp *usblp = file->private_data;
+
+ if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ))
+ return -EINVAL;
+
+ switch (_IOC_NR(cmd)) {
+ case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
+ length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+#if 0
+ dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'",
+ length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+#endif
+ if (length > _IOC_SIZE(cmd))
+ length = _IOC_SIZE(cmd); /* truncate */
+ if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length))
+ return -EFAULT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
@@ -230,7 +270,7 @@
if (signal_pending(current))
return writecount ? writecount : -EINTR;
- timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
+ timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
}
}
@@ -248,14 +288,14 @@
usblp->writeurb.transfer_buffer_length = 0;
} else {
if (!(retval = usblp_check_status(usblp))) {
- err("usblp%d: error %d writing to printer",
- usblp->minor, usblp->writeurb.status);
+ err("usblp%d: error %d writing to printer (retval=%d)",
+ usblp->minor, usblp->writeurb.status, retval);
return -EIO;
}
return retval;
}
-
+
if (writecount == count)
continue;
@@ -286,7 +326,7 @@
while (usblp->readurb.status == -EINPROGRESS) {
if (signal_pending(current))
return -EINTR;
- interruptible_sleep_on(&usblp->wait);
+ interruptible_sleep_on(&usblp->wait);
}
}
@@ -318,6 +358,7 @@
struct usb_endpoint_descriptor *epread, *epwrite;
struct usblp *usblp;
int minor, i, alts = -1, bidir = 0;
+ int length, err;
char *buf;
for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
@@ -386,6 +427,13 @@
return NULL;
}
+ if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
+ err("out of memory");
+ kfree(usblp);
+ kfree(buf);
+ return NULL;
+ }
+
FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf, 0, usblp_bulk, usblp);
@@ -393,6 +441,27 @@
FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
+ /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
+ err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+ if (err >= 0) {
+ length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+ if (length < DEVICE_ID_SIZE)
+ usblp->device_id_string[length] = '\0';
+ else
+ usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
+ dbg ("usblp%d Device ID string [%d]=%s",
+ minor, length, &usblp->device_id_string[2]);
+ }
+ else {
+ err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
+ minor, err);
+ usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
+ }
+
+#ifdef DEBUG
+ usblp_check_status(usblp);
+#endif
+
info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
@@ -418,16 +487,20 @@
if (usblp->used) return;
+ kfree(usblp->device_id_string);
+
usblp_table[usblp->minor] = NULL;
kfree(usblp);
}
static struct file_operations usblp_fops = {
+ owner: THIS_MODULE,
read: usblp_read,
write: usblp_write,
+ poll: usblp_poll,
+ ioctl: usblp_ioctl,
open: usblp_open,
release: usblp_release,
- poll: usblp_poll,
};
static struct usb_driver usblp_driver = {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)