(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 */