It looks like this may be my problem, is there a kernel patch about?
http://sourceforge.net/mailarchive/message.php?msg_id=2307801
From: Duncan Sands <[EMAIL PROTECTED]>
VIA workaround, was: unending timeouts
2002-10-21 01:04
SUMMARY: I have found a workaround for a hardware problem
with my VIA USB hub (PCI ID: 1106 VIA, 3038 USB hub). I
need help integrating it into the UHCI hcd.
THE PROBLEM: plugging in a new device, with a device already
plugged in, causes the existing device to malfunction, either by
causing some urbs to fail (the case with my webcam) or all urbs
to fail from then on (the case with my speedtouch modem).
THE SOLUTION: this problem does not occur with windows. By
observing reads and writes to the USB I/O registers I found
that some VIA specific code (viausb.sys) does the following
on a PORT_RESET:
Clears the run/stop bit in USBCMD.
Writes the numbers 0 to 1023 consecutively to port 0x80.
Sets the enter global suspend mode bit in USBCMD.
Calls the standard port reset function in uhcd.sys.
Clears the force global resume bit in USBCMD.
Sets the force global resume and enter global suspend mode bits in USBCMD.
Writes the numbers 0 to 1023 consecutively to port 0x80.
Clears the force global resume and enter global suspend mode bits, and
sets the run/stop bit in USBCMD.
In essence: the host controller is suspended before the port reset, and
woken up afterwards.
Inserting the same sequence in uhci.c fixes the problem under linux.
Here is some example code (in rh_submit_urb, uhci.c, kernel 2.4.19).
I replaced the writes to port 0x80 with a five millisecond delay, since
that is how long those writes take on my machine. It is possible that
writing to port 0x80 is also used to slow down traffic on the bus, but
on my machine the delay works OK.
case RH_PORT_RESET:
status = inb(io_addr); /* USBCMD */
status &= 0xFE; /* clear run/stop */
outb(status, io_addr);
/* for(i=0; i < 1024; i++) outl(i, 0x80);*/
mdelay(5);
status = inb(io_addr); /* USBCMD */
status |= 0x08; /* set EGSM */
outb(status, io_addr);
/* usual port reset */
SET_RH_PORTSTAT(USBPORTSC_PR);
mdelay(50); /* USB v1.1 7.1.7.3 */
uhci->rh.c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
SET_RH_PORTSTAT(USBPORTSC_PE);
mdelay(10);
SET_RH_PORTSTAT(0xa);
status = inb(io_addr); /* USBCMD */
status &= 0xEF; /* clear FGR */
outb(status, io_addr);
status = inb(io_addr);
status |= 0x18; /* set FGR and EGSM */
outb(status, io_addr);
/* for(i=0; i < 1024; i++) outl(i, 0x80);*/
mdelay(5);
status = inb(io_addr); /* USBCMD */
status &= 0xE7; /* clear FGR and EGSM */
status |= 0x01; /* set run/stop */
outb(status, io_addr);
OK(0);
TO DO (need help): this workaround needs to be properly integrated
into the uhci hcd code.
(1) this code should only be run when using this VIA USB controller.
(2) probably a generic hcd suspend / resume function should be used
instead of this do-it-yourself suspend/resume sequence.
(3) locking?
(4) need to make sure this does not collide with other code, for example
if I put this code in usb-uhci.c then the suspend state is detected and
cleared ("Host controller halted, trying to restart"). This doesn't seem to
hurt by the way.
Please help!
Thanks,
Duncan.
PS: Here is how windows does it, note the hardcoded values:
mov al, 80h
out dx, al /* write to USBCMD */
push dx
xor eax, eax
mov dx, 80h /* port 0x80 */
A: inc eax
out dx, eax
cmp eax, 400h
jb short A
pop dx
mov al, 88h
out dx, al
... peform port reset ...
mov al, 88h
out dx, al /* write to USBCMD */
mov al, 98h
out dx, al
push dx
xor eax, eax
mov dx, 80h /* port 0x80 */
B: inc eax
out dx, eax
cmp eax, 400h
jb short B
pop dx
mov al, 81h
out dx, al
-------------------------------------------------------
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-users