UHCI can find usb on emulators but not on real hardware
UHCI can find usb on emulators but not on real hardware
So im working on a UHCI driver. I initialised the controller and I want to see which ports are connected. On qemu and bochs this goes well. On real hardware it keeps rising interrupts and saying there is nothing in the ports. This is my code: https://github.com/AdeRegt/SanderOSUSB/ ... CI?files=1
Re: UHCI can find usb on emulators but not on real hardware
I haven't had a chance to look over your code yet, but I plan on it soon.
One of the biggest things to recognize when it works on emulators, whom are horrible at absolute timing, and real hardware, which is excellent at real timing, is, well you guessed it, timing.
You must allow the hardware to actually do what it is asked to do. On an emulator, the emulation is already there. i.e.: as soon as you request the data, the data is already there waiting to be sent. On real hardware, this is not necessarily the case.
Also, the reset of the device has a lot of differences between emulators and hardware. On an emulator, it simply is the setting and clearing of the reset bit. Done. On real hardware, it is the timing between the time the reset bit is set, then cleared, as well as which other bits are set or cleared at the same time. If my memory serves, one of the bits in the Ports register *must* be cleared before or at the same time you clear the reset bit or a device will not reset.
Welcome to the art of real hardware testing. I will tell you, a hardware analyzer, such as the Beagle I got, is a wonderful piece of hardware to help with this stuff, if you can afford the expense.
When I get a chance, I will have a look at your code. In the meantime, check your reset timing and other timing code.
Ben
- http://www.fysnet.net/the_universal_serial_bus.htm
One of the biggest things to recognize when it works on emulators, whom are horrible at absolute timing, and real hardware, which is excellent at real timing, is, well you guessed it, timing.
You must allow the hardware to actually do what it is asked to do. On an emulator, the emulation is already there. i.e.: as soon as you request the data, the data is already there waiting to be sent. On real hardware, this is not necessarily the case.
Also, the reset of the device has a lot of differences between emulators and hardware. On an emulator, it simply is the setting and clearing of the reset bit. Done. On real hardware, it is the timing between the time the reset bit is set, then cleared, as well as which other bits are set or cleared at the same time. If my memory serves, one of the bits in the Ports register *must* be cleared before or at the same time you clear the reset bit or a device will not reset.
Welcome to the art of real hardware testing. I will tell you, a hardware analyzer, such as the Beagle I got, is a wonderful piece of hardware to help with this stuff, if you can afford the expense.
When I get a chance, I will have a look at your code. In the meantime, check your reset timing and other timing code.
Ben
- http://www.fysnet.net/the_universal_serial_bus.htm
Re: UHCI can find usb on emulators but not on real hardware
In your code, you acknowledge the Master before the Slave. This is backwards. You should acknowledge the slave first. If not, the master might try to "fire" the slave pin while the slave is still "busy".
In your you say that you are initializing the port. However, you are writing to the first register of the address space, yes? This isn't where the first port is.
In I send the Global Reset (bit 2) instead of the HCReset (bit 1). This makes sure that all devices attached also see a reset.
Just for your information, it is much easier to read the following: than i.e.: Using "(1<<8)" is much easier to read than "0b0000000100000000". You don't have to count bits with (1<<8).
A few more notes:
- Some controllers/devices require the schedule to be running before a port reset.
- You *must* check the "HcHalted" bit after starting/stopping the schedule. Simply setting or clearing the "Run" bit does not mean it is started/stopped. The "HcHalted" bit indicates if the schedule is running or not.
- Write your port initialize code so that sending a port index value will indicate which port you are initializing. i.e: should be All routines that manipulate a port should have an index such as this.
("phy_address" is defined/typedef as 32-bits or 64-bits depending on the machine it is compiled for. However, for PORT I/O, this isn't must of a need. For MEM-MAPPED I/O, this is a great need.)
- Use #define's for registers. i.e.: etc., then useThis is so much easier to read, allowing the reader (you) to know which register you are writing to. Go a little further and use #define's for each bit as well.
Hope this helps,
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Code: Select all
void irq_uhci(){
...
outportb(0x20,0x20);
outportb(0xA0,0x20);
}
In your
Code: Select all
void init_uhci_port(unsigned long BAR){
uhciBAR = BAR;
printstring("UHCI: initialising port at BAR ");
...
outportw(BAR,0b0000000010000100);
...
}
In
Code: Select all
void init_uhci(unsigned long BAR,unsigned char intnum){
...
outportw(BAR,0b0000000000000010);
...
}
Just for your information, it is much easier to read the following:
Code: Select all
outportw(BAR,(1<<1)); // set bit 1
Code: Select all
outportw(BAR,0b0000000000000010);
A few more notes:
- Some controllers/devices require the schedule to be running before a port reset.
- You *must* check the "HcHalted" bit after starting/stopping the schedule. Simply setting or clearing the "Run" bit does not mean it is started/stopped. The "HcHalted" bit indicates if the schedule is running or not.
- Write your port initialize code so that sending a port index value will indicate which port you are initializing. i.e:
Code: Select all
void init_uhci_port(unsigned long BAR){
Code: Select all
void init_uhci_port(const phy_address BAR, const int portnum) {
("phy_address" is defined/typedef as 32-bits or 64-bits depending on the machine it is compiled for. However, for PORT I/O, this isn't must of a need. For MEM-MAPPED I/O, this is a great need.)
- Use #define's for registers. i.e.:
Code: Select all
#define UHCI_COMMAND 0x0000
Code: Select all
outportw(BAR + UHCI_COMMAND, value);
Hope this helps,
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Re: UHCI can find usb on emulators but not on real hardware
Thank you very much for the fast answer.
I tried to add the things you have said.
I uploaded the new code to GitHub.
When I change the code to
it keeps hanging in there "forever" and shows this (emulator snapshot) :
Also, must I set the runbit in order to detect the devices? since I have no commands for my queue.
Thank you.
I tried to add the things you have said.
I uploaded the new code to GitHub.
When I change the code to
Code: Select all
outportw(BAR,0b0000000000000000);
resetTicks(); // 1 tick is on real hardware one second
while(1){
if(getTicks()==10){
break;
}
}
outportw(BAR,0b0000000000000100);
while(1){
volatile unsigned short duringreset = inportw(BAR+USBCMD);
if((duringreset & 0b0000000000000110)==0){
break;
}
}
printstring("UHCI: reset completed!\n");
Code: Select all
-elcome to the Sanderslando Kernel!!
Loading core components...
=> Global Description Table...
=> Interrupt Description Table...
Loading utilities...
=> Programmable Interrupt Timer...
=> PS2...
PS2: data for controller
PS2: port1 interrupt enabled
PS2: port2 clock enabled
PS2: porttranslation enabled
PS2: keyboard
PS2: keyboard enabled!
PS2: mouse disabled!
=> PCI...
PCI: detecting devices....
PCI: device detected, bridge device: host bridge
PCI: device detected, bridge device: ISA bridge
PCI: device detected, mass storage device: IDE controller
PCI: device detected, serial buss controller: USB controller, UHCI [USB 1]
UHCI: Initialising UHCI
UHCI: using I/O port c020 and irq 9
UHCI: USBCMD register before reset: 0
UHCI: USBSTS register before reset: 20
Thank you.
Re: UHCI can find usb on emulators but not on real hardware
Because the controller will not clear bit 2 when it is done. You must clear it after 10ms. Please note that this is 10 milliseconds, not 10 seconds. Your code suggests that you are waiting one (1) second per tick. This is way too long. Also, after the reset, clearing the bit, you need to delay again for USB_TRSTRCY milliseconds. This is the recovery wait.SanderR wrote:When I change the code toit keeps hanging in there "forever" and shows this (emulator snapshot) :Code: Select all
outportw(BAR,0b0000000000000000); resetTicks(); // 1 tick is on real hardware one second while(1){ if(getTicks()==10){ break; } } outportw(BAR,0b0000000000000100); while(1){ volatile unsigned short duringreset = inportw(BAR+USBCMD); if((duringreset & 0b0000000000000110)==0){ break; } } printstring("UHCI: reset completed!\n");
All of this is explained in the UHCI specification sheet. A quick search for "UHCI specs" will bring it up. (Hint, this is the first)
You shouldn't have to, per the specification, but I have found that if the run bit is not set, some controllers don't perform as advertised. I have seen comments to this in other code/documentation as well.SanderR wrote: Also, must I set the run bit in order to detect the devices? since I have no commands for my queue.
Thank you.
Ben
Re: UHCI can find usb on emulators but not on real hardware
Just curious to see if you made any progress on this?
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Ben
- http://www.fysnet.net/osdesign_book_series.htm
Re: UHCI can find usb on emulators but not on real hardware
No, I have not made any progress.
I had a small pause and then started again with hope this time it would go better.
Still, on the emulators (BOCHS and QEMU) it is working while on real hardware it is still refusing.
I am currently working on a way to make the queue work and maybe it is detected that way.
The system is booted from USB, but LEGACY says it is 0xFFFF so probably it will not change the outcome of my code.
https://github.com/AdeRegt/SanderOSUSB/tree/uhci_2 is the newest link
I had a small pause and then started again with hope this time it would go better.
Still, on the emulators (BOCHS and QEMU) it is working while on real hardware it is still refusing.
I am currently working on a way to make the queue work and maybe it is detected that way.
The system is booted from USB, but LEGACY says it is 0xFFFF so probably it will not change the outcome of my code.
https://github.com/AdeRegt/SanderOSUSB/tree/uhci_2 is the newest link