OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:00 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: USB Handshake Not Received (EHCI USB 2.0)
PostPosted: Tue May 17, 2022 2:32 pm 
Offline
Member
Member

Joined: Fri Feb 11, 2022 4:55 am
Posts: 435
Location: behind the keyboard
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:
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:
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:
#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)


Top
 Profile  
 
 Post subject: Re: USB Handshake Not Received (EHCI USB 2.0)
PostPosted: Wed May 18, 2022 8:04 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
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


Top
 Profile  
 
 Post subject: Re: USB Handshake Not Received (EHCI USB 2.0)
PostPosted: Wed May 18, 2022 10:23 am 
Offline
Member
Member

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


Top
 Profile  
 
 Post subject: Re: USB Handshake Not Received (EHCI USB 2.0)
PostPosted: Wed May 18, 2022 11:33 am 
Offline
Member
Member

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

#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;
}



Top
 Profile  
 
 Post subject: Re: USB Handshake Not Received (EHCI USB 2.0)
PostPosted: Wed May 18, 2022 1:16 pm 
Offline
Member
Member

Joined: Fri Feb 11, 2022 4:55 am
Posts: 435
Location: behind the keyboard
[url][/url]Here is the results, thank you another time !

Image

Image Link


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: DotBot [Bot], Google [Bot] and 67 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group