USB Handshake Not Received (EHCI USB 2.0)

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
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

USB Handshake Not Received (EHCI USB 2.0)

Post by devc1 »

Hello, I was recently working on a USB Driver, I started with EHCI, I've read the entire EHCI Spec from Intel and everything seems to works fine. I have an initial queue head for control transfers (setup on startup before Controller Enabling) with 1 QTD (SETUP_PID "2") . I tested it on qemu and everything works fine.

I Send the SETUP_TOKEN_PACKET and there is no error.
After that, I send the DEVICE_REQUEST with (Request = GET_DESCRIPTOR, ReqType = 0x80, Value = 1 << 8, Length = 0x12).
and also if I try and mess with qemu by setting DEVICE_REQUEST.Value = 0. It gives me this error message "usb_desc_get_descriptor: 0 unknown type 0 (len 18)" Which means that everything works fine.

To now everything is fine, but I do not get a handshake (PID = 0 And all that buffer is 0). here is a code trying to fetch close buffer:

Code: Select all

USB_HANDSHAKE_PACKET* Handshake = (USB_HANDSHAKE_PACKET*)((UINT64)Transfer->Qtd->BufferPointer0 | ((UINT64)Transfer->Qtd->ExtendedBufferPointer0 << 32));
// Trying to see if the handshake is somewhere on the buffer
    SystemDebugPrint(L"SETUP_TOKEN SENT. PID : %x, FIRST : %x SECOND : %x", Handshake->Pid, *(UINT64*)((UINT64)Transfer->Qtd->BufferPointer0 - 8), *(UINT64*)((UINT64)Transfer->Qtd->BufferPointer0));
Here is the code for the control transfer :

Code: Select all

int EhciControlDeviceRequest(RFEHCI_ASYNC_TRANSFER Transfer, USB_DEVICE_REQUEST* DeviceRequest, UINT NumBytes /*For Buffer*/, void* Buffer){
    Transfer->Qtd->PidCode = EHCI_SETUP;
    ZeroMemory(Transfer->Buffer, 0x1000);
    Transfer->Qtd->BufferPointer0 &= ~(0xfff);
    USB_TOKEN_PACKET* Setup = Transfer->Buffer;
    Setup->Pid = USB_PID_SETUP;
    Setup->DeviceAddress = 0;
    // Setup->SyncField = 1;

    Transfer->Qtd->TotalBytesToTransfer = 8;
    Transfer->Qtd->Active = 1;
    while(Transfer->Qtd->Active);


    memcpy((void*)((char*)Transfer->Buffer + 8), DeviceRequest, 8);
    Transfer->Qtd->TotalBytesToTransfer = 8;
    // Transfer->Qtd->DataToggle = 1;
    Transfer->Qtd->Active = 1;
    while(Transfer->Qtd->Active);
    USB_HANDSHAKE_PACKET* Handshake = (USB_HANDSHAKE_PACKET*)((UINT64)Transfer->Qtd->BufferPointer0 | ((UINT64)Transfer->Qtd->ExtendedBufferPointer0 << 32));
    SystemDebugPrint(L"SETUP_TOKEN SENT. PID : %x, FIRST : %x SECOND : %x", Handshake->Pid, *(UINT64*)((UINT64)Transfer->Qtd->BufferPointer0 - 8), *(UINT64*)((UINT64)Transfer->Qtd->BufferPointer0));
    while(1);
    return 0;
}
Here is structures :

Code: Select all

#pragma pack(push, 1)

typedef struct _USB_TOKEN_PACKET{
    UINT64 SyncField : 32;
    UINT64 Pid : 8; // Packet Id

    UINT64 DeviceAddress : 7;
    UINT64 Endpoint : 4;
    UINT64 CRC5 : 5; // Cyclic Redundancy Check
} USB_TOKEN_PACKET;

typedef struct _USB_DATA_PACKET{
    UINT32 SyncField;
    UINT8 Pid;
    char Data[8]; // [8] Just temporarely
    UINT16 CRC16;
    UINT16 EOP;
} USB_DATA_PACKET;

typedef struct _USB_HANDSHAKE_PACKET{
    UINT64 SyncField : 32;
    UINT64 Pid : 8;
} USB_HANDSHAKE_PACKET;

typedef struct _USB_SOF_PACKET{
    UINT64 SyncField : 32;
    UINT64 Pid : 8;
    UINT64 FrameNumber : 11;
    UINT64 CRC5 : 5;
} USB_SOF_PACKET;


typedef struct _USB_DEVICE_REQUEST{
    unsigned char RequestType;
    unsigned char Request;
    unsigned short Value;
    unsigned short Index;
    unsigned short Length;
} USB_DEVICE_REQUEST;

typedef enum _USB_DESCRIPTOR_TYPE{
    USB_DESCRIPTOR_TYPE_DEVICE = 1,
    USB_DESCRIPTOR_TYPE_CONFIGURATION = 2,
    USB_DESCRIPTOR_TYPE_STRING = 3,
    USB_DESCRIPTOR_TYPE_INTERFACE = 4,
    USB_DESCRIPTOR_TYPE_ENDPOINT = 5,
    USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER = 6,
    USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION = 7,
    USB_DESCRIPTOR_TYPE_INTERFACE_POWER = 8
} USB_DESCRIPTOR_TYPE;

typedef struct _USB_DEVICE_DESCRIPTOR{
    UINT8 Length;
    UINT8 DescriptorType;
    UINT16 UsbSpecificationReleaseNumber;
    UINT8 DeviceClass;
    UINT8 DeviceSubclass;
    UINT8 DeviceProtocol;
    UINT8 Endpoint0MaxPacketSize;
    UINT16 VendorId;
    UINT16 ProductId;
    UINT16 DeviceRelease;
    UCHAR Manufacturer; // index of string descriptor
    UCHAR Product;
    UCHAR SerialNumber;
    UINT8 NumConfigurations;
} USB_DEVICE_DESCRIPTOR;

#pragma pack(pop)
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: USB Handshake Not Received (EHCI USB 2.0)

Post by BenLunt »

Hi,
devc1 wrote:Hello, I was recently working on a USB Driver, I started with EHCI, ...
eeewwww. IMHO, this was the wrong one to start with :-) Again, IMHO, the EHCI was a hodge-podge of pieces trying to allow the new high-speed but keeping completely backward compatible. It was, and still is a mess. However, this is just my opinion.

A few questions, and if I may, a few suggestions.

Are you sure the attached device is a high-speed device? (In general) the EHCI will not communicate with a high-speed device. i.e.: you won't get a response unless the device is a high-speed device.

Unless I interpreted your question wrong, you are waiting for a response that never is exposed to the software side. The Handshake is done internally. However, if you are talking about the Status packet, this is sent by software, not received by software.

May I suggest that you do not use bit-fields? Bit-fields are compiler specific and may or may not represent the bits corresponding to the hardware. You may in-fact be setting bits that do not correspond with the same position bits on the EHCI.

Which brings me to the more revealing code. The Setup packet does not have a SyncField or CRC, at least not the software exposed packet. The software is not exposed to the SOF packet nor the Handshake packet.

To send a Control packet, you send an 8-byte SETUP packet (_USB_DEVICE_REQUEST), zero or more 1 to 8-byte DATA packets, and a single 0-byte STATUS packet. The software side does not see, nor wait for the Handshake or SOF packets. These are bytes prepended/appended (by the hardware) to the 8-byte packets you send/receive.

Don't worry, this is a result of reading only the specification. The specification is written for those creating EHCI controllers. The software side is a little different.

Ben
- https://www.fysnet.net/the_universal_serial_bus.htm
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: USB Handshake Not Received (EHCI USB 2.0)

Post by devc1 »

Thanks, this is helpful. All structures are packed, I was setting the Sync Field to 1, I Forgot to include that. However, I do not know how to calculate the CRC maybe it is not required (optional). When messing with device request, there is something that get written to the buffer (and QEMU sends that error message), otherwise there is nothing. Also, the problem with QEMU is that it's trying to give the fastest possible experience, it does not allot of checks, but with some updates I was able to run my OS on My Computer.

- I'm attaching a mouse and a keyboard in QEMU, when running the command "info usb", it shows me that they're both 480 MB/S which means that they're high speed.

So, to read the device request I will need to send an IN Token Right, do I need to create an OUT QTD or Keep up with SETUP QTD ?

- To Read the Values, I set Data Toggle bit and the Active bit and wait until the request is done, is it right ? (The device will probably send a DATA1 Packet)
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: USB Handshake Not Received (EHCI USB 2.0)

Post by devc1 »

Thank you very much ! I was gonna give up and try another driver. I got the device descriptor (with some buffer checking), the device does not send any DATA1 Token or something else. It just sends the data.

- In QEMU I've set another PID by fault rather than SETUP_PID(0xB4) and everything works fine
- Maybe the setup token is also set by controller ?
- So I removed SETUP_PID and Everything is fine (the controller was doing all that stuff)


And the data matches what I found on the command "info usbhost". With length = 0x12, and desc_type = 1.


Here is the simple code I used:

Code: Select all


#define CURRENT_QTD_PTR(qtd) (void*)((UINT64)qtd->BufferPointer0 | ((UINT64)qtd->ExtendedBufferPointer0 << 32))

void EhciControlWrite(RFEHCI_ASYNC_TRANSFER Transfer, void* Buffer, UINT NumBytes){
    memcpy(CURRENT_QTD_PTR(Transfer->Qtd), Buffer, 8);
    Transfer->Qtd->TotalBytesToTransfer = NumBytes;
    Transfer->Qtd->Active = 1;
    while(Transfer->Qtd->Active);
}

void EhciControlRead(RFEHCI_ASYNC_TRANSFER Transfer, void* Buffer, UINT* _NumBytes){
    UINT NumBytes = *_NumBytes;
    void* Src = CURRENT_QTD_PTR(Transfer->Qtd);
    UINT64* _D = CURRENT_QTD_PTR(Transfer->Qtd);
    Transfer->Qtd->DataToggle = 1;
    Transfer->Qtd->TotalBytesToTransfer = NumBytes;
    Transfer->Qtd->Active = 1;
    while(Transfer->Qtd->Active);
    *_NumBytes = Transfer->Qtd->TotalBytesToTransfer;
    memcpy(Buffer, Src, NumBytes);
    Transfer->Qtd->DataToggle = 0;
}

int EhciControlDeviceRequest(RFEHCI_ASYNC_TRANSFER Transfer, void* DeviceRequest, UINT NumBytes, void* Buffer){
    
    // Refresh some data

    Transfer->Qtd->PidCode = EHCI_SETUP;
    Transfer->Qtd->BufferPointer0 = (UINT32)(UINT64)Transfer->Buffer;
    Transfer->Qtd->ExtendedBufferPointer0 = (UINT32)((UINT64)Transfer->Buffer >> 32);
    Transfer->Qtd->DataToggle = 0;


    USB_TOKEN_PACKET Token = {0};
    Token.SyncField = 1;
    
    // Send DEVICE_REQUEST

    EhciControlWrite(Transfer, DeviceRequest, 8);

    // Set PID_CODE to IN & Receive data from the device

    Transfer->Qtd->PidCode = EHCI_IN;
    EhciControlRead(Transfer, Buffer, &NumBytes);

    // Set PID_CODE to OUT & Send ACK

    Transfer->Qtd->PidCode = EHCI_OUT;

    Token.Pid = USB_PID_ACK;
    EhciControlWrite(Transfer, &Token, 8);
  
    return 0;
}

devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: USB Handshake Not Received (EHCI USB 2.0)

Post by devc1 »

Here is the results, thank you another time !

Image

Image Link
Post Reply