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]