[Solved] Odd problem with UHCI setup packet

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
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

[Solved] Odd problem with UHCI setup packet

Post by BrightLight »

I'm trying to send a setup packet to a USB 1.1 device using UHCI.
I do the following to send the packet:
  • I construct the USB setup packet in memory, using the structure in the USB 1.1 specs.
  • I stop the UHCI if it is running.
  • I construct a transfer descriptor on a 32 byte-aligned address with max. length 7 (size of setup packet - 1) and type 0x2D (setup packet.)
  • If the data length in the setup packet is not zero, I construct another transfer descriptor for that data.
  • I construct the frame list with one valid entry pointing to the first TD and one invalid entry. (The first TD pointers to the second TD.)
  • I set the frame number register to zero, to start from the beginning of the frame list.
  • I start the host controller.
On QEMU, I get an interrupt error (UHCI status register has bit 1 set.) On Bochs, the log spits out lots of error messages:

Code: Select all

00023253606i[UHCI  ] port #1: speed = low
00023642803i[UHCI  ] port #1: speed = low
00023642815i[UHCI  ] port #1: speed = low
00023642815i[UHCI  ] Port1: Reset
00024042827i[UHCI  ] Port2: Reset
00024476000e[UHCI  ] invalid max. length value 0x06c6
00028572000e[UHCI  ] invalid max. length value 0x06c6
00032668000e[UHCI  ] invalid max. length value 0x06c6
00036764000e[UHCI  ] invalid max. length value 0x06c6
00040860000e[UHCI  ] invalid max. length value 0x06c6
00044956000e[UHCI  ] invalid max. length value 0x06c6
00049052000e[UHCI  ] invalid max. length value 0x06c6
The last messages about invalid max. length are repeated forever. So, I decided to check what my TDs have, and everything looks sane to me.
The first TD contains:

Code: Select all

0000d800 04000000 00e0002d 0000cce0
The second TD also looks valid:

Code: Select all

00000001 04000000 02200069 0000cacd
The second 4 DWORDs of both TDs are zero. I've read the UHCI specification up to down and down to up; is there something obvious I'm missing? It's odd that I can't find a 0x6C6 anywhere, like the Bochs log says.
Last edited by BrightLight on Wed Jan 25, 2017 5:35 pm, edited 1 time in total.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: Odd problem with UHCI setup packet

Post by BenLunt »

Hi,

First, if you send a setup and possibly a data packet or two, you must send a status packet afterward.

SETUP(0)
DATA(1)
DATA(0)
DATA(1)
STATUS(1)

Also, it looks to me that you don't have the physical address in the BASE address register correct. Either that, or you have dummy QH's and/or TD's that are not marked invalid (T=1).

Check all of your addresses to be sure. The first TD you have points to the second which should be at physical address 0x0D800. This seems to be way to low in memory. Remember, the UHCI controller does not use segment/selectors. You must supply actual physical addresses.

You don't have to turn off the controller's schedule to insert a queue or TD. Just check to see which frame it is on and insert your Queue or TD in a different frame. The controller will stay on that frame for 1mS, so if you make sure you don't insert your next TD in that frame or the next frame, you have a least 1mS and up to 2mS to insert.

Ben
http://www.fysnet.net/the_universal_serial_bus.htm
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Odd problem with UHCI setup packet

Post by BrightLight »

The base addresses of my memory structures are correct; my kernel is loaded in low memory (my bootloader loads the kernel at physical address 0x1000) and the first 8 MB of memory are identity-mapped, so all these addresses are correct.
I am not sending a data packet to the device; I am expecting a data packet from the device (I'm trying to use the GetDescriptor command). Do I still need to send a data packet?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: Odd problem with UHCI setup packet

Post by BenLunt »

When you say "identity mapped", you are still using physical addresses for all Controller structures, correct?

To send the Get Descriptor request, you send an 8-byte setup packet, then an 8-byte IN packet. As soon as you receive the data, you need to send a zero-byte out packet. Make sure your D-bits are 0, 1, 1.

A side note. Since you are using Bochs and QEMU, this won't be a problem for now, but in future references, some devices won't respond to a Get Descriptor request of 8-bytes. They are expecting a 64-byte request. i.e.: a high-speed device will expect that you request a 64-byte Get Descriptor, even though it will only return 18 bytes in three packets, (8, 8, 2). On that same idea, some devices will only respond to a request of the first 8 bytes. On a fail, you have try again with either a 64-byte request, or visa-versa.

Back to what we were doing. The following is the example from Page 11-5 of my book.

Code: Select all

Queue at 0x01234000:
  0x00000001
  0x01234010
  0x00000000
  0x00000000
TD0 at 0x01234010:
  0x01234030
  0x1C800000
  0x00E0002D
  0x01234070
  0x00000000
  0x00000000
  0x00000000
  0x00000000
TD1 at 0x01234030:
  0x01234050
  0x1C800000
  0x00E80069
  0x01234080
  0x00000000
  0x00000000
  0x00000000
  0x00000000
TD2 at 0x01234050:
  0x00000001
  0x1D800000
  0xFFE800E1
  0x00000000
  0x00000000
  0x00000000
  0x00000000
  0x00000000
0x01234070: (request packet)
  0x80 0x06, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00
0x01234080: (buffer for the return)
(I hope I typed all that in correctly)

Please note that the above does not wait for the IN packet before sending the Status Packet. It assumes the IN packet will be valid. Once you get the idea, you will need to re-write your code to wait for a valid IN packet before you send the Status Packet.

The above assumes your buffers start at 0x01234000 and the TD's are 8 dwords in size. You will need to adjust the addresses to match your code.

Hope this helps,
Ben
http://www.fysnet.net/the_universal_serial_bus.htm
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Odd problem with UHCI setup packet

Post by BrightLight »

Thanks! I'll try this tonight.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Odd problem with UHCI setup packet

Post by BrightLight »

Update: It works, thanks for the help! I definitely missed the concept of data toggle bit (DATA0 and DATA1) in my transfer descriptors. I can now receive the descriptors. Thanks again!
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: [Solved] Odd problem with UHCI setup packet

Post by BenLunt »

Glad to help.

Just for future reference:
1. When you get to Bulk In/Out packets, the Data0/1 bit does not reset for each transfer. It alternates through to the next transfer. To reset it, send a Clear request.
2. Some high-speed devices (on a UHCI) will NAK the first time you access them. Simply remove that TD and try again.
3. One very big misconception most people have is if a device is USB 2.0 compliant is must be a high-speed device. This is not the case. A low-speed device can be USB 3.0 compliant, but still only be low-speed. And visa/versa, a USB 3.0 Super-speed device can work just fine on a UHCI controller (USB 1.1), just not have all the capabilities of USB 3.0 and super-speed. The number after the USB has nothing to do with the speed it is rated at.

Without sounding like I am trying to peddle my book, might I suggest you have a look at http://www.fysnet.net/the_universal_serial_bus.htm. It has information for the UHCI, OHCI, EHCI, and xHCI controllers, low-, full-, high-, and super-speed devices, examples for all, as well as "gotcha's" for some types of devices. If you or anyone else here is serious about the USB part of their OS, this might be a big help to you. Again, not trying to peddle my book, I just want to help. If you have any questions, please continue to post here for all to see and I will do my best to help.

Thanks,
Ben
Post Reply