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]

Reply via email to