OSDev.org

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

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Tue Jun 20, 2017 2:52 am 
Offline
Member
Member
User avatar

Joined: Sat Oct 23, 2004 11:00 pm
Posts: 154
Hello

I have built XHCI driver and it's working fine with a USB thumb drive - which uses Bulk In/Out endpoints

I am now developing a USB keyboard driver which uses Interrupt In/Out endpoints

If I type slowly then I am able to receive key press + release events for all the keys typed. However, if I type at normal speed (or faster) then some of the key press/release events are not generated - i.e. I don't see them in the event ring. Most of the times, key press events will be missing while corresponding key release events are present in the event ring

I use TR (transfer) ring of size 64. I create 32 "Interrupt IN" TRBs upfront and then upon every Key press/release event, the event handler adds an "Interrupt IN" TRB back onto Transfer ring

Any idea why if I type at normal speed/faster - some of key press/release events are missed out by XHCI controller ?

PS: I can confirm there is no issue with USB keyboard device as I can type fine on windows/Linux :)

Regards
Prajwal

_________________
complexity is the core of simplicity


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Tue Jun 20, 2017 9:14 am 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
Are you sure your XHCI driver is at fault? Maybe you're just interpreting the HID packets wrongly. USB HID does not have dedicated key release packets. A key is simply released when it is not reported as being pressed anymore.

_________________
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Tue Jun 20, 2017 3:44 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Without seeing it in action, via a floppy/harddrive/iso/usb image, or a heck of a lot more details, I can't help you much either. However, one thing that jumps out to me is that you add numerous Interrupt transactions to the schedule, all at once?

There is an "Interval" value in the descriptor that tells you how often to "poll" for data via an interrupt request. You should only send a single request once per this interval. If you send two within this interval, the device may clear its internal buffer thinking you already read the next keystroke.

Again, without much more information, this is just a shot in the dark.

On a different note, have you ran your code under Bochs? If you set the debug setting to show all output (BX_DEBUG), it may help you find out what is going on.

Ben
http://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Tue Jun 20, 2017 6:20 pm 
Offline
Member
Member
User avatar

Joined: Sat Oct 23, 2004 11:00 pm
Posts: 154
Korona wrote:
Are you sure your XHCI driver is at fault? Maybe you're just interpreting the HID packets wrongly. USB HID does not have dedicated key release packets. A key is simply released when it is not reported as being pressed anymore.


Every key press/release on the keyboard is giving me 2 packets (8 bytes each --> processing 2 TRBs on TR Ring --> generating 2 Events on event ring) - the first one has the code for the key that is pressed and the second one with all zeros

BenLunt wrote:
There is an "Interval" value in the descriptor that tells you how often to "poll" for data via an interrupt request. You should only send a single request once per this interval. If you send two within this interval, the device may clear its internal buffer thinking you already read the next keystroke.


I fail to understand this part - in my case, I have a TR ring of size 64. if I have a scheduled task/timer task which will create an 'Interrupt In' transaction every "interval" while I don't press any keys at all for say next 64 * "interval" period - wouldn't the TR ring be full with all the "Interrupt In" TRBs ? Wouldn't that be same situation as 'schedule all at once' ?

Thanks
Prajwal

_________________
complexity is the core of simplicity


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Wed Jun 21, 2017 10:00 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
prajwal wrote:
BenLunt wrote:
There is an "Interval" value in the descriptor that tells you how often to "poll" for data via an interrupt request. You should only send a single request once per this interval. If you send two within this interval, the device may clear its internal buffer thinking you already read the next keystroke.


I fail to understand this part - in my case, I have a TR ring of size 64. if I have a scheduled task/timer task which will create an 'Interrupt In' transaction every "interval" while I don't press any keys at all for say next 64 * "interval" period - wouldn't the TR ring be full with all the "Interrupt In" TRBs ? Wouldn't that be same situation as 'schedule all at once' ?

An HID device, a keyboard for example, returns reports to the Host. These reports contain information about the state of the HID device. A keyboard, for example, will return key status changes in a report. The Keyboard may have a small buffer to contain multiple reports so that they are buffered until the Host reads them. Once the Host reads a report, via the interrupt request, it removes it from the buffer giving room for the next report.

However, when a report is ready, it does not return an interrupt as the PS/2 style keyboard does. Therefore, the host has no way of knowing that a key has been pressed or released. The Host must poll the device by sending out an interrupt request. How does the Host know how often to send out this request? The interrupt endpoint descriptor. Within this descriptor is an interval member.

The one I use for an example with in my book has an interval value of 24ms, meaning that I should send out an interrupt request once every 24ms. This means the the keyboard is capable of creating a report every 24ms, giving a report with a possible change in the status of the keyboard every 24ms. Can you type fast enough to make a key status change once every 24ms? :-)

The keyboard may respond with the same report even though no change has taken place. Therefore, most keyboards support the Set Idle request. This request tells the keyboard to only return a report if there is a change in the state of the keyboard. Sending this request can tell the keyboard to only return a report when a key is pressed or released.

A note: If you send out an interrupt request every 24ms and there is no change which means there is no report to receive, the keyboard may/should return a NAK. Be prepared to expect it.

Once you have setup the keyboard via this Set Idle request, you have parsed the HID report to get the format of the report returned, you can then place an interrupt request on your schedule every 24ms. Most of the interrupt requests will NAK since you can't type fast enough to keep up with a 24ms cycle. However, some of them will return a report.

Pressing a key may return:
00 00 05 00 00 00 00 00

while releasing that key may return:
00 00 00 00 00 00 00 00

There was a change when the key was pressed, so the report was generated and returned. Then there was a change in the report when the key was released, so another report was generated and returned, though this time all zeros because there is nothing to report, other than, there was a change.

If you do not send the Set Idle request, the keyboard may return:

00 00 05 00 00 00 00 00
00 00 05 00 00 00 00 00
...
00 00 05 00 00 00 00 00
00 00 05 00 00 00 00 00

repeatedly until the key is released. Then the keyboard may return:

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
...
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

repeatedly until there is another change in the keyboard.

Look up the Set Idle request to see more about it. It should be sent as:

21 0A 00 00 00 00 00 00

Does this now make sense? Kind of?

Ben
http://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Wed Jun 21, 2017 1:59 pm 
Offline
Member
Member
User avatar

Joined: Wed Aug 17, 2016 4:55 am
Posts: 251
BenLunt wrote:
Can you type fast enough to make a key status change once every 24ms? :-)

Not long ago I was working on helping document a rare keyboard (custom protocol) which would return up to 15 bytes worth of data each time it was polled (it gimmicked PS/2 set 2 scancodes, so worst case would be 7 key releases). We were polling it at 60Hz (around 16.67ms per polling), and surely nobody can press/release keys fast enough to make it a problem, right?

Yeah, about that... I could nearly fill the buffer without much trouble in those 16ms. Consistently (・_・; )


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Thu Jun 22, 2017 11:31 am 
Offline
Member
Member

Joined: Thu Aug 13, 2015 4:57 pm
Posts: 384
With regards to the polling intervals, don't forget gamers. With 24ms polling interval in worst case it's possible that the polling just ended and then right then a key down is registered by the keyboard and it won't be noticed by the OS until 24ms later. I'd say that's absurdly bad.

I'd like to see the latency in the us (microsecond) range, at which point it shouldn't matter, also note that while 1ms might be unnoticeable for most intents and purposes in worst case it might make a difference, and more importantly, in most cases the latencies add up. Consider server sending game state update, local game code processes it, sends update to 3D driver which does its own processing, sends screen update to display which might take another 1/60th of a second to update actual screen, then user reacts and presses key and is granted another 24ms of delay...

Also, if it takes 24ms (at worst, avg 12ms) for the key to be reported to OS and an app takes say 24ms to update it's window then the ~50ms latency may become irritating, where with 1ms keyboard latency it would only be 25ms..


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Thu Jun 22, 2017 1:49 pm 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
The interval is reported by the device itself (as defined by the USB standard). Higher quality devices will allow changing the polling rate. My mouse has a default polling rate of 2 ms and lets you specify up to 1 ms.

_________________
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Fri Jun 23, 2017 7:18 pm 
Offline
Member
Member
User avatar

Joined: Sat Oct 23, 2004 11:00 pm
Posts: 154
Hi Ben

Thanks a lot for the explanation. The information I provided was insufficient to identify the cause (I just put my observations and I wasn't sure either) but still your explanation made me go back and check in detail the way I configured interrupt endpoint and there the culprit was... !

My mistake was I didn't setup 3 values on interrupt endpoint:-
1. Max Burst Size --> In my case, it is 'zero' so no impact but still added code to properly set this with wMaxPacketSize & 1800 >> 11
2. Max ESIT Payload --> I was setting this to zero. In my case, it is 8 bytes --> wMaxPacketSize * (maxBurstSize + 1)
3. Interval --> This was the main thing I was getting wrong... I was setting this to the value bInterval but then I read the XHCI spec again and found that for LS/FS interrupt endpoints it should be nearest base 2 multiple of bInterval * 8 !!. In my case, I was earlier setting this to bInterval = "10", now after the fix, it is set to "6" (2 ^ 6 ~ (10 * 8))
Fix in (3) got my USB keyboard working as smooth as it can.. :)

However, I still don't understand few things:- Based on your explanation, it seems like whenever a TD is added to Interrupt IN endpoint every 'interval' period, XHCI should process it right away ? But, what I am observing in my case is this:-
1. I post a TD on Interrupt IN endpoint every "interval" milliseconds
2. My Interrupt Transfer Ring is of size 64 (63 + 1 Link TD)
3. If I don't press any keys, all the TDs I posted gets filled into Transfer Ring - which is 63 TDs in total
4. Because the Transfer Ring is now full, the scheduler stops (actually waits) posting any further TDs into Interrtup IN endpoint
5. Now if I press a keyboard key, I then see TDs getting processed and reported back on event ring starting from 1st TD i.e, I mean TDs are processed only when a key is pressed

If this is how Interrupt IN endpoint transfer ring schedules are to work then why should I add/post TDs into Interrupt IN endpoint every interval period ? It will anyways stop after filling the Transfer Ring. Why can't I upfront add 63 TDs into the Transfer Ring and add a new TD every time an event on the event Ring is processed upon IRQ (i.e. every time I press a key, 2 TDs will be processed and I will then add 2 more TDs back at the end of Transfer ring)

6. Also, I didn't find anything about how to handle NAK. How does XHCI report a NAK back ? I don't find anything on EventTRB that tells it's a NAK - is it EventTRB with CompletionCode (CC) = 1 ?

Thanks
Prajwal

_________________
complexity is the core of simplicity


Top
 Profile  
 
 Post subject: Re: XHCI USB Keyboard - Missing key press events (Slow)
PostPosted: Sun Jun 25, 2017 6:06 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Sorry for the late reply.

It has been a little while since I worked with a keyboard on the xHCI, so this is from memory.

You need to send an interrupt in (but for some reason, bulk in comes to mind) every interval. Then if nothing is available, the device will return a NAK (and possibly stall). If it stalls, you need to send a Clear Stall setup packet. (actually any Setup Packet clears a stall). The TD is now considered dead, whether it was successful or not. The controller processed the TD and your schedule should have processed that TD. Therefore it is dead.

The TD ring should, aside from other devices, be completely empty until another interval takes place.

Here is an example of what could be done:
Code:
  while (1) {
    while (now < next_interval)
      ;
    res = insert_TD_on_xHCI_ring();
    if (res == STALL)
      send_clear_stall();
    if (res == SUCCESS)
      insert_key_pressed_into_kernels_key_buffer()
  }

Of course you need a much more detailed code base, but you get the idea.

Does this help? To be more detailed, I would have to get out my notes.

Ben


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Majestic-12 [Bot] and 62 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