(patch 1 of 2) Hi, Here's a patch for the usb scanner driver against 2.2.20-pre2 that brings it up to the same logic level that is in 2.4.5. thanks, greg k-h
diff -Nru a/drivers/usb/scanner.c b/drivers/usb/scanner.c --- a/drivers/usb/scanner.c Wed Jun 13 21:02:21 2001 +++ b/drivers/usb/scanner.c Wed Jun 13 21:02:21 2001 @@ -1,7 +1,7 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.4.0test1-ac7) + * Driver for USB Scanners (linux-2.4.0) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -199,6 +199,34 @@ * - Fixed HP S20 ID's...again..sigh. Thanks to Ruud * Linders <[EMAIL PROTECTED]>. * + * 0.4.4 + * - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB, + * and 1200 UB. Thanks to Henning Meier-Geinitz <[EMAIL PROTECTED]>. + * - Added the Vuego Scan Brisa 340U ID's. Apparently this scanner is + * marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to + * David Gundersen <[EMAIL PROTECTED]>. + * - Added the Epson Expression1600 ID's. Thanks to Karl Heinz + * Kremer <[EMAIL PROTECTED]>. + * + * 0.4.5 2/28/2001 + * - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F). + * Thanks to Henning Meier-Geinitz <[EMAIL PROTECTED]>. + * - Added read_timeout module parameter to override RD_NAK_TIMEOUT + * when read()'ing from devices. + * - Stalled pipes are now checked and cleared with + * usb_clear_halt() for the read_scanner() function. This should + * address the "funky result: -32" error messages. + * - Removed Microtek scanner ID's. Microtek scanners are now + * supported via the drivers/usb/microtek.c driver. + * - Added scanner specific read timeout's. + * - Return status errors are NEGATIVE!!! This should address the + * "funky result: -110" error messages. + * - Replaced USB_ST_TIMEOUT with ETIMEDOUT. + * - rd_nak was still defined in MODULE_PARM. It's been updated with + * read_timeout. Thanks to Mark W. Webb <[EMAIL PROTECTED]> for + * reporting this bug. + * - Added Epson Perfection 1640SU and 1640SU Photo. Thanks to + * Jean-Luc <[EMAIL PROTECTED]>. * * TODO * @@ -236,6 +264,7 @@ */ #include "scanner.h" + static void irq_scanner(struct urb *urb) { @@ -266,13 +295,18 @@ kdev_t scn_minor; + int err=0; + + lock_kernel(); + scn_minor = USB_SCN_MINOR(inode); dbg("open_scanner: scn_minor:%d", scn_minor); if (!p_scn_table[scn_minor]) { err("open_scanner(%d): Unable to access minor data", scn_minor); - return -ENODEV; + err = -ENODEV; + goto out_error; } scn = p_scn_table[scn_minor]; @@ -281,17 +315,20 @@ if (!dev) { err("open_scanner(%d): Scanner device not present", scn_minor); - return -ENODEV; + err = -ENODEV; + goto out_error; } if (!scn->present) { err("open_scanner(%d): Scanner is not present", scn_minor); - return -ENODEV; + err = -ENODEV; + goto out_error; } if (scn->isopen) { err("open_scanner(%d): Scanner device is already open", scn_minor); - return -EBUSY; + err = -EBUSY; + goto out_error; } init_waitqueue_head(&scn->rd_wait_q); @@ -302,7 +339,11 @@ MOD_INC_USE_COUNT; - return 0; +out_error: + + unlock_kernel(); + + return err; } static int @@ -338,7 +379,7 @@ { struct scn_usb_data *scn; struct usb_device *dev; - + ssize_t bytes_written = 0; /* Overall count of bytes written */ ssize_t ret = 0; @@ -347,7 +388,7 @@ int this_write; /* Number of bytes to write */ int partial; /* Number of bytes successfully written */ int result = 0; - + char *obuf; scn = file->private_data; @@ -360,6 +401,8 @@ file->f_dentry->d_inode->i_atime = CURRENT_TIME; + down(&(scn->gen_lock)); + while (count > 0) { if (signal_pending(current)) { @@ -368,7 +411,7 @@ } this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count; - + if (copy_from_user(scn->obuf, buffer, this_write)) { ret = -EFAULT; break; @@ -377,15 +420,15 @@ result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ); dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial); - if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */ + if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */ warn("write_scanner: NAK received."); - ret = -ETIME; + ret = result; break; } else if (result < 0) { /* We should not get any I/O errors */ warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result); ret = -EIO; break; - } + } #ifdef WR_DATA_DUMP if (partial) { @@ -412,6 +455,7 @@ break; } } + up(&(scn->gen_lock)); mdelay(5); /* This seems to help with SANE queries */ return ret ? ret : bytes_written; } @@ -450,6 +494,7 @@ atime of the device node */ + down(&(scn->gen_lock)); while (count > 0) { if (signal_pending(current)) { @@ -458,11 +503,11 @@ } this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; - - result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT); + + result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), +ibuf, this_read, &partial, scn->rd_nak_timeout); dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count); -/* +/* * Scanners are sometimes inheriently slow since they are mechanical * in nature. USB bulk reads tend to timeout while the scanner is * positioning, resetting, warming up the lamp, etc if the timeout is @@ -473,26 +518,38 @@ * that something had hung or crashed when in fact the USB read was * just waiting on data. So, the below code retains the same long * timeout period, but splits it up into smaller parts so that - * Ctrl-C's are acted upon in a reasonable amount of time. + * Ctrl-C's are acted upon in a reasonable amount of time. */ - if (result == USB_ST_TIMEOUT && !partial) { /* Timeout - and no - data */ - if (--rd_expire <= 0) { - warn("read_scanner(%d): excessive NAK's received", scn_minor); - ret = -ETIME; - break; - } else { - interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT); - continue; + if (result == -ETIMEDOUT) { /* NAK */ + if (!partial) { /* No data */ + if (--rd_expire <= 0) { /* Give it up */ + warn("read_scanner(%d): excessive NAK's +received", scn_minor); + ret = result; + break; + } else { /* Keep trying to read data */ + +interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout); + continue; + } + } else { /* Timeout w/ some data */ + goto data_recvd; } + } + + if (result == -EPIPE) { /* No hope */ + if(usb_clear_halt(dev, scn->bulk_in_ep)) { + err("read_scanner(%d): Failure to clear endpoint halt +condition (%Zd).", scn_minor, ret); + } + ret = result; + break; } else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) { warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result); ret = -EIO; break; } + data_recvd: + #ifdef RD_DATA_DUMP if (partial) { unsigned char cnt, cnt_max; @@ -518,7 +575,8 @@ break; } } - + up(&(scn->gen_lock)); + return ret ? ret : bytes_read; } @@ -528,7 +586,7 @@ struct scn_usb_data *scn; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; - + int ep_cnt; int ix; @@ -550,7 +608,7 @@ * 3. Determine/Assign Intr Endpoint */ -/* +/* * There doesn't seem to be an imaging class defined in the USB * Spec. (yet). If there is, HP isn't following it and it doesn't * look like anybody else is either. Therefore, we have to test the @@ -577,7 +635,7 @@ dev->descriptor.idProduct == product) { /* User specified */ valid_device = 1; } - + if (!valid_device) return NULL; /* We didn't find anything pleasing */ @@ -599,7 +657,7 @@ interface = dev->config[0].interface[ifnum].altsetting; endpoint = interface[ifnum].endpoint; -/* +/* * Start checking for two bulk endpoints OR two bulk endpoints *and* one * interrupt endpoint. If we have an interrupt endpoint go ahead and * setup the handler. FIXME: This is a future enhancement... @@ -622,7 +680,7 @@ dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in); continue; } - + if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) { ep_cnt++; have_bulk_out = ep_cnt; @@ -665,7 +723,7 @@ } -/* +/* * Determine a minor number and initialize the structure associated * with it. The problem with this is that we are counting on the fact * that the user will sequentially add device nodes for the scanner @@ -695,7 +753,7 @@ /* Ok, if we detected an interrupt EP, setup a handler for it */ if (have_intr) { dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr); - FILL_INT_URB(&scn->scn_irq, dev, + FILL_INT_URB(&scn->scn_irq, dev, usb_rcvintpipe(dev, have_intr), &scn->button, 1, irq_scanner, scn, // endpoint[(int)have_intr].bInterval); @@ -724,6 +782,26 @@ return NULL; } dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf); + + + switch (dev->descriptor.idVendor) { /* Scanner specific read timeout +parameters */ + case 0x04b8: /* Seiko/Epson */ + scn->rd_nak_timeout = HZ * 40; + break; + case 0x055f: /* Mustek */ + case 0x0400: /* Another Mustek */ + case 0x0ff5: /* And yet another Mustek */ + scn->rd_nak_timeout = HZ * 1; + default: + scn->rd_nak_timeout = RD_NAK_TIMEOUT; + } + + + if (read_timeout > 0) { /* User specified read timeout overrides everything */ + info("probe_scanner: User specified USB read timeout - %d", +read_timeout); + scn->rd_nak_timeout = read_timeout; + } + scn->bulk_in_ep = have_bulk_in; scn->bulk_out_ep = have_bulk_out; @@ -733,6 +811,8 @@ scn->scn_minor = scn_minor; scn->isopen = 0; + init_MUTEX(&(scn->gen_lock)); + return p_scn_table[scn_minor] = scn; } @@ -740,7 +820,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr) { struct scn_usb_data *scn = (struct scn_usb_data *) ptr; - + if(scn->intr_ep) { dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor); usb_unlink_urb(&scn->scn_irq); @@ -762,11 +842,11 @@ unsigned int cmd, unsigned long arg) { struct usb_device *dev; - + int result; kdev_t scn_minor; - + scn_minor = USB_SCN_MINOR(inode); if (!p_scn_table[scn_minor]) { @@ -775,7 +855,7 @@ } dev = p_scn_table[scn_minor]->scn_dev; - + switch (cmd) { case PV8630_IOCTL_INREQUEST : @@ -786,10 +866,10 @@ __u16 value; __u16 index; } args; - + if (copy_from_user(&args, (void *)arg, sizeof(args))) return -EFAULT; - + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), args.request, USB_TYPE_VENDOR| USB_RECIP_DEVICE|USB_DIR_IN, @@ -802,7 +882,7 @@ return -EFAULT; dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result); - + return result; } case PV8630_IOCTL_OUTREQUEST : @@ -812,10 +892,10 @@ __u16 value; __u16 index; } args; - + if (copy_from_user(&args, (void *)arg, sizeof(args))) return -EFAULT; - + dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request); result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -825,7 +905,7 @@ 0, HZ*5); dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result); - + return result; } default: @@ -848,12 +928,11 @@ static struct usb_driver scanner_driver = { - "usbscanner", - probe_scanner, - disconnect_scanner, - { NULL, NULL }, - &usb_scanner_fops, - SCN_BASE_MNR + name: "usbscanner", + probe: probe_scanner, + disconnect: disconnect_scanner, + fops: &usb_scanner_fops, + minor: SCN_BASE_MNR, }; void __exit diff -Nru a/drivers/usb/scanner.h b/drivers/usb/scanner.h --- a/drivers/usb/scanner.h Wed Jun 13 21:02:21 2001 +++ b/drivers/usb/scanner.h Wed Jun 13 21:02:21 2001 @@ -1,5 +1,5 @@ /* - * Driver for USB Scanners (linux-2.4.0test1-ac7) + * Driver for USB Scanners (linux-2.4.0) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -30,12 +30,13 @@ #include <linux/delay.h> #include <linux/ioctl.h> #include <linux/sched.h> +#include <linux/smp_lock.h> // #define DEBUG #include <linux/usb.h> -static __s32 vendor=-1, product=-1; +static __s32 vendor=-1, product=-1, read_timeout=0; MODULE_AUTHOR("David E. Nelson, [EMAIL PROTECTED], http://www.jump.net/~dnelson"); MODULE_DESCRIPTION("USB Scanner Driver"); @@ -46,6 +47,9 @@ MODULE_PARM(product, "i"); MODULE_PARM_DESC(product, "User specified USB idProduct"); +MODULE_PARM(read_timeout, "i"); +MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds"); + /* Enable to activate the ioctl interface. This is mainly meant for */ /* development purposes until an ioctl number is officially registered */ @@ -72,7 +76,7 @@ #define OBUF_SIZE 4096 /* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */ -#define RD_NAK_TIMEOUT (10*HZ) /* Number of X seconds to wait */ +#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */ #define RD_EXPIRE 12 /* Number of attempts to wait X seconds */ @@ -89,11 +93,13 @@ unsigned int ifnum; /* Interface number of the USB device */ kdev_t scn_minor; /* Scanner minor - used in disconnect() */ unsigned char button; /* Front panel buffer */ - char isopen; /* Not zero if the device is open */ + char isopen; /* Not zero if the device is open */ char present; /* Not zero if device is present */ char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */ wait_queue_head_t rd_wait_q; /* read timeouts */ + struct semaphore gen_lock; /* lock to prevent concurrent reads or writes */ + unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */ }; static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */}; @@ -106,8 +112,10 @@ /* Acer */ { 0x04a5, 0x2060 }, /* Prisa Acerscan 620U & 640U (!) */ { 0x04a5, 0x2040 }, /* Prisa AcerScan 620U (!) */ + { 0x04a5, 0x2022 }, /* Vuego Scan Brisa 340U */ /* Agfa */ { 0x06bd, 0x0001 }, /* SnapScan 1212U */ + { 0x06bd, 0x0002 }, /* SnapScan 1236U */ { 0x06bd, 0x2061 }, /* Another SnapScan 1212U (?) */ { 0x06bd, 0x0100 }, /* SnapScan Touch */ /* Colorado -- See Primax/Colorado below */ @@ -120,20 +128,28 @@ { 0x03f0, 0x0105 }, /* 4200C */ { 0x03f0, 0x0102 }, /* PhotoSmart S20 */ { 0x03f0, 0x0401 }, /* 5200C */ + // { 0x03f0, 0x0701 }, /* 5300C - NOT SUPPORTED - see +http://www.neatech.nl/oss/HP5300C/ */ { 0x03f0, 0x0201 }, /* 6200C */ { 0x03f0, 0x0601 }, /* 6300C */ /* iVina */ { 0x0638, 0x0268 }, /* 1200U */ - /* Microtek */ - { 0x05da, 0x0099 }, /* ScanMaker X6 - X6U */ - { 0x05da, 0x0094 }, /* Phantom 336CX - C3 */ - { 0x05da, 0x00a0 }, /* Phantom 336CX - C3 #2 */ - { 0x05da, 0x009a }, /* Phantom C6 */ - { 0x05da, 0x00a3 }, /* ScanMaker V6USL */ - { 0x05da, 0x80a3 }, /* ScanMaker V6USL #2 */ - { 0x05da, 0x80ac }, /* ScanMaker V6UL - SpicyU */ + /* Microtek No longer supported - Enable SCSI and USB Microtek in kernel +config */ + // { 0x05da, 0x0099 }, /* ScanMaker X6 - X6U */ + // { 0x05da, 0x0094 }, /* Phantom 336CX - C3 */ + // { 0x05da, 0x00a0 }, /* Phantom 336CX - C3 #2 */ + // { 0x05da, 0x009a }, /* Phantom C6 */ + // { 0x05da, 0x00a3 }, /* ScanMaker V6USL */ + // { 0x05da, 0x80a3 }, /* ScanMaker V6USL #2 */ + // { 0x05da, 0x80ac }, /* ScanMaker V6UL - SpicyU */ /* Mustek */ { 0x055f, 0x0001 }, /* 1200 CU */ + { 0x0400, 0x1000 }, /* BearPaw 1200 */ + { 0x055f, 0x0002 }, /* 600 CU */ + { 0x055f, 0x0003 }, /* 1200 USB */ + { 0x055f, 0x0006 }, /* 1200 UB */ + { 0x0400, 0x1001 }, /* BearPaw 2400 */ + { 0x055f, 0x0008 }, /* 1200 CU Plus */ + { 0x0ff5, 0x0010 }, /* BearPaw 1200F */ /* Primax/Colorado */ { 0x0461, 0x0300 }, /* G2-300 #1 */ { 0x0461, 0x0380 }, /* G2-600 #1 */ @@ -151,7 +167,11 @@ { 0x04b8, 0x0101 }, /* Perfection 636U and 636Photo */ { 0x04b8, 0x0103 }, /* Perfection 610 */ { 0x04b8, 0x0104 }, /* Perfection 1200U and 1200Photo */ + { 0x04b8, 0x0106 }, /* Stylus Scan 2500 */ + { 0x04b8, 0x0107 }, /* Expression 1600 */ + { 0x04b8, 0x010a }, /* Perfection 1640SU and 1640SU Photo */ { 0x04b8, 0x010b }, /* Perfection 1240U and 1240Photo */ + { 0x04b8, 0x010c }, /* Perfection 640U */ /* Umax */ { 0x1606, 0x0010 }, /* Astra 1220U */ { 0x1606, 0x0002 }, /* Astra 1236U */ @@ -161,6 +181,10 @@ { 0x04a7, 0x0221 }, /* OneTouch 5300 */ { 0x04a7, 0x0221 }, /* OneTouch 7600 duplicate ID (!) */ { 0x04a7, 0x0231 }, /* 6100 */ + { 0x04a7, 0x0211 }, /* OneTouch 7600 USB */ + { 0x04a7, 0x0311 }, /* 6200 EPP/USB */ + { 0x04a7, 0x0321 }, /* OneTouch 8100 EPP/USB */ + { 0x04a7, 0x0331 }, /* OneTouch 8600 EPP/USB */ }; /* Forward declarations */