Tag Archives: hid

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.

Advertisement

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!

xf86-input-xwiimote-0.2

During Google Summer of Code (GSoC) 2011 I developed a Linux kernel driver for the Nintendo Wii Remote. With linux-3.1 release the driver was released with the upstream kernel sources and in a few weeks with linux-3.3 extension-support will be available. I tested the driver for a while now and despite several Bluetooth HIDP bugs I didn’t find any bugs in the hid-wiimote driver. The Bluetooth core is currently undergoing heavy changes and it might take a few weeks until the HIDP driver is stable but it works quite reliable for me.

Although the driver is available in most mainstream distributions the user-space part lagged behind for half a year. So I decided to write an X11 driver that works with the kernel Wii Remote driver. The first step was creating the xwiimote tools which provide a user-space library that allows very easy access to connected Wii Remotes and some debugging tools for connection tests. The library is still under development but the Core, Accelerometer and IR interfaces of Wii Remotes are supported. Based on this library I started the X11 input driver and released the version 0.2 yesterday. It currently only supports button input but the most challenging part was getting the X.Org module right and working around some epoll+O_SETSIG bugs.

Anyway, if you own a Nintendo Wii Remote there’s few steps you need to do to connect your Wii Remote:

  1. Install the xf86-input-xwiimote driver (this requires installing the xwiimote-tools). If you use ArchLinux they are available in the AUR. Make sure the hid-wiimote kernel driver is loaded.
  2. Install the BlueZ Bluetooth stack (this is the official Linux Bluetooth stack). See your distribution for more information.
  3. Start your Bluetooth-Applet of choice (like gnome-bluetooth, blueman or bluez-simple-agent)
  4. Search for nearby devices (device inquiry) and connect to your Wii Remote (it is called Nintendo RVL-CNT-1). If you use bluez-4.96 or newer than everything should work out-of-the box. However, if you are asked for PIN-input then you either use an older version or your Wii Remote is not detected. Simply connect to the device without Pairing/Bonding and everything should work fine. Pairing with Wii Remotes is only supported since bluez-4.96 as the Wii Remote does not follow the standards and needs special BlueZ-plugins.
  5. If your Wii Remote is connected dmesg should show some information about the Wii Remote. You can also use the xwiishow tool from the xwiimote-tools project (See man xwiishow).
  6. Your X-Server should automatically pick up the Wii Remote and load the xwiimote driver. The D-Pad should work as Left/Right/Up/Down keys and the other keys should also have useful mappings. Seeman xorg-xwiimote for configuration options.

That’s all you need to do to enable your Wii Remote as input device. I must admit that the most interesting parts (getting the IR cam and accelerometer as mouse-emulation, sound support, extension support) are still not supported by the X.Org driver. However, the kernel driver does support all this (except sound support) so it shouldn’t be very difficult to add support for these to xf86-input-xwiimote. At least the Linux user-space now has support for Nintendo Wii Remotes based on the hid-wiimote kernel driver and the most requested feature (button/key input) is now available and can be mapped to arbitrary buttons/keys.

If the software is not working on your distribution, please don’t hesitate to fill bug reports at http://github.com/dvdhrm/xwiimote or contact me directly per email.