Hi,
Some USB printers (different models) report the same
vendor:product ID codes. To differentiate them more, software
should use the IEEE 1284 Device ID string from the printer.
This patch provides an ioctl so that a printer app can
read the Device ID string from the USB printer driver
for an open printer device.
Comments?
~Randy
--
___________________________________________________
|Randy Dunlap Intel Corp., DAL Sr. SW Engr.|
|randy.dunlap.at.intel.com 503-696-2055|
|NOTE: Any views presented here are mine alone |
|and may not represent the views of my employer. |
|_________________________________________________|
--- usb-240t1-ac7/printer.c Mon May 15 11:38:12 2000
+++ usb/printer.c Fri Jun 2 10:32:26 2000
@@ -1,9 +1,10 @@
/*
- * printer.c Version 0.4
+ * printer.c Version 0.5
*
- * Copyright (c) 1999 Michael Gee <[EMAIL PROTECTED]>
- * Copyright (c) 1999 Pavel Machek <[EMAIL PROTECTED]>
- * Copyright (c) 2000 Vojtech Pavlik <[EMAIL PROTECTED]>
+ * Copyright (c) 1999 Michael Gee <[EMAIL PROTECTED]>
+ * Copyright (c) 1999 Pavel Machek <[EMAIL PROTECTED]>
+ * Copyright (c) 2000 Vojtech Pavlik <[EMAIL PROTECTED]>
+ * Copyright (c) 2000 Randy Dunlap <[EMAIL PROTECTED]>
*
* 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.
@@ -122,7 +139,6 @@
}
if (status & LP_PERRORP) {
-
if (status & LP_POUTPA) {
info("usblp%d: out of paper", usblp->minor);
return -ENOSPC;
@@ -197,6 +213,7 @@
}
usblp_table[usblp->minor] = NULL;
+ kfree(usblp->device_id_string);
kfree(usblp);
MOD_DEC_USE_COUNT;
@@ -212,6 +229,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;
@@ -318,6 +363,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 +432,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 +446,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,6 +492,8 @@
if (usblp->used) return;
+ kfree(usblp->device_id_string);
+
usblp_table[usblp->minor] = NULL;
kfree(usblp);
}
@@ -425,9 +501,10 @@
static struct file_operations usblp_fops = {
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 = {
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]