Hi Blake,

Blake wrote:
...
> It seems that everyone having this problem has a 440BX chipset/PIIX4 USB
> controller. My system is Debian Woody with a 2.4.18 kernel, on a dual Celeron
> 500 ABIT BP6 with 384 MB RAM.
...

My system is 430HX/PIIX3 and no linux kernel (earliest 2.4.0, latest
2.4.18) ever worked (the usual "usb_control/bulk_msg: timeout" which is
reported on the list over and over again). As you seem to have problems
using a scanner I attached patches to scanner.c and usb-uhci.c that do
the job for my setup. If you feel like experimenting just give it a try.

Cheers
        Stephan
--- linux/drivers/usb/scanner.c Wed Jan  2 00:37:59 2002
+++ -   Tue Mar 19 23:30:59 2002
@@ -410,8 +410,6 @@
                goto out_error;
        }
 
-       init_waitqueue_head(&scn->rd_wait_q);
-
        scn->isopen = 1;
 
        file->private_data = scn; /* Used by the read and write methods */
@@ -546,123 +544,187 @@
        return ret ? ret : bytes_written;
 }
 
-static ssize_t
-read_scanner(struct file * file, char * buffer,
-             size_t count, loff_t *ppos)
-{
-       struct scn_usb_data *scn;
-       struct usb_device *dev;
-
-       ssize_t bytes_read;     /* Overall count of bytes_read */
-       ssize_t ret;
+#define SCANNER_URB_SIZE (64)
+#define SCANNER_URB_COUNT (IBUF_SIZE / sizeof (struct scanner_urb))
 
-       kdev_t scn_minor;
+struct scanner_urb
+{
+       struct urb          urb;
+       char                buf[SCANNER_URB_SIZE];
+};
 
-       int partial;            /* Number of bytes successfully read */
-       int this_read;          /* Max number of bytes to read */
-       int result;
-       int rd_expire = RD_EXPIRE;
+struct scanner_context
+{
+       wait_queue_head_t wait;
+       unsigned int      count;
+};
 
-       char *ibuf;
+static void
+scanner_complete (struct urb* urb)
+{
+       struct scanner_context* context;
+       unsigned long           count;
 
-       scn = file->private_data;
+       context = urb->context;
+       count = context->count + urb->transfer_buffer_length;
+       dbg ("complete: %lu", (unsigned long) count);
+       barrier ();
+       context->count = count;
+       wake_up_sync (&context->wait);
+}
 
-       down(&(scn->sem));
+static inline void
+scanner_dec (struct scanner_urb** urb_ptr,
+             struct scanner_urb*  urbs)
+{
+       if (urbs == *urb_ptr) {
+               *urb_ptr = urbs + (SCANNER_URB_COUNT - 1);
+       }
+       else {
+               *urb_ptr -= 1;
+       }
+}
 
-       scn_minor = scn->scn_minor;
+static ssize_t
+read_scanner (struct file* file,
+              char*        buffer,
+              size_t       count,
+              loff_t*      ppos)
+{
+       struct scn_usb_data*   scn;
+       struct scanner_context context;
+       struct scanner_urb*    urbs;
+       struct scanner_urb*    in;
+       struct scanner_urb*    out;
+       unsigned int           rcv;
+       unsigned int           snd;
+       char*                  ptr;
+       ssize_t                result;
+
+       dbg ("reading: %lu", (unsigned long) count);
+
+       /* early return */
+
+       if (count == 0) {
+               dbg ("nothing to do");
+               return 0;
+       }
 
-       ibuf = scn->ibuf;
+       scn = file->private_data;
 
-       dev = scn->scn_dev;
+       /* locking */
 
-       bytes_read = 0;
-       ret = 0;
+       if (down_interruptible (&scn->sem)) {
+               dbg ("interrupted");
+               return -ERESTARTSYS;
+       }
 
-       file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
-                                                            atime of
-                                                            the device
-                                                            node */
-       while (count > 0) {
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
+       /* Updating atime of the device node */
 
-               this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+       file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 
-               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);
+       /* initialising */
 
-/*
- * 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
- * set too low.  A very long timeout parameter for bulk reads was used
- * to overcome this limitation, but this sometimes resulted in folks
- * having to wait for the timeout to expire after pressing Ctrl-C from
- * an application. The user was sometimes left with the impression
- * 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.
- */
-
-               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;
+       ptr = buffer;
+       urbs = (struct scanner_urb*) scn->ibuf;
+       memset (urbs, 0, sizeof (struct scanner_urb) * SCANNER_URB_COUNT);
+       in = out = urbs + (SCANNER_URB_COUNT - 1);
+       context.count = snd = rcv = 0;
+       init_waitqueue_head (&context.wait);
+
+       /* looping */
+
+       do {
+               /* scheduling */
+               while (((in != out) || (snd == rcv)) && (snd != count)) {
+                       FILL_BULK_URB (&out->urb,
+                                      scn->scn_dev,
+                                      usb_rcvbulkpipe (scn->scn_dev,
+                                                       scn->bulk_in_ep),
+                                      &out->buf,
+                                      min_t (size_t, 
+                                             count - snd, 
+                                             SCANNER_URB_SIZE),
+                                      scanner_complete,
+                                      &context);
+                       out->urb.transfer_flags = USB_QUEUE_BULK;
+                       result = usb_submit_urb (&out->urb);
+                       if (result != 0) {
+                               err ("schedule failed: %li", (long) result);
+                               goto scanner_read_cleanup;
                        }
-               }
-               
-               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);
+                       snd += out->urb.transfer_buffer_length;
+                       scanner_dec (&out, urbs);
+                       dbg ("scheduled: %lu", (unsigned long) snd);
+               }
+
+               /* waiting */
+
+               result = wait_event_interruptible (context.wait,
+                                                  rcv != context.count);
+               if (result != 0) {
+                       dbg ("wait interrupted");
+                       goto scanner_read_cleanup;
+               }
+
+               /* processing */
+
+               result = in->urb.status;
+               if ((result != 0) && (result != -EREMOTEIO)) {
+                       warn ("read_scanner(%d): error:%d. "
+                             "Consult Documentation/usb/scanner.txt.",
+                             scn->scn_minor, result);
+                       if (usb_endpoint_halted (
+                                 scn->scn_dev,
+                                 usb_rcvbulkpipe (scn->scn_dev,
+                                                  scn->bulk_in_ep),
+                                 0)) {
+                               if (usb_clear_halt (scn->scn_dev,
+                                                   scn->bulk_in_ep)) {
+                                       err ("read_scanner(%d): Failure to "
+                                            "clear endpoint halt condition "
+                                            "(%Zd).",
+                                            scn->scn_minor, result);
+                               }
                        }
-                       ret = result;
-                       break;
-               } else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
-                       warn("read_scanner(%d): funky result:%d. Consult 
Documentation/usb/scanner.txt.", scn_minor, (int)result);
-                       ret = -EIO;
-                       break;
+                       result = -EIO;
+                       goto scanner_read_cleanup;
                }
+               if (in->urb.actual_length == 0) {
+                       result = ptr - buffer;
+                       err ("no data");
+                       goto scanner_read_cleanup;
+               }
+               copy_to_user (ptr, in->buf, in->urb.actual_length);
+               ptr += in->urb.actual_length;
+               rcv += in->urb.transfer_buffer_length;
+               scanner_dec (&in, urbs);
+               dbg ("received: %lu", (unsigned long) rcv);
+       }
+       while (rcv != count);
 
-       data_recvd:
+       result = ptr - buffer;
 
-#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");
-               }
-#endif
+       /* cleaning up */
 
-               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;
+scanner_read_cleanup:
+
+       if (rcv != snd) {
+               dbg ("cleaning up");
+               do {
+                       usb_unlink_urb (&in->urb);
+                       scanner_dec (&in, urbs);
                }
+               while (in != out);
        }
-       up(&(scn->sem));
-       return ret ? ret : bytes_read;
+
+       /* unlocking */
+
+       up (&scn->sem);
+
+       dbg ("returning %li", (signed long) result);
+
+       return result;
 }
 
 static int
--- linux/drivers/usb/usb-uhci.c        2002/03/03 12:21:04     1.1
+++ linux/drivers/usb/usb-uhci.c        2002/03/03 12:21:30
@@ -95,7 +95,7 @@
  * is optimal, but PCI can be slowed down up-to 5 times, slowing down
  * system performance (eg. framebuffer devices).
  */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
+// #define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
 
 /* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
  * somehow similar effect to FSBR (higher speed), but does not
@@ -103,8 +103,8 @@
  * in FSBR case and single device could hog whole USB, starving
  * other devices.
  */
-#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+#define USE_CTRL_DEPTH_FIRST 1  // 0: Breadth first, 1: Depth first
+#define USE_BULK_DEPTH_FIRST 1  // 0: Breadth first, 1: Depth first
 
 /* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
  * will lead to <64KB/sec performance over USB for bulk transfers targeting

Reply via email to