Friday, August 22, 2014

Capturing the Azio Keyboard Data

By the time I had replaced every component of my computer, including the mouse, I thought hey, why not the keyboard too? As I mentioned in the first part of this series of posts, I got an Azio L70 Gaming Keyboard. The last thing I expected was for it to not work on Linux. To be honest, it did not even occur to me that might be a possibility. I scrutinized every single piece of hardware I bought for my new computer, making sure they would all place nice with Kubuntu, except the keyboard.

Mistakenly I thought all keyboards used a standard protocol. Although, the device reported itself as a standard HID compliant device, the Linux usbhid driver was not receiving all key-presses. In particular the Ctrl, Alt and Meta (Windows) keys did nothing.

After verifying on Azio’s website that Linux really was not supported, I made the decision to attempt to write a driver for it. The first step toward my goal was reverse engineering the protocol. Again, it clearly was not standard, so what was it?

In order to understand what was going on I needed some way to read the raw I/O that was going over the USB bus. After a brief bit of searching, I found out that with the usbmon driver, Wireshark can do just that.

See: http://macgyverque.net/2012/12/03/monitoring-usb-traffic-using-wireshark-under-linux/

There were a few hoops to jump through in order to get things to work. First, ensure that you have the usbmon kernel module installed. I will leave it as an exercise for the reader to determine the specific instructions for their distro. You will also need to insert the module into the kernel, if it is not by default. On Kubuntu I ran:

$ lsmod | grep usbmon
$ sudo modprobe usbmon

When you first run Wireshark you will not see any interfaces to capture. You need extra priviledges to do that. This makes sense since you are accessing the hardware at a pretty low level and could read other users’ io. So close it down and run:

$ sudo wireshark

You will get an error right off the hop, and a tip about running as an unpriviledged user (I am guessing they disable lua as it is a programming language and we all know what happens when you run macros as a superuser, *cough* MS Office *cough*)

Lua Error

Unless you are going to do a lot of capturing, you can do what I did and just ignore the error. At which point, you will get the next dialog, this time a warning:

I am sure there *is* a better way. But reading a doc would take time and I have got better (and more fun) things to do.

[Aside: they need to sick a UX designer on these dialogs. They are all messed up]

Now you can actually start a capture. You do this by going to the Capture menu and clicking the Interfaces option. This will bring up ridiculously sized dialog that you will first have to make bigger (every time!). Once that annoyance is out of the way, you will see all of your usb and network interfaces. There are often many usb interfaces and it can be a little tricky to find which is the device you are looking for. Basically you will want to interact with the device and watch the Packets column on the dialog. You might have to try a couple, but basically you are looking for the one who’s packet count goes up while using the device in question.

Finding the right usbmon interface

When you have narrowed it down to an interface you want to try, just click the start button and that will begin the capture process.

Now the fun part begins.

The hardest part of this whole process was figuring out which of the various packets had the info I was looking for. First, because driver responds back the the keyboard with each keypress, you have to figure out who’s who. In other words, which packets are from the keyboard and which are from your computer. Once that is sorted out, you have to figure out which packets the keyboard are sending have the keypresses in them (there are a bunch of control packets in the mix) and finally you have to find out what part of the packet has the code for the key that was pressed.

Example usbmon capture

I am a little embarrassed to think how much time it actually took me. Once I had it figured out, it seemed so obvious, but for some reason I just was not picking up on the pattern at first. Everything I needed was in the Leftover Capture Data field.

Once I had narrowed down where in the packet the key code was I began the tedious process of clicking each and every key on the keyboard and figuring out the keycode pattern. Additionally, I had to decypher the system for the Caps, Num and Scroll locks and their associated LEDs. They are slightly different because the driver must maintain the state of each lock and signal that back to the keyboard.

How I did all that will be covered in the next post.

No comments:

Post a Comment