Re: Busted keyboard, fix, and Question about default HID device plumbing
From: Terry Lambert <hidden>
Date: 2011-10-07 23:09:39
Whoops. Flip those last two bit decodes! -- Terry On Fri, Oct 7, 2011 at 4:01 PM, Terry Lambert [off-list ref] wrote:
Thanks for replying, Dmitry... I guess I need to clarify a point or two. On Fri, Oct 7, 2011 at 3:07 PM, Dmitry Torokhov [off-list ref] wrote:quoted
Hi Terry, On Fri, Oct 07, 2011 at 01:44:29PM -0700, Terry Lambert wrote:quoted
I have a USB keyboard that needs a workaround. I know what the workaround is, but not where to plumb it in. This is apparently an issue with a number of keyboards from a number of vendors, and Mac OS X and Windows both work around it. It impacts all Linux desktops, Android, and Chrome OS for a number of popular folding keyboards, as well as other keyboards. I'm perfectly able to write the workaround, and have done so using the boot protocol, but now I want to fix the issue in the default stack used for the console. I don't care about the UHCI/EHCI plumbing, or anything up to hiddev; but from there it gets murky as to how an event in the raw driver ends up getting turned into a keyboard key. It appears to be lost in callbacks I'm having a hard time tracing through. I've read three books on the Linux USB system, two of them very out of date, and they're all written from the perspective of "So, you want to write a device driver", rather than the perspective of "This book documents the plumbing between the driver and userspace and how to figure it out". So the question is: how are things plumbed between hiddev and the console driver,They aren't. Or maybe we are talking about different "hiddev"s. The generic HID driver binds devices to hid-input which registers them with input core as separate input devices. The legacy console registers a separate input handler (see drivers/tty/vt/keyboard.c) that binds to all keyboard-like devices, listens to input events and converts them to keystrokes and sends them to tty.My question is "who processes USB report packets from a USB keyboard into EV_KEY events?" I understand that there's a separate evdev handler that publishes raw events as /dev/input/eventX. It's handling the events from somewhere, but it's not clear to me how a hidraw1 event turns into a console input event. Somewhere someone is translating a USB 1.11 section 8.3 report into an EV_KEY, and I need to do the modifier magic to alter the contents of the reports before it gets to whoever that is. You seem to be saying hid-input.c ... but I'm not seeing the modifier bits being processed out of the report?quoted
There is also a evdev input handler (that's where evtest utility gets its data from) that provides input event data to userspace via /dev/input/eventX nodes where X picks it does its own thing with it.quoted
so I can figure out where I need to hack on the events. I just need to know the correct place/method to interpose the events. Any help would be appreciated. Thanks, -- Terry PS: For the curious: I put a USB protocol analyzer on this thing, and discovered the problem. The issue is that modifier keys are not reported in the bitmap on the keyboard, and are instead signaled as in-band key events themselves. The Mac OS X and Windows drivers work around the issue by pre-processing the event stream looking for in-band modifier keys, and then converting them into bit-sets in the (0'ed) bitmap of modifier keys, and then dropping them from the key event stream. Without the workaround, the report order is such that it looks like a modifier up report followed by a keystroke. Here's evtest output for the sequence after processing by the (unknown to me -- that's what I'm trying to find out) code: Event: time 1318019769.922534, type 4 (Misc), code 4 (ScanCode), value 700e1 Event: time 1318019769.922550, type 1 (Key), code 42 (LeftShift), value 1 Event: time 1318019769.922554, -------------- Report Sync ------------ Event: time 1318019770.082521, type 4 (Misc), code 4 (ScanCode), value 700e1 XXXX Event: time 1318019770.082534, type 1 (Key), code 42 (LeftShift), value 0 XXXXHmm, so the shift is reported as released before we get the next key... Wierd...quoted
Event: time 1318019770.082549, type 4 (Misc), code 4 (ScanCode), value 7001e Event: time 1318019770.082553, type 1 (Key), code 2 (1), value 1 Event: time 1318019770.082555, -------------- Report Sync ------------ 1Event: time 1318019770.242541, type 4 (Misc), code 4 (ScanCode), value 7001e Event: time 1318019770.242552, type 1 (Key), code 2 (1), value 0 Event: time 1318019770.242555, -------------- Report Sync ------------ This is a shift-1. The patch for usbkbd.c looks like this:diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 0658173..d22ecdb 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c@@ -2,6 +2,10 @@* Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support + * + * Device Class Definition for Human Interface Devices (HID) Version 1.11 + * Section 8.3 describes the report formant. + * http://www.usb.org/developers/devclass_docs/HID1_11.pdf */ /*@@ -97,6 +101,16 @@ static void usb_kbd_irq(struct urb *urb)goto resubmit; } + /* Convert in-band modifier keys to modifier bits */ + for (i = 2; i < 8; i++) { + if (kbd->new[i] >= 0xE0 && kbd->new[i] <= 0xE7) { + kbd->new[0] |= (1 >> (kbd->new[i] - 0xE0)); + kbd->new[i] = 0; + } + }Wait, why are you using usbkbd? Unless you have very compelling reason you should be using hid & hid-input.I fixed it there because it was accessible and a way to test the fix. I'm also going to have to do something similar for coreboot/u-boot to allow the keyboard to be used in the boot loader, so it's not wasted effort, and it was an OK proof of concept. So there was a good reason. I'm getting the impression from the above that the file I should be looking in is: drivers/hid/hid-input.c Where are the modifier bits being decoded there? Maybe I'm just not seeing something in front of me... The analyzer reports the USB over the wire report as: <-- left shift key down --> 00 00 E1 00 00 00 00 00 <- transaction 69 82 18 <- input packet 48 00 00 E1 00 00 00 00 00 A8 45 <-- breakout : <-- Keyboard LeftControl : 0b0 Keyboard LeftShift : 0b0 <-- ***WRONG *** Keyboard LeftAlt : 0b0 Keyboard LeftGUI : 0b0 Keyboard RightControl : 0b0 Keyboard RightShiftl : 0b0 Keyboard RightAlt : 0b0 Keyboard RightGUI : 0b0 Keyboard/Keypad Array : Keyboard LeftShift (225) <-- ***WRONG *** Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : --> <-- 1 key down --> 00 00 E1 1E 00 00 00 00 <- transaction 69 82 18 <- input packet C3 00 00 E1 1E 00 00 00 00 A8 45 <-- breakout : <-- Keyboard LeftControl : 0b0 Keyboard LeftShift : 0b0 <-- ***WRONG *** Keyboard LeftAlt : 0b0 Keyboard LeftGUI : 0b0 Keyboard RightControl : 0b0 Keyboard RightShiftl : 0b0 Keyboard RightAlt : 0b0 Keyboard RightGUI : 0b0 Keyboard/Keypad Array : Keyboard LeftShift (d225) <-- *** WRONG *** Keyboard/Keypad Array : Keyboard 1 and ! (d30) Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 --> <-- 1 key up -- > 00 00 E1 00 00 00 00 00 <- transaction 69 82 18 <- input packet 48 00 00 E1 00 00 00 00 00 A8 45 <-- breakout : <-- Keyboard LeftControl : 0b0 Keyboard LeftShift : 0b0 Keyboard LeftAlt : 0b0 Keyboard LeftGUI : 0b0 Keyboard RightControl : 0b0 Keyboard RightShiftl : 0b0 Keyboard RightAlt : 0b0 Keyboard RightGUI : 0b0 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 Keyboard/Keypad Array : 00 --> <-- left shift key up --> 00 00 00 00 00 00 00 00 <- transaction 69 82 18 <- input packet 48 00 00 00 00 00 00 00 00 BF F4 <-- breakout : <-- Keyboard LeftControl : 0b0 Keyboard LeftShift : 0b0 <-- ***WRONG *** Keyboard LeftAlt : 0b0 Keyboard LeftGUI : 0b0 Keyboard RightControl : 0b0 Keyboard RightShiftl : 0b0 Keyboard RightAlt : 0b0 Keyboard RightGUI : 0b0 Keyboard/Keypad Array : Keyboard LeftShift (225) <-- ***WRONG *** Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : Keyboard/Keypad Array : --> I just need to know where in the code to stomp the report into correctness. Should make a bunch of people happy. 8-) Thanks, -- Terryquoted
Thanks. -- Dmitry
-- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html