The following patch fixes "read_scanner(0): funky result:-75" errors
which lead to application freeze and unusable scanner module until
reboot. The bug was recently reported here for the Nikon LS-40, but I
believe it also applieas to similar problems reported for Epson and Acer
USB scanners over the past year on this list, sane-devel, and elsewhere.

Cause: read_scanner() sits in a loop, trying to bulk read all 'count'
bytes of data. It erroneously decrements bytes remaining by 'this_read',
what it asked for, instead of 'partial', what it got. 

For large reads (spanning multiple slow stepper-motor steps?) the
scanner sometimes returns a short read, which makes 'count' shrink
faster than it should, causing an attempt to read less than
wMaxPacketSize bytes to be read before the last packet of the bulk
transfer, causing EOVERFLOW. 

The conservative patch for 2.4.19 would be the following:

--- linux-2.4.19/drivers/usb/scanner.c.orig     Fri Oct  4 18:28:45 2002
+++ linux-2.4.19/drivers/usb/scanner.c  Fri Oct  4 18:49:04 2002
@@ -653,7 +653,7 @@
                                ret = -EFAULT;
                                break;
                        }
-                       count -= this_read; /* Compensate for short reads */
+                       count -= partial; /* Compensate for short reads */
                        bytes_read += partial; /* Keep tally of what actually was read 
*/
                        buffer += partial;
                } else {
===========================================================

However, I believe for 2.5 the loop should be rewritten as retry loop,
and the function should immediately return whatever it reads, like the
majority of drivers do. As a side effect, the number of retries on
TIMEOUT/NAK would change, so the TIMEOUT values for various scanners
would need to be retuned based on experience.

For example, the following works fine for me under 2.4.19 (and also
opens up opportunities for simplification of read_scanner()):

--- linux-2.4.19/drivers/usb/scanner.c.orig     Fri Oct  4 18:28:45 2002
+++ linux-2.4.19/drivers/usb/scanner.c  Fri Oct  4 18:48:23 2002
@@ -553,13 +553,13 @@
        struct scn_usb_data *scn;
        struct usb_device *dev;
 
-       ssize_t bytes_read;     /* Overall count of bytes_read */
        ssize_t ret;
 
        kdev_t scn_minor;
 
        int partial;            /* Number of bytes successfully read */
        int this_read;          /* Max number of bytes to read */
+       int retries;
        int result;
        int rd_expire = RD_EXPIRE;
 
@@ -575,14 +575,14 @@
 
        dev = scn->scn_dev;
 
-       bytes_read = 0;
+       retries = 3;
        ret = 0;
 
        file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
                                                             atime of
                                                             the device
                                                             node */
-       while (count > 0) {
+       while (retries) {
                if (signal_pending(current)) {
                        ret = -ERESTARTSYS;
                        break;
@@ -615,10 +615,11 @@
                                        break;
                                } else { /* Keep trying to read data */
                                        
interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
+                                       retries--;
                                        continue;
                                }
                        } else { /* Timeout w/ some data */
-                               goto data_recvd;
+                               break;
                        }
                }
                
@@ -633,36 +634,31 @@
                        ret = -EIO;
                        break;
                }
-
-       data_recvd:
+               if (result == 0) {
+                       break;
+               }
+       }
 
 #ifdef RD_DATA_DUMP
-               if (partial) {
-                       unsigned char cnt, cnt_max;
-                       cnt_max = (partial > 24) ? 24 : partial;
-                       printk(KERN_DEBUG "dump(%d): ", scn_minor);
-                       for (cnt=0; cnt < cnt_max; cnt++) {
-                               printk("%X ", ibuf[cnt]);
-                       }
-                       printk("\n");
+       if (partial) {
+               unsigned char cnt, cnt_max;
+               cnt_max = (partial > 24) ? 24 : partial;
+               printk(KERN_DEBUG "dump(%d): ", scn_minor);
+               for (cnt=0; cnt < cnt_max; cnt++) {
+                       printk("%X ", ibuf[cnt]);
                }
+               printk("\n");
+       }
 #endif
 
-               if (partial) { /* Data returned */
-                       if (copy_to_user(buffer, ibuf, partial)) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       count -= this_read; /* Compensate for short reads */
-                       bytes_read += partial; /* Keep tally of what actually was read 
*/
-                       buffer += partial;
-               } else {
-                       ret = 0;
-                       break;
+       if (partial) { /* Data returned */
+               if (copy_to_user(buffer, ibuf, partial)) {
+                       ret = -EFAULT;
                }
        }
+
        up(&(scn->sem));
-       return ret ? ret : bytes_read;
+       return ret ? ret : partial;
 }
 
 static int
===========================================================

-- 
     ,_
     /_)              /| /
    /   i e t e r    / |/ a g e l
    http://www.nagel.co.za



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to