thefloweringash / iousbhiddriver-descriptor-override

Fix broken USB HID descriptors. Now with Noppoo Choc Mini support!
http://thefloweringash.github.io/iousbhiddriver-descriptor-override
GNU Lesser General Public License v3.0
204 stars 25 forks source link

Varmilo VA87M #17

Open randalla0622 opened 9 years ago

randalla0622 commented 9 years ago

I was hoping that I might find a solution to allow this stubborn keyboard to work on OS X. It is from Varmilo, which seems to be a sister company to Leopold, and the board itself may be somewhat related to the FC750R, though it's pure speculation on my part.

I followed the instructions to build the kernel extension here, and had no issues with that. I tried the rake scan process, but it did not appear to output anything accept to the terminal itself, and just to make sure I make sure no existing descriptors folder existed before I ran it. It identified my mouse and apple keyboard to the screen, created a descriptors folder, but did not actually create any descriptor files. Seems like this board does not appear in it's list.

Using USB Overdrive I see that the board does show as two completely different USB interfaces, one with 49 programmable keys and the other with 48. Nothing on the board functions at all when plugged into either of my Macs, which are a mid-2012 mini and Macbook Pro). This also includes the controls for non-host things like the back-light.

One thing I did notice that was interesting is that on my Macbook Pro I have the full disk encryption enabled (FileVault). During boot where it asks me for my password, the keyboard does work there, which I believe is in the land of EFI.

I have also been told that the keyboard works in Linux, not that that's much help I'm sure.

Your thoughts, and suggestions are most welcome.

Adam.

dr-jam commented 9 years ago

It looks like we've both been burned by the same Massdrop >< The "Unsupported Devices" instructions for building this kext also failed me by not producing a yaml file (I'm assuming that's what it was supposed to do) to be mapped into the Info.plist. Coming loaded with absolutely no experience with the inner workings of USB devices or this particular driver, I created my own called va87m.yaml (is there magic to the numbers before the names of the other .yaml files?) with the following contents:

---
- idVendor: 65535
  idProduct: 4174
  bcdDevice: 258
  bConfigurationValue: 1
  bInterfaceNumber: 0
  hidReportDescriptor: !binary |-
    BQEJBqEBBQgZASkDFQAlAXUBlQORApUFkQEFBxngKeeVCIECGQQpJwktCS4JLwkwCTEJMwk0CTYJ
    Nwk4CTUJLAk5CSgJK5UzgQIZSilOlQWBAsA=

- idVendor: 65535
  idProduct: 4174
  bcdDevice: 258
  bConfigurationValue: 1
  bInterfaceNumber: 1
  hidReportDescriptor: !binary |-
    BQwJAaEBhQEZACo8AhUAJjwClQF1EIEAwAUBCQahAYUDBQcZ4CnnFQAlAXUBlQiBAhk5KWUJKQkq
    CUkVACUBlTCBAsA=

So far, this has not produced good results (the character spam from pressing keys on the va87m has changed to different character spam) after repeating the "build" portion of the installation instructions. In particular, only one IOUSBHIDDriverDescriptorOverride is present when I expected two:

$ ioreg -b -f | grep IOUSBHIDDriverDescriptorOverride
    | | | |     | +-o IOUSBHIDDriverDescriptorOverride  <class IOUSBHIDDriverDescriptorOverride, id 0x100000ac5, registered, matched, active, busy 0 (3 ms), retain 10>

Any advice would be appreciated.

The HID report descriptors were mapped into YAML binary via the following Python script:

import yaml

descriptor0 = bytes([
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x08,  0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01,  
0x75, 0x01, 0x95, 0x03, 0x91, 0x02, 0x95, 0x05,  0x91, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7,  
0x95, 0x08, 0x81, 0x02, 0x19, 0x04, 0x29, 0x27,  0x09, 0x2D, 0x09, 0x2E, 0x09, 0x2F, 0x09, 0x30,  
0x09, 0x31, 0x09, 0x33, 0x09, 0x34, 0x09, 0x36,  0x09, 0x37, 0x09, 0x38, 0x09, 0x35, 0x09, 0x2C,  
0x09, 0x39, 0x09, 0x28, 0x09, 0x2B, 0x95, 0x33,  0x81, 0x02, 0x19, 0x4A, 0x29, 0x4E, 0x95, 0x05,  
0x81, 0x02, 0xC0])
print(yaml.dump(descriptor0))

descriptor1 = bytes([
0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x01,  0x19, 0x00, 0x2A, 0x3C, 0x02, 0x15, 0x00, 0x26,
0x3C, 0x02, 0x95, 0x01, 0x75, 0x10, 0x81, 0x00, 0xC0, 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x85, 
0x03, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 
0x02, 0x19, 0x39, 0x29, 0x65, 0x09, 0x29, 0x09, 0x2A, 0x09, 0x49, 0x15, 0x00, 0x25, 0x01, 0x95,
0x30, 0x81, 0x02, 0xC0])
print(yaml.dump(descriptor1))

The following is all the device information I could dig up given the USB Prober tool in the mac hardware dev kit (it includes the HID request descriptors used above in hex):

Full Speed device @ 1 (0x14100000): .............................................   Composite device: "zhihaihe  keyboard"
    Port Information:   0x101a
           Not Captive
           Attached to Root Hub
           External Device
           Connected
           Enabled
           Connected to External Port
    Number Of Endpoints (includes EP0):   
        Total Endpoints for Configuration 1 (current):   3
    Device Descriptor   
        Descriptor Version Number:   0x0200
        Device Class:   0   (Composite)
        Device Subclass:   0
        Device Protocol:   0
        Device MaxPacketSize:   64
        Device VendorID/ProductID:   0xFFFF/0x104E   (unknown vendor)
        Device Version Number:   0x0102
        Number of Configurations:   1
        Manufacturer String:   1 "zhihaihe elec c0"
        Product String:   2 "zhihaihe  keyboard"
        Serial Number String:   3 "Ver1.0 N001"
    Configuration Descriptor (current config)   
        Length (and contents):   59
            Raw Descriptor (hex)    0000: 09 02 3B 00 02 01 00 A0  F4 09 04 00 00 01 03 01  
            Raw Descriptor (hex)    0010: 01 00 09 21 11 01 00 01  22 53 00 07 05 81 03 08  
            Raw Descriptor (hex)    0020: 00 0A 09 04 01 00 01 03  00 00 00 09 21 11 01 00  
            Raw Descriptor (hex)    0030: 01 22 44 00 07 05 82 03  08 00 0A 
        Number of Interfaces:   2
        Configuration Value:   1
        Attributes:   0xA0 (bus-powered, remote wakeup)
        MaxPower:   488 mA
        Interface #0 - HID/Boot Interface   
            Alternate Setting   0
            Number of Endpoints   1
            Interface Class:   3   (HID)
            Interface Subclass;   1   (Boot Interface)
            Interface Protocol:   1
            HID Descriptor   
                Descriptor Version Number:   0x0111
                Country Code:   0
                Descriptor Count:   1
                Descriptor 1   
                    Type:   0x22  (Report Descriptor)
                    Length (and contents):   83
                        Raw Descriptor (hex)    0000: 05 01 09 06 A1 01 05 08  19 01 29 03 15 00 25 01  
                        Raw Descriptor (hex)    0010: 75 01 95 03 91 02 95 05  91 01 05 07 19 E0 29 E7  
                        Raw Descriptor (hex)    0020: 95 08 81 02 19 04 29 27  09 2D 09 2E 09 2F 09 30  
                        Raw Descriptor (hex)    0030: 09 31 09 33 09 34 09 36  09 37 09 38 09 35 09 2C  
                        Raw Descriptor (hex)    0040: 09 39 09 28 09 2B 95 33  81 02 19 4A 29 4E 95 05  
                        Raw Descriptor (hex)    0050: 81 02 C0 
                    Parsed Report Descriptor:   
                          Usage Page    (Generic Desktop) 
                          Usage (Keyboard)    
                              Collection (Application)    
                                Usage Page    (LED) 
                                Usage Minimum...........    (1)  
                                Usage Maximum...........    (3)  
                                Logical Minimum.........    (0)  
                                Logical Maximum.........    (1)  
                                Report Size.............    (1)  
                                Report Count............    (3)  
                                Output..................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) 
                                Report Count............    (5)  
                                Output..................   (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) 
                                Usage Page    (Keyboard/Keypad) 
                                Usage Minimum...........    (224)  
                                Usage Maximum...........    (231)  
                                Report Count............    (8)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                                Usage Minimum...........    (4)  
                                Usage Maximum...........    (39)  
                                Usage 45 (0x2d)    
                                Usage 46 (0x2e)    
                                Usage 47 (0x2f)    
                                Usage 48 (0x30)    
                                Usage 49 (0x31)    
                                Usage 51 (0x33)    
                                Usage 52 (0x34)    
                                Usage 54 (0x36)    
                                Usage 55 (0x37)    
                                Usage 56 (0x38)    
                                Usage 53 (0x35)    
                                Usage 44 (0x2c)    
                                Usage 57 (0x39)    
                                Usage 40 (0x28)    
                                Usage 43 (0x2b)    
                                Report Count............    (51)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                                Usage Minimum...........    (74)  
                                Usage Maximum...........    (78)  
                                Report Count............    (5)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                              End Collection     
            Endpoint 0x81 - Interrupt Input   
                Address:   0x81  (IN)
                Attributes:   0x03  (Interrupt)
                Max Packet Size:   8
                Polling Interval:   10 ms
        Interface #1 - HID   
            Alternate Setting   0
            Number of Endpoints   1
            Interface Class:   3   (HID)
            Interface Subclass;   0
            Interface Protocol:   0
            HID Descriptor   
                Descriptor Version Number:   0x0111
                Country Code:   0
                Descriptor Count:   1
                Descriptor 1   
                    Type:   0x22  (Report Descriptor)
                    Length (and contents):   68
                        Raw Descriptor (hex)    0000: 05 0C 09 01 A1 01 85 01  19 00 2A 3C 02 15 00 26  
                        Raw Descriptor (hex)    0010: 3C 02 95 01 75 10 81 00  C0 05 01 09 06 A1 01 85  
                        Raw Descriptor (hex)    0020: 03 05 07 19 E0 29 E7 15  00 25 01 75 01 95 08 81  
                        Raw Descriptor (hex)    0030: 02 19 39 29 65 09 29 09  2A 09 49 15 00 25 01 95  
                        Raw Descriptor (hex)    0040: 30 81 02 C0 
                    Parsed Report Descriptor:   
                          Usage Page    (Consumer) 
                          Usage 1 (0x1)    
                              Collection (Application)    
                                ReportID................    (1)  
                                Usage Minimum...........    (0)  
                                Usage Maximum...........    (572)  
                                Logical Minimum.........    (0)  
                                Logical Maximum.........    (572)  
                                Report Count............    (1)  
                                Report Size.............    (16)  
                                Input...................   (Data, Array, Absolute) 
                              End Collection     
                          Usage Page    (Generic Desktop) 
                          Usage (Keyboard)    
                              Collection (Application)    
                                ReportID................    (3)  
                                Usage Page    (Keyboard/Keypad) 
                                Usage Minimum...........    (224)  
                                Usage Maximum...........    (231)  
                                Logical Minimum.........    (0)  
                                Logical Maximum.........    (1)  
                                Report Size.............    (1)  
                                Report Count............    (8)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                                Usage Minimum...........    (57)  
                                Usage Maximum...........    (101)  
                                Usage 41 (0x29)    
                                Usage 42 (0x2a)    
                                Usage 73 (0x49)    
                                Logical Minimum.........    (0)  
                                Logical Maximum.........    (1)  
                                Report Count............    (48)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                              End Collection     
            Endpoint 0x82 - Interrupt Input   
                Address:   0x82  (IN)
                Attributes:   0x03  (Interrupt)
                Max Packet Size:   8
                Polling Interval:   10 ms
thefloweringash commented 9 years ago

Hi,

In the case of @randalla0622, where nothing from the keyboard works at all, that's hard to work with. If you're motivated, I've pushed a utility (in hid_report_dumper) that will show raw hid reports and might help with debugging. It's quite rough around the edges.

Looking at the descriptor in @dr-jam's post, it looks like the exact thing this project sets out to solve. I'm a little surprised it didn't JustWork™. There's no magic in the name for the .yaml files, it's just the PID/VID to keep the files separate. Using the file you pasted, the modified descriptor looks sensible. Can you give an example of the key spam you're seeing? You might also find the hid_report_dumper useful for debugging.

Cheers, Andrew

randalla0622 commented 9 years ago

I have a second one that is working as intended. I don't know why the one that I had to evaluate is not typing anything where my second one is sending out a flurry of keys. I'll post some keys from my personal board tomorrow (as it's not hooked up at the moment).

randalla0622 commented 9 years ago
A: k/
B: ik,/
C: jk./
D: ijk,./
E: l`
F: il,`
G: jl.`
H: ijl,.`
I: kl/`
J: ikl,/`
K: jkl./`
L: ijkl,./`
M: m<space>
N: im,<space>
O: jm.<space>
P: ijm,.<space>
Q: km/<space>
R: ikm,/<space>
S: jkm./<space>
T: ijkm,./<space>
U: lm`<space>
V: ilm,`<space>
W: jlm.`<space>
X: ijlm,.`<space>
Y: klm/`<space>
Z: iklm,/`<space>

`: ikmn,/<space><capslock>
1: jklm./`<space>
2: ijklm,./`<space>
3: n<capslock>
4: in,<capslock>
5: jn.<capslock>
6: ijn,.<capslock>
7: kn/<capslock>
8: ikn,/<capslock>
9: jkn./<capslock>
0: ijkn,./<space>caps
-: ikln,/`<capslock>
=: jkln./`<capslock>
[: mn<space><capslock>
]: imn,<space><capslock>
\: jmn.<space><capslock>
;: ijmn,.<space><capslock>
': kmn/<space>caps
,: jkmn./<space><capslock>
.: ijkmn,./<space><capslock>
/: lmn`<space><capslock>

ESCAPE: iln,`<capslock>
BS: jln.`<capslock>
TAB: ijln,.`<capslock>
CAPS: ilmn,`<space><capslock>
LSHIFT: nothing
RSHIFT: nothing
LCTRL: nothing
LWIN: nothing
LALT: nothing
SPACE: kln/`<capslock>
RALT: nothing
RWIN: nothing
FN: mnop<space><enter><tab>
RCTRL: nothing

PRINTSCREEN: jko./<enter>
SCROLLLOCK: ijko,./<enter>
PAUSE: lo`<enter>
INSERT: ilo,`<enter>
HOME: jlo.`<enter>
PAGEUP: ijlo,.`<enter>
DELETE: klo/`<enter>
END: iklo,/`<enter>
PAGEDOWN: jklo./`<enter>

UP: jmo.<space><enter>
DOWN: imo,<space><enter>
LEFT: mo<space><enter>
RIGHT: ijklo,./`<enter>
dr-jam commented 9 years ago

Unfortunately I am going to say the following in a vague, cryptic way: while playing with the hid_report_dumper, I reached a mode where nearly all of the keyboard's functionality worked. This included media keys and changing the led light level (fn+up and down arrows). However, I cannot reliably reproduce this state.

This seems to happen in at least two steps: 1) Through simultaneous pressing many keys around the enter key (approximately the area starting at f9 and extending to right control -- perhaps print screen through delete as well), the report id from 0 to 3 and the report size went from 8 to 3 on the second interface. 2) This allowed fn+f6 and fn+f7 to toggle between the original report size and report id. After experimenting, these fn+f{6,7} combos moved the location of where the keys a-Z were reported: from byte 3 to byte 2 as shown by the hid_report_dumper.

This holds true both when the IOUSBH driver descriptor is or is not overridden (the kernel extension was removed by using kextunload and deleting System/Library/Extensions/IOUSBHIDDriverDescriptorOverride.kext).

Speculation leads me to believe that there are key combinations for changing how the board orders its output. I'm new to both mechanical keyboards and the inner workings of USB -- is this common or reasonable?

The commands used to remove the kernel extension:

sudo kextunload \
    /System/Library/Extensions/IOUSBHIDDriverDescriptorOverride.kext
sudo rm -rf \
    /System/Library/Extensions/IOUSBHIDDriverDescriptorOverride.kext

For reference, here is the keyboard spam for the yaml files I posted earlier: [a-z] k ik jk ijk l il jl ijl kl ikl jkl ijkl m im jm ijm km ikm jkm ijkm lm ilm jlm ijlm klm iklm [A-Z] K QS QRTU IJK L IL JL IJL ST IKL RST QRST U QU RU QRU KM IKM JKM IJKM LM QTU JLM KM KLM QSTU [1-0] jklm ijklm n in jn ijn kn ikn jkn ijkn

CollinCunningham commented 9 years ago

I tried similar steps as dr-jam which produced the same multi-character output. In addition, I noticed pressing Fn+up arrow outputs: “JUVWX.NO PROBLEM” Perhaps there is some device initialization message that’s not being sent by OS X?

I also tried connecting the board to the Arduino Yun running OpenWrt Linux. Everything seems to function except for the LED indicators for Caps Lock & Scroll Lock. I can see the board mounts as two separate interfaces recorded as event1 & event2 event2 handles: backspace, arrow keys, insert, escape, F1 -> F12, print screen, scroll lock, pause all other keys come in on event1

thefloweringash commented 9 years ago

HID keyboards have a simple mode (boot protocol) for environments where doing full HID isn't an option, it's a simple well-known descriptor that sends key state through as an array of up to 6 bytes. When the operating system takes over from the low level, it's meant to issue SET_PROTOCOL and then use the descriptor supplied by the device.

The output above looks like the keyboard is sending boot-protocol style reports, but they're being interpreted by the OS as the bitfield. Pressing two keys at once should take you further through the alphabet.

I don't know why these keyboards aren't running in the normal high level mode, but it's worth sending the SET_REPORT request to see if they respond to it. I've pushed a script in scripts/set-protocol.rb, which works on my Noppoo.

randalla0622 commented 9 years ago

Hey Andrew, do you happen to be in the Seattle area?

Adam Randall http://www.xaren.net AIM: blitz574 Twitter: @randalla0622

"To err is human... to really foul up requires the root password." On Dec 15, 2014 11:13 PM, "Andrew Childs" notifications@github.com wrote:

HID keyboards have a simple mode (boot protocol) for environments where doing full HID isn't an option, it's a simple well-known descriptor that sends key state through as an array of up to 6 bytes. When the operating system takes over from the low level, it's meant to issue SET_PROTOCOL and then use the descriptor supplied by the device.

The output above looks like the keyboard is sending boot-protocol style reports, but they're being interpreted by the OS as the bitfield. Pressing two keys at once should take you further through the alphabet.

I don't know why these keyboards aren't running in the normal high level mode, but it's worth sending the SET_REPORT request to see if they respond to it. I've pushed a script in scripts/set-protocol.rb, which works on my Noppoo.

— Reply to this email directly or view it on GitHub https://github.com/thefloweringash/iousbhiddriver-descriptor-override/issues/17#issuecomment-67121099 .

thefloweringash commented 9 years ago

Not even close sorry, I'm in New Zealand.

CollinCunningham commented 9 years ago

thnx - should we test the script by running it specifically or would it be utilized in the compiled kext?

thefloweringash commented 9 years ago

The script is standalone. By default it will send SET_PROTCOL with REQUEST_PROTOCOL to every hid device. You can restrict the devices with -v vendor-id and -p product-id. The protocol can be specified with -P, where -P 1 is request protocol (high level mode, bitset) and -P 0 is boot protocol (low level mode, literal bytes).

Example usage:

./scripts/set-protocol.rb -v 0xFFFF -p 0x104E -P 1
CollinCunningham commented 9 years ago

Thanks for clarifying. Sadly, there's no change in behavior after running the script.

$ ./scripts/set-protocol.rb -v 0xFFFF -p 0x104E -P 1
{:bClass=>3, :idVendor=>65535, :idProduct=>4174}
Setting report on device: #<LIBUSB::Device 250/8 ffff:104e zhihaihe elec c0 zhihaihe  keyboard Ver1.0 N001 (HID (01,01), HID (00,00))>
    interface: #<LIBUSB::Interface 0>
    interface: #<LIBUSB::Interface 1>

and -P 0 yielded the same results.

Proletariat99 commented 9 years ago

I hope you guys can pull this off, since you're our best hope at this point. I'd try to throw in something useful, but you've already far surpassed my knowledge. Let me know if I can help test anything (2008 Late MBP 2.53 + Mid 2014 MBP 2.8 i7.) or provide add'l datas.

Thanks for the map, randall, I was working on that myself, but you've already done it! Awesome.

randalla0622 commented 9 years ago

Hopefully it's a use to someone :)

berkfrei commented 9 years ago

I'm with Proletariat99, I'm rooting for you guys and I wish I could be of more help! God Speed.

bluerise commented 9 years ago

Any update on this? Am thinking about buying one of these myself, but if it's broken on OSX...

randalla0622 commented 9 years ago

I've heard nothing, unfortunately.

charlespeach commented 9 years ago

@randalla0622 I am thinking about pulling the trigger on one of these boards, as my leopold FC660M's are starting to test my patients when writing markdown documents and such.

If you havent got very far yet, are you still on the mission to get it working? and if so, do you want help finishing it?

Proletariat99 commented 9 years ago

I love this keyboard and have actually scheduled a return because it seemed prohibitively hard for me, a MK neophyte, to figure out what in the hell these bastards did with this keyboard and why they're unwilling to help us.

That being said, if you're a linux guy and want to buy for a few bucks off of MD, lemme know :)

On Tue, Feb 17, 2015 at 2:36 PM, Charles Peach notifications@github.com wrote:

@thefloweringash https://github.com/thefloweringash I also live in NZ, Wellington to be precise. I am thinking about pulling the trigger on one of these boards, as my leopold FC660M's are starting to test my patients when writing markdown documents and such.

If you havent got very far yet, are you still on the mission to get it working? and if so, do you want help finishing it?

— Reply to this email directly or view it on GitHub https://github.com/thefloweringash/iousbhiddriver-descriptor-override/issues/17#issuecomment-74759136 .

charlespeach commented 9 years ago

@Proletariat99 where in the world are you? Also what switches? I am keen to replace my home keyboard also. My email address is on my github profile

Edit: I see you are Colorado, I am in New Zealand so would need to know total cost incl cheapest shipping

dennis-nguyen commented 9 years ago

@Proletariat99

I had to make an account just to post this. If the sales with charlespeach falls through, let me know, I am looking for mx clears :)

thefloweringash commented 9 years ago

@charlespeach I haven't made any progress on this bug yet, mostly because I don't have the hardware to poke. If you do get one I would like to spend some time with to see what I can do. Can't make any promises though.

waldofe commented 8 years ago

What a sad end of discussion :/

I would definitely lend the hardware if I were geographically closer to you @thefloweringash. But thanks for the initiative.

So if there's any interested one around brazilian region, I got a VA87MD w/ black case, mint key caps, white cherry mx.