patch-2.3.35 linux/drivers/usb/printer.c
Next file: linux/drivers/usb/proc_usb.c
Previous file: linux/drivers/usb/mouse.c
Back to the patch index
Back to the overall index
- Lines: 328
- Date:
Mon Dec 27 14:01:05 1999
- Orig file:
v2.3.34/linux/drivers/usb/printer.c
- Orig date:
Thu Nov 18 20:25:37 1999
diff -u --recursive --new-file v2.3.34/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
@@ -1,4 +1,3 @@
-
/* Driver for USB Printers
*
* Copyright 1999 Michael Gee (michael@linuxspecific.com)
@@ -22,10 +21,21 @@
#include "usb.h"
+/* Define IEEE_DEVICE_ID if you want to see the IEEE-1284 Device ID string.
+ * This may include the printer's serial number.
+ * 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: ;
+ */
+#define IEEE_DEVICE_ID
+
#define NAK_TIMEOUT (HZ) /* stall wait for printer */
#define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT) /* should not take 1 minute a page! */
#define BIG_BUF_SIZE 8192
+#define SUBCLASS_PRINTERS 1
+#define PROTOCOL_UNIDIRECTIONAL 1
+#define PROTOCOL_BIDIRECTIONAL 2
/*
* USB Printer Requests
@@ -59,12 +69,16 @@
static unsigned char printer_read_status(struct pp_usb_data *p)
{
__u8 status;
+ int err;
struct usb_device *dev = p->pusb_dev;
- if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+ err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
USB_PRINTER_REQ_GET_PORT_STATUS,
USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
- 0, 0, &status, 1, HZ)) {
+ 0, 0, &status, sizeof(status), HZ);
+ if (err < 0) {
+ printk(KERN_ERR "usblp%d: read_status control_msg error = %d\n",
+ p->minor, err);
return 0;
}
return status;
@@ -81,36 +95,39 @@
else if ((status & LP_POUTPA)) {
if (last != LP_POUTPA) {
last = LP_POUTPA;
- printk(KERN_INFO "usblp%d out of paper\n", p->minor);
+ printk(KERN_INFO "usblp%d out of paper (%x)\n", p->minor, status);
}
} else if (!(status & LP_PSELECD)) {
if (last != LP_PSELECD) {
last = LP_PSELECD;
- printk(KERN_INFO "usblp%d off-line\n", p->minor);
+ printk(KERN_INFO "usblp%d off-line (%x)\n", p->minor, status);
}
} else {
if (last != LP_PERRORP) {
last = LP_PERRORP;
- printk(KERN_INFO "usblp%d on fire\n", p->minor);
+ printk(KERN_INFO "usblp%d on fire (%x)\n", p->minor, status);
}
}
p->last_error = last;
-
return status;
}
static void printer_reset(struct pp_usb_data *p)
{
struct usb_device *dev = p->pusb_dev;
+ int err;
- usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+ err = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
USB_PRINTER_REQ_SOFT_RESET,
USB_TYPE_CLASS | USB_RECIP_OTHER,
0, 0, NULL, 0, HZ);
+ if (err < 0)
+ printk(KERN_ERR "usblp%d: reset control_msg error = %d\n",
+ p->minor, err);
}
-static int open_printer(struct inode * inode, struct file * file)
+static int open_printer(struct inode *inode, struct file *file)
{
struct pp_usb_data *p;
@@ -123,10 +140,14 @@
p->minor = MINOR(inode->i_rdev);
if (p->isopen++) {
+ printk(KERN_ERR "usblp%d: printer is already open\n",
+ p->minor);
return -EBUSY;
}
if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) {
p->isopen = 0;
+ printk(KERN_ERR "usblp%d: cannot allocate memory\n",
+ p->minor);
return -ENOMEM;
}
@@ -140,7 +161,7 @@
return 0;
}
-static int close_printer(struct inode * inode, struct file * file)
+static int close_printer(struct inode *inode, struct file *file)
{
struct pp_usb_data *p = file->private_data;
@@ -156,8 +177,8 @@
return 0;
}
-static ssize_t write_printer(struct file * file,
- const char * buffer, size_t count, loff_t *ppos)
+static ssize_t write_printer(struct file *file,
+ const char *buffer, size_t count, loff_t *ppos)
{
struct pp_usb_data *p = file->private_data;
unsigned long copy_size;
@@ -174,6 +195,7 @@
if (copy_from_user(p->obuf, buffer, copy_size))
return -EFAULT;
maxretry = MAX_RETRY_COUNT;
+
while (thistime) {
if (!p->pusb_dev)
return -ENODEV;
@@ -212,8 +234,8 @@
return bytes_written ? bytes_written : -EIO;
}
-static ssize_t read_printer(struct file * file,
- char * buffer, size_t count, loff_t *ppos)
+static ssize_t read_printer(struct file *file,
+ char *buffer, size_t count, loff_t *ppos)
{
struct pp_usb_data *p = file->private_data;
int read_count = 0;
@@ -231,11 +253,14 @@
}
if (!p->pusb_dev)
return -ENODEV;
- this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
+ this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
result = usb_bulk_msg(p->pusb_dev,
usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep),
buf, this_read, &partial, HZ*20);
+ if (result < 0)
+ printk(KERN_ERR "usblp%d read_printer bulk_msg error = %d\n",
+ p->minor, result);
/* unlike writes, we don't retry a NAK, just stop now */
if (!result & partial)
@@ -251,14 +276,16 @@
buffer += this_read;
}
}
+
return read_count;
}
-static void * printer_probe(struct usb_device *dev, unsigned int ifnum)
+static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
struct pp_usb_data *pp;
int i;
+ __u8 status;
/*
* FIXME - this will not cope with combined printer/scanners
@@ -274,8 +301,9 @@
/* Let's be paranoid (for the moment). */
if (interface->bInterfaceClass != USB_CLASS_PRINTER ||
- interface->bInterfaceSubClass != 1 ||
- (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1) ||
+ interface->bInterfaceSubClass != SUBCLASS_PRINTERS ||
+ (interface->bInterfaceProtocol != PROTOCOL_BIDIRECTIONAL &&
+ interface->bInterfaceProtocol != PROTOCOL_UNIDIRECTIONAL) ||
interface->bNumEndpoints > 2) {
return NULL;
}
@@ -308,75 +336,89 @@
break;
}
if (i >= MAX_PRINTERS) {
- printk("No minor table space available for USB Printer\n");
+ printk(KERN_ERR "No minor table space available for new USB printer\n");
return NULL;
}
- printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum);
+ printk(KERN_INFO "USB printer found at address %d\n", dev->devnum);
if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
- printk(KERN_DEBUG "usb_printer: no memory!\n");
+ printk(KERN_DEBUG "USB printer: no memory!\n");
return NULL;
}
memset(pp, 0, sizeof(struct pp_usb_data));
minor_data[i] = PPDATA(pp);
- minor_data[i]->minor = i;
- minor_data[i]->pusb_dev = dev;
- minor_data[i]->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
- if (interface->bInterfaceProtocol != 2) /* if not bidirectional */
- minor_data[i]->noinput = 1;
- minor_data[i]->bulk_out_index =
+ pp->minor = i;
+ pp->pusb_dev = dev;
+ pp->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
+ if (interface->bInterfaceProtocol != PROTOCOL_BIDIRECTIONAL)
+ pp->noinput = 1;
+
+ pp->bulk_out_index =
((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
== USB_DIR_OUT) ? 0 : 1;
- minor_data[i]->bulk_in_index = minor_data[i]->noinput ? -1 :
- (minor_data[i]->bulk_out_index == 0) ? 1 : 0;
- minor_data[i]->bulk_in_ep = minor_data[i]->noinput ? -1 :
- interface->endpoint[minor_data[i]->bulk_in_index].bEndpointAddress &
+ pp->bulk_in_index = pp->noinput ? -1 :
+ (pp->bulk_out_index == 0) ? 1 : 0;
+ pp->bulk_in_ep = pp->noinput ? -1 :
+ interface->endpoint[pp->bulk_in_index].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
- minor_data[i]->bulk_out_ep =
- interface->endpoint[minor_data[i]->bulk_out_index].bEndpointAddress &
+ pp->bulk_out_ep =
+ interface->endpoint[pp->bulk_out_index].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
- if (interface->bInterfaceProtocol == 2) { /* if bidirectional */
- minor_data[i]->maxin =
- interface->endpoint[minor_data[i]->bulk_in_index].wMaxPacketSize;
+ if (interface->bInterfaceProtocol == PROTOCOL_BIDIRECTIONAL) {
+ pp->maxin =
+ interface->endpoint[pp->bulk_in_index].wMaxPacketSize;
}
- printk(KERN_INFO "USB Printer Summary:\n");
- printk(KERN_INFO "index=%d, maxout=%d, noinput=%d\n",
- i, minor_data[i]->maxout, minor_data[i]->noinput);
+ printk(KERN_INFO "usblp%d Summary:\n", pp->minor);
+ printk(KERN_INFO "index=%d, maxout=%d, noinput=%d, maxin=%d\n",
+ i, pp->maxout, pp->noinput, pp->maxin);
printk(KERN_INFO "bulk_in_ix=%d, bulk_in_ep=%d, bulk_out_ix=%d, bulk_out_ep=%d\n",
- minor_data[i]->bulk_in_index,
- minor_data[i]->bulk_in_ep,
- minor_data[i]->bulk_out_index,
- minor_data[i]->bulk_out_ep);
+ pp->bulk_in_index,
+ pp->bulk_in_ep,
+ pp->bulk_out_index,
+ pp->bulk_out_ep);
-#if 0
+#ifdef IEEE_DEVICE_ID
{
- __u8 status;
- __u8 ieee_id[64];
+ __u8 ieee_id[64]; /* first 2 bytes are (big-endian) length */
+ /* This string space may be too short. */
+ int length = (ieee_id[0] << 8) + ieee_id[1]; /* high-low */
+ /* This calc. or be16_to_cpu() both get
+ * some weird results for <length>. */
+ int err;
/* Let's get the device id if possible. */
- if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+ err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
USB_PRINTER_REQ_GET_DEVICE_ID,
USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
0, 0, ieee_id,
- sizeof(ieee_id)-1, HZ) == 0) {
+ sizeof(ieee_id)-1, HZ);
+ if (err >= 0) {
if (ieee_id[1] < sizeof(ieee_id) - 1)
ieee_id[ieee_id[1]+2] = '\0';
else
ieee_id[sizeof(ieee_id)-1] = '\0';
- printk(KERN_INFO " USB Printer ID is %s\n",
- &ieee_id[2]);
+ printk(KERN_INFO "usblp%d Device ID length=%d [%x:%x]\n",
+ pp->minor, length, ieee_id[0], ieee_id[1]);
+ printk(KERN_INFO "usblp%d Device ID=%s\n",
+ pp->minor, &ieee_id[2]);
}
- status = printer_read_status(PPDATA(pp));
- printk(KERN_INFO " Status is %s,%s,%s\n",
- (status & LP_PSELECD) ? "Selected" : "Not Selected",
- (status & LP_POUTPA) ? "No Paper" : "Paper",
- (status & LP_PERRORP) ? "No Error" : "Error");
+ else
+ printk(KERN_INFO "usblp%d: error = %d reading IEEE-1284 Device ID\n",
+ pp->minor, err);
}
#endif
+
+ status = printer_read_status(PPDATA(pp));
+ printk(KERN_INFO "usblp%d probe status is %x: %s,%s,%s\n",
+ pp->minor, status,
+ (status & LP_PSELECD) ? "Selected" : "Not Selected",
+ (status & LP_POUTPA) ? "No Paper" : "Paper",
+ (status & LP_PERRORP) ? "No Error" : "Error");
+
return pp;
}
@@ -422,7 +464,7 @@
if (usb_register(&printer_driver))
return -1;
- printk(KERN_INFO "USB Printer support registered.\n");
+ printk(KERN_INFO "USB Printer driver registered.\n");
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)