patch-2.3.40 linux/drivers/usb/printer.c
Next file: linux/drivers/usb/proc_usb.c
Previous file: linux/drivers/usb/ov511.h
Back to the patch index
Back to the overall index
- Lines: 824
- Date:
Thu Jan 20 09:49:41 2000
- Orig file:
v2.3.39/linux/drivers/usb/printer.c
- Orig date:
Wed Dec 29 13:13:19 1999
diff -u --recursive --new-file v2.3.39/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
@@ -1,481 +1,450 @@
-/* Driver for USB Printers
- *
- * Copyright 1999 Michael Gee (michael@linuxspecific.com)
- * Copyright 1999 Pavel Machek (pavel@suse.cz)
+/*
+ * printer.c Version 0.3
+ *
+ * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
+ *
+ * USB Printer Device Class driver for USB printers and printer cables
+ *
+ * Sponsored by SuSE
+ *
+ * ChangeLog:
+ * v0.1 - thorough cleaning, URBification, almost a rewrite
+ * v0.2 - some more cleanups
+ * v0.3 - cleaner again, waitqueue fixes
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * Distribute under GPL version 2 or later.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/lp.h>
-#include <linux/spinlock.h>
+
+#define DEBUG
#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 USBLP_BUF_SIZE 8192
+
+/*
+ * USB Printer Requests
*/
-#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 USBLP_REQ_GET_ID 0x00
+#define USBLP_REQ_GET_STATUS 0x01
+#define USBLP_REQ_RESET 0x02
+
+#define USBLP_MINORS 16
+#define USBLP_MINOR_BASE 0
+
+#define USBLP_WRITE_TIMEOUT (60*HZ) /* 60 seconds */
+
+struct usblp {
+ struct usb_device *dev; /* USB device */
+ struct urb readurb, writeurb; /* The urbs */
+ wait_queue_head_t wait; /* Zzzzz ... */
+ int readcount; /* Counter for reads */
+ int ifnum; /* Interface number */
+ int minor; /* minor number of device */
+ unsigned char used; /* True if open */
+ unsigned char bidir; /* interface is bidirectional */
+};
-#define BIG_BUF_SIZE 8192
-#define SUBCLASS_PRINTERS 1
-#define PROTOCOL_UNIDIRECTIONAL 1
-#define PROTOCOL_BIDIRECTIONAL 2
+static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
/*
- * USB Printer Requests
+ * Functions for usblp control messages.
*/
-#define USB_PRINTER_REQ_GET_DEVICE_ID 0
-#define USB_PRINTER_REQ_GET_PORT_STATUS 1
-#define USB_PRINTER_REQ_SOFT_RESET 2
-
-#define MAX_PRINTERS 8
-
-struct pp_usb_data {
- struct usb_device *pusb_dev;
- __u8 isopen; /* True if open */
- __u8 noinput; /* True if no input stream */
- __u8 minor; /* minor number of device */
- __u8 status; /* last status from device */
- int maxin, maxout; /* max transfer size in and out */
- char *obuf; /* transfer buffer (out only) */
- wait_queue_head_t wait_q; /* for timeouts */
- unsigned int last_error; /* save for checking */
- int bulk_in_ep; /* Bulk IN endpoint */
- int bulk_out_ep; /* Bulk OUT endpoint */
- int bulk_in_index; /* endpoint[bulk_in_index] */
- int bulk_out_index; /* endpoint[bulk_out_index] */
-};
-static struct pp_usb_data *minor_data[MAX_PRINTERS];
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, 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);
+ return retval < 0 ? retval : 0;
+}
-#define PPDATA(x) ((struct pp_usb_data *)(x))
+#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)
+#define usblp_reset(usblp)\
+ usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, NULL, 0)
+
+/*
+ * URB callback.
+ */
-static unsigned char printer_read_status(struct pp_usb_data *p)
+static void usblp_bulk(struct urb *urb)
{
- __u8 status;
- int err;
- struct usb_device *dev = p->pusb_dev;
+ struct usblp *usblp = urb->context;
- 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, 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;
+ if (!usblp || !usblp->dev || !usblp->used)
+ return;
+
+ if (urb->status)
+ warn("nonzero read bulk status received: %d", urb->status);
+
+ wake_up_interruptible(&usblp->wait);
}
-static int printer_check_status(struct pp_usb_data *p)
+/*
+ * Get and print printer errors.
+ */
+
+static int usblp_check_status(struct usblp *usblp)
{
- unsigned int last = p->last_error;
- unsigned char status = printer_read_status(p);
+ unsigned char status;
- if (status & LP_PERRORP)
- /* No error. */
- last = 0;
- else if ((status & LP_POUTPA)) {
- if (last != LP_POUTPA) {
- last = LP_POUTPA;
- printk(KERN_INFO "usblp%d out of paper (%x)\n", p->minor, status);
+ if (usblp_read_status(usblp, &status)) {
+ err("failed reading usblp status");
+ return -EIO;
+ }
+
+ if (status & LP_PERRORP) {
+
+ if (status & LP_POUTPA) {
+ printk(KERN_INFO "usblp%d: out of paper", usblp->minor);
+ return -ENOSPC;
}
- } else if (!(status & LP_PSELECD)) {
- if (last != LP_PSELECD) {
- last = LP_PSELECD;
- printk(KERN_INFO "usblp%d off-line (%x)\n", p->minor, status);
+ if (~status & LP_PSELECD) {
+ printk(KERN_INFO "usblp%d: off-line", usblp->minor);
+ return -EIO;
}
- } else {
- if (last != LP_PERRORP) {
- last = LP_PERRORP;
- printk(KERN_INFO "usblp%d on fire (%x)\n", p->minor, status);
+ if (~status & LP_PERRORP) {
+ printk(KERN_INFO "usblp%d: on fire", usblp->minor);
+ return -EIO;
}
}
- p->last_error = last;
- return status;
+ return 0;
}
-static void printer_reset(struct pp_usb_data *p)
-{
- struct usb_device *dev = p->pusb_dev;
- int err;
-
- 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);
-}
+/*
+ * File op functions.
+ */
-static int open_printer(struct inode *inode, struct file *file)
+static int usblp_open(struct inode *inode, struct file *file)
{
- struct pp_usb_data *p;
+ int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
+ struct usblp *usblp;
+ int retval;
- if (MINOR(inode->i_rdev) >= MAX_PRINTERS ||
- !minor_data[MINOR(inode->i_rdev)]) {
+ if (minor < 0 || minor >= USBLP_MINORS)
return -ENODEV;
- }
- p = minor_data[MINOR(inode->i_rdev)];
- p->minor = MINOR(inode->i_rdev);
+ usblp = usblp_table[minor];
- if (p->isopen++) {
- printk(KERN_ERR "usblp%d: printer is already open\n",
- p->minor);
+ if (!usblp || !usblp->dev)
+ return -ENODEV;
+
+ if (usblp->used)
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;
- }
- printer_check_status(p);
-
- file->private_data = p;
-// printer_reset(p);
- init_waitqueue_head(&p->wait_q);
+ if ((retval = usblp_check_status(usblp)))
+ return retval;
MOD_INC_USE_COUNT;
+ usblp->used = 1;
+ file->private_data = usblp;
+
+ usblp->writeurb.transfer_buffer_length = 0;
+ usblp->writeurb.status = 0;
+ usblp->readcount = 0;
+
+ usb_submit_urb(&usblp->readurb);
return 0;
}
-static int close_printer(struct inode *inode, struct file *file)
+static int usblp_release(struct inode *inode, struct file *file)
{
- struct pp_usb_data *p = file->private_data;
+ struct usblp *usblp = file->private_data;
- free_page((unsigned long)p->obuf);
- p->isopen = 0;
- file->private_data = NULL;
- /* free the resources if the printer is no longer around */
- if (!p->pusb_dev) {
- minor_data[p->minor] = NULL;
- kfree(p);
- }
MOD_DEC_USE_COUNT;
+ usblp->used = 0;
+
+ if (usblp->dev) {
+ usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(&usblp->writeurb);
+ return 0;
+ }
+
+ usblp_table[usblp->minor] = NULL;
+ kfree(usblp);
+
return 0;
}
-static ssize_t write_printer(struct file *file,
- const char *buffer, size_t count, loff_t *ppos)
+static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
- struct pp_usb_data *p = file->private_data;
- unsigned long copy_size;
- unsigned long bytes_written = 0;
- unsigned long partial;
- int result = USB_ST_NOERROR;
- int maxretry;
-
- do {
- char *obuf = p->obuf;
- unsigned long thistime;
-
- thistime = copy_size = (count > p->maxout) ? p->maxout : count;
- if (copy_from_user(p->obuf, buffer, copy_size))
- return -EFAULT;
- maxretry = MAX_RETRY_COUNT;
-
- while (thistime) {
- if (!p->pusb_dev)
- return -ENODEV;
- if (signal_pending(current)) {
- return bytes_written ? bytes_written : -EINTR;
- }
- result = usb_bulk_msg(p->pusb_dev,
- usb_sndbulkpipe(p->pusb_dev, p->bulk_out_ep),
- obuf, thistime, &partial, HZ*20);
- if (partial) {
- obuf += partial;
- thistime -= partial;
- maxretry = MAX_RETRY_COUNT;
- }
- if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */
- if (!maxretry--)
- return -ETIME;
- interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT);
- continue;
- } else if (!result && !partial) {
- break;
+ struct usblp *usblp = file->private_data;
+ poll_wait(file, &usblp->wait, wait);
+ return (usblp->readurb.status == -EINPROGRESS ? 0 : POLLIN | POLLRDNORM)
+ | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
+}
+
+static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct usblp *usblp = file->private_data;
+ int retval, timeout, writecount = 0;
+
+ while (writecount < count) {
+
+ if (usblp->writeurb.status == -EINPROGRESS) {
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ timeout = USBLP_WRITE_TIMEOUT;
+ while (timeout && usblp->writeurb.status == -EINPROGRESS) {
+
+ if (signal_pending(current))
+ return writecount ? writecount : -EINTR;
+
+ timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
}
- };
- if (result) {
- /* whoops - let's reset and fail the request */
-// printk("Whoops - %x\n", result);
- printer_reset(p);
- interruptible_sleep_on_timeout(&p->wait_q, 5*HZ); /* let reset do its stuff */
+ }
+
+ if (usblp->writeurb.status == -EINPROGRESS) {
+ usb_unlink_urb(&usblp->writeurb);
+ printk(KERN_ERR "usblp%d: timed out\n", usblp->minor);
return -EIO;
}
- bytes_written += copy_size;
- count -= copy_size;
- buffer += copy_size;
- } while ( count > 0 );
-
- return bytes_written ? bytes_written : -EIO;
-}
-
-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;
- int this_read;
- char buf[64];
- unsigned long partial;
- int result;
+
+ if (!usblp->dev)
+ return -ENODEV;
+
+ if (!usblp->writeurb.status)
+ writecount += usblp->writeurb.transfer_buffer_length;
+ else {
+ if (!(retval = usblp_check_status(usblp))) {
+ printk(KERN_ERR "usblp%d: error %d writing to printer\n",
+ usblp->minor, usblp->writeurb.status);
+ return -EIO;
+ }
+
+ return retval;
+ }
- if (p->noinput)
+ if (writecount == count)
+ continue;
+
+ usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+ (count - writecount) : USBLP_BUF_SIZE;
+
+ if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
+ usblp->writeurb.transfer_buffer_length)) return -EFAULT;
+
+ usb_submit_urb(&usblp->writeurb);
+ }
+
+ return count;
+}
+
+static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct usblp *usblp = file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (!usblp->bidir)
return -EINVAL;
- while (count) {
- if (signal_pending(current)) {
- return read_count ? read_count : -EINTR;
- }
- if (!p->pusb_dev)
- return -ENODEV;
+ if (usblp->readurb.status == -EINPROGRESS) {
- 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)
- count = this_read = partial;
- else if (result)
- return -EIO;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
- if (this_read) {
- if (copy_to_user(buffer, buf, this_read))
- return -EFAULT;
- count -= this_read;
- read_count += this_read;
- buffer += this_read;
+ while (usblp->readurb.status == -EINPROGRESS) {
+ if (signal_pending(current))
+ return -EINTR;
+ interruptible_sleep_on(&usblp->wait);
}
}
- return read_count;
+ if (!usblp->dev)
+ return -ENODEV;
+
+ if (usblp->readurb.status) {
+ printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+ usblp->minor, usblp->readurb.status);
+ usb_submit_urb(&usblp->readurb);
+ return -EIO;
+ }
+
+ count = count < usblp->readurb.actual_length - usblp->readcount ?
+ count : usblp->readurb.actual_length - usblp->readcount;
+
+ if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
+ return -EFAULT;
+
+ if ((usblp->readcount += count) == usblp->readurb.actual_length)
+ usb_submit_urb(&usblp->readurb);
+
+ return count;
}
-static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usblp_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
- */
- if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER &&
- dev->descriptor.bDeviceClass != 0) ||
- dev->descriptor.bNumConfigurations != 1 ||
- dev->actconfig->bNumInterfaces != 1) {
- return NULL;
- }
+ struct usb_endpoint_descriptor *epread, *epwrite;
+ struct usblp *usblp;
+ int minor, i, alts = -1, bidir = 0;
+ char *buf;
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- /* Let's be paranoid (for the moment). */
- if (interface->bInterfaceClass != USB_CLASS_PRINTER ||
- interface->bInterfaceSubClass != SUBCLASS_PRINTERS ||
- (interface->bInterfaceProtocol != PROTOCOL_BIDIRECTIONAL &&
- interface->bInterfaceProtocol != PROTOCOL_UNIDIRECTIONAL) ||
- interface->bNumEndpoints > 2) {
- return NULL;
+ for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[i];
+
+ if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
+ (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) ||
+ (interface->bInterfaceProtocol > interface->bNumEndpoints))
+ continue;
+
+ if (alts == -1)
+ alts = i;
+
+ if (!bidir && interface->bInterfaceProtocol == 2) {
+ bidir = 1;
+ alts = i;
+ }
}
- /* Does this (these) interface(s) support bulk transfers? */
- if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_BULK) {
+ if (alts == -1)
return NULL;
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[alts];
+ if (usb_set_interface(dev, ifnum, alts))
+ err("can't set desired altsetting %d on interface %d", alts, ifnum);
+
+ epwrite = interface->endpoint + 0;
+ epread = NULL;
+
+ if (bidir) {
+ epread = interface->endpoint + 1;
+ if ((epread->bEndpointAddress & 0x80) != 0x80) {
+ epwrite = interface->endpoint + 1;
+ epread = interface->endpoint + 0;
+
+ if ((epread->bEndpointAddress & 0x80) != 0x80)
+ return NULL;
+ }
}
- if ((interface->bNumEndpoints > 1) &&
- ((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_BULK)) {
+
+ if ((epwrite->bEndpointAddress & 0x80) == 0x80)
return NULL;
- }
- /*
- * Does this interface have at least one OUT endpoint
- * that we can write to: endpoint index 0 or 1?
- */
- if ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- != USB_DIR_OUT &&
- (interface->bNumEndpoints > 1 &&
- (interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- != USB_DIR_OUT)) {
- return NULL;
- }
-
- for (i=0; i<MAX_PRINTERS; i++) {
- if (!minor_data[i])
- break;
- }
- if (i >= MAX_PRINTERS) {
- printk(KERN_ERR "No minor table space available for new USB printer\n");
+ for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
+ if (usblp_table[minor]) {
+ err("no more free usblp devices");
return NULL;
}
- printk(KERN_INFO "USB printer found at address %d\n", dev->devnum);
+ if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
+ err("out of memory");
+ return NULL;
+ }
+ memset(usblp, 0, sizeof(struct usblp));
- if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
- printk(KERN_DEBUG "USB printer: no memory!\n");
+ usblp->dev = dev;
+ usblp->ifnum = ifnum;
+ usblp->minor = minor;
+ usblp->bidir = bidir;
+
+ init_waitqueue_head(&usblp->wait);
+
+ if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
+ err("out of memory");
+ kfree(usblp);
return NULL;
}
- memset(pp, 0, sizeof(struct pp_usb_data));
- minor_data[i] = PPDATA(pp);
+ FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+ buf, 0, usblp_bulk, usblp);
- 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;
- 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;
- pp->bulk_out_ep =
- interface->endpoint[pp->bulk_out_index].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- if (interface->bInterfaceProtocol == PROTOCOL_BIDIRECTIONAL) {
- pp->maxin =
- interface->endpoint[pp->bulk_in_index].wMaxPacketSize;
- }
-
- 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",
- pp->bulk_in_index,
- pp->bulk_in_ep,
- pp->bulk_out_index,
- pp->bulk_out_ep);
-
-#ifdef IEEE_DEVICE_ID
- {
- __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. */
- 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);
- 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 "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]);
- }
- else
- printk(KERN_INFO "usblp%d: error = %d reading IEEE-1284 Device ID\n",
- pp->minor, err);
+ if (bidir) {
+ FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+ buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
}
-#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");
+ printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d if %d alt %d\n",
+ minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
- return pp;
+ return usblp_table[minor] = usblp;
}
-static void printer_disconnect(struct usb_device *dev, void *ptr)
+static void usblp_disconnect(struct usb_device *dev, void *ptr)
{
- struct pp_usb_data *pp = ptr;
+ struct usblp *usblp = ptr;
- if (pp->isopen) {
- /* better let it finish - the release will do whats needed */
- pp->pusb_dev = NULL;
+ if (!usblp || !usblp->dev) {
+ err("disconnect on nonexisting interface");
return;
}
- minor_data[pp->minor] = NULL;
- kfree(pp);
+
+ usblp->dev = NULL;
+
+ usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(&usblp->writeurb);
+
+ kfree(usblp->writeurb.transfer_buffer);
+
+ if (usblp->used) return;
+
+ usblp_table[usblp->minor] = NULL;
+ kfree(usblp);
}
-static struct file_operations usb_printer_fops = {
- NULL, /* seek */
- read_printer,
- write_printer,
- NULL, /* readdir */
- NULL, /* poll - out for the moment */
- NULL, /* ioctl */
- NULL, /* mmap */
- open_printer,
- NULL, /* flush ? */
- close_printer,
- NULL,
- NULL
+static struct file_operations usblp_fops = {
+ read: usblp_read,
+ write: usblp_write,
+ open: usblp_open,
+ release: usblp_release,
+ poll: usblp_poll
};
-static struct usb_driver printer_driver = {
- "printer",
- printer_probe,
- printer_disconnect,
- { NULL, NULL },
- &usb_printer_fops,
- 0
+static struct usb_driver usblp_driver = {
+ name: "usblp",
+ probe: usblp_probe,
+ disconnect: usblp_disconnect,
+ fops: &usblp_fops,
+ minor: USBLP_MINOR_BASE
};
-int usb_printer_init(void)
+#ifdef MODULE
+void cleanup_module(void)
{
- if (usb_register(&printer_driver))
- return -1;
-
- printk(KERN_INFO "USB Printer driver registered.\n");
- return 0;
+ usb_deregister(&usblp_driver);
}
-
-#ifdef MODULE
int init_module(void)
+#else
+int usb_printer_init(void)
+#endif
{
- return usb_printer_init();
-}
+ if (usb_register(&usblp_driver))
+ return -1;
-void cleanup_module(void)
-{
- usb_deregister(&printer_driver);
+ return 0;
}
-#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)