Implementing USB Support

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.
Post Reply
madeofstaples
Member
Member
Posts: 204
Joined: Thu Apr 12, 2007 8:15 am
Location: Michigan

Implementing USB Support

Post by madeofstaples »

Sorry this is a little off topic but I wanted to respond to this:
mosman wrote:Now I was just trying to implement USB. Going over the (really good and helpful) USB tutorial in this wiki and other documents. I felt its really really tough one to implement :((. But I will go on with your help anyways.
I'm still planning on writing entries for the different USB controllers, and perhaps a tutorial to help others see how everything interacts. However, if you need help before I do that, especially with EHCI, feel free to send me a PM (or ask on the forums if it's not a problem very specific to your own development). Good luck!
Some people are offended by the verifiable truth; such people tend to remain blissfully unencumbered by fact.
If you are one of these people, my posts may cause considerable discomfort. Read at your own risk.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: Implementing USB Support

Post by Dex »

madeofstaples wrote:Sorry this is a little off topic but I wanted to respond to this:
mosman wrote:Now I was just trying to implement USB. Going over the (really good and helpful) USB tutorial in this wiki and other documents. I felt its really really tough one to implement :((. But I will go on with your help anyways.
I'm still planning on writing entries for the different USB controllers, and perhaps a tutorial to help others see how everything interacts. However, if you need help before I do that, especially with EHCI, feel free to send me a PM (or ask on the forums if it's not a problem very specific to your own development). Good luck!
I have a ? madeofstaples for you, lets say you have implemented UHCI and you want it to work on a EHCI PC ( as EHCI also have the slower UHCI ) How do you get it to swich to using UHCI, so the UHCI code work (even though it will be at a slower rate ).
This is the bit i am finding hard to geting working.

PS: Thanks gravaera and Tommy for your kind words.
madeofstaples
Member
Member
Posts: 204
Joined: Thu Apr 12, 2007 8:15 am
Location: Michigan

Re: Implementing USB Support

Post by madeofstaples »

By default, the EHCI controller should route ports to the companion classic host controller (usually UHCI). So you shouldn't have to worry about it.

However, if you want your OS to boot from a USB drive, and you let the BIOS handle communication with the USB device up until protected/long mode (or real mode but you don't want to depend on the BIOS), it's possible that some or all high-speed devices (i.e, USB 2.0 capable devices) will have already been configured by the BIOS. I believe some BIOS will release/reset the EHCI controller when the processor transfers to protected mode (I could be wrong about that, but the BIOS would do this during an SMI in system management mode). Not all BIOS will do that and in fact the particular PC may take advantage of EHCI's extended capabilities, which includes a semaphore mechanism for transferring ownership of the EHCI controller form the BIOS to the OS.

Supposing the worst--that the BIOS configures devices and neglects to reset them in case the OS doesn't support EHCI--you may want your OS to do the following:
  1. Before initializing any UHCI controllers, locate the EHCI controllers on the PCI bus. Note that the EHCI controller will have a higher function number than its associated companion controllers, as per the EHCI specifications, page 54:
    The USB 2.0 host controller must be implemented as a multi-function PCI device if the implementation includes companion controllers. The companion host controllers’ function numbers must be less than the EHCI host controller function number. The EHCI host controller must be a larger function number with respect to the companion host controllers associated with this EHCI host controller. If a PCI device implementation contains only an EHCI controller (i.e. no companion controllers or other PCI functions), then the EHCI host controller must be function zero, in accordance with the PCI Specification.
  2. Use the USBBASE (edit: USBBASE is the value of the first PCI BAR with a non-zero value) field of the PCI configuration space to obtain the address of the memory-mapped registers of the EHCI controller. Specifically, this points to a first set of registers called the capability registers.
  3. Read the DWORD at address USBBASE+0x08, perform a logical AND with the value 0x0000FF00 and shift the value 16 bits to the right to obtain the EHCI Extended Capabilities Pointer (EECP). That is, something like:
    EECP = (* ((unsigned long int*) ( ((char*)USBBASE) + 0x08 )) & 0x0FF00) >> 16;
    • If EECP < 0x40 (it should be zero, but any number less than 0x40 is invalid), then the EHCI controller does not implement the extended capabilities. If this it the case, then skip down to step 4.
    • If EECP >= 0x40, then this indicates an offset in the PCI configuration space.
    • In the PCI configuration space, you only care about bits 16 (HCBIOSSEM, the BIOS semaphore) and 24 (HCOSSEM, the OS semaphore) of the entire DWORD at the offset specified by EECP.
    • First you want to know the value of HCBIOSSEM to know if the BIOS even claims control over the EHCI controller., so you'll just need to read in one byte from port 0x0CFE as opposed to reading a DWORD from port 0x0CFC (see the PCI wiki entry for a refresher, if necessary, I know I had to :))
      • Note: It shouldn't matter if you do read in the full DWORD, but when writing to this field, the EHCI specification says that the two bits we are interested in (16 and 24) were placed in separate bytes specifically to prevent race conditions between the OS and the BIOS, on page 121:
        These fields are in adjacent bytes, which allows each agent (OS or BIOS) to update their respective semaphore without overwriting the other ownership semaphore.
    • Thus we have something like (assuming the function pciConfigReadByte doesn't consider endian-ness, and we're on x86/little-endian architecture):
      HCBIOSSEM = pciConfigReadByte(EHCIBus, EHCISlot, EHCIFunc, EECP+0x02) & 0x01;
    • If HCBIOSSEM is not zero, then the BIOS is claiming ownership and you should take the following actions:
      • Write the byte 0x01 to the PCI configuration space in order to set HCOSSEM, or bit 24 of the DWORD at offset EECP. That is:
        pciConfigWriteByte(EHCIBus, EHCISlot, EHCIFunc, EECP+0x03, 0x01);
      • At this point, the OS must poll the value of HCBIOSSEM by continuously accessing the PCI configuration space as discussed above.
      • When the OS reads HCBIOSSEM as 0x00, it then needs to poll HCOSSEM until it reads as 0x01.
      • It is probably a good idea to implement sleep(msec), and you should always foresee potential hardware errors--make the polling process time out after a certain number of polls or a certain time period. Should polling time out rather than give the expected results, you should probably manually try to disable the EHCI from issuing SMIs:
        • Now you are interested in the lowest-order byte from the DWORD in the PCI configuration space at offset EECP, this is the Capability ID, we'll call it CAPID:
          CAPID = pciConfigReadByte(EHCIBus, EHCISlot, EHCIFunc, EECP);
        • If CAPID is not 0x01, then you cannot enable/disable SMIs. At this point, it wouldn't hurt to just assume the BIOS has relinquished control; you'll only need to change one control register and if the BIOS hasn't relinquished control, chances are it won't check/reset the control register, so it'll never notice. However, if that's not the case then you've found some interesting hardware.
        • If CAPID is 0x01, it indicates the presence of a DWORD in the PCI configuration space at EECP+0x04, but you only need to worry about the WORD at this address (the 16 low-order bits of the DWORD)--you want to reset all bits in this WORD to 0:
          pciConfigWriteWord(EHCIBus, EHCISlot, EHCIFunc, EECP+0x04, 0x0000);
        • Now the EHCI controller won't issue SMIs on any event and so the BIOS should no longer be able to handle events for the controller.
      • Now your OS should have exclusive control over the EHCI controller. The BIOS will usually reset all the control registers and disabled the controller before handing over control, but there are only a few more steps to make sure all ports are routed to the companion host controllers.
  4. Now you need to locate the memory-mapped address of a second set of EHCI registers called the operational registers, we'll call them OPREGS. This address is computed by adding an offset to USBBASE, the offset is stored in the first byte of the first set of registers (at address USBBASE, itself):
    OPREGS = USBBASE + ( (* ((unsigned long int*) (USBBASE))) & 0x0FF );
  5. Finally, you just want to clear the configure flag, which is located in the first bit of the DWORD at OPREGS+0x40. All other bits are reserved and also set to zero, so:
    OPREGS[0x40 / sizeof(OPREGS[0])] = 0x00;
    Now the EHCI controller's port routing logic routes all ports to the companion controllers, so UHCI drivers should work as expected.
Whew, maybe that should be a stub entry for UHCI or EHCI controllers. I only specified a few types in the examples which would ensure that the compiler didn't insert an implicit multiplier, but depending on the types you choose to use, they of course may not be necessary or correct. Hopefully they communicate the right idea, though.

Sorry again to the OP for getting off topic, mods should feel free to split this thread.
Some people are offended by the verifiable truth; such people tend to remain blissfully unencumbered by fact.
If you are one of these people, my posts may cause considerable discomfort. Read at your own risk.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: Implementing USB Support

Post by Dex »

First thankyou very much for that info madeofstaples, I will give it ago, as you seem to have explaned everythink very well.
What you posted makes alot of sence, as some of my PC work fine even though they have EHCI with my UHCI code and others do not.
As a side note, it may be possible to set this in BIOS setting.
Thanks again, regards Dex.
madeofstaples
Member
Member
Posts: 204
Joined: Thu Apr 12, 2007 8:15 am
Location: Michigan

Re: Implementing USB Support

Post by madeofstaples »

No problem! Good luck!

Please let me know if you run into problems, or if you find that you need to use any sort of particular trickery on certain hardware. Also, it would be good to know if you find some BIOS options to be particularly important for getting these things to work. These would be good things to include on the wiki.

I do recall having seen some BIOS options to disable USB 2.0, but I do not remember which machine that was (or if I even have that machine any more), but I'm guessing that would force the BIOS to only use the companion controllers and thus not cause any trouble for the OS that doesn't support EHCI.
Some people are offended by the verifiable truth; such people tend to remain blissfully unencumbered by fact.
If you are one of these people, my posts may cause considerable discomfort. Read at your own risk.
lihawl
Posts: 6
Joined: Fri Nov 29, 2013 7:08 pm

Re: Implementing USB Support

Post by lihawl »

I think there is a Tiny problem. Is
Read the DWORD at address USBBASE+0x08, perform a logical AND with the value 0x0000FF00 and shift the value 16 bits to the right to obtain the EHCI Extended Capabilities Pointer (EECP).
correct? That's not logical. It's clearly a bitwise(not logical) AND . According to a specification,We should shift the value 8 bits(not 16 bits) to right.
rdos
Member
Member
Posts: 3276
Joined: Wed Oct 01, 2008 1:55 pm

Re: Implementing USB Support

Post by rdos »

In some (possibly many) new PCs there are no companion controllers. Thus, writing drivers for UHCI/OHCI will not help in getting those to operate with typical USB 1.x capable devices. Instead, these new computers require a driver for EHCI and a USB hub driver as well, as their root ports are typically connected to USB hubs. My Sony Vaio portable has two physical USB ports, and both of them are connected to an internal USB hub.

So the issue is actually even worse. In order to support USB on future computers you need at least an EHCI and a USB hub driver.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Implementing USB Support

Post by Combuster »

lihawl wrote:I think there is a Tiny problem.
The problem is 2009 :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply