Tag Archives: bluetooth

Linux Wii Remote Driver Updates

Linux Bluetooth HID handling has been slightly broken in the kernel since several years. Reconnecting devices caused a kernel oops nearly every time you tried. Two months ago I sat down and rewrote the HIDP session handling and fixed several bugs. The series now got merged and will be part of linux-3.10. If you still encounter bugs please leave me a note.

Based on this I tried recovering my hid-wiimote work. Since the last time I reverse-engineered Nintendo devices, a lot has happened. The most significant change is probably the release of the Wii U. While the Gamepad is still an ongoing target for r/e, other devices were much easier to get working. Motivated by the new hardware I just got, I finally figured out a reliable way for extension hotplugging. This wasn’t supported in the kernel until now and required nasty polling-techniques to work around race-conditions in the proprietary protocol (who designs asynchronous protocols without protocol barriers?). So I rewrote most of the core device handling and moved the input parsers to a module based infrastructure. This allows us to easily extend the hid-wiimote driver to support new devices that are based on the same protocol.

The series is still pending on the linux-input ML but I hope to get basic hotplugging support into linux-3.10. Further support for the built-in speaker device or the Wii U Pro Controller will hopefully follow with 3.11.

The xwiimote user-space stack has already been updated and I will push the changes this weekend.

Advertisements

UHID: User-Space HID I/O drivers

Linux-next currently contains a new HID transport-level driver called UHID. If nothing goes wrong it will be released with linux-3.6 in about 2 months. The curious reader can currently find it in the HID maintainer’s (Jiri Kosina) tree. I get often asked what this driver is good for and why uinput wasn’t used to achieve the same? Lets look closer at this:

HID Subsystem Overview

The kernel HID subsystem (./drivers/hid/) implements the HID specifications and is responsible for handling HID requests from devices and forwarding them to the related kernel interfaces. The most known devices are USB keyboards. Therefore, the HID subsystem contains an USBHID called driver (it can be found in ./drivers/hid/usbhid/) which takes care of handling the transport-level I/O details of the USB HID devices. It registers each device it finds with the HID core and therefore is only responsible for handling pure I/O. The protocol parsing is done by the HID core. There is also the HIDP driver (it can be found in ./net/bluetooth/hidp) which does the same for Bluetooth devices. USBHID and HIDP are called “hid_ll_drivers: HID low level drivers” and are responsible for the transport-level (or I/O), thus also called “transport-level driver” or “I/O driver”.

In a perfect world, the HID core would handle the HID reports from the low-level drivers, parse them and feed them into the input subsystem which provides them as input data to user-space. However, many devices need some quirks to work correctly as they are not standard-conforming. Therefore, the “hid_driver: HID device driver” infrastructure was built which allows to write HID drivers handling the device-specific quirks or protocol. They are mostly independent of the transport-level and can work with any low-level HID driver. Some drivers (specifically hid-picolcd and hid-wiimote) even implement complex input-unrelated protocols on top of HID to allow full device-control.

UHID Driver

The UHID driver is a “low-level/transport-level driver (hid_ll_driver)” which was written to allow user-space to act as I/O drivers for the HID subsystem. The UHID driver does not allow writing HID-device drivers (hid_driver), though. There is already the “hidraw” driver which can serve for this purpose.

User-space can simply open /dev/uhid and create/destroy hid-devices in the hid-core. Each open file-descriptor on /dev/uhid can control exactly one device. Let’s look at this from the perspective of HoG (HID over GATT/Bluetooth-Low-Energy): GATT is a Bluetooth protocol implemented in user-space. When user-space opens an LE (low-energy) connection to a Bluetooth device, the device can advertise HID capabilities via GATT. User-space then opens /dev/uhid and creates a new device via the UHID_CREATE message. The UHID driver registers the new device with the HID core and user-space can now transmit I/O data to the kernel. The important design pattern is, that the transport-driver is actually implemented in user-space. If it was realized in kernel-space, then you wouldn’t need UHID and could register your own low-level HID driver. The reasons why HoG is implemented in user-space are out of the scope of this document.

So why doesn’t HoG use uinput? uinput is a kernel module that allows creating kernel input-devices from user-space. It does not do any sophisticated protocol parsing or similar but simply forwards the events to all interested listeners. If HoG was using uinput, it would have to implement the whole HID stack in user-space, although the kernel already has the whole infrastructure for that. Hence, we would duplicate a whole bunch of code without a real gain. uinput isn’t even faster than UHID, neither is it smaller. uinput is simply not suited for this use-case. Therefore, UHID was created.

UHID Design

Each open file-descriptor on /dev/uhid can register a single HID device with the HID-core. Communication is solely done via write()/read() with a special buffer-format. The in-tree documentation describes the protocol in full detail. Each write()/read() call transmit zero or one messages. If multiple messages are to be transmitted, user-space must use readv()/writev(). The UHID_CREATE and UHID_DESTROY messages allow user-space to register and destroy the HID device so it can control the device lifetime. UHID_INPUT is used to feed raw I/O data into the kernel. Similarly, the kernel sends several events to user-space (which can be poll()’ed for) to notify the application about new output-data or device-state changes.

The initial patchset already includes an example program that demonstrates how to use the UHID API. It emulates an HID mouse with 3 buttons and a mouse-wheel. Obviously, this program can be easily written with uinput and uinput would be better suited for this use-case. But again, this is only an example to demonstrate how this is achieved. Systems like HoG cannot use uinput so they can now be seamlessly integrated into the linux eco-system with UHID, without needing any special application support to use these new devices.

User-space HoG implementation has already been merged into BlueZ so you can test this feature when running linux-next. Lets see how all this works out. If the performance is Ok, there is also the idea of moving HIDP into user-space, too. That is, both Bluetooth HID transport-drivers would run inside of the user-space Bluetooth daemon. But lets first make sure HoG is working great!