USB, UHCI, host controller process error

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

USB, UHCI, host controller process error

Post by Artlav »

USB support, seems simple, easy to do in emulator, insane to make on real hardware.
I'm working on making a UHCI driver, and got stuck.
I've been scavenging information about USB from all around, OSDev wiki, UHCI docs, Linux sources, random places on the net, but there seems to be no complete and correct documentation on how to get started.

In emulators all is perfect, on real PC (eeepc, got 4 UHCI and one EHCI) nothing works.

Nothing works can be defined as no transactions working.

The simple test of filling a frame list with $00000001 and printing frame counter works nicely (all said about real HW if not said otherwise), but anything more complex does not.

Trying to request a descriptor straight away or assign address to a device results in $0030 or $0028 being returned in USBSTS, with TD left unchanged in active state.
frame counter vary between 0 and 17, each test giving different values and different status.
Tried it with a bunch of USB1 devices - mouses, keypad, old BT stick, floppy pad, no significant differences.

PCI status on each attempt is either $0280 or $2280, not sure what it means.
No apparent link between UHCI status and PCI status, they can come in any pair.

Can anyone help?
What have i missed or misunderstood?

Outline of the code:

Code: Select all

SR_GET_STATUS    =$00;
SR_SET_ADDRESS   =$05;
SR_GET_DESCRIPTOR=$06;

DSC_DEVICE=$01;
DSC_STRING=$03;

UHCI_REG_USBCMD   =$00;
UHCI_REG_USBSTS   =$02;
UHCI_REG_USBINTR  =$04;
UHCI_REG_FRNUM    =$06;
UHCI_REG_FRBASEADD=$08;
UHCI_REG_PORTBASE =$10;
UHCI_REG_SOFMOD   =$0C;
UHCI initialization for each detected HC:

Code: Select all

  //--Acquire device dev--
  
  //--Legacy off, keyboards stop working at this point, so i guess that's done right--
  pci_write_word(dev,$C0,$8F00);
  
  //--HCRESET--
  rd:=readregw(dev,UHCI_REG_USBCMD);
  rd:=rd or 2;
  writeregw(dev,UHCI_REG_USBCMD,rd);
	
  //--Wait one second or until (readregw(dev,UHCI_REG_USBCMD) and 2)=0 ---

  //--Clear all--
  writeregw(uhci.dev,UHCI_REG_USBINTR,0);
  writeregw(uhci.dev,UHCI_REG_USBCMD,0);
  
  //--Set frame list, TDs, QHs, page-aligned, physical memory-- 

  //--Set frame list base--
  writeregd(uhci.dev,UHCI_REG_FRBASEADD,uhci.frs); 
  
  //--Set timing--
  writeregb(uhci.dev,UHCI_REG_SOFMOD,64);
  
  //--Flag configured, 64kb--
  writeregw(uhci.dev,UHCI_REG_USBCMD,$C0);
  
  //--Install interrupt handler--
  irq_install_handler(dev.irq,@uhci_intr);
  //Without dummy IRQ the all-1 frame list test hangs on random frame count.
  //If IRQ handle is installed earlier, nothing else works, despite no interrupts received. Weird.
Interrupt handler:
Without it the test with frame list filled with $00000001's hangs on random frame count, and keeps calling the interrupt.

Code: Select all

  rd:=readregw(uhci.dev,UHCI_REG_USBSTS);
  writeregw(uhci.dev,UHCI_REG_USBSTS,rd or 1);
After that, each port of each HC is tested for device presence and the device is addressed:

Code: Select all

 //--Disable, reset, enable the port, then check if something is connected to it. If it is, assume pipe 0 is it, and proceed.
 for i:=uhci.lastport to uhci.ports-1 do begin
  writeregw(uhci.dev,UHCI_REG_PORTBASE+i*2,0);//Disable
  wide_delay(100); //millisecs
  writeregw(uhci.dev,UHCI_REG_PORTBASE+i*2,$0204);//Reset
  wide_delay(50);
  writeregw(uhci.dev,UHCI_REG_PORTBASE+i*2,$0004);//Enable
  wide_delay(10);
  rd:=readregw(uhci.dev,UHCI_REG_PORTBASE+i*2);
  if(rd and 1)<>0 then //--select this, device present, update uhci.lastport--
 end;
 
 //---Try to assign address, addr - next free address---
 //Setup and status TDs.
 uhci_xfer(uhci,0, 1,$2D,0,0,0,8,uhci.buffer);                 //uhci struct, TD to write to,LINK to next td,PID,dev,endpoint,D,len,buffer
 mk_setup_buf(@uhci.buffer[0],$00,SR_SET_ADDRESS,addr,0,0);    //buffer, RequestType, Request, Value, Index, Length 
 uhci_xfer(uhci,1,-1,$69,0,0,1,4,@uhci.buffer[8]);             //Link=-1 means set T=1.
 
 //--Clean, set run, wait till completed, stop, USBSTS=$0020 at this point--
 uhci_reinit_q(uhci);   //--Fill the frame list with 1's, make one QH with TDs list above referenced in it, put that into frame 0.---
 writeregw(uhci.dev,UHCI_REG_FRNUM,0);
 writeregw(uhci.dev,UHCI_REG_USBCMD,$C1);
 if not uhci_wait_q(uhci,2) then exit;
 writeregw(uhci.dev,UHCI_REG_USBCMD,$C0);
 wide_delay(62);

 //--Here comes the first fault, the TD[0] is never set as complete, status is either $30 or $28--
That's pretty much what it takes to get the problem, there are further transactions for information, configuration, etc, working nicely in Bochs&Qemu, but none work on real PC.
Matthew
Member
Member
Posts: 48
Joined: Wed Jul 01, 2009 11:47 am

Re: USB, UHCI, host controller process error

Post by Matthew »

Two things come to mind: try disabling EHCI (either in BIOS at first, or in your driver, do a search of this forum to find code).

The other thing is that I've never tried messing with port status or any kind of device enumeration until the HC is up and running. If you are worried about getting the TDs into the current frame, here is the trick we use for non-isochronous transfers: have every frame entry link initialized to point at a single QH, from which the TDs are attached vertically. Later you can have a horizontal chain of additional QHs for multiple transactions. And isochronous TDs can be inserted horizontally in-between the frame entry and the QH.

Now it does not matter what the current frame number is, every frame entry will lead to the TDs you attach from that single QH.
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

Matthew wrote:Two things come to mind: try disabling EHCI (either in BIOS at first, or in your driver, do a search of this forum to find code).
I'll try that. No option in BIOS for it.
What about older OSes, do they work with USB1.1 devices on USB2.0 system? The docs seems to assume they are, making EHCI state irrelevant.
Matthew wrote:The other thing is that I've never tried messing with port status or any kind of device enumeration until the HC is up and running.
I had the impression that HC was up and running by the time i get to enumeration, according to the code above. What exactly do you consider "up and running", if it's not?

Port status and enumeration is irrelevant to the problem btw, just requesting a device descriptor from whatever one is on pipe 0 after HC reset gives the same exact problem.
Matthew wrote:If you are worried about getting the TDs into the current frame, here is the trick we use for non-isochronous transfers: have every frame entry link initialized to point at a single QH, from which the TDs are attached vertically. Later you can have a horizontal chain of additional QHs for multiple transactions. And isochronous TDs can be inserted horizontally in-between the frame entry and the QH.

Now it does not matter what the current frame number is, every frame entry will lead to the TDs you attach from that single QH.
Interesting idea, but doing it like that reduces the set of systems it work on to Bochs only. Even Qemu doesn't work, and there seems to be no errors given.

If i understood it right, i fill the frame list with links to one QH, then on each transaction i put the link to TD into that QH and wait?

The link is supposed to clear once the Q is complete, so on the next frame it should not run once again.

That key last statement seem to contradict the info in the wiki, which states that the elements can be prefetched and redistributed: http://wiki.osdev.org/Image:Usbtransactionreorder.gif

So it's either a flawed method or i misunderstood it.
Not tried it on real hw yet.
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: USB, UHCI, host controller process error

Post by XanClic »

Artlav wrote:What about older OSes, do they work with USB1.1 devices on USB2.0 system? The docs seems to assume they are, making EHCI state irrelevant.
You are working with low/full speed devices (as far as I can see), thus the EHCI is not involved at all.
Artlav wrote:Interesting idea, but doing it like that reduces the set of systems it work on to Bochs only. Even Qemu doesn't work, and there seems to be no errors given.
It works in qemu and it works on real hardware, because that's the way I do it and it's also the way the UHCI specification suggests:
Image
As you can see, all isochronous TDs finally point to one queue of QHs which is the same for all frames.
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

I've managed to minimize the problem, which seems to appear much earlier on:

Code: Select all

  //--Legacy off, keyboards stop working at this point, so i guess that's done right--
  //---If that is not done everything halts, system and all, after RUN is set---
  pci_write_word(dev,$C0,$8F00);
 
  //--HCRESET--
  rd:=readregw(dev,UHCI_REG_USBCMD);
  rd:=rd or 2;
  writeregw(dev,UHCI_REG_USBCMD,rd);

  //--Wait one second or until (readregw(dev,UHCI_REG_USBCMD) and 2)=0 ---

  //--Disable interrupts, or don't, no effect either way.
  //writeregw(uhci.dev,UHCI_REG_USBINTR,0);
 
  //--Set frame list, TDs, QHs, page-aligned, physical memory--
  //--Write 1 to all frames, or make a frame list all point to a qh made of two 1's, error either way

  //--Set frame list base--
  writeregd(uhci.dev,UHCI_REG_FRBASEADD,uhci.frs);
 
  //--Set timing, or don't - no effect on the problem
  //writeregb(uhci.dev,UHCI_REG_SOFMOD,64);
 
  //--Flag configured, set RUN ($B1, $C1, $A1, $01 - all cause error)--
  writeln('pre: sts=$',...,', cmd=',...);
  writeregw(uhci.dev,UHCI_REG_USBCMD,$C1);
  wide_delay(100); 
  writeln('post: sts=$',...,', cmd=',...);
Pre shows STS=$20, CMD=$00, post shows cmd=$x0, STS= either $28 or $30.
Frame counter advances to random value within 200-300 frames, usually within 1 to 10.

I guess there is some fundamental issue here, but now i'm entirelly at loss where to look for one.
The test above never worked, i thought it was working because apparently of a flux when it runned for a whole half second i had as a time limit for it.

Any idea what is wrong?
XanClic wrote:It works in qemu and it works on real hardware, because that's the way I do it and it's also the way the UHCI specification suggests:
{img}
As you can see, all isochronous TDs finally point to one queue of QHs which is the same for all frames.
It does not work in Qemu, and on real hardware it gives the same kind of errors that the initial method, so now i have two errors somewhere, or the initial one makes it fail even in Qemu.
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: USB, UHCI, host controller process error

Post by XanClic »

Artlav wrote:Pre shows STS=$20, CMD=$00, post shows cmd=$x0, STS= either $28 or $30.
Well, 0x20 is already bad, isn't it?
Artlav wrote:It does not work in Qemu, and on real hardware it gives the same kind of errors that the initial method, so now i have two errors somewhere, or the initial one makes it fail even in Qemu.
It (the concept) does work. Your code just doesn't. :wink:
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

XanClic wrote:Well, 0x20 is already bad, isn't it?
Is it?
That's HCHalted bit set, and none of the error ones.
What should it be right after a reset?
If it's bad, what can cause it, there are no error codes anywhere i know of?
XanClic wrote:It (the concept) does work. Your code just doesn't. :wink:
Quite likely.
Therefore, this thread.
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: USB, UHCI, host controller process error

Post by XanClic »

Artlav wrote:
XanClic wrote:Well, 0x20 is already bad, isn't it?
Is it?
That's HCHalted bit set, and none of the error ones.
What should it be right after a reset?
If it's bad, what can cause it, there are no error codes anywhere i know of?
Ah, well, nvm. It's just that my code treats it as a fatal condition — which is correct after the HC is started, but before that… Yeah, it's ok.
Artlav wrote:
XanClic wrote:It (the concept) does work. Your code just doesn't. :wink:
Quite likely.
Therefore, this thread.
Well, the only things I do different than you do are:
1st) I set the PCI command register to 5 (enable busmaster capability and the I/O space), though this should be done by BIOS already
2nd) I drive the resume signal after enabling the HC on all ports (and after a reset), but this explains neither the HC process error nor the host system error you're receiving.
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

XanClic wrote:1st) I set the PCI command register to 5 (enable busmaster capability and the I/O space), though this should be done by BIOS already
Tried that, no use. Besides, it reads 5 at start.

The most annoying part is that the damn emulators work whatever i try, while real hw always give the same error.

Maybe something is wrong upstream?
Should i do something at PCI stage, besides reading off I/O location of the device in question?

EDIT: Can i have an image of a thing you do, maybe yours won't work on that laptop either? (Must be GRUB bootable - no CD or floppy on it)
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: USB, UHCI, host controller process error

Post by XanClic »

Yes, you may – though I haven't done anything at that code for several months :mrgreen:

Multiboot-compatible kernel

(Code is here, UHCI driver is under drivers/network-controller/uhci.c)
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

XanClic wrote:Yes, you may – though I haven't done anything at that code for several months :mrgreen:

Multiboot-compatible kernel

(Code is here, UHCI driver is under drivers/network-controller/uhci.c)
Thank you.
The image says something about EHCI legacy support and nothing else happens, judging by the code it wants to load some file, not sure what should happen.

The code looks quite close to what i have, i tried to get mine as close to it as i can, but got no results - same errors, which make me strongly believe that there is something outside UHCI that gives the problem.

Any ideas?
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

Some progress:
I tried it on another laptop, and out of 5 UHCI several work each second run, giving "CRC/Time Out Error" in TD on descriptor read attempt (Port suspend/resume logic. not described anywhere i looked, not emulated. damn.).
The other half of the times they give the same old errors.

Just what the heck?
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: USB, UHCI, host controller process error

Post by XanClic »

Artlav wrote:Any ideas?
Sounds like my code works neither, which is also bad news to me. :wink:
Nugget
Posts: 16
Joined: Sun May 02, 2010 2:54 am

Re: USB, UHCI, host controller process error

Post by Nugget »

Hi Artlav,

Emulators are typically quite bad at emulating some devices. Timing problems are usually the first to show up, but real USB systems are very fussy about the TD contents and packet data. The emulators just assume your code is right and don't check anything. For example, if your toggle bits aren't right, a real device will complain, but an emulator might just carry on regardless. :roll:

Your code looks ok, and the HC should be able to happily process and frame list containing all 1s. Are you absolutely sure that you're giving the physical address of the frame list? I'd double check that you're 4KB aligned as well. (A emulator will probably just use whatever you give it, but hardware might assume that the bottom bits are zero and not even store them.)

Once that's ok, I expect that you'll need to put the port through the correct reset-enable sequence before queuing any TDs.

What is the device that you're testing with on real hardware? If it's a 2.0 device then it'll be handled by the EHCI controller rather than the UHCI.
User avatar
Artlav
Member
Member
Posts: 178
Joined: Fri Aug 21, 2009 5:54 am
Location: Moscow, Russia
Contact:

Re: USB, UHCI, host controller process error

Post by Artlav »

Matthew wrote:Two things come to mind: try disabling EHCI (either in BIOS at first, or in your driver, do a search of this forum to find code).
Nugget wrote:If it's a 2.0 device then it'll be handled by the EHCI controller rather than the UHCI.
I made a mistake, among many, of assuming without checking.
So, i spent a day researching EHCI and making a basic driver to initialize and shut it down.
That had an effect - now the errors only show up half the times, and only status $28 (Host System Error) is shown, $30 appearing very rarely.

No luck enumerating anything - the enable bit in port registers won't set, delay or not.

I guess half the problem is solved, but something stays wrong still.
Any more good ideas?
Nugget wrote:Are you absolutely sure that you're giving the physical address of the frame list? I'd double check that you're 4KB aligned as well. (A emulator will probably just use whatever you give it, but hardware might assume that the bottom bits are zero and not even store them.)
Positive. Drivers work under 1-1 mapping, and i checked page alignment among the first things i tried, it would assert if frame list is not aligned.
Nugget wrote:What is the device that you're testing with on real hardware?
Mouses, keyboards, floppy drive, bt stick, all confirmed USB1.1, none affect the original problem, none worked yet.
Nugget wrote:Once that's ok, I expect that you'll need to put the port through the correct reset-enable sequence before queuing any TDs.
Would be interesting to know what it is, since i'm almost to it.
Currently i do disable, wait 100ms, reset, wait 50 ms, reset off, enable, wait till enable bit reads 1.
But, it never read 1. Line status is D+, whatever it means.
Post Reply