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