pax_global_header00006660000000000000000000000064117736375010014524gustar00rootroot0000000000000052 comment=083a8fee2eec0454745ae566746f022a50243250 xwiimote-0.3+20120630/000077500000000000000000000000001177363750100141245ustar00rootroot00000000000000xwiimote-0.3+20120630/.gitignore000066400000000000000000000006011177363750100161110ustar00rootroot00000000000000# Ignore generated files driver/.tmp_versions driver/Module.symvers driver/modules.order driver/.*.cmd driver/*.ko driver/*.mod.c driver/*.o *.swp *.o *.lo *.la Makefile Makefile.in aclocal.m4 autom4te.cache/ build-aux/ config.h config.h.in config.h.in~ config.log config.status configure *.tar.bz2 libtool m4/ stamp-* .deps .dirstamp .libs xwiidump xwiishow xwiikeymap libxwiimote.pc xwiimote-0.3+20120630/COPYING000066400000000000000000000022551177363750100151630ustar00rootroot00000000000000= Licensing Information = This software package is licensed under a 2-clause BSD license. See LICENSE for the licensing terms. This applies to all files (code, documentation, ...) shipped with this distribution. If a specific file has no license header, the header in LICENSE shall apply. If a file has a license header which differs from LICENSE, then the license terms specified in this file shall apply. == Exceptions == The following files are not considered part of this distribution: - driver/* including: - driver/hid-wiimote.h - driver/hid-wiimote-*.c - driver/hid-wiimote.ko: The kernel driver is licensed under the terms of the GPL. This file is only a copy of the current driver. See the official kernel repo for driver development. == Developers == This software is written by: David Herrmann - dh.herrmann@googlemail.com == Contributors == This project could not have been realized without several other software projects. We are very grateful to the following people and projects for their contributions: Linux Kernel - http://www.kernel.org BlueZ - http://www.bluez.org WiiBrew Project - http://www.wiibrew.org/ xwiimote-0.3+20120630/DEV000066400000000000000000000010371177363750100144660ustar00rootroot00000000000000= Development = This file contains information about the development of this software package. This contains no information for end-users. == Git == This software is developed in a git-repository hosted by github: https://github.com/dvdhrm/xwiimote The related linux device driver development is hosted at kernel.org: http://git.kernel.org The driver is developed upstream. Discussion takes place at linux-input@vger.kernel.org == Changelog == There is no classic changelog file. See the git history for a comprehensive changelog. xwiimote-0.3+20120630/LICENSE000066400000000000000000000021301177363750100151250ustar00rootroot00000000000000XWiimote License: Copyright (c) 2011, 2012 David Herrmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xwiimote-0.3+20120630/Makefile.am000066400000000000000000000023331177363750100161610ustar00rootroot00000000000000# # XWiimote - makefile # Written by David Herrmann, 2011 # Dedicated to the Public Domain # ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = \ README \ COPYING \ DEV \ LICENSE \ res/50-xorg-fix-xwiimote.conf lib_LTLIBRARIES = libxwiimote.la bin_PROGRAMS = xwiishow xwiikeymap noinst_PROGRAMS = xwiidump include_HEADERS = lib/xwiimote.h man_MANS = \ doc/xwiimote.7 \ doc/libxwiimote.7 \ doc/xwiishow.1 \ doc/xwiikeymap.1 EXTRA_DIST += $(man_MANS) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libxwiimote.pc EXTRA_DIST += $(pkgconfig_DATA) AM_CFLAGS = \ -Wall AM_CPPFLAGS = \ -I $(srcdir)/lib AM_LDFLAGS = \ -Wall if DEBUG AM_CFLAGS += -O0 -g else AM_CFLAGS += -O2 endif libxwiimote_la_SOURCES = \ lib/internal.h \ lib/xwiimote.h \ lib/core.c \ lib/monitor.c \ lib/sfs.c libxwiimote_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(UDEV_CFLAGS) libxwiimote_la_LIBADD = \ $(UDEV_LIBS) libxwiimote_la_LDFLAGS = \ -version-info 1:0:0 xwiishow_SOURCES = \ tools/xwiishow.c xwiishow_LDADD = \ libxwiimote.la xwiishow_LDFLAGS = \ $(AM_LDFLAGS) \ -lncurses xwiikeymap_SOURCES = \ tools/xwiikeymap.c \ tools/eloop.c tools/eloop.h \ tools/log.c tools/log.h xwiikeymap_LDADD = \ libxwiimote.la xwiidump_SOURCES = \ tools/xwiidump.c xwiimote-0.3+20120630/README000066400000000000000000000205031177363750100150040ustar00rootroot00000000000000= Nintendo Wii Remote Linux Device Driver Tools = This distribution contains tools and libraries related to the open source Nintendo Wii Remote linux device driver which is available since linux-3.1 in the official linux kernel sources. This distribution is hosted at: https://github.com/dvdhrm/xwiimote Use this website to contact the maintainers or developers or to file bug reports. It also provides access to the source code history of the git repository. For email contact please see ./COPYING for a list of contributors or write an email to the current maintainer at: dh.herrmann@googlemail.com Thank you for using this driver! == Install == To install the libxwiimote.so library and the related tools, use: $ ./configure [--enable-debug] [--prefix=/usr] $ make $ make install If "configure" is not available, use: $ ./autogen.sh Dependencies: - libudev: Used for device enumeration - ncurses: Used for UI of xwiishow This software packages contains: libxwiimote.so: A userspace library which helps accessing connected Wii Remotes in the system. It can be used by applications to use Wii Remotes as input. You can also use the direct kernel interface, though. xwiishow: A test application which lists all connected Wii Remotes. If a Wii Remote is passed as argument, it continuously reads input from the device and prints it to the screen. 50-xorg-fix-xwiimote.conf: X configuration file which should be installed into /etc/X11/xorg.conf.d/ by your distribution. It adds all Wii Remotes to the input blacklist of the X-server. This is needed since the raw Wii Remote kernel interface is useless (even irritating) to the X-server. Instead the emulators should be used or the xf86-input-xwiimote driver. xwiikeymap: The most basic emulator. It reads input from a Wii Remote, maps it to other configured keys and feeds it as input into the system. This allows to remap the Wii Remote buttons to your needs and have it as input to the X-server or similar. This is only for the buttons and has no accelerometer, IR, etc. support. The following tools are available but not installed into the system: xwiidump: A test application which reads the EEPROM memory of a connected Wii Remote and prints it to stdout. This requires debugfs support in the kernel and hid-wiimote kernel module. Following software is not part of this package: hid-wiimote.ko: The wiimote kernel module is available in the official linux kernel sources and should already be installed in your system if you run a kernel linux-3.1 or newer. The ./driver/ directory contains a copy of the driver but you should instead rely on the in-kernel driver. wiimote.so: The BlueZ bluetoothd wiimote plugin is part of the upstream BlueZ package and available since bluez-4.96. It should be already installed on your system. == Usage == The XWiimote software stack is split into 3 parts: - BlueZ: The official linux bluetooth stack (BlueZ) needs a few patches to allow pairing with Wii Remotes. These patches are part of BlueZ since bluez-4.96. They are available as plugin wiimote.so, which needs to be enabled during configuration with: ./configure --enable-wiimote Most distribution should already contain the plugin. With this plugin you should be able to pair your Wii Remote like any other bluetooth device. If this plugin is not available, you need to connect to the device without pairing/bonding. Simply select "Connect without authentication/pairing/bonding" or "Use no PIN" during connection. The Wii Remote can be put into discoverable mode by pressing the red sync-button behind the battery cover on the back of the Wii Remote. You can also put it into discoverable mode by holding the 1+2 buttons simultaneously. However, the red-sync button works more reliably and auto-reconnect is not available when the 1+2 buttons are used. This plugin is responsible for pairing Wii Remotes. It does not provide any input from the peripheral. This is done by the kernel driver. This plugin is provided by most distributions by default and you shouldn't care about this. - Kernel: The linux kernel includes an hid-wiimote.ko plugin since version linux-3.1. The related config option is CONFIG_HID_WIIMOTE. It is available in the configuration under: "Linux Kernel/Device Drivers/HID/HID Drivers" With linux-3.1 only basic LED and button input is available. With linux-3.2 accelerometer, IR and rumble support is added. With linux-3.3 extension and debug support is added. Your kernel should already include this driver and you shouldn't care about this. If the kernel driver is loaded and a Wii Remote is connected via BlueZ, the driver automatically takes control over the Wii Remote and provides a kernel interface to user-space. The libxwiimote.so library can be used to access this interface. You may also access it directly. Read ./doc/INTERFACE for a description of the kernel interface. It is recommended to use the library, though. The kernel interface hides the protocol details but still provides very generic access to the Wii Remote. This interface is not suitable to be used as direct application input. Instead several emulators exist which emulate a mouse or keyboard based on the kernel interface. This is needed because there are several different ways to interpret the input and use the Wii Remote as input device. We do not want to limit it to a single mode so you need to use an emulator to get proper input. Applications may choose to use the libxwiimote.so library, though, if they want direct access to the Wii Remote and the emulators are not sufficient. See ./doc/LIBRARY for the library interface. - Userspace: The userspace part (aside from BlueZ) consists of a library called libxwiimote.so to access the Wii Remotes directly and several emulators which provide emulated mouse/keyboard input to the system based on the raw kernel interface. Applications should ignore the kernel input devices from Wii Remotes as they provide only raw data. Instead an emulator should be started which provides a separate input device which can be accessed by the X-server or other applications and provides basic mouse and keyboard input. To use Wii Remotes you always need the BlueZ wiimote plugin and the hid-wiimote.ko kernel driver. Both are part of the upstream repositories of the linux kernel and the BlueZ project and automatically built in the distributions. For testing purposes it is recommended to use the xwiishow tool. It has an ncurses based user-interface and is the most straightforward way to test whether the Wii Remote works on your machine. For more sophisticated tasks you should read the documentation of the emulators or the libxwiimote.so library depending on your needs. Happy Playing! == Documentation == ./doc/*.3: Manpages of the tools ./doc/LIBRARY: Description of the libxwiimote.so library interface ./doc/INTERFACE: Description of the direct kernel interface of hid-wiimote.ko == Development == Please see ./DEV for development information. == Copying == This whole distribution is dedicated to the Public Domain. Please see ./COPYING for more information. == Compatibility == Two other commonly used Wii-Remote libraries are cwiid and wiiuse. Both provide a full user-space driver and were used heavily in the past. We do not provide API compatibility to them as both APIs are very restricted: - cwiid: This API is highly asynchronous with threads. It does not allow a single-threaded application to use it. This makes it very hard to use and we decided not to provide a compatibility layer as we do not want to support such library-API designs. - wiiuse: This API is tightly bound to the idea that the application is supposed to discover and connect the Bluetooth devices. It uses a static array for all used Wii Remotes and requires callbacks for notification. Same as cwiid, we do not provide a compatibility layer as the API is very different from our API. We designed our API to have as few restrictions as possible. We do not force an application to use a special programming technique. Instead, an application can use our API to support event-based, callback-based or thread-based event-loops or any other kind that it wants. We achieve this by keeping the user-space API very similar to the kernel-API so the application can integrate this into any infrastructure it wants. xwiimote-0.3+20120630/autogen.sh000077500000000000000000000002741177363750100161300ustar00rootroot00000000000000#!/bin/sh # # XWiimote - Generate Build Files # Written by David Herrmann, 2011 # Dedicated to the Public Domain # mkdir -p m4/ autoreconf -i ./configure --enable-debug --prefix=/usr $* xwiimote-0.3+20120630/configure.ac000066400000000000000000000020741177363750100164150ustar00rootroot00000000000000# # XWiimote - configure # Written by David Herrmann, 2011 # Dedicated to the Public Domain # AC_PREREQ(2.68) AC_INIT([xwiimote], [0.3]) AC_SUBST(PACKAGE_URL, [https://github.com/dvdhrm/xwiimote]) AC_CONFIG_SRCDIR([lib/xwiimote.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE([foreign 1.11 subdir-objects dist-bzip2 no-dist-gzip tar-pax -Wall -Werror]) AM_SILENT_RULES([yes]) # Don't add a default "-g -O2" if CFLAGS wasn't specified : ${CFLAGS=""} AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AM_PROG_AR LT_PREREQ(2.2) LT_INIT PKG_CHECK_MODULES([UDEV], [libudev]) AC_SUBST(UDEV_CFLAGS) AC_SUBST(UDEV_LIBS) AC_MSG_CHECKING([whether to build with debugging on]) AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], [whether to build with debugging on)])], [debug="$enableval"], [debug=no; AC_DEFINE([NDEBUG], [1], [No Debug])]) AM_CONDITIONAL([DEBUG], [test x$debug = xyes]) AC_MSG_RESULT([$debug]) AC_CONFIG_FILES([Makefile libxwiimote.pc]) AC_OUTPUT xwiimote-0.3+20120630/doc/000077500000000000000000000000001177363750100146715ustar00rootroot00000000000000xwiimote-0.3+20120630/doc/INTERFACE000066400000000000000000000052761177363750100161260ustar00rootroot00000000000000= Wiimote Interface = This is the documentation of the kernel interface to the wiimote. If you use the xwiimote library, you do not need to know this, however, if you plan to write an XINPUT driver or similar and don't want to use this library, read below. A wiimote, when connected to the system, will show up as: /sys/bus/hid/devices/ is a unique id which will never be used twice. To monitor for new devices, you can simply place an inotify on /sys/bus/hid/devices or use libudev (recommended). Notice: When this directory shows up, you need to wait a short time until everything below this directory is set up. If you use libudev, it will notify you, when the device is fully setup. A short sleep of 10ms should be enough, though. Or simply wait for the correct child device to show up instead of waiting for the parent device. To work with a wiimote, there are actually two APIs. Input events are reported through an input device. The subdirectory of each device: ./input/inputX/ contains information about the input device. Udev will automatically set up: /dev/input/eventY for each wiimote. However, if you run without udev, you need to create your own device node with "mknod". Major and minor number are available in: ./input/inputX/dev The name of the eventY file that is created by udev is actually the same as: ./input/inputX/eventY However, its only the same name, not the same file! Also inputX and eventY have different suffixes. The X of inputX increases systemwide and is never reused, whereas eventY may reuse free numbers which are no longer used. This input device is used to report input events. Please see INTERFACE_INPUT for information about what data is reported. Recent versions of the wiimote driver create multiple input devices to allow proper power management and split the events. See INTERFACE_INPUT for more information. Other features which can not be controlled via the input device include debug information and extension setup. They can be controlled with sysfs attributes in /sys/bus/hid/devices/ and can be accessed from a shell. See INTERFACE_SYSFS for information about these files. They allow to read battery status, control wiimote LEDs and much more. Last but not least, there are some debugfs files. These are only for debugging wiimotes and shall not be used in applications. If debugfs is mounted as: /sys/kernel/debug then you may access it via: /sys/kernel/debug/hid// It will contains several files to access the wiimote. Be sure NOT TO WRITE to the files if you don't know what they do. For instance, writing to the "eeprom" file allows to overwrite the internal EEPROM memory of the wiimote. These files are also documented in INTERFACE_SYSFS. xwiimote-0.3+20120630/doc/INTERFACE_INPUT000066400000000000000000000046521177363750100171020ustar00rootroot00000000000000 Wiimote Input Interface (evdev) The wiimote registers input interfaces that are accessible via evdev for every connected wiimote device. See INTERFACE_SYSFS on information how to get the right /dev/input/eventX devices. Don't open devices that you do not need. Otherwise power-management cannot work correctly. For instance: The wiimote's IR camera is only enabled if someone is currently reading the input event device for the IR cam. If no-one has an open file-descriptor to it, the wiimote's IR cam is turned off to save energy. Also do not open devices just to read the device names. Use sysfs to retrieve the correct event device and then only open this device. If an event device is opened the first time, complex initialization sequences are sent to the wiimote. They do not harm the wiimote but cost lots of energy so try to open only the devices you need. The input devices can be matched by name. The following devices are available: - "Nintendo Wii Remote" Wiimote core key events are reported here and also force-feedback support is available. Button Events: Button events are reported as EV_KEY events. The following mappings from wiimote buttons to KEY_* flags are used: Button: Flag: UP KEY_UP DOWN KEY_DOWN LEFT KEY_LEFT RIGHT KEY_RIGHT A BTN_A B BTN_B MINUS KEY_PREVIOUS PLUS KEY_NEXT HOME BTN_MODE ONE BTN_1 TWO BTN_2 Key-repeat events are also generated by the input layer. Force-Feedback support is available via FF_RUMBLE or compatible flags. It is only one single motor that can be turned on and off. - "Nintendo Wii Remote Accelerometer" This input device is used to report accelerometer data. The wiimote accelerometer reports 3 axis accelerometer data as EV_ABS values via: ABS_RX, ABS_RY and ABS_RZ Maximum value of each is 500, minimum is -500. - "Nintendo Wii Remote IR" Reading this device will report IR events. The IR Cam can track up to 4 dots and reports absolute positions for each dot. It reports them via ABS_HAT0X/Y to ABS_HAT3X/Y. - "Nintendo Wii Remote Motion+" If a motion+ adapter is attached, this device will appear. You can read ABS_RX, ABS_RY and ABS_RZ values which represent the gyro-sensor values. - "Nintendo Wii Remote Extension" If an extension is attached, you can read extension events from this device. Depending on the connected extension, the received values may differ. xwiimote-0.3+20120630/doc/INTERFACE_SYSFS000066400000000000000000000032221177363750100171020ustar00rootroot00000000000000What: /sys/bus/hid/drivers/wiimote//input// Date: July 2011 Contact: David Herrmann Description: This is the evdev interface of the wiimote. It can be used to get access to the /dev/input/eventY interface. See evdev API for further access information. See INTERFACE_INPUT for information on the data that is reported via this input interface. Read .../input//name to identify the input device and read .../input//eventY to get the event name. Only open the event devices that you really need. What: /sys/bus/hid/drivers/wiimote//leds// Date: February 2012 Contact: David Herrmann Description: Four directories for each LED of the Wii Remote is available here. You can use the "brightness" file in each directory to set the brightness. You can only set it to 0 or 1 to disable or enable the LED. What: /sys/bus/hid/drivers/wiimote//power_supply/wiimote_battery/ Date: February 2012 Contact: David Herrmann Description: This represents the battery of the Wii Remote. Reading the "capacity" file will return the current battery charge level in per-cent. What: /sys/bus/hid/drivers/wiimote//extension Date: February 2012 Contact: David Herrmann Description: This file contains the name of the currently connected and initialized extensions. It can be one of: motionp+nunchuck motionp+classic motionp nunchuck classic none The driver does not support extension hotplug. If the extensions are removed you need to reconnect the device to redetect them properly. xwiimote-0.3+20120630/doc/LIBRARY000066400000000000000000000002601177363750100157160ustar00rootroot00000000000000There is currently no documentation available. Please see lib/xwiimote.h for the function prototypes and tools/*.c for examples. Especially tools/xwiishow.c should be helpful. xwiimote-0.3+20120630/doc/PROTOCOL000066400000000000000000000527241177363750100160670ustar00rootroot00000000000000= Nintendo Wii Remote Protocol = The wiimote communicates via standard bluetooth technology with the host. This document is divided into two parts. The first part described the low-level bluetooth connection that is established between the host and the wiimote with pairing support. The second part is about the protocol that is used to communicate with the wiimote. == Bluetooth Connection == The wiimote can be in the following states: off: The wiimote power is turned off and no interactions are possible. discoverable: The wiimote is not connected to any host but put into bluetooth discoverable mode. Furthermore, it is possible to establish a new bluetooth baseband connection to the wiimote. connecting: The wiimote is currently establishing a connection with a host or vice versa. connected: The wiimote is currently connected to a host. === Discoverable State === The wiimote is built around a Broadcom bluetooth chip that can be placed into discoverable mode in two ways: 1: Pressing the red sync-button behind the battery-cover on the back of the wiimote. This will place the wiimote directly into discoverable mode for exactly 20 seconds and then turn the wiimote off again. 2: Holding down the 1 and 2 buttons on the front of the wiimote will put the wiimote into discoverable mode. First, the wiimote performs auto-reconnect and if that fails it goes into discoverable mode. If the buttons are held down continuously, the wiimote will stay in discoverable mode, otherwise it turns off after 20 seconds. When in discoverable mode, the wiimote is seen as: "Nintendo RVL-CNT-01" For all later references in this document, we assume the wiimote has the following bluetooth address: "00:1E:35:3B:7E:6D" The binary representation of BD-addresses is in reversed order so this would be the six byte array: 0x6d 0x7e 0x3b 0x35 0x1e 0x00 When in discoverable mode, a host may establish a new bluetooth baseband connection to the wiimote. Every host is allowed to do that. No encryption nor pairing is required. When in discoverable mode, all four LEDs on the wiimote will blink when the battery is full. With lower battery status, less LEDs will blink. If the battery is nearly empty, only the left most LED blinks. === Connecting State === There are two ways to establish a connection with a wiimote: 1: Initiate a baseband connection to the wiimote while the wiimote is in discoverable state. 2: Let the wiimote auto-reconnect to your host. ==== Initiating a Connection ==== When the wiimote is in discoverable state, any bluetooth host can create a new baseband BR/EDR bluetooth connection to the wiimote. There are no special considerations or non-standard procedures. However, optionally, you may initiate pairing with the wiimote. This is not required and may be skipped, though, auto-reconnection can only be used when the host is paired with the wiimote. Pairing can be initiated by sending an HCI authentication request. The bluetooth stack will require a PIN for legacy pairing. This PIN depends on the method used to put the wiimote into discoverable mode. If method (1) was used (that means, the red sync button was pressed) then the PIN is the bluetooth address of the host in binary form (that is reversed order). If the buttons 1+2 were used (that is method (2)), then the PIN is the address of the wiimote in binary form. In our case this would be the 6-byte array: 0x6d 0x7e 0x3b 0x35 0x1e 0x00 When pairing is done, all further connections may use the new link-key instead of PIN-requests, but this should be handled by the bluetooth stack automatically. When the wiimote is paired with a host with method (1) (And only with this method! That is, red sync button!) then the wiimote will save the bluetooth address of the host for further reference so it can automatically reconnect to the host on disconnection. ==== Auto-Reconnection ==== The wiimote maintains a list of bluetooth addresses of hosts that it was connected to and paired with. If any single button on the wiimote is pressed while it is turned off, the wiimote turns on and tries to connect to one of the hosts in this list. It tries only once so you may need to press a single button multiple times to get connected to a host. It is currently impossible to control which host is tried first. Moreover, it is unknown how many addresses the wiimote can save so it may take many times (5 times, 10 times or even more) until the wiimote connects to an available host. If more than one host is available, it is not possible to predict what host the wiimote connects to. However, it seems that the wiimote maintains an internal sorted list of hosts and if it successfully connects to a host, this host is put on top of this list and hence tried first next time. When using auto-reconnection, no pairing is required and pairing does not provide any more functionality here. ==== SDP Information ==== When a low-level connection is established, you may query the SDP server of the xwiimote which returns a great deal of information: * Name: "Nintendo RVL-CNT-01" * PnP: VendorID: 0x057e ProductID: 0x0306 And a lot more PnP, SDP and HID related information. When the low-level baseband connection is established, the l2cap channels can be opened. On auto-reconnection, the wiimote will connect to the host (that is, the host must listen on the l2cap channels). If the connection is initiated by the host, then the wiimote listens for incoming connections on the l2cap channels. Two l2cap channels are used for communication: * Channel PSM 0x11 for sending data to the Wiimote * Channel PXM 0x13 for receiving data from the Wiimote Both must be opened for communication with the wiimote. No further steps are required to setup the connection with the wiimote. The wiimote is considered to be in "connected" state now. === Connected State === When in connected state, the host can communicate with the wiimote. The protocol used for communication is described below in "Fake-HID Protocol". To shutdown the connection, simply shut down the l2cap connections to the wiimote. The wiimote will shut down the connection when the "power"-button is pressed for 3 seconds. == Fake-HID Protocol == Communication is done via HID input/output reports. The wiimote's HID descriptor table does not contain any information about the reports except the data length. Many bits in the commands are still unknown and shall be initialized to 0 to avoid unwanted behaviour. === Reports === Following a list of all input and output reports. Many reports include the same information. These common structures are listed separately and each report that uses them just refers to them. Every report is built as a byte array of a fixed length. The array shall be initialized to 0 if not noted otherwise. If a report has a variable length parameter with a fixed maximum, then always the trailing bytes shall be padded with 0 if not used. Multibyte integers are always in big-endian format. A single report is constructred the following way: report[0] = 0xa1 (for input reports) report[0] = 0x52 (for output reports) report[1] = report[2-X] = The first byte is the HID command which is the same for all input and output reports. They are often omitted or automatically set by your HID layer. See your kernel/library documentation. The second byte is the report identifier. Byte 3 up to X is the report payload. Each report has a fixed length that specifies how long this payload is (without the report byte). A report with length 8 would need 10 bytes to be constructed: 8 payload bytes + 1 HID byte + 1 report byte = 10 bytes The "Data" decription of each report below gives a short overview of how the report is assembled. Each integer is given as hexadecimal number without the 0x prefix. Two characters form a single byte. ==== Common (Output) ==== Length: 1 Data: CC This is no real output report but rather a common structure that is used in almost all other output reports. Byte 1 (CC) contains the following flags: 0x01: This enables the rumble motor. This flag must be set on every output to keep the rumble motor running. If this flag is not set then the rumble is disabled. 0x02: This requests a report acknowledgement. The wiimote will send a 0x22 input report in response to this report. 0x04: Enable flag. This has different meanings depending on the output report but is generally used to enable/disable the requested feature. 0x08: unknown 0xf0: The upper bits are used by different output reports for special features. ==== Rumble Report (Output) ==== Report: 0x10 Length: 1 Data: 52 10 CC Payload information contains only the common output report. This report is no special rumble report, because rumble is enabled and disabled with every output report that includes the common output report. However, this report has no side effects so it may be used to affect the rumble motor without changing any other peripheral. ==== LED Report (Output) ==== Report: 0x11 Length: 1 Data: 52 11 CC Payload includes only the common output report. The upper 4 bits of the common output report set the different leds: 0x10: LED 1 0x20: LED 2 0x40: LED 3 0x80: LED 4 Turning all four LEDs off for too long is discouraged since it may lead the user to believe the wiimote is turned off while it is still turned on. Brightness modulation can be achieved by turning the leds off and on very fast. ==== DRM Set Report (Output) ==== Report: 0x12 Length: 2 Data: 52 12 CC MM The first byte is the common output report. The Enable Flag in the common output report (0x04) is used to enabled or disable continuous input reporting. If enabled, the wiimote continously sends input reports to the host. If disabled, the wiimote sends input reports only when data has changed. The second byte is used to request a specific data reporting mode (DRM). You should set it to the report identifier of the request input report. The wiimote will send data input reports always with the requested DRM. Upon powerup, the DRM defaults to 0x30. After an extension is (un)plugged, data reporting is disabled and needs to be reset with this report. A specific DRM does not explicitely enable or disable the peripherals of the wiimote. The wiimote simply pulls the data from its peripherals, puts it into the output report and sends it to the host. If the requested DRM needs data from a disabled peripheral, then the data is set to 0 in the input report. You have to enabled/disable the specific peripherals of the wiimote independently. Also the requested DRM should match the current data mode of each peripheral. For example if the IR is in extended state, then it reports IR data only if the requested DRM has 12 IR bytes. It must have exactly 12 bytes, not 10 and not 36! However, each peripheral will give hints what DRM to use below. ==== IR Set1 Report (Output) ==== Report: 0x13 Length: 1 Data: 52 13 CC This request is used to enable the IR camera. The payload is the common output report. The Enable Flag (0x04) of the common output report is used to enable or disable the IR camera. This is only one part of the initialization procedure of the IR camera. See below for full instructions how to initialize IR. ==== Speaker Set Report (Output) ==== Report: 0x14 Length: 1 Data: 52 14 CC This request is used to enable the speaker. The payload is the common output report. The Enable Flag (0x04) of the common output report is used to enable or disable the speaker. This is only one part of the initialization procedure of the speaker. See below for full instructions how to initialize the speaker. ==== Status Request Report (Output) ==== Report: 0x15 Length: 1 Data: 52 15 CC The payload is the common output report with no special flags. This report requests a status report from the wiimote. The wiimote will answer with input report 0x20. ==== Write Memory Report (Output) ==== Report: 0x16 Length: 21 Data: 52 16 CC OO OO OO SS DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD This writes data into the wiimote's EEPROM or registers. The first byte is the common output report. Its Enable Flag (0x04) specifies the namespace. If set, then the wiimote's registers are written, otherwise the EEPROM is written. The following 3 bytes OO OO OO specify the offset where to start the write followed by one byte SS specifying the size of the data that is written. SS can be a maximum of 16. The rest of the report is the data (DD). Trailing bytes are padded with 0. Acknowledgement is always received via input report 0x22. ==== Read Memory Report (Output) ==== Report: 0x17 Length: 6 Data: 52 17 CC OO OO OO SS SS This request a memory read of the wiimote's EEPROM or registers. The first byte (CC) is the common output report. Its Enable Flag (0x04) specifies whether EEPROM or registers shall be read. If set, the registers are read, otherwise internal EEPROM is read. The following three bytes OO OO OO specify the data offset where to start the memory read. The last two bytes SS SS specify the amount of data that is read starting at the offset. ==== Speaker Data Report (Output) ==== Report: 0x18 Length: 21 Data: 52 18 CC DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD This sends speaker data to the wiimote. The exact format of the data is described below in the speaker peripheral details. The first byte is the common output report. The upper 5 bits of the common output report specify the size of the data payload (they shall be shifted right for 3 bits). All following bytes (DD) contain the sound data that is sent to the speaker. ==== Speaker Mute Report (Output) ==== Report: 0x19 Length: 1 Data: 52 19 CC This mutes or unmutes the speaker. The payload is the common output report and the Enable Flag (0x04) specifies whether to mute (if enabled) or to unmute (if disabled) the speaker. ==== IR Set2 Report (Output) ==== Report: 0x1a Length: 1 Data: 52 1a CC This has the same syntax as "IR Set1 Report" and is also used to initialize the IR camera. ==== Common (Input) ==== Length: 2 Data: BB BB This is no real input report but rather a common structure that is used in almost all other input reports. The two BB BB bytes include the current state of the buttons on the wiimote. If the following flags are set, then the related button is currently pressed: Byte 1: Byte 2: 0x01: Left Two 0x02: Right One 0x04: Down B 0x08: Up A 0x10: Plus Minus 0x20: - - 0x40: - - 0x80: Home The power-button is never included in input reports. The 0x80 flag of byte one is never used. The bits 0x20 and 0x40 of both bytes are not used for button information but often include important LSB/MSBs or other flags of the surrounding input report. They are referred to as "Special Flags" of the common input report. The sync button on the back of the wiimote is also never included in the button input report. ==== Status Report (Input) ==== Report: 0x20 Length: 6 Data: a1 20 BB BB LF UU UU VV This is sent in request to Status Request Report (0x15) and also when an extension is plugged or unplugged. In the latter case you need to reset the DRM mode (see DRM Set Report), otherwise not further input reports will be sent. The first two bytes of this report include the common input report. The last byte VV is the current battery level from 0-255 where 0 is empty and 255 is full. The four upper bits of LF (L) are the leds: 0x10: LED 1 0x20: LED 2 0x40: LED 3 0x80: LED 4 These flags are set if the related LED is enabled. The lower 4 bits of LF (F) specfiy different things: 0x01: Set if battery is nearly empty 0x02: Set if an extension is plugged 0x04: Set if speaker is enabled 0x08: Set if IR is enabled The two bytes in between (UU UU) are always zero and its unknown why they exist. ==== Memory Report (Input) ==== Report: 0x21 Length: 21 Data: a1 21 BB BB SE OO OO DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD This is sent when data is read via read-memory request. The first two bytes include the common input information. The upper bits in SE are the size of the data that is read minus one (0xff => 16 byte, 0x00 => 1 byte) and the lower bits of SE are the error flag which is 0 when everything is ok, 7 when reading write-only memory and 8 when reading from unexisting memory. Other error flags are unknown. The two OO bytes are the lower 2 bytes of the offset. The upper two bytes are not reported back and must be known by the caller. The 16 DD bytes are the actual data and padded with zeros at the end if less data than 16 bytes were read. If the read-memory request has read more than 16 bytes, multiple responses are sent with the offset increased by 16 each time. Input reporting is disabled during those reads and continues after the read is done. ==== Result Report (Input) ==== Report: 0x22 Length: 4 Data: a1 22 BB BB RR EE This report is sent when a output report failed or explicit acknowledgement was requested by the caller via 0x02 bit in the common output request. The two BB bytes include the common input information, the RR byte is the number of the related report that this report is the result of. The EE byte is the error identifier: 0 if everything was ok, and >0 on error. The meaning of each error number is unknown. ==== DRM reports (Input) ==== All following reports are used to report input information to the host. The DRM-set output report is used to select the DRM report that is used for input reports. ==== DRM B ==== Report: 0x30 Length: 2 Data: a1 30 BB BB ==== DRM BA ==== Report: 0x31 Length: 5 Data: a1 31 BB BB AA AA AA ==== DRM BE ==== Report: 0x32 Length: 10 Data: a1 32 BB BB EE EE EE EE EE EE EE EE ==== DRM BAI ==== Report: 0x33 Length: 17 Data: a1 33 BB BB AA AA AA II II II II II II II II II II II II ==== DRM BEE ==== Report: 0x34 Length: 21 Data: a1 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE ==== DRM BAE ==== Report: 0x35 Length: 21 Data: a1 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE ==== DRM BIE ==== Report: 0x36 Length: 21 Data: a1 36 BB BB II II II II II II II II II II EE EE EE EE EE EE EE EE EE ==== DRM BAIE ==== Report: 0x37 Length: 21 Data: a1 37 BB BB AA AA AA II II II II II II II II II II EE EE EE EE EE EE ==== DRM E ==== Report: 0x3d Length: 21 Data: a1 3d EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE ==== DRM SBAI1 ==== Report: 0x3e Length: 21 Data: a1 3e BB BB AA II II II II II II II II II II II II II II II II II II ==== DRM SBAI2 ==== Report: 0x3f Length: 21 Data: a1 3f BB BB AA II II II II II II II II II II II II II II II II II II == Authors == This document is written by: * David Herrmann - dh.herrmann@googlemail.com The following people contributed to this document: * WiiBrew Project: http://www.wiibrew.org/ http://www.wiibrew.org/wiki/Wiimote * BlueZ Mailing List: http://www.bluez.org/ * Wiimote Project: http://www.wiimoteproject.com/ * Wiiuse: http://sourceforge.net/projects/wiiuse * WiiYourself: http://wiiyourself.gl.tter.org/ == Links == * Gyro hardware: http://invensense.com/mems/gyro/idg650.html == Unknown == The following list contains protocol details which where not investigated and are still unknown: * What happens if two hosts try to connect to the wiimote? * Does the Wiimote implement the BT HID profile or just use HID commands via an l2cap channel? * How many host can be saved for auto-reconnection on the wiimote? * How to manage the list of auto-reconnection hosts? * How to reset the wiimote? * Is pairing possible when using auto-reconnection? Which key to use? xwiimote-0.3+20120630/doc/eeprom.dump000066400000000000000000001136451177363750100170610ustar00rootroot00000000000000This is a wiimote EEPROM dump using the 0x04 flag in READ_MEM requests. One byte is read per request. 0x00000000: 0x88 0x85 0x8b 0x8b 0x8a 0x97 0x3f 0x30 0x00000008: 0x8c 0x39 0xcd 0x88 0x85 0x8b 0x8b 0x8a 0x00000010: 0x97 0x3f 0x30 0x8c 0x39 0xcd 0x84 0x82 0x00000018: 0x86 0x30 0x9f 0x9d 0x9f 0x02 0x40 0x2e 0x00000020: 0x84 0x82 0x86 0x30 0x9f 0x9d 0x9f 0x02 0x00000028: 0x40 0x2e 0x00 0x00 0x00 0x00 0x00 0x00 0x00000030: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000038: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000040: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000048: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000050: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000058: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000060: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000068: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000070: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000078: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000080: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000088: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000090: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000098: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000000f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000100: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000108: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000110: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000118: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000120: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000128: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000130: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000138: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000140: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000148: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000150: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000158: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000160: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000168: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000170: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000178: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000180: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000188: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000190: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000198: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000001f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000200: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000208: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000210: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000218: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000220: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000228: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000230: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000238: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000240: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000248: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000250: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000258: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000260: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000268: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000278: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000280: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000288: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000290: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000298: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000002f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000300: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000308: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000310: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000318: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000320: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000328: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000330: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000338: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000340: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000348: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000350: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000358: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000360: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000368: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000370: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000378: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000380: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000388: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000390: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000398: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000003f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000400: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000408: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000410: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000418: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000420: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000428: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000430: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000438: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000440: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000448: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000450: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000458: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000460: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000468: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000470: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000478: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000480: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000488: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000490: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000498: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000004f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000500: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000508: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000510: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000518: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000520: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000528: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000530: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000538: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000540: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000548: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000550: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000558: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000560: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000568: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000570: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000578: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000580: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000588: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000590: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000598: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000005f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000600: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000608: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000610: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000618: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000620: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000628: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000630: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000638: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000640: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000648: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000650: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000658: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000660: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000668: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000670: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000678: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000680: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000688: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000690: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000698: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000006f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000700: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000708: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000710: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000718: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000720: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000728: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000730: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000738: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000740: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000748: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000750: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000758: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000760: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000768: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000770: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000778: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000780: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000788: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000790: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000798: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000007f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000800: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000808: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000810: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000818: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000820: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000828: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000830: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000838: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000840: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000848: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000850: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000858: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000860: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000868: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000870: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000878: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000880: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000888: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000890: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000898: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000008f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000900: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000908: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000910: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000918: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000920: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000928: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000930: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000938: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000940: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000948: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000950: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000958: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000960: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000968: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000970: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000978: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000980: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000988: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000990: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000998: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000009f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000a98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000aa0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000aa8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ab0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ab8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ac0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ac8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ad0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ad8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ae0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ae8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000af0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000af8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000b98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ba0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ba8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bb0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bb8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bc0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bc8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bd0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bd8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000be0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000be8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bf0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000bf8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000c98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ca0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ca8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cb0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cb8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cc0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cc8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cd0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cd8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ce0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ce8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cf0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000cf8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000d98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000da0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000da8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000db0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000db8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000dc0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000dc8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000dd0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000dd8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000de0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000de8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000df0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000df8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000e98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ea0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ea8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000eb0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000eb8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ec0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ec8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ed0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ed8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ee0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ee8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ef0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ef8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f68: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f88: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000f98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fa0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fa8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fb0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fb8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fc0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fc8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fd0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fd8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fe0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000fe8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ff0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00000ff8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001000: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001008: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001010: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001018: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001020: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001028: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001030: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001038: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001040: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001048: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001050: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001058: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001060: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001068: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001070: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001078: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001080: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001088: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001090: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001098: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000010f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001100: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001108: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001110: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001118: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001120: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001128: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001130: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001138: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001140: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001148: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001150: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001158: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001160: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001168: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001170: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001178: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001180: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001188: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001190: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001198: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000011f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001200: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001208: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001210: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001218: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001220: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001228: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001230: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001238: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001240: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001248: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001250: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001258: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001260: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001268: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001278: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001280: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001288: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001290: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001298: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000012f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001300: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001308: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001310: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001318: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001320: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001328: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001330: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001338: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001340: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001348: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001350: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001358: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001360: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001368: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001370: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001378: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001380: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001388: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001390: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001398: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000013f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001400: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001408: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001410: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001418: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001420: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001428: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001430: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001438: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001440: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001448: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001450: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001458: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001460: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001468: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001470: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001478: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001480: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001488: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001490: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001498: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000014f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001500: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001508: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001510: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001518: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001520: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001528: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001530: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001538: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001540: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001548: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001550: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001558: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001560: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001568: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001570: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001578: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001580: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001588: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001590: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001598: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000015f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001600: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001608: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001610: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001618: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001620: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001628: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001630: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001638: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001640: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001648: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001650: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001658: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001660: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001668: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001670: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001678: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001680: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001688: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001690: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001698: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016d0: 0x00 0x00 0x00 0xff 0x11 0xee 0x00 0x00 0x000016d8: 0x33 0xcc 0x44 0xbb 0x00 0x00 0x00 0x00 0x000016e0: 0x00 0x00 0x00 0x00 0x57 0x01 0x98 0x12 0x000016e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000016f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00001700: (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) 0x00001708: (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) (read error 5) ... continues with errors until 0x10000 ... The Block 0x0000 until 0x16ff is repeated at 0x10000. It is probably also repeated at 0x20000, 0x30000 and higher, but it is not tested. xwiimote-0.3+20120630/doc/libxwiimote.7000066400000000000000000000022051177363750100173140ustar00rootroot00000000000000.\" .\" Written 2012 by David Herrmann .\" Dedicated to the Public Domain .\" .TH "LIBXWIIMOTE" 7 "February 2012" "David Herrmann" "Wii Remote Driver" .SH NAME libxwiimote \- XWiimote user-space library .SH SYNOPSIS .B #include .SH DESCRIPTION The xwiimote library is a helper-library to manage connected Wii Remotes from user-space. If you write an application that wants to support Wii Remotes as input devics but you cannot rely on X or the kernel to provide a suitable input device for you (eg., because you need finer grained access), then you an use this library to access Wii Remotes. This library provides an simple, but still comprehensive, API to access connected Wii Remotes. The API documentation is still in process. Please read the tools in xwiimote/tools/ or the header in xwiimote/lib/xwiimote.h for information on the API. .SH BUGS The library does not support all Wii Remote peripherals, yet. Please consider contributing to the project if you need further functionality. .SH AUTHOR David Herrmann .br The XWiimote Project: http://github.com/dvdhrm/xwiimote .SH "SEE ALSO" .BR xwiimote (7), xwiimote-0.3+20120630/doc/rdesc.dump000066400000000000000000000244551177363750100166720ustar00rootroot00000000000000The HID report descriptor of a wiimote Raw dump (hexadecimal): 05 01 09 05 a1 01 85 10 15 00 26 ff 00 75 08 95 01 06 00 ff 09 01 91 00 85 11 95 01 09 01 91 00 85 12 95 02 09 01 91 00 85 13 95 01 09 01 91 00 85 14 95 01 09 01 91 00 85 15 95 01 09 01 91 00 85 16 95 15 09 01 91 00 85 17 95 06 09 01 91 00 85 18 95 15 09 01 91 00 85 19 95 01 09 01 91 00 85 1a 95 01 09 01 91 00 85 20 95 06 09 01 81 00 85 21 95 15 09 01 81 00 85 22 95 04 09 01 81 00 85 30 95 02 09 01 81 00 85 31 95 05 09 01 81 00 85 32 95 0a 09 01 81 00 85 33 95 11 09 01 81 00 85 34 95 15 09 01 81 00 85 35 95 15 09 01 81 00 85 36 95 15 09 01 81 00 85 37 95 15 09 01 81 00 85 3d 95 15 09 01 81 00 85 3e 95 15 09 01 81 00 85 3f 95 15 09 01 81 00 c0 00 Linux Kernel parsed HID output INPUT(32)[INPUT] Field(0) Usage(6) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(6) Report Offset(0) Flags( Array Absolute ) INPUT(33)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(34)[INPUT] Field(0) Usage(4) ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(4) Report Offset(0) Flags( Array Absolute ) INPUT(48)[INPUT] Field(0) Usage(2) ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(2) Report Offset(0) Flags( Array Absolute ) INPUT(49)[INPUT] Field(0) Usage(5) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(5) Report Offset(0) Flags( Array Absolute ) INPUT(50)[INPUT] Field(0) Usage(10) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(10) Report Offset(0) Flags( Array Absolute ) INPUT(51)[INPUT] Field(0) Usage(17) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(17) Report Offset(0) Flags( Array Absolute ) INPUT(52)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(53)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(54)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(55)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(61)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(62)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) INPUT(63)[INPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) OUTPUT(16)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(17)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(18)[OUTPUT] Field(0) Usage(2) ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(2) Report Offset(0) Flags( Array Absolute ) OUTPUT(19)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(20)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(21)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(22)[OUTPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) OUTPUT(23)[OUTPUT] Field(0) Usage(6) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(6) Report Offset(0) Flags( Array Absolute ) OUTPUT(24)[OUTPUT] Field(0) Usage(21) ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(21) Report Offset(0) Flags( Array Absolute ) OUTPUT(25)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) OUTPUT(26)[OUTPUT] Field(0) Usage(1) ff00.0001 Logical Minimum(0) Logical Maximum(255) Report Size(8) Report Count(1) Report Offset(0) Flags( Array Absolute ) xwiimote-0.3+20120630/doc/xwiikeymap.1000066400000000000000000000102361177363750100171440ustar00rootroot00000000000000.\" .\" Written 2012 by David Herrmann .\" Dedicated to the Public Domain .\" .TH "XWIIKEYMAP" 1 "February 2012" "David Herrmann" "Wii Remote Driver" .SH NAME xwiikeymap \- Remap Wii Remote buttons to other keys .SH SYNOPSIS .B xwiikeymap [-d|--daemon] [-u|--uinput /dev/uinput] [-n|--name "XWiimote Keyboard"] [-L|--left ] ... [-T|--two ] .SH DESCRIPTION The .B xwiikeymap tool is a low level button mapping application which can be used to remap the buttons of connected Wii Remotes to other keys. The application will run as a daemon and wait for connecting Wii Remotes. If a Wii Remote is detected, it will create a new input device via .B uinput (the kernel .B uinput module must be loaded). If a button is pressed on the device, the daemon will emit the mapped key on the fake input device. An application that uses the new faked input device will therefore only get the new mapping and not the raw keycodes. When starting the daemon, you can pass the mapping as command line arguments. You can find the available keys in .B /usr/include/linux/input.h with the .B KEY_* prefix. You need the decimal value of the constants and then you can pass it to the daemon. For instance to remap the .B HOME button of the Wii Remote to .B KEY_F1 59 you would pass .B --home 59 as argument. See below for more information on arguments. This key-mapping works on a very low-level. It works on the kernel<->user-space layer and you won't find all keys you want inside /usr/include/linux/input.h. For instance there is no KEY_PLUS as this key is not available on standard American keyboards. They use SHIFT+KEY_MINUS. You must also take into account, that the X-Server will put a keyboard-layout on top of your mapping. So if you map a button to KEY_Z but the xserver puts an European layout on the keyboard, this might become KEY_Y instead. .SH OPTIONS .IP "\fB\-d, \-\-daemon\fP" Start application as daemon, that is, fork into background. .IP "\fB\-u, \-\-uinput \fIdevice\-path\fP" Path to the uinput device. This is used to create new user-space controlled input devices. By default this is "/dev/uinput". .IP "\fB\-n, \-\-name \fIdevice\-name\fP" Specify the device name that will be used for the new fake input device that is created with uinput. By default this is "XWiimote Keyboard". .SS Mappings To remap buttons to other keys you can use the following options. All options take as argument a decimal value which will be the new value of the key. If it is 0, the key is disabled and never emitted. .br You can find the key-constants in /usr/include/linux/input.h .IP "\fB\-L, \-\-left \fIval\fP" Map the left button to the new value. By default this is KEY_LEFT. .IP "\fB\-R, \-\-right \fIval\fP" Map the right button to the new value. By default this is KEY_RIGHT. .IP "\fB\-U, \-\-up \fIval\fP" Map the up button to the new value. By default this is KEY_UP. .IP "\fB\-D, \-\-down \fIval\fP" Map the down button to the new value. By default this is KEY_DOWN. .IP "\fB\-A, \-\-a \fIval\fP" Map the A button to the new value. By default this is KEY_ENTER. .IP "\fB\-B, \-\-b \fIval\fP" Map the B button to the new value. By default this is KEY_SPACE. .IP "\fB\-P, \-\-plus \fIval\fP" Map the plus button to the new value. By default this is KEY_VOLUMEUP. .IP "\fB\-M, \-\-minus \fIval\fP" Map the minus button to the new value. By default this is KEY_VOLUMEDOWN. .IP "\fB\-H, \-\-home \fIval\fP" Map the home button to the new value. By default this is KEY_ESC. .IP "\fB\-O, \-\-one \fIval\fP" Map the 1 button to the new value. By default this is KEY_1. .IP "\fB\-T, \-\-two \fIval\fP" Map the 2 button to the new value. By default this is KEY_2. .SH EXAMPLES .B $ xwiikeymap -d --home 59 --one 0 --two 0 .br This will keep the standard keymap but map the HOME-button to KEY_F1 and disable the ONE and TWO buttons. It will run as daemon in the background. .SH BUGS This tool works on a very low level and may not be suitable for your needs. It is recommended to use X11 mappings instead. See the other tools of the xwiimote suite for better mappings. .SH AUTHOR David Herrmann .br The XWiimote Project: http://github.com/dvdhrm/xwiimote .SH "SEE ALSO" .BR xwiimote (7), .BR libxwiimote (7), xwiimote-0.3+20120630/doc/xwiimote.7000066400000000000000000000137421177363750100166350ustar00rootroot00000000000000.\" .\" Written 2012 by David Herrmann .\" Dedicated to the Public Domain .\" .TH "XWIIMOTE" 7 "February 2012" "David Herrmann" "Wii Remote Driver" .SH NAME XWiimote \- Nintendo Wii Remote Linux Device Driver .SH DESCRIPTION The XWiimote driver and utilities can be used to connect a Nintendo Wii Remote to your computer. It consists of a linux kernel driver, a BlueZ Bluetooth plugin and user-space utilities. They replace the old user-space drivers like .B cwiid or .B wiiuse. Since bluez-4.96 the .B wiimote plugin is available upstream and you should be able to pair your Wii Remote like any other Bluetooth device. If pairing fails, simply connect the Wii Remote without pairing/bonding. The .B linux kernel driver for the Wii Remote is available since linux-3.1 and full support for Wii Remotes since linux-3.3. It is called .B hid-wiimote and requires the HID core drivers to be loaded. No configuration is needed for the driver and plugin. The user-space utilities provide a library that can be used to monitor and access connected Wii Remotes and they provide several applications to manage connected Wii Remotes. There are also tools to remap the peripheral input to arbitrary system input so you can use Wii Remotes as input devices for any application even if the desired application has no special Wii Remote support. .SS Connecting Wii Remotes To connect a Wii Remote to your host be sure that the official linux Bluetooth stack (BlueZ) is installed on your system and your kernel has the .B hid-wiimote kernel plugin loaded. Then connect your Wii Remote like any other Bluetooth device. The system log .B (dmesg) should print some messages about the new connected device. The Wii Remote can be put into discoverable mode by pressing the red sync-button behind the battery cover on the back. The Wii Remote will stay in discoverable mode for 20s. You can also hold the 1+2 buttons to put the Wii Remote into discoverable state. However, the first method works more reliably! If you are asked for PIN input while bonding the devices, then your BlueZ bluetoothd daemon does not include the wiimote plugin. See .B Bugs below for more information. If this does not help, you can still connect to your Wii Remote without pairing/bonding (i.e. not using authentication with a PIN). This should work with any BlueZ version. .SS User-Space Tools If you have a Wii Remote connected to your host you can test it with the .BR xwiishow (1) application. However, if you do not have the .B xwiimote user-space tools installed, you can find Wii Remotes with .br .B " ls /sys/module/hid_wiimote/drivers/hid:wiimote/" .br They are listed there with their device ID inside that directory. For example .B /sys/module/hid_wiimote/drivers/hid:wiimote/0005:057E:0306.0001 .br You can retrieve kernel information about the device by reading the files in this directory. If you want to remap the keys of the Wii Remote to other keys, use the .BR xwiikeymap (1) utility. Further tools are under development. .SS BlueZ wiimote plugin Since bluez-4.96 the bluetooth daemon includes a special wiimote plugin which handles wiimote pairing requests. If you pair a Wii Remote, the plugin will automatically generate the right PIN and pair the device. If you are asked for PIN input, you either do not have this plugin installed or your device is not detected. See .B BUGS for troubleshooting Wii Remote connection problems. .SS Wii Remote kernel driver The wiimote kernel driver is available since linux-3.1 in the official linux kernel. Since linux-3.2 the accelerometer and IR sensor are supported. Since linux-3.3 extension support is available. There is no need to configure this driver. All configuration should be done in the user-space utilities. The kernel driver provides a simple abstraction layer which does not need any configuration. .SS libxwiimote The kernel API for the Wii Remote is quite complex. It is documented in the xwiimote source repository in .B doc/INTERFACE .br To help application developers to use special Wii Remote functionality, we developed the .BR libxwiimote (7) library which provides an easy API to manage connected Wii Remotes. If an application does not support Wii Remotes explicitely you can still use the user-space tools like .BR xwiikeymap (1) to map Wii Remote buttons to arbitrary keys which then can be access as input device by any application which accepts keyboard input. However, if an application wants to use the IR or accelerometer sensors of a Wii Remote or if it requires more advanced key-maps, then it should use .B libxwiimote to access connected Wii Remotes. .SH BUGS .SS Connecting the Wii Remote requires PIN input If you are asked for PIN input while connecting your Wii Remote then you either do not have the BlueZ wiimote plugin installed or your device is not detected as a Wii Remote. This might happen with 3rd party Wii Remotes which are not sold by Nintendo. You can still use these devices by connecting them without pairing or bonding. Tools like gnome-bluetooth require you to select "Use no PIN" to connect devices without pairing/bonding. There are attempts to improve the detection of Wii Remotes in BlueZ. If you are sure that your device is not detected properly, please report a bug upstream. .SS The X-Server reacts weirdly on Wii Remote input By default the X-Server opens all input devices that are available on your machine. The Wii Remote input devices are very useless without a proper keymap so you should instruct your X-Server to ignore raw Wii Remotes input devices. The xwiimote source repository contains an xorg-config file .B res/50-xorg-disable-wiimote.conf which can be installed into .B /etc/X11/xorg.conf.d/ to ignore all raw Wii Remote input devices. .br This only ignores raw Wii Remote devices. If you used some of the user-space utilities to remap the buttons then the new devices will still be detected by your X-Server. .SH AUTHOR David Herrmann .br The XWiimote Project: http://github.com/dvdhrm/xwiimote .SH "SEE ALSO" .BR libxwiimote (7), .BR xwiishow (1), .BR xwiikeymap (1) xwiimote-0.3+20120630/doc/xwiishow.1000066400000000000000000000033551177363750100166420ustar00rootroot00000000000000.\" .\" Written 2012 by David Herrmann .\" Dedicated to the Public Domain .\" .TH "XWIISHOW" 1 "February 2012" "David Herrmann" "Wii Remote Driver" .SH NAME xwiishow \- Test connected Wii Remote devices .SH SYNOPSIS .B xwiishow [-h] .br .B xwiishow list .br .B xwiishow .br .B xwiishow /sys/bus/hid/devices/ .SH DESCRIPTION The .B xwiishow tool, when called without arguments, shows a short usage information. If the .B list parameter is given, it lists all connected Wii Remotes. Each connected Wii Remote is given a number. If you pass this number to .B xwiishow then this device is opened and the UI shows a graphical representation of the device. Instead of passing this number you can also pass an absolute path to the device-root in the sysfs directory. In the ncurses-based interface you can press 'q' to quit the application, 'r' to toggle the rumble motor and 'a' to toggle the accelerometer. .SH EXAMPLES .B $ xwiishow list .br No device path given. Listing devices: .br Found device: /sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2/3-2:1.0/bluetooth/hci0/hci0:11/0005:057E:0306.0001 .br End of device list .B $ xwiishow /sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2/3-2:1.0/bluetooth/hci0/hci0:11/0005:057E:0306.0001 .br .SH BUGS This tool is quite incomplete. It does not support all interfaces that are provided by the wiimote kernel driver. However, it provides enough functionality to test whether a Wii Remote is detected properly. The tool reads the input devices directly so you might need root rights to properly access the Wii Remote. .SH AUTHOR David Herrmann .br The XWiimote Project: http://github.com/dvdhrm/xwiimote .SH "SEE ALSO" .BR xwiimote (7), .BR libxwiimote (7), xwiimote-0.3+20120630/driver/000077500000000000000000000000001177363750100154175ustar00rootroot00000000000000xwiimote-0.3+20120630/driver/Makefile000066400000000000000000000037501177363750100170640ustar00rootroot00000000000000# # XWiimote - driver - makefile # Written by David Herrmann, 2011 # Released under the terms of the GPLv2 # See COPYING for details # # # Build the Wii Remote Kernel Driver # # Starting with linux-3.1 the upstream linux kernel includes the Wii Remote # driver. You do not need to compile it on your own. Please read below if you # want to compile an out-of-tree module, anyway: # # This builds the wiimote driver for the currently running kernel. This # distribution contains a recent stable source code of the driver # (hid-wiimote-*.c), but if you want a more recent one with unstable features, # copy the files ./hid/drivers/hid-wiimote* from the xwiimote kernel repository # into this directory. # "make copy" does exactly this, assuming you have checked out a kernel source # in the same directory as "xwiimote". You can adjust DRVPATH to point to your # kernel source directory if you want to use "make copy". This path is # relative to this "./driver/" directory. # # New wiimote driver releases split the source into multiple files so the # correct list of files is: # hid-wiimote.h hid-wiimote-core.c hid-wiimote-ext.c hid-wiimote-debug.c # # Run "make" or "make build" to compile the source. This will produce a # hid-wiimote.ko file which can be loaded with: "insmod ./hid-wiimote.ko" # # "make clean" will remove all temporary files. # ifeq ($(KERNELRELEASE),) DRVPATH=../../kernel/xwiimote_kernel KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) .PHONY: build copy clean test build: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules copy: @cp -v $(DRVPATH)/drivers/hid/hid-wiimote*.[ch] . clean: @rm -rvf .tmp_versions/ .*.cmd *.o *.ko *.mod.? modules.order @rm -rvf Module.symvers *.orig *.rej test: make copy build ; sudo rmmod hid-wiimote ; sudo insmod ./hid-wiimote.ko else hid-wiimote-y := hid-wiimote-core.o ifdef CONFIG_HID_WIIMOTE_EXT hid-wiimote-y += hid-wiimote-ext.o endif ifdef CONFIG_DEBUG_FS hid-wiimote-y += hid-wiimote-debug.o endif obj-m := hid-wiimote.o endif xwiimote-0.3+20120630/driver/hid-ids.h000066400000000000000000000001241177363750100171060ustar00rootroot00000000000000#define USB_VENDOR_ID_NINTENDO 0x057e #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 xwiimote-0.3+20120630/driver/hid-wiimote-core.c000066400000000000000000001016761177363750100207430ustar00rootroot00000000000000/* * HID driver for Nintendo Wiimote devices * Copyright (c) 2011 David Herrmann */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include #include #include #include #include #include #include #include #include #include "hid-ids.h" #include "hid-wiimote.h" #define WIIMOTE_VERSION "0.2" enum wiiproto_keys { WIIPROTO_KEY_LEFT, WIIPROTO_KEY_RIGHT, WIIPROTO_KEY_UP, WIIPROTO_KEY_DOWN, WIIPROTO_KEY_PLUS, WIIPROTO_KEY_MINUS, WIIPROTO_KEY_ONE, WIIPROTO_KEY_TWO, WIIPROTO_KEY_A, WIIPROTO_KEY_B, WIIPROTO_KEY_HOME, WIIPROTO_KEY_COUNT }; static __u16 wiiproto_keymap[] = { KEY_LEFT, /* WIIPROTO_KEY_LEFT */ KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ KEY_UP, /* WIIPROTO_KEY_UP */ KEY_DOWN, /* WIIPROTO_KEY_DOWN */ KEY_NEXT, /* WIIPROTO_KEY_PLUS */ KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ BTN_1, /* WIIPROTO_KEY_ONE */ BTN_2, /* WIIPROTO_KEY_TWO */ BTN_A, /* WIIPROTO_KEY_A */ BTN_B, /* WIIPROTO_KEY_B */ BTN_MODE, /* WIIPROTO_KEY_HOME */ }; static enum power_supply_property wiimote_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY }; static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, size_t count) { __u8 *buf; ssize_t ret; if (!hdev->hid_output_raw_report) return -ENODEV; buf = kmemdup(buffer, count, GFP_KERNEL); if (!buf) return -ENOMEM; ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT); kfree(buf); return ret; } static void wiimote_worker(struct work_struct *work) { struct wiimote_data *wdata = container_of(work, struct wiimote_data, worker); unsigned long flags; spin_lock_irqsave(&wdata->qlock, flags); while (wdata->head != wdata->tail) { spin_unlock_irqrestore(&wdata->qlock, flags); wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data, wdata->outq[wdata->tail].size); spin_lock_irqsave(&wdata->qlock, flags); wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE; } spin_unlock_irqrestore(&wdata->qlock, flags); } static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer, size_t count) { unsigned long flags; __u8 newhead; if (count > HID_MAX_BUFFER_SIZE) { hid_warn(wdata->hdev, "Sending too large output report\n"); return; } /* * Copy new request into our output queue and check whether the * queue is full. If it is full, discard this request. * If it is empty we need to start a new worker that will * send out the buffer to the hid device. * If the queue is not empty, then there must be a worker * that is currently sending out our buffer and this worker * will reschedule itself until the queue is empty. */ spin_lock_irqsave(&wdata->qlock, flags); memcpy(wdata->outq[wdata->head].data, buffer, count); wdata->outq[wdata->head].size = count; newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE; if (wdata->head == wdata->tail) { wdata->head = newhead; schedule_work(&wdata->worker); } else if (newhead != wdata->tail) { wdata->head = newhead; } else { hid_warn(wdata->hdev, "Output queue is full"); } spin_unlock_irqrestore(&wdata->qlock, flags); } /* * This sets the rumble bit on the given output report if rumble is * currently enabled. * \cmd1 must point to the second byte in the output report => &cmd[1] * This must be called on nearly every output report before passing it * into the output queue! */ static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1) { if (wdata->state.flags & WIIPROTO_FLAG_RUMBLE) *cmd1 |= 0x01; } static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble) { __u8 cmd[2]; rumble = !!rumble; if (rumble == !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE)) return; if (rumble) wdata->state.flags |= WIIPROTO_FLAG_RUMBLE; else wdata->state.flags &= ~WIIPROTO_FLAG_RUMBLE; cmd[0] = WIIPROTO_REQ_RUMBLE; cmd[1] = 0; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) { __u8 cmd[2]; leds &= WIIPROTO_FLAGS_LEDS; if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds) return; wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds; cmd[0] = WIIPROTO_REQ_LED; cmd[1] = 0; if (leds & WIIPROTO_FLAG_LED1) cmd[1] |= 0x10; if (leds & WIIPROTO_FLAG_LED2) cmd[1] |= 0x20; if (leds & WIIPROTO_FLAG_LED3) cmd[1] |= 0x40; if (leds & WIIPROTO_FLAG_LED4) cmd[1] |= 0x80; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } /* * Check what peripherals of the wiimote are currently * active and select a proper DRM that supports all of * the requested data inputs. */ static __u8 select_drm(struct wiimote_data *wdata) { __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR; bool ext = wiiext_active(wdata); if (ir == WIIPROTO_FLAG_IR_BASIC) { if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) return WIIPROTO_REQ_DRM_KAIE; else return WIIPROTO_REQ_DRM_KIE; } else if (ir == WIIPROTO_FLAG_IR_EXT) { return WIIPROTO_REQ_DRM_KAI; } else if (ir == WIIPROTO_FLAG_IR_FULL) { return WIIPROTO_REQ_DRM_SKAI1; } else { if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) { if (ext) return WIIPROTO_REQ_DRM_KAE; else return WIIPROTO_REQ_DRM_KA; } else { if (ext) return WIIPROTO_REQ_DRM_KE; else return WIIPROTO_REQ_DRM_K; } } } void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm) { __u8 cmd[3]; if (drm == WIIPROTO_REQ_NULL) drm = select_drm(wdata); cmd[0] = WIIPROTO_REQ_DRM; cmd[1] = 0; cmd[2] = drm; wdata->state.drm = drm; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } static void wiiproto_req_status(struct wiimote_data *wdata) { __u8 cmd[2]; cmd[0] = WIIPROTO_REQ_SREQ; cmd[1] = 0; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel) { accel = !!accel; if (accel == !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL)) return; if (accel) wdata->state.flags |= WIIPROTO_FLAG_ACCEL; else wdata->state.flags &= ~WIIPROTO_FLAG_ACCEL; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); } static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags) { __u8 cmd[2]; cmd[0] = WIIPROTO_REQ_IR1; cmd[1] = flags; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } static void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags) { __u8 cmd[2]; cmd[0] = WIIPROTO_REQ_IR2; cmd[1] = flags; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } #define wiiproto_req_wreg(wdata, os, buf, sz) \ wiiproto_req_wmem((wdata), false, (os), (buf), (sz)) #define wiiproto_req_weeprom(wdata, os, buf, sz) \ wiiproto_req_wmem((wdata), true, (os), (buf), (sz)) static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom, __u32 offset, const __u8 *buf, __u8 size) { __u8 cmd[22]; if (size > 16 || size == 0) { hid_warn(wdata->hdev, "Invalid length %d wmem request\n", size); return; } memset(cmd, 0, sizeof(cmd)); cmd[0] = WIIPROTO_REQ_WMEM; cmd[2] = (offset >> 16) & 0xff; cmd[3] = (offset >> 8) & 0xff; cmd[4] = offset & 0xff; cmd[5] = size; memcpy(&cmd[6], buf, size); if (!eeprom) cmd[1] |= 0x04; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, __u32 offset, __u16 size) { __u8 cmd[7]; if (size == 0) { hid_warn(wdata->hdev, "Invalid length %d rmem request\n", size); return; } cmd[0] = WIIPROTO_REQ_RMEM; cmd[1] = 0; cmd[2] = (offset >> 16) & 0xff; cmd[3] = (offset >> 8) & 0xff; cmd[4] = offset & 0xff; cmd[5] = (size >> 8) & 0xff; cmd[6] = size & 0xff; if (!eeprom) cmd[1] |= 0x04; wiiproto_keep_rumble(wdata, &cmd[1]); wiimote_queue(wdata, cmd, sizeof(cmd)); } /* requries the cmd-mutex to be held */ int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset, const __u8 *wmem, __u8 size) { unsigned long flags; int ret; spin_lock_irqsave(&wdata->state.lock, flags); wiimote_cmd_set(wdata, WIIPROTO_REQ_WMEM, 0); wiiproto_req_wreg(wdata, offset, wmem, size); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); if (!ret && wdata->state.cmd_err) ret = -EIO; return ret; } /* requries the cmd-mutex to be held */ ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, __u8 *rmem, __u8 size) { unsigned long flags; ssize_t ret; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.cmd_read_size = size; wdata->state.cmd_read_buf = rmem; wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, offset & 0xffff); wiiproto_req_rreg(wdata, offset, size); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.cmd_read_buf = NULL; spin_unlock_irqrestore(&wdata->state.lock, flags); if (!ret) { if (wdata->state.cmd_read_size == 0) ret = -EIO; else ret = wdata->state.cmd_read_size; } return ret; } static int wiimote_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct wiimote_data *wdata = container_of(psy, struct wiimote_data, battery); int ret = 0, state; unsigned long flags; ret = wiimote_cmd_acquire(wdata); if (ret) return ret; spin_lock_irqsave(&wdata->state.lock, flags); wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0); wiiproto_req_status(wdata); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); state = wdata->state.cmd_battery; wiimote_cmd_release(wdata); if (ret) return ret; switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: val->intval = state * 100 / 255; break; default: ret = -EINVAL; break; } return ret; } static int wiimote_init_ir(struct wiimote_data *wdata, __u16 mode) { int ret; unsigned long flags; __u8 format = 0; static const __u8 data_enable[] = { 0x01 }; static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64 }; static const __u8 data_sens2[] = { 0x63, 0x03 }; static const __u8 data_fin[] = { 0x08 }; spin_lock_irqsave(&wdata->state.lock, flags); if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) { spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } if (mode == 0) { wdata->state.flags &= ~WIIPROTO_FLAGS_IR; wiiproto_req_ir1(wdata, 0); wiiproto_req_ir2(wdata, 0); wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_acquire(wdata); if (ret) return ret; /* send PIXEL CLOCK ENABLE cmd first */ spin_lock_irqsave(&wdata->state.lock, flags); wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0); wiiproto_req_ir1(wdata, 0x06); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); if (ret) goto unlock; if (wdata->state.cmd_err) { ret = -EIO; goto unlock; } /* enable IR LOGIC */ spin_lock_irqsave(&wdata->state.lock, flags); wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0); wiiproto_req_ir2(wdata, 0x06); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); if (ret) goto unlock; if (wdata->state.cmd_err) { ret = -EIO; goto unlock; } /* enable IR cam but do not make it send data, yet */ ret = wiimote_cmd_write(wdata, 0xb00030, data_enable, sizeof(data_enable)); if (ret) goto unlock; /* write first sensitivity block */ ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1, sizeof(data_sens1)); if (ret) goto unlock; /* write second sensitivity block */ ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2, sizeof(data_sens2)); if (ret) goto unlock; /* put IR cam into desired state */ switch (mode) { case WIIPROTO_FLAG_IR_FULL: format = 5; break; case WIIPROTO_FLAG_IR_EXT: format = 3; break; case WIIPROTO_FLAG_IR_BASIC: format = 1; break; } ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format)); if (ret) goto unlock; /* make IR cam send data */ ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin)); if (ret) goto unlock; /* request new DRM mode compatible to IR mode */ spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags &= ~WIIPROTO_FLAGS_IR; wdata->state.flags |= mode & WIIPROTO_FLAGS_IR; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); unlock: wiimote_cmd_release(wdata); return ret; } static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev) { struct wiimote_data *wdata; struct device *dev = led_dev->dev->parent; int i; unsigned long flags; bool value = false; wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); for (i = 0; i < 4; ++i) { if (wdata->leds[i] == led_dev) { spin_lock_irqsave(&wdata->state.lock, flags); value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1); spin_unlock_irqrestore(&wdata->state.lock, flags); break; } } return value ? LED_FULL : LED_OFF; } static void wiimote_leds_set(struct led_classdev *led_dev, enum led_brightness value) { struct wiimote_data *wdata; struct device *dev = led_dev->dev->parent; int i; unsigned long flags; __u8 state, flag; wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); for (i = 0; i < 4; ++i) { if (wdata->leds[i] == led_dev) { flag = WIIPROTO_FLAG_LED(i + 1); spin_lock_irqsave(&wdata->state.lock, flags); state = wdata->state.flags; if (value == LED_OFF) wiiproto_req_leds(wdata, state & ~flag); else wiiproto_req_leds(wdata, state | flag); spin_unlock_irqrestore(&wdata->state.lock, flags); break; } } } static int wiimote_ff_play(struct input_dev *dev, void *data, struct ff_effect *eff) { struct wiimote_data *wdata = input_get_drvdata(dev); __u8 value; unsigned long flags; /* * The wiimote supports only a single rumble motor so if any magnitude * is set to non-zero then we start the rumble motor. If both are set to * zero, we stop the rumble motor. */ if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude) value = 1; else value = 0; spin_lock_irqsave(&wdata->state.lock, flags); wiiproto_req_rumble(wdata, value); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static int wiimote_input_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); return hid_hw_open(wdata->hdev); } static void wiimote_input_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); hid_hw_close(wdata->hdev); } static int wiimote_accel_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); int ret; unsigned long flags; ret = hid_hw_open(wdata->hdev); if (ret) return ret; spin_lock_irqsave(&wdata->state.lock, flags); wiiproto_req_accel(wdata, true); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimote_accel_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wiiproto_req_accel(wdata, false); spin_unlock_irqrestore(&wdata->state.lock, flags); hid_hw_close(wdata->hdev); } static int wiimote_ir_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); int ret; ret = hid_hw_open(wdata->hdev); if (ret) return ret; ret = wiimote_init_ir(wdata, WIIPROTO_FLAG_IR_BASIC); if (ret) { hid_hw_close(wdata->hdev); return ret; } return 0; } static void wiimote_ir_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); wiimote_init_ir(wdata, 0); hid_hw_close(wdata->hdev); } static void handler_keys(struct wiimote_data *wdata, const __u8 *payload) { input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT], !!(payload[0] & 0x01)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT], !!(payload[0] & 0x02)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN], !!(payload[0] & 0x04)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP], !!(payload[0] & 0x08)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS], !!(payload[0] & 0x10)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO], !!(payload[1] & 0x01)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE], !!(payload[1] & 0x02)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B], !!(payload[1] & 0x04)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A], !!(payload[1] & 0x08)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS], !!(payload[1] & 0x10)); input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME], !!(payload[1] & 0x80)); input_sync(wdata->input); } static void handler_accel(struct wiimote_data *wdata, const __u8 *payload) { __u16 x, y, z; if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL)) return; /* * payload is: BB BB XX YY ZZ * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ * contain the upper 8 bits of each value. The lower 2 bits are * contained in the buttons data BB BB. * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y * accel value and bit 6 is the second bit of the Z value. * The first bit of Y and Z values is not available and always set to 0. * 0x200 is returned on no movement. */ x = payload[2] << 2; y = payload[3] << 2; z = payload[4] << 2; x |= (payload[0] >> 5) & 0x3; y |= (payload[1] >> 4) & 0x2; z |= (payload[1] >> 5) & 0x2; input_report_abs(wdata->accel, ABS_RX, x - 0x200); input_report_abs(wdata->accel, ABS_RY, y - 0x200); input_report_abs(wdata->accel, ABS_RZ, z - 0x200); input_sync(wdata->accel); } #define ir_to_input0(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \ ABS_HAT0X, ABS_HAT0Y) #define ir_to_input1(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \ ABS_HAT1X, ABS_HAT1Y) #define ir_to_input2(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \ ABS_HAT2X, ABS_HAT2Y) #define ir_to_input3(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \ ABS_HAT3X, ABS_HAT3Y) static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir, bool packed, __u8 xid, __u8 yid) { __u16 x, y; if (!(wdata->state.flags & WIIPROTO_FLAGS_IR)) return; /* * Basic IR data is encoded into 3 bytes. The first two bytes are the * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits * of both. * If data is packed, then the 3rd byte is put first and slightly * reordered. This allows to interleave packed and non-packed data to * have two IR sets in 5 bytes instead of 6. * The resulting 10bit X/Y values are passed to the ABS_HATXY input dev. */ if (packed) { x = ir[1] << 2; y = ir[2] << 2; x |= ir[0] & 0x3; y |= (ir[0] >> 2) & 0x3; } else { x = ir[0] << 2; y = ir[1] << 2; x |= (ir[2] >> 4) & 0x3; y |= (ir[2] >> 6) & 0x3; } input_report_abs(wdata->ir, xid, x); input_report_abs(wdata->ir, yid, y); } static void handler_status(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); /* on status reports the drm is reset so we need to resend the drm */ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); wiiext_event(wdata, payload[2] & 0x02); if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) { wdata->state.cmd_battery = payload[5]; wiimote_cmd_complete(wdata); } } static void handler_data(struct wiimote_data *wdata, const __u8 *payload) { __u16 offset = payload[3] << 8 | payload[4]; __u8 size = (payload[2] >> 4) + 1; __u8 err = payload[2] & 0x0f; handler_keys(wdata, payload); if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_RMEM, offset)) { if (err) size = 0; else if (size > wdata->state.cmd_read_size) size = wdata->state.cmd_read_size; wdata->state.cmd_read_size = size; if (wdata->state.cmd_read_buf) memcpy(wdata->state.cmd_read_buf, &payload[5], size); wiimote_cmd_complete(wdata); } } static void handler_return(struct wiimote_data *wdata, const __u8 *payload) { __u8 err = payload[3]; __u8 cmd = payload[2]; handler_keys(wdata, payload); if (wiimote_cmd_pending(wdata, cmd, 0)) { wdata->state.cmd_err = err; wiimote_cmd_complete(wdata); } else if (err) { hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err, cmd); } } static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); handler_accel(wdata, payload); } static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); wiiext_handle(wdata, &payload[2]); } static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); handler_accel(wdata, payload); ir_to_input0(wdata, &payload[5], false); ir_to_input1(wdata, &payload[8], false); ir_to_input2(wdata, &payload[11], false); ir_to_input3(wdata, &payload[14], false); input_sync(wdata->ir); } static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); wiiext_handle(wdata, &payload[2]); } static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); ir_to_input0(wdata, &payload[2], false); ir_to_input1(wdata, &payload[4], true); ir_to_input2(wdata, &payload[7], false); ir_to_input3(wdata, &payload[9], true); input_sync(wdata->ir); wiiext_handle(wdata, &payload[12]); } static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); handler_accel(wdata, payload); wiiext_handle(wdata, &payload[5]); } static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); handler_accel(wdata, payload); ir_to_input0(wdata, &payload[5], false); ir_to_input1(wdata, &payload[7], true); ir_to_input2(wdata, &payload[10], false); ir_to_input3(wdata, &payload[12], true); input_sync(wdata->ir); wiiext_handle(wdata, &payload[15]); } static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload) { wiiext_handle(wdata, payload); } static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload) { handler_keys(wdata, payload); wdata->state.accel_split[0] = payload[2]; wdata->state.accel_split[1] = (payload[0] >> 1) & (0x10 | 0x20); wdata->state.accel_split[1] |= (payload[1] << 1) & (0x40 | 0x80); ir_to_input0(wdata, &payload[3], false); ir_to_input1(wdata, &payload[12], false); input_sync(wdata->ir); } static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload) { __u8 buf[5]; handler_keys(wdata, payload); wdata->state.accel_split[1] |= (payload[0] >> 5) & (0x01 | 0x02); wdata->state.accel_split[1] |= (payload[1] >> 3) & (0x04 | 0x08); buf[0] = 0; buf[1] = 0; buf[2] = wdata->state.accel_split[0]; buf[3] = payload[2]; buf[4] = wdata->state.accel_split[1]; handler_accel(wdata, buf); ir_to_input2(wdata, &payload[3], false); ir_to_input3(wdata, &payload[12], false); input_sync(wdata->ir); } struct wiiproto_handler { __u8 id; size_t size; void (*func)(struct wiimote_data *wdata, const __u8 *payload); }; static struct wiiproto_handler handlers[] = { { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status }, { .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data }, { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return }, { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, { .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA }, { .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE }, { .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI }, { .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE }, { .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE }, { .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE }, { .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE }, { .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E }, { .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 }, { .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 }, { .id = 0 } }; static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { struct wiimote_data *wdata = hid_get_drvdata(hdev); struct wiiproto_handler *h; int i; unsigned long flags; bool handled = false; if (size < 1) return -EINVAL; spin_lock_irqsave(&wdata->state.lock, flags); for (i = 0; handlers[i].id; ++i) { h = &handlers[i]; if (h->id == raw_data[0] && h->size < size) { h->func(wdata, &raw_data[1]); handled = true; } } if (!handled) hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0], size); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimote_leds_destroy(struct wiimote_data *wdata) { int i; struct led_classdev *led; for (i = 0; i < 4; ++i) { if (wdata->leds[i]) { led = wdata->leds[i]; wdata->leds[i] = NULL; led_classdev_unregister(led); kfree(led); } } } static int wiimote_leds_create(struct wiimote_data *wdata) { int i, ret; struct device *dev = &wdata->hdev->dev; size_t namesz = strlen(dev_name(dev)) + 9; struct led_classdev *led; char *name; for (i = 0; i < 4; ++i) { led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); if (!led) { ret = -ENOMEM; goto err; } name = (void*)&led[1]; snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i); led->name = name; led->brightness = 0; led->max_brightness = 1; led->brightness_get = wiimote_leds_get; led->brightness_set = wiimote_leds_set; ret = led_classdev_register(dev, led); if (ret) { kfree(led); goto err; } wdata->leds[i] = led; } return 0; err: wiimote_leds_destroy(wdata); return ret; } static struct wiimote_data *wiimote_create(struct hid_device *hdev) { struct wiimote_data *wdata; int i; wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); if (!wdata) return NULL; wdata->input = input_allocate_device(); if (!wdata->input) goto err; wdata->hdev = hdev; hid_set_drvdata(hdev, wdata); input_set_drvdata(wdata->input, wdata); wdata->input->open = wiimote_input_open; wdata->input->close = wiimote_input_close; wdata->input->dev.parent = &wdata->hdev->dev; wdata->input->id.bustype = wdata->hdev->bus; wdata->input->id.vendor = wdata->hdev->vendor; wdata->input->id.product = wdata->hdev->product; wdata->input->id.version = wdata->hdev->version; wdata->input->name = WIIMOTE_NAME; set_bit(EV_KEY, wdata->input->evbit); for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) set_bit(wiiproto_keymap[i], wdata->input->keybit); set_bit(FF_RUMBLE, wdata->input->ffbit); if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play)) goto err_input; wdata->accel = input_allocate_device(); if (!wdata->accel) goto err_input; input_set_drvdata(wdata->accel, wdata); wdata->accel->open = wiimote_accel_open; wdata->accel->close = wiimote_accel_close; wdata->accel->dev.parent = &wdata->hdev->dev; wdata->accel->id.bustype = wdata->hdev->bus; wdata->accel->id.vendor = wdata->hdev->vendor; wdata->accel->id.product = wdata->hdev->product; wdata->accel->id.version = wdata->hdev->version; wdata->accel->name = WIIMOTE_NAME " Accelerometer"; set_bit(EV_ABS, wdata->accel->evbit); set_bit(ABS_RX, wdata->accel->absbit); set_bit(ABS_RY, wdata->accel->absbit); set_bit(ABS_RZ, wdata->accel->absbit); input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4); input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4); input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4); wdata->ir = input_allocate_device(); if (!wdata->ir) goto err_ir; input_set_drvdata(wdata->ir, wdata); wdata->ir->open = wiimote_ir_open; wdata->ir->close = wiimote_ir_close; wdata->ir->dev.parent = &wdata->hdev->dev; wdata->ir->id.bustype = wdata->hdev->bus; wdata->ir->id.vendor = wdata->hdev->vendor; wdata->ir->id.product = wdata->hdev->product; wdata->ir->id.version = wdata->hdev->version; wdata->ir->name = WIIMOTE_NAME " IR"; set_bit(EV_ABS, wdata->ir->evbit); set_bit(ABS_HAT0X, wdata->ir->absbit); set_bit(ABS_HAT0Y, wdata->ir->absbit); set_bit(ABS_HAT1X, wdata->ir->absbit); set_bit(ABS_HAT1Y, wdata->ir->absbit); set_bit(ABS_HAT2X, wdata->ir->absbit); set_bit(ABS_HAT2Y, wdata->ir->absbit); set_bit(ABS_HAT3X, wdata->ir->absbit); set_bit(ABS_HAT3Y, wdata->ir->absbit); input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4); input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4); spin_lock_init(&wdata->qlock); INIT_WORK(&wdata->worker, wiimote_worker); spin_lock_init(&wdata->state.lock); init_completion(&wdata->state.ready); mutex_init(&wdata->state.sync); wdata->state.drm = WIIPROTO_REQ_DRM_K; return wdata; err_ir: input_free_device(wdata->accel); err_input: input_free_device(wdata->input); err: kfree(wdata); return NULL; } static void wiimote_destroy(struct wiimote_data *wdata) { wiidebug_deinit(wdata); wiiext_deinit(wdata); wiimote_leds_destroy(wdata); power_supply_unregister(&wdata->battery); input_unregister_device(wdata->accel); input_unregister_device(wdata->ir); input_unregister_device(wdata->input); cancel_work_sync(&wdata->worker); hid_hw_stop(wdata->hdev); kfree(wdata); } static int wiimote_hid_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct wiimote_data *wdata; int ret; wdata = wiimote_create(hdev); if (!wdata) { hid_err(hdev, "Can't alloc device\n"); return -ENOMEM; } ret = hid_parse(hdev); if (ret) { hid_err(hdev, "HID parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); if (ret) { hid_err(hdev, "HW start failed\n"); goto err; } ret = input_register_device(wdata->accel); if (ret) { hid_err(hdev, "Cannot register input device\n"); goto err_stop; } ret = input_register_device(wdata->ir); if (ret) { hid_err(hdev, "Cannot register input device\n"); goto err_ir; } ret = input_register_device(wdata->input); if (ret) { hid_err(hdev, "Cannot register input device\n"); goto err_input; } wdata->battery.properties = wiimote_battery_props; wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props); wdata->battery.get_property = wiimote_battery_get_property; wdata->battery.name = "wiimote_battery"; wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; wdata->battery.use_for_apm = 0; ret = power_supply_register(&wdata->hdev->dev, &wdata->battery); if (ret) { hid_err(hdev, "Cannot register battery device\n"); goto err_battery; } ret = wiimote_leds_create(wdata); if (ret) goto err_free; ret = wiiext_init(wdata); if (ret) goto err_free; ret = wiidebug_init(wdata); if (ret) goto err_free; hid_info(hdev, "New device registered\n"); /* by default set led1 after device initialization */ spin_lock_irq(&wdata->state.lock); wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); spin_unlock_irq(&wdata->state.lock); return 0; err_free: wiimote_destroy(wdata); return ret; err_battery: input_unregister_device(wdata->input); wdata->input = NULL; err_input: input_unregister_device(wdata->ir); wdata->ir = NULL; err_ir: input_unregister_device(wdata->accel); wdata->accel = NULL; err_stop: hid_hw_stop(hdev); err: input_free_device(wdata->ir); input_free_device(wdata->accel); input_free_device(wdata->input); kfree(wdata); return ret; } static void wiimote_hid_remove(struct hid_device *hdev) { struct wiimote_data *wdata = hid_get_drvdata(hdev); hid_info(hdev, "Device removed\n"); wiimote_destroy(wdata); } static const struct hid_device_id wiimote_hid_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { } }; MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); static struct hid_driver wiimote_hid_driver = { .name = "wiimote", .id_table = wiimote_hid_devices, .probe = wiimote_hid_probe, .remove = wiimote_hid_remove, .raw_event = wiimote_hid_event, }; static int __init wiimote_init(void) { int ret; ret = hid_register_driver(&wiimote_hid_driver); if (ret) pr_err("Can't register wiimote hid driver\n"); return ret; } static void __exit wiimote_exit(void) { hid_unregister_driver(&wiimote_hid_driver); } module_init(wiimote_init); module_exit(wiimote_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Herrmann "); MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver"); MODULE_VERSION(WIIMOTE_VERSION); xwiimote-0.3+20120630/driver/hid-wiimote-debug.c000066400000000000000000000115501177363750100210700ustar00rootroot00000000000000/* * Debug support for HID Nintendo Wiimote devices * Copyright (c) 2011 David Herrmann */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include #include #include #include #include #include "hid-wiimote.h" struct wiimote_debug { struct wiimote_data *wdata; struct dentry *eeprom; struct dentry *drm; }; static int wiidebug_eeprom_open(struct inode *i, struct file *f) { f->private_data = i->i_private; return 0; } static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, loff_t *off) { struct wiimote_debug *dbg = f->private_data; struct wiimote_data *wdata = dbg->wdata; unsigned long flags; ssize_t ret; char buf[16]; __u16 size; if (s == 0) return -EINVAL; if (*off > 0xffffff) return 0; if (s > 16) s = 16; ret = wiimote_cmd_acquire(wdata); if (ret) return ret; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.cmd_read_size = s; wdata->state.cmd_read_buf = buf; wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, *off & 0xffff); wiiproto_req_reeprom(wdata, *off, s); spin_unlock_irqrestore(&wdata->state.lock, flags); ret = wiimote_cmd_wait(wdata); if (!ret) size = wdata->state.cmd_read_size; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.cmd_read_buf = NULL; spin_unlock_irqrestore(&wdata->state.lock, flags); wiimote_cmd_release(wdata); if (ret) return ret; else if (size == 0) return -EIO; if (copy_to_user(u, buf, size)) return -EFAULT; *off += size; ret = size; return ret; } static const struct file_operations wiidebug_eeprom_fops = { .owner = THIS_MODULE, .open = wiidebug_eeprom_open, .read = wiidebug_eeprom_read, .llseek = generic_file_llseek, }; static const char *wiidebug_drmmap[] = { [WIIPROTO_REQ_NULL] = "NULL", [WIIPROTO_REQ_DRM_K] = "K", [WIIPROTO_REQ_DRM_KA] = "KA", [WIIPROTO_REQ_DRM_KE] = "KE", [WIIPROTO_REQ_DRM_KAI] = "KAI", [WIIPROTO_REQ_DRM_KEE] = "KEE", [WIIPROTO_REQ_DRM_KAE] = "KAE", [WIIPROTO_REQ_DRM_KIE] = "KIE", [WIIPROTO_REQ_DRM_KAIE] = "KAIE", [WIIPROTO_REQ_DRM_E] = "E", [WIIPROTO_REQ_DRM_SKAI1] = "SKAI1", [WIIPROTO_REQ_DRM_SKAI2] = "SKAI2", [WIIPROTO_REQ_MAX] = NULL }; static int wiidebug_drm_show(struct seq_file *f, void *p) { struct wiimote_debug *dbg = f->private; const char *str = NULL; unsigned long flags; __u8 drm; spin_lock_irqsave(&dbg->wdata->state.lock, flags); drm = dbg->wdata->state.drm; spin_unlock_irqrestore(&dbg->wdata->state.lock, flags); if (drm < WIIPROTO_REQ_MAX) str = wiidebug_drmmap[drm]; if (!str) str = "unknown"; seq_printf(f, "%s\n", str); return 0; } static int wiidebug_drm_open(struct inode *i, struct file *f) { return single_open(f, wiidebug_drm_show, i->i_private); } static ssize_t wiidebug_drm_write(struct file *f, const char __user *u, size_t s, loff_t *off) { struct wiimote_debug *dbg = f->private_data; unsigned long flags; char buf[16]; ssize_t len; int i; if (s == 0) return -EINVAL; len = min((size_t) 15, s); if (copy_from_user(buf, u, len)) return -EFAULT; buf[15] = 0; for (i = 0; i < WIIPROTO_REQ_MAX; ++i) { if (!wiidebug_drmmap[i]) continue; if (!strcasecmp(buf, wiidebug_drmmap[i])) break; } if (i == WIIPROTO_REQ_MAX) i = simple_strtoul(buf, NULL, 10); spin_lock_irqsave(&dbg->wdata->state.lock, flags); wiiproto_req_drm(dbg->wdata, (__u8) i); spin_unlock_irqrestore(&dbg->wdata->state.lock, flags); return len; } static const struct file_operations wiidebug_drm_fops = { .owner = THIS_MODULE, .open = wiidebug_drm_open, .read = seq_read, .llseek = seq_lseek, .write = wiidebug_drm_write, .release = single_release, }; int wiidebug_init(struct wiimote_data *wdata) { struct wiimote_debug *dbg; unsigned long flags; int ret = -ENOMEM; dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); if (!dbg) return -ENOMEM; dbg->wdata = wdata; dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR, dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops); if (!dbg->eeprom) goto err; dbg->drm = debugfs_create_file("drm", S_IRUSR, dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops); if (!dbg->drm) goto err_drm; spin_lock_irqsave(&wdata->state.lock, flags); wdata->debug = dbg; spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; err_drm: debugfs_remove(dbg->eeprom); err: kfree(dbg); return ret; } void wiidebug_deinit(struct wiimote_data *wdata) { struct wiimote_debug *dbg = wdata->debug; unsigned long flags; if (!dbg) return; spin_lock_irqsave(&wdata->state.lock, flags); wdata->debug = NULL; spin_unlock_irqrestore(&wdata->state.lock, flags); debugfs_remove(dbg->drm); debugfs_remove(dbg->eeprom); kfree(dbg); } xwiimote-0.3+20120630/driver/hid-wiimote-ext.c000066400000000000000000000521411177363750100206030ustar00rootroot00000000000000/* * HID driver for Nintendo Wiimote extension devices * Copyright (c) 2011 David Herrmann */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include #include #include #include #include "hid-wiimote.h" struct wiimote_ext { struct wiimote_data *wdata; struct work_struct worker; struct input_dev *input; struct input_dev *mp_input; atomic_t opened; atomic_t mp_opened; atomic_t schedule; bool plugged; bool mp_plugged; bool motionp; __u8 ext_type; }; enum wiiext_type { WIIEXT_NONE, /* placeholder */ WIIEXT_CLASSIC, /* Nintendo classic controller */ WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ }; enum wiiext_keys { WIIEXT_KEY_C, WIIEXT_KEY_Z, WIIEXT_KEY_A, WIIEXT_KEY_B, WIIEXT_KEY_X, WIIEXT_KEY_Y, WIIEXT_KEY_ZL, WIIEXT_KEY_ZR, WIIEXT_KEY_PLUS, WIIEXT_KEY_MINUS, WIIEXT_KEY_HOME, WIIEXT_KEY_LEFT, WIIEXT_KEY_RIGHT, WIIEXT_KEY_UP, WIIEXT_KEY_DOWN, WIIEXT_KEY_LT, WIIEXT_KEY_RT, WIIEXT_KEY_COUNT }; static __u16 wiiext_keymap[] = { BTN_C, /* WIIEXT_KEY_C */ BTN_Z, /* WIIEXT_KEY_Z */ BTN_A, /* WIIEXT_KEY_A */ BTN_B, /* WIIEXT_KEY_B */ BTN_X, /* WIIEXT_KEY_X */ BTN_Y, /* WIIEXT_KEY_Y */ BTN_TL2, /* WIIEXT_KEY_ZL */ BTN_TR2, /* WIIEXT_KEY_ZR */ KEY_NEXT, /* WIIEXT_KEY_PLUS */ KEY_PREVIOUS, /* WIIEXT_KEY_MINUS */ BTN_MODE, /* WIIEXT_KEY_HOME */ KEY_LEFT, /* WIIEXT_KEY_LEFT */ KEY_RIGHT, /* WIIEXT_KEY_RIGHT */ KEY_UP, /* WIIEXT_KEY_UP */ KEY_DOWN, /* WIIEXT_KEY_DOWN */ BTN_TL, /* WIIEXT_KEY_LT */ BTN_TR, /* WIIEXT_KEY_RT */ }; /* diable all extensions */ static void ext_disable(struct wiimote_ext *ext) { unsigned long flags; __u8 wmem = 0x55; if (!wiimote_cmd_acquire(ext->wdata)) { wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem)); wiimote_cmd_release(ext->wdata); } spin_lock_irqsave(&ext->wdata->state.lock, flags); ext->motionp = false; ext->ext_type = WIIEXT_NONE; wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&ext->wdata->state.lock, flags); } static bool motionp_read(struct wiimote_ext *ext) { __u8 rmem[2], wmem; ssize_t ret; bool avail = false; if (!atomic_read(&ext->mp_opened)) return false; if (wiimote_cmd_acquire(ext->wdata)) return false; /* initialize motion plus */ wmem = 0x55; ret = wiimote_cmd_write(ext->wdata, 0xa600f0, &wmem, sizeof(wmem)); if (ret) goto error; /* read motion plus ID */ ret = wiimote_cmd_read(ext->wdata, 0xa600fe, rmem, 2); if (ret == 2 || rmem[1] == 0x5) avail = true; error: wiimote_cmd_release(ext->wdata); return avail; } static __u8 ext_read(struct wiimote_ext *ext) { ssize_t ret; __u8 rmem[2], wmem; __u8 type = WIIEXT_NONE; if (!ext->plugged || !atomic_read(&ext->opened)) return WIIEXT_NONE; if (wiimote_cmd_acquire(ext->wdata)) return WIIEXT_NONE; /* initialize extension */ wmem = 0x55; ret = wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem)); if (!ret) { /* disable encryption */ wmem = 0x0; wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem)); } /* read extension ID */ ret = wiimote_cmd_read(ext->wdata, 0xa400fe, rmem, 2); if (ret == 2) { if (rmem[0] == 0 && rmem[1] == 0) type = WIIEXT_NUNCHUCK; else if (rmem[0] == 0x01 && rmem[1] == 0x01) type = WIIEXT_CLASSIC; } wiimote_cmd_release(ext->wdata); return type; } static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type) { unsigned long flags; __u8 wmem; int ret; if (motionp) { if (wiimote_cmd_acquire(ext->wdata)) return; if (ext_type == WIIEXT_CLASSIC) wmem = 0x07; else if (ext_type == WIIEXT_NUNCHUCK) wmem = 0x05; else wmem = 0x04; ret = wiimote_cmd_write(ext->wdata, 0xa600fe, &wmem, sizeof(wmem)); wiimote_cmd_release(ext->wdata); if (ret) return; } spin_lock_irqsave(&ext->wdata->state.lock, flags); ext->motionp = motionp; ext->ext_type = ext_type; wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&ext->wdata->state.lock, flags); } static void wiiext_worker(struct work_struct *work) { struct wiimote_ext *ext = container_of(work, struct wiimote_ext, worker); bool motionp; __u8 ext_type; /* fresh worker needs no reschedule so reset schedule count */ atomic_set(&ext->schedule, 1); ext_disable(ext); motionp = motionp_read(ext); ext_type = ext_read(ext); ext_enable(ext, motionp, ext_type); /* worker done; check for reschedule */ if (!atomic_dec_and_test(&ext->schedule)) schedule_work(work); } /* schedule work only once, otherwise mark for reschedule */ static void wiiext_schedule(struct wiimote_ext *ext) { if (atomic_inc_return(&ext->schedule) == 1) schedule_work(&ext->worker); } /* * Reacts on extension port events * Whenever the driver gets an event from the wiimote that an extension has been * plugged or unplugged, this funtion shall be called. It checks what extensions * are connected and initializes and activates them. * This can be called in atomic context. The initialization is done in a * separate worker thread. The state.lock spinlock must be held by the caller. */ void wiiext_event(struct wiimote_data *wdata, bool plugged) { if (!wdata->ext) return; if (wdata->ext->plugged == plugged) return; wdata->ext->plugged = plugged; if (!plugged) wdata->ext->mp_plugged = false; /* * We need to call wiiext_schedule(wdata->ext) here, however, the * extension initialization logic is not fully understood and so * automatic initialization is not supported, yet. */ } /* * Returns true if the current DRM mode should contain extension data and false * if there is no interest in extension data. * All supported extensions send 6 byte extension data so any DRM that contains * extension bytes is fine. * The caller must hold the state.lock spinlock. */ bool wiiext_active(struct wiimote_data *wdata) { if (!wdata->ext) return false; return wdata->ext->motionp || wdata->ext->ext_type; } static void handler_motionp(struct wiimote_ext *ext, const __u8 *payload) { __s32 x, y, z; bool plugged; /* | 8 7 6 5 4 3 | 2 | 1 | * -----+------------------------------+-----+-----+ * 1 | Yaw Speed <7:0> | * 2 | Roll Speed <7:0> | * 3 | Pitch Speed <7:0> | * -----+------------------------------+-----+-----+ * 4 | Yaw Speed <13:8> | Yaw |Pitch| * -----+------------------------------+-----+-----+ * 5 | Roll Speed <13:8> |Roll | Ext | * -----+------------------------------+-----+-----+ * 6 | Pitch Speed <13:8> | 1 | 0 | * -----+------------------------------+-----+-----+ * The single bits Yaw, Roll, Pitch in the lower right corner specify * whether the wiimote is rotating fast (0) or slow (1). Speed for slow * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast * and 9 for slow. * If the wiimote is not rotating the sensor reports 2^13 = 8192. * Ext specifies whether an extension is connected to the motionp. */ x = payload[0]; y = payload[1]; z = payload[2]; x |= (((__u16)payload[3]) << 6) & 0xff00; y |= (((__u16)payload[4]) << 6) & 0xff00; z |= (((__u16)payload[5]) << 6) & 0xff00; x -= 8192; y -= 8192; z -= 8192; if (!(payload[3] & 0x02)) x *= 18; else x *= 9; if (!(payload[4] & 0x02)) y *= 18; else y *= 9; if (!(payload[3] & 0x01)) z *= 18; else z *= 9; input_report_abs(ext->mp_input, ABS_RX, x); input_report_abs(ext->mp_input, ABS_RY, y); input_report_abs(ext->mp_input, ABS_RZ, z); input_sync(ext->mp_input); plugged = payload[5] & 0x01; if (plugged != ext->mp_plugged) { ext->mp_plugged = plugged; wiiext_schedule(ext); } } static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload) { __s16 x, y, z, bx, by; /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 | * -----+----------+---------+---------+----+-----+ * 1 | Button X <7:0> | * 2 | Button Y <7:0> | * -----+----------+---------+---------+----+-----+ * 3 | Speed X <9:2> | * 4 | Speed Y <9:2> | * 5 | Speed Z <9:2> | * -----+----------+---------+---------+----+-----+ * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ | * -----+----------+---------+---------+----+-----+ * Button X/Y is the analog stick. Speed X, Y and Z are the * accelerometer data in the same format as the wiimote's accelerometer. * The 6th byte contains the LSBs of the accelerometer data. * BC and BZ are the C and Z buttons: 0 means pressed * * If reported interleaved with motionp, then the layout changes. The * 5th and 6th byte changes to: * -----+-----------------------------------+-----+ * 5 | Speed Z <9:3> | EXT | * -----+--------+-----+-----+----+----+----+-----+ * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 | * -----+--------+-----+-----+----+----+----+-----+ * All three accelerometer values lose their LSB. The other data is * still available but slightly moved. * * Center data for button values is 128. Center value for accelerometer * values it 512 / 0x200 */ bx = payload[0]; by = payload[1]; bx -= 128; by -= 128; x = payload[2] << 2; y = payload[3] << 2; z = payload[4] << 2; if (ext->motionp) { x |= (payload[5] >> 3) & 0x02; y |= (payload[5] >> 4) & 0x02; z &= ~0x4; z |= (payload[5] >> 5) & 0x06; } else { x |= (payload[5] >> 2) & 0x03; y |= (payload[5] >> 4) & 0x03; z |= (payload[5] >> 6) & 0x03; } x -= 0x200; y -= 0x200; z -= 0x200; input_report_abs(ext->input, ABS_HAT0X, bx); input_report_abs(ext->input, ABS_HAT0Y, by); input_report_abs(ext->input, ABS_RX, x); input_report_abs(ext->input, ABS_RY, y); input_report_abs(ext->input, ABS_RZ, z); if (ext->motionp) { input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x04)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x08)); } else { input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x01)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x02)); } input_sync(ext->input); } static void handler_classic(struct wiimote_ext *ext, const __u8 *payload) { __s8 rx, ry, lx, ly, lt, rt; /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | RX <5:4> | LX <5:0> | * 2 | RX <3:2> | LY <5:0> | * -----+-----+-----+-----+-----------------------------+ * 3 |RX<1>| LT <5:4> | RY <5:1> | * -----+-----+-----------+-----------------------------+ * 4 | LT <3:1> | RT <5:1> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * All buttons are 0 if pressed * RX and RY are right analog stick * LX and LY are left analog stick * LT is left trigger, RT is right trigger * BLT is 0 if left trigger is fully pressed * BRT is 0 if right trigger is fully pressed * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons * BZL is left Z button and BZR is right Z button * B-, BH, B+ are +, HOME and - buttons * BB, BY, BA, BX are A, B, X, Y buttons * LSB of RX, RY, LT, and RT are not transmitted and always 0. * * With motionp enabled it changes slightly to this: * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | RX <4:3> | LX <5:1> | BDU | * 2 | RX <2:1> | LY <5:1> | BDL | * -----+-----+-----+-----+-----------------------+-----+ * 3 |RX<0>| LT <4:3> | RY <4:0> | * -----+-----+-----------+-----------------------------+ * 4 | LT <2:0> | RT <4:0> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest * is the same as before. */ if (ext->motionp) { lx = payload[0] & 0x3e; ly = payload[0] & 0x3e; } else { lx = payload[0] & 0x3f; ly = payload[0] & 0x3f; } rx = (payload[0] >> 3) & 0x14; rx |= (payload[1] >> 5) & 0x06; rx |= (payload[2] >> 7) & 0x01; ry = payload[2] & 0x1f; rt = payload[3] & 0x1f; lt = (payload[2] >> 2) & 0x18; lt |= (payload[3] >> 5) & 0x07; rx <<= 1; ry <<= 1; rt <<= 1; lt <<= 1; input_report_abs(ext->input, ABS_HAT1X, lx - 0x20); input_report_abs(ext->input, ABS_HAT1Y, ly - 0x20); input_report_abs(ext->input, ABS_HAT2X, rx - 0x20); input_report_abs(ext->input, ABS_HAT2Y, ry - 0x20); input_report_abs(ext->input, ABS_HAT3X, rt - 0x20); input_report_abs(ext->input, ABS_HAT3Y, lt - 0x20); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RIGHT], !!(payload[4] & 0x80)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_DOWN], !!(payload[4] & 0x40)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LT], !!(payload[4] & 0x20)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_MINUS], !!(payload[4] & 0x10)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_HOME], !!(payload[4] & 0x08)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_PLUS], !!(payload[4] & 0x04)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RT], !!(payload[4] & 0x02)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZL], !!(payload[5] & 0x80)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_B], !!(payload[5] & 0x40)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_Y], !!(payload[5] & 0x20)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_A], !!(payload[5] & 0x10)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_X], !!(payload[5] & 0x08)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZR], !!(payload[5] & 0x04)); if (ext->motionp) { input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP], !!(payload[0] & 0x01)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT], !!(payload[1] & 0x01)); } else { input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP], !!(payload[5] & 0x01)); input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT], !!(payload[5] & 0x02)); } input_sync(ext->input); } /* call this with state.lock spinlock held */ void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) { struct wiimote_ext *ext = wdata->ext; if (!ext) return; if (ext->motionp && (payload[5] & 0x02)) { handler_motionp(ext, payload); } else if (ext->ext_type == WIIEXT_NUNCHUCK) { handler_nunchuck(ext, payload); } else if (ext->ext_type == WIIEXT_CLASSIC) { handler_classic(ext, payload); } } static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr, char *buf) { struct wiimote_data *wdata = dev_to_wii(dev); __u8 type = WIIEXT_NONE; bool motionp = false; unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); if (wdata->ext) { motionp = wdata->ext->motionp; type = wdata->ext->ext_type; } spin_unlock_irqrestore(&wdata->state.lock, flags); if (type == WIIEXT_NUNCHUCK) { if (motionp) return sprintf(buf, "motionp+nunchuck\n"); else return sprintf(buf, "nunchuck\n"); } else if (type == WIIEXT_CLASSIC) { if (motionp) return sprintf(buf, "motionp+classic\n"); else return sprintf(buf, "classic\n"); } else { if (motionp) return sprintf(buf, "motionp\n"); else return sprintf(buf, "none\n"); } } static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL); static int wiiext_input_open(struct input_dev *dev) { struct wiimote_ext *ext = input_get_drvdata(dev); int ret; ret = hid_hw_open(ext->wdata->hdev); if (ret) return ret; atomic_inc(&ext->opened); wiiext_schedule(ext); return 0; } static void wiiext_input_close(struct input_dev *dev) { struct wiimote_ext *ext = input_get_drvdata(dev); atomic_dec(&ext->opened); wiiext_schedule(ext); hid_hw_close(ext->wdata->hdev); } static int wiiext_mp_open(struct input_dev *dev) { struct wiimote_ext *ext = input_get_drvdata(dev); int ret; ret = hid_hw_open(ext->wdata->hdev); if (ret) return ret; atomic_inc(&ext->mp_opened); wiiext_schedule(ext); return 0; } static void wiiext_mp_close(struct input_dev *dev) { struct wiimote_ext *ext = input_get_drvdata(dev); atomic_dec(&ext->mp_opened); wiiext_schedule(ext); hid_hw_close(ext->wdata->hdev); } /* Initializes the extension driver of a wiimote */ int wiiext_init(struct wiimote_data *wdata) { struct wiimote_ext *ext; unsigned long flags; int ret, i; ext = kzalloc(sizeof(*ext), GFP_KERNEL); if (!ext) return -ENOMEM; ext->wdata = wdata; INIT_WORK(&ext->worker, wiiext_worker); ext->input = input_allocate_device(); if (!ext->input) { ret = -ENOMEM; goto err_input; } input_set_drvdata(ext->input, ext); ext->input->open = wiiext_input_open; ext->input->close = wiiext_input_close; ext->input->dev.parent = &wdata->hdev->dev; ext->input->id.bustype = wdata->hdev->bus; ext->input->id.vendor = wdata->hdev->vendor; ext->input->id.product = wdata->hdev->product; ext->input->id.version = wdata->hdev->version; ext->input->name = WIIMOTE_NAME " Extension"; set_bit(EV_KEY, ext->input->evbit); for (i = 0; i < WIIEXT_KEY_COUNT; ++i) set_bit(wiiext_keymap[i], ext->input->keybit); set_bit(EV_ABS, ext->input->evbit); set_bit(ABS_HAT0X, ext->input->absbit); set_bit(ABS_HAT0Y, ext->input->absbit); set_bit(ABS_HAT1X, ext->input->absbit); set_bit(ABS_HAT1Y, ext->input->absbit); set_bit(ABS_HAT2X, ext->input->absbit); set_bit(ABS_HAT2Y, ext->input->absbit); set_bit(ABS_HAT3X, ext->input->absbit); set_bit(ABS_HAT3Y, ext->input->absbit); input_set_abs_params(ext->input, ABS_HAT0X, -120, 120, 2, 4); input_set_abs_params(ext->input, ABS_HAT0Y, -120, 120, 2, 4); input_set_abs_params(ext->input, ABS_HAT1X, -30, 30, 1, 1); input_set_abs_params(ext->input, ABS_HAT1Y, -30, 30, 1, 1); input_set_abs_params(ext->input, ABS_HAT2X, -30, 30, 1, 1); input_set_abs_params(ext->input, ABS_HAT2Y, -30, 30, 1, 1); input_set_abs_params(ext->input, ABS_HAT3X, -30, 30, 1, 1); input_set_abs_params(ext->input, ABS_HAT3Y, -30, 30, 1, 1); set_bit(ABS_RX, ext->input->absbit); set_bit(ABS_RY, ext->input->absbit); set_bit(ABS_RZ, ext->input->absbit); input_set_abs_params(ext->input, ABS_RX, -500, 500, 2, 4); input_set_abs_params(ext->input, ABS_RY, -500, 500, 2, 4); input_set_abs_params(ext->input, ABS_RZ, -500, 500, 2, 4); ret = input_register_device(ext->input); if (ret) { input_free_device(ext->input); goto err_input; } ext->mp_input = input_allocate_device(); if (!ext->mp_input) { ret = -ENOMEM; goto err_mp; } input_set_drvdata(ext->mp_input, ext); ext->mp_input->open = wiiext_mp_open; ext->mp_input->close = wiiext_mp_close; ext->mp_input->dev.parent = &wdata->hdev->dev; ext->mp_input->id.bustype = wdata->hdev->bus; ext->mp_input->id.vendor = wdata->hdev->vendor; ext->mp_input->id.product = wdata->hdev->product; ext->mp_input->id.version = wdata->hdev->version; ext->mp_input->name = WIIMOTE_NAME " Motion+"; set_bit(EV_ABS, ext->mp_input->evbit); set_bit(ABS_RX, ext->mp_input->absbit); set_bit(ABS_RY, ext->mp_input->absbit); set_bit(ABS_RZ, ext->mp_input->absbit); input_set_abs_params(ext->mp_input, ABS_RX, -160000, 160000, 4, 8); input_set_abs_params(ext->mp_input, ABS_RY, -160000, 160000, 4, 8); input_set_abs_params(ext->mp_input, ABS_RZ, -160000, 160000, 4, 8); ret = input_register_device(ext->mp_input); if (ret) { input_free_device(ext->mp_input); goto err_mp; } ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension); if (ret) goto err_dev; spin_lock_irqsave(&wdata->state.lock, flags); wdata->ext = ext; spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; err_dev: input_unregister_device(ext->mp_input); err_mp: input_unregister_device(ext->input); err_input: kfree(ext); return ret; } /* Deinitializes the extension driver of a wiimote */ void wiiext_deinit(struct wiimote_data *wdata) { struct wiimote_ext *ext = wdata->ext; unsigned long flags; if (!ext) return; spin_lock_irqsave(&wdata->state.lock, flags); wdata->ext = NULL; spin_unlock_irqrestore(&wdata->state.lock, flags); device_remove_file(&wdata->hdev->dev, &dev_attr_extension); input_unregister_device(ext->mp_input); input_unregister_device(ext->input); cancel_work_sync(&ext->worker); kfree(ext); } xwiimote-0.3+20120630/driver/hid-wiimote.h000066400000000000000000000126241177363750100200140ustar00rootroot00000000000000#ifndef __HID_WIIMOTE_H #define __HID_WIIMOTE_H /* * HID driver for Nintendo Wiimote devices * Copyright (c) 2011 David Herrmann */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #include #include #include #include #include #include #include #include #include #define WIIMOTE_NAME "Nintendo Wii Remote" #define WIIMOTE_BUFSIZE 32 #define WIIPROTO_FLAG_LED1 0x01 #define WIIPROTO_FLAG_LED2 0x02 #define WIIPROTO_FLAG_LED3 0x04 #define WIIPROTO_FLAG_LED4 0x08 #define WIIPROTO_FLAG_RUMBLE 0x10 #define WIIPROTO_FLAG_ACCEL 0x20 #define WIIPROTO_FLAG_IR_BASIC 0x40 #define WIIPROTO_FLAG_IR_EXT 0x80 #define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */ #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) #define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \ WIIPROTO_FLAG_IR_FULL) /* return flag for led \num */ #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) struct wiimote_buf { __u8 data[HID_MAX_BUFFER_SIZE]; size_t size; }; struct wiimote_state { spinlock_t lock; __u8 flags; __u8 accel_split[2]; __u8 drm; /* synchronous cmd requests */ struct mutex sync; struct completion ready; int cmd; __u32 opt; /* results of synchronous requests */ __u8 cmd_battery; __u8 cmd_err; __u8 *cmd_read_buf; __u8 cmd_read_size; }; struct wiimote_data { struct hid_device *hdev; struct input_dev *input; struct led_classdev *leds[4]; struct input_dev *accel; struct input_dev *ir; struct power_supply battery; struct wiimote_ext *ext; struct wiimote_debug *debug; spinlock_t qlock; __u8 head; __u8 tail; struct wiimote_buf outq[WIIMOTE_BUFSIZE]; struct work_struct worker; struct wiimote_state state; }; enum wiiproto_reqs { WIIPROTO_REQ_NULL = 0x0, WIIPROTO_REQ_RUMBLE = 0x10, WIIPROTO_REQ_LED = 0x11, WIIPROTO_REQ_DRM = 0x12, WIIPROTO_REQ_IR1 = 0x13, WIIPROTO_REQ_SREQ = 0x15, WIIPROTO_REQ_WMEM = 0x16, WIIPROTO_REQ_RMEM = 0x17, WIIPROTO_REQ_IR2 = 0x1a, WIIPROTO_REQ_STATUS = 0x20, WIIPROTO_REQ_DATA = 0x21, WIIPROTO_REQ_RETURN = 0x22, WIIPROTO_REQ_DRM_K = 0x30, WIIPROTO_REQ_DRM_KA = 0x31, WIIPROTO_REQ_DRM_KE = 0x32, WIIPROTO_REQ_DRM_KAI = 0x33, WIIPROTO_REQ_DRM_KEE = 0x34, WIIPROTO_REQ_DRM_KAE = 0x35, WIIPROTO_REQ_DRM_KIE = 0x36, WIIPROTO_REQ_DRM_KAIE = 0x37, WIIPROTO_REQ_DRM_E = 0x3d, WIIPROTO_REQ_DRM_SKAI1 = 0x3e, WIIPROTO_REQ_DRM_SKAI2 = 0x3f, WIIPROTO_REQ_MAX }; #define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ dev)) extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm); extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset, const __u8 *wmem, __u8 size); extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, __u8 *rmem, __u8 size); #define wiiproto_req_rreg(wdata, os, sz) \ wiiproto_req_rmem((wdata), false, (os), (sz)) #define wiiproto_req_reeprom(wdata, os, sz) \ wiiproto_req_rmem((wdata), true, (os), (sz)) extern void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, __u32 offset, __u16 size); #ifdef CONFIG_HID_WIIMOTE_EXT extern int wiiext_init(struct wiimote_data *wdata); extern void wiiext_deinit(struct wiimote_data *wdata); extern void wiiext_event(struct wiimote_data *wdata, bool plugged); extern bool wiiext_active(struct wiimote_data *wdata); extern void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload); #else static inline int wiiext_init(void *u) { return 0; } static inline void wiiext_deinit(void *u) { } static inline void wiiext_event(void *u, bool p) { } static inline bool wiiext_active(void *u) { return false; } static inline void wiiext_handle(void *u, const __u8 *p) { } #endif #ifdef CONFIG_DEBUG_FS extern int wiidebug_init(struct wiimote_data *wdata); extern void wiidebug_deinit(struct wiimote_data *wdata); #else static inline int wiidebug_init(void *u) { return 0; } static inline void wiidebug_deinit(void *u) { } #endif /* requires the state.lock spinlock to be held */ static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd, __u32 opt) { return wdata->state.cmd == cmd && wdata->state.opt == opt; } /* requires the state.lock spinlock to be held */ static inline void wiimote_cmd_complete(struct wiimote_data *wdata) { wdata->state.cmd = WIIPROTO_REQ_NULL; complete(&wdata->state.ready); } static inline int wiimote_cmd_acquire(struct wiimote_data *wdata) { return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0; } /* requires the state.lock spinlock to be held */ static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd, __u32 opt) { INIT_COMPLETION(wdata->state.ready); wdata->state.cmd = cmd; wdata->state.opt = opt; } static inline void wiimote_cmd_release(struct wiimote_data *wdata) { mutex_unlock(&wdata->state.sync); } static inline int wiimote_cmd_wait(struct wiimote_data *wdata) { int ret; ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ); if (ret < 0) return -ERESTARTSYS; else if (ret == 0) return -EIO; else return 0; } #endif xwiimote-0.3+20120630/lib/000077500000000000000000000000001177363750100146725ustar00rootroot00000000000000xwiimote-0.3+20120630/lib/core.c000066400000000000000000000346111177363750100157730ustar00rootroot00000000000000/* * XWiimote - lib * Written 2010, 2011, 2012 by David Herrmann * Dedicated to the Public Domain */ #include #include #include #include #include #include #include #include #include #include #include "internal.h" #include "xwiimote.h" struct xwii_iface { size_t ref; char *syspath; int efd; int rumble_id; unsigned int ifaces; int if_core; int if_accel; int if_ir; int if_mp; int if_ext; struct xwii_event_abs accel_cache; struct xwii_event_abs ir_cache[4]; }; /* * Create new interface structure * This does not validate \syspath. \syspath is first opened when calling * xwii_iface_open(). It must point to the base-directory in sysfs of the * xwiimote HID device. This is most often: * /sys/bus/hid/devices/ * On success 0 is returned and the new device is stored in \dev. On failure, * \dev is not touched and a negative error is returned. * Initial refcount is 1 so you need to call *_unref() to free the device. * * Internally we use multiple file-descriptors for all the event devices of each * Wii Remote. However, externally we want only one fd for the application so we * use epoll to multiplex between all the internal fds. Note that you can poll * on epoll-fds like any other fd so the user won't notice. */ int xwii_iface_new(struct xwii_iface **dev, const char *syspath) { struct xwii_iface *d; int ret; if (!dev || !syspath) return -EINVAL; d = malloc(sizeof(*d)); if (!d) return -ENOMEM; memset(d, 0, sizeof(*d)); d->ref = 1; d->if_core = -1; d->if_accel = -1; d->if_ir = -1; d->if_mp = -1; d->if_ext = -1; d->rumble_id = -1; d->syspath = strdup(syspath); if (!d->syspath) { ret= -ENOMEM; goto err; } d->efd = epoll_create1(EPOLL_CLOEXEC); if (d->efd < 0) { ret = -EFAULT; goto err_path; } *dev = d; return 0; err_path: free(d->syspath); err: free(d); return ret; } void xwii_iface_ref(struct xwii_iface *dev) { if (!dev || !dev->ref) return; dev->ref++; } void xwii_iface_unref(struct xwii_iface *dev) { if (!dev || !dev->ref) return; if (--dev->ref) return; xwii_iface_close(dev, XWII_IFACE_ALL); close(dev->efd); free(dev->syspath); free(dev); } int xwii_iface_get_fd(struct xwii_iface *dev) { if (!dev) return -1; return dev->efd; } /* maps interface ID to interface name */ static const char *id2name_map[] = { [XWII_IFACE_CORE] = XWII_NAME_CORE, [XWII_IFACE_ACCEL] = XWII_NAME_ACCEL, [XWII_IFACE_IR] = XWII_NAME_IR, [XWII_IFACE_MP] = XWII_NAME_MP, [XWII_IFACE_EXT] = XWII_NAME_EXT, }; /* * Opens an event interface and checks whether it is of the right type. * \path: absolute path to event interface (eg., /dev/input/event5) * \type: type of event interface (eg., XWII_IFACE_CORE) * \wr: Open file as writable * Returns positive fd on success or negative error on error. */ static int open_ev(const char *path, unsigned int type, bool wr) { uint16_t id[4]; char name[256]; int ret, fd, mod; if (wr) mod = O_RDWR; else mod = O_RDONLY; ret = open(path, mod | O_NONBLOCK | O_CLOEXEC); if (ret < 0) return -errno; fd = ret; if (ioctl(fd, EVIOCGID, id)) { close(fd); return -errno; } if (id[ID_BUS] != XWII_ID_BUS || id[ID_VENDOR] != XWII_ID_VENDOR || id[ID_PRODUCT] != XWII_ID_PRODUCT) { close(fd); return -EINVAL; } if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) { close(fd); return -errno; } name[sizeof(name) - 1] = 0; if (strcmp(id2name_map[type], name)) { close(fd); return -EINVAL; } return fd; } /* * Search in \list for a matching entry of \iface. * This allocates a new string containig the path to the event device: * /dev/input/eventX * It returns NULL if \list does not contain a matching entry or on memory * allocation failure. * You must free the returned buffer with free()! */ static char *find_event(struct sfs_input_dev *list, unsigned int iface) { char *res; static const char prefix[] = "/dev/input/"; static const size_t plen = sizeof(prefix) - 1; size_t len, size; while (list) { if (list->name && !strcmp(list->name, id2name_map[iface])) break; list = list->next; } if (!list || !list->event) return NULL; len = strlen(list->event); size = plen + len; res = malloc(size + 1); if (!res) return NULL; res[size] = 0; memcpy(res, prefix, plen); memcpy(&res[plen], list->event, len); return res; } /* * Open interface \iface. * Opens the iface always in readable mode and if \wr is true also in writable * mode. \list is used to find the related event interface. * Returns <0 on error. Otherwise returns the open FD. */ static int open_iface(struct xwii_iface *dev, unsigned int iface, bool wr, struct sfs_input_dev *list) { char *path; int ret; struct epoll_event ep; path = find_event(list, iface); if (!path) return -ENOENT; ret = open_ev(path, iface, wr); free(path); if (ret < 0) return ret; memset(&ep, 0, sizeof(ep)); ep.events = EPOLLIN; ep.data.ptr = dev; if (epoll_ctl(dev->efd, EPOLL_CTL_ADD, ret, &ep) < 0) { close(ret); return -EFAULT; } dev->ifaces |= iface; return ret; } /* * Upload the generic rumble event to the device. This may later be used for * force-feedback effects. The event id is safed for later use. */ static void upload_rumble(struct xwii_iface *dev) { struct ff_effect effect = { .type = FF_RUMBLE, .id = -1, .u.rumble.strong_magnitude = 1, .replay.length = 0, .replay.delay = 0, }; if (ioctl(dev->if_core, EVIOCSFF, &effect) != -1) dev->rumble_id = effect.id; } /* * Opens the interfaces that are specified by \ifaces. * If an interface is already opened, it is not touched. If \ifaces contains * XWII_IFACE_WRITABLE, then the interfaces are also opened for writing. But * if an interface is already opened, it is not reopened in write-mode so you * need to close them first. * * If one of the ifaces cannot be opened, a negative error code is returned. * Some of the interfaces may be opened successfully, though. So if you need to * know which interfaces failed, check xwii_iface_opened() after calling this. * This will give you a list of interfaces that were opened before one interface * failed. The order of opening is equal to the ascending order of the absolute * values of the iface-flags. XWII_IFACE_CORE first, then XWII_IFACE_ACCEL and * so on. * Returns 0 on success. */ int xwii_iface_open(struct xwii_iface *dev, unsigned int ifaces) { bool wr; int ret = 0; struct sfs_input_dev *list; if (!dev) return -EINVAL; wr = ifaces & XWII_IFACE_WRITABLE; /* remove invalid and already opened ifaces */ ifaces &= ~dev->ifaces; ifaces &= XWII_IFACE_ALL; if (!ifaces) return 0; /* retrieve event file names */ ret = sfs_input_list(dev->syspath, &list); if (ret) return ret; if (ifaces & XWII_IFACE_CORE) { ret = open_iface(dev, XWII_IFACE_CORE, wr, list); if (ret < 0) goto err_sys; dev->if_core = ret; ret = 0; if (wr) upload_rumble(dev); } if (ifaces & XWII_IFACE_ACCEL) { ret = open_iface(dev, XWII_IFACE_ACCEL, wr, list); if (ret < 0) goto err_sys; dev->if_accel = ret; ret = 0; } if (ifaces & XWII_IFACE_IR) { ret = open_iface(dev, XWII_IFACE_IR, wr, list); if (ret < 0) goto err_sys; dev->if_ir = ret; ret = 0; } if (ifaces & XWII_IFACE_MP) { ret = open_iface(dev, XWII_IFACE_MP, wr, list); if (ret < 0) goto err_sys; dev->if_mp = ret; ret = 0; } if (ifaces & XWII_IFACE_EXT) { ret = open_iface(dev, XWII_IFACE_EXT, wr, list); if (ret < 0) goto err_sys; dev->if_ext = ret; ret = 0; } err_sys: sfs_input_unref(list); return ret; } /* closes the interfaces given in \ifaces */ void xwii_iface_close(struct xwii_iface *dev, unsigned int ifaces) { if (!dev || !ifaces) return; ifaces &= XWII_IFACE_ALL; if (ifaces & XWII_IFACE_CORE && dev->if_core != -1) { epoll_ctl(dev->efd, EPOLL_CTL_DEL, dev->if_core, NULL); close(dev->if_core); dev->if_core = -1; } if (ifaces & XWII_IFACE_ACCEL && dev->if_accel != -1) { epoll_ctl(dev->efd, EPOLL_CTL_DEL, dev->if_accel, NULL); close(dev->if_accel); dev->if_accel = -1; } if (ifaces & XWII_IFACE_IR && dev->if_ir != -1) { epoll_ctl(dev->efd, EPOLL_CTL_DEL, dev->if_ir, NULL); close(dev->if_ir); dev->if_ir = -1; } if (ifaces & XWII_IFACE_MP && dev->if_mp != -1) { epoll_ctl(dev->efd, EPOLL_CTL_DEL, dev->if_mp, NULL); close(dev->if_mp); dev->if_mp = -1; } if (ifaces & XWII_IFACE_EXT && dev->if_ext != -1) { epoll_ctl(dev->efd, EPOLL_CTL_DEL, dev->if_ext, NULL); close(dev->if_ext); dev->if_ext = -1; } dev->ifaces &= ~ifaces; } /* returns bitmap of opened interfaces */ unsigned int xwii_iface_opened(struct xwii_iface *dev) { return dev->ifaces; } static int read_event(int fd, struct input_event *ev) { int ret; ret = read(fd, ev, sizeof(*ev)); if (ret < 0) return -errno; else if (ret == 0) return 0; else if (ret != sizeof(*ev)) return -EIO; else return 1; } static int read_core(struct xwii_iface *dev, struct xwii_event *ev) { int ret; struct input_event input; unsigned int key; if (dev->if_core == -1) return -EAGAIN; try_again: ret = read_event(dev->if_core, &input); if (ret == -EAGAIN) { return -EAGAIN; } else if (ret <= 0) { xwii_iface_close(dev, XWII_IFACE_CORE); return -ENODEV; } if (input.type != EV_KEY) goto try_again; if (input.value < 0 || input.value > 2) goto try_again; switch (input.code) { case KEY_LEFT: key = XWII_KEY_LEFT; break; case KEY_RIGHT: key = XWII_KEY_RIGHT; break; case KEY_UP: key = XWII_KEY_UP; break; case KEY_DOWN: key = XWII_KEY_DOWN; break; case KEY_NEXT: key = XWII_KEY_PLUS; break; case KEY_PREVIOUS: key = XWII_KEY_MINUS; break; case BTN_1: key = XWII_KEY_ONE; break; case BTN_2: key = XWII_KEY_TWO; break; case BTN_A: key = XWII_KEY_A; break; case BTN_B: key = XWII_KEY_B; break; case BTN_MODE: key = XWII_KEY_HOME; break; default: goto try_again; } memset(ev, 0, sizeof(*ev)); memcpy(&ev->time, &input.time, sizeof(struct timeval)); ev->type = XWII_EVENT_KEY; ev->v.key.code = key; ev->v.key.state = input.value; return 0; } static int read_accel(struct xwii_iface *dev, struct xwii_event *ev) { int ret; struct input_event input; if (dev->if_accel == -1) return -EAGAIN; try_again: ret = read_event(dev->if_accel, &input); if (ret == -EAGAIN) { return -EAGAIN; } else if (ret <= 0) { xwii_iface_close(dev, XWII_IFACE_ACCEL); return -ENODEV; } if (input.type == EV_SYN) { memset(ev, 0, sizeof(*ev)); memcpy(&ev->time, &input.time, sizeof(struct timeval)); memcpy(ev->v.abs, &dev->accel_cache, sizeof(dev->accel_cache)); ev->type = XWII_EVENT_ACCEL; return 0; } if (input.type != EV_ABS) goto try_again; if (input.code == ABS_RX) dev->accel_cache.x = input.value; else if (input.code == ABS_RY) dev->accel_cache.y = input.value; else if (input.code == ABS_RZ) dev->accel_cache.z = input.value; goto try_again; } static int read_ir(struct xwii_iface *dev, struct xwii_event *ev) { int ret; struct input_event input; if (dev->if_ir == -1) return -EAGAIN; try_again: ret = read_event(dev->if_ir, &input); if (ret == -EAGAIN) { return -EAGAIN; } else if (ret <= 0) { xwii_iface_close(dev, XWII_IFACE_IR); return -ENODEV; } if (input.type == EV_SYN) { memset(ev, 0, sizeof(*ev)); memcpy(&ev->time, &input.time, sizeof(struct timeval)); memcpy(&ev->v.abs, dev->ir_cache, sizeof(dev->ir_cache)); ev->type = XWII_EVENT_IR; return 0; } if (input.type != EV_ABS) goto try_again; if (input.code == ABS_HAT0X) dev->ir_cache[0].x = input.value; else if (input.code == ABS_HAT0Y) dev->ir_cache[0].y = input.value; else if (input.code == ABS_HAT1X) dev->ir_cache[1].x = input.value; else if (input.code == ABS_HAT1Y) dev->ir_cache[1].y = input.value; else if (input.code == ABS_HAT2X) dev->ir_cache[2].x = input.value; else if (input.code == ABS_HAT2Y) dev->ir_cache[2].y = input.value; else if (input.code == ABS_HAT3X) dev->ir_cache[3].x = input.value; else if (input.code == ABS_HAT3Y) dev->ir_cache[3].y = input.value; goto try_again; } /* * Read new event from any opened interface of \dev. * Returns -EAGAIN if no new event can be read. * Returns 0 on success and writes the new event into \ev. * Returns negative error on failure. * Returns -ENODEV *once* if *any* interface failed and got closed. Further * reads may succeed on other interfaces but this seems unlikely as all event * devices are created and destroyed by the kernel at the same time. Therefore, * it is recommended to assume the device was disconnected if this returns * -ENODEV. * Returns -EAGAIN on further reads if no interface is open anymore. */ static int read_iface(struct xwii_iface *dev, struct xwii_event *ev) { int ret; if (!dev || !ev) return -EFAULT; ret = read_core(dev, ev); if (ret != -EAGAIN) return ret; ret = read_accel(dev, ev); if (ret != -EAGAIN) return ret; ret = read_ir(dev, ev); if (ret != -EAGAIN) return ret; return -EAGAIN; } int xwii_iface_read(struct xwii_iface *dev, struct xwii_event *ev) { return read_iface(dev, ev); } /* * Poll for events on device \dev. * Returns -EAGAIN if no new events can be read. * Returns 0 on success and writes the new event into \ev. * Returns negative error on failure. * Returns -ENODEV *once* if *any* interface failed and got closed. Further * reads may succeed on other interfaces but this seems unlikely as all event * devices are created and destroyed by the kernel at the same time. Therefore, * it is recommended to assume the device was disconnected if this returns * -ENODEV. * Returns -EAGAIN on further reads if no interface is open anymore. * * This also writes all pending requests to the devices in contrast to *_read() * which only reads for events. If \ev is NULL, only pending requests are * written but no read is performed. */ int xwii_iface_poll(struct xwii_iface *dev, struct xwii_event *ev) { if (!dev) return -EFAULT; if (ev) return read_iface(dev, ev); return 0; } /* * Toogle wiimote rumble motor * Enable or disable the rumble motor of \dev depending on \on. This requires * the core interface to be opened. */ int xwii_iface_rumble(struct xwii_iface *dev, bool on) { struct input_event ev; int ret; if (dev->if_core == -1 || dev->rumble_id == -1) return -EINVAL; ev.type = EV_FF; ev.code = dev->rumble_id; ev.value = on; ret = write(dev->if_core, &ev, sizeof(ev)); if (ret == -1) return -errno; else return 0; } xwiimote-0.3+20120630/lib/internal.h000066400000000000000000000030061177363750100166560ustar00rootroot00000000000000/* * XWiimote - lib * Written 2010, 2011, 2012 by David Herrmann * Dedicated to the Public Domain */ #ifndef XWII_INTERNAL_H #define XWII_INTERNAL_H #include #include #include /* * Sysfs attributes * Files in sysfs are called attributes. They often contain only a single value * for a single kernel parameter/event. */ extern int sfs_attr_read(const char *path, size_t *len, char **out); /* * Generic directory handling * Helper functions for directory traversal and similar. */ typedef int (*sfs_dir_callback) (const char *path, const struct dirent *ent, void *extra); extern int sfs_dir_foreach(const char *path, sfs_dir_callback callback, void *extra); /* * Input devices * Each input device has a directory inside /sys/class/input. This helps reading * input device attributes to identify the device. * This also helps finding all input devices a parent has registered. */ struct sfs_input_dev { size_t ref; struct sfs_input_dev *next; char *path; char *event; char *name; }; extern int sfs_input_read(const char *path, struct sfs_input_dev **dev); extern struct sfs_input_dev *sfs_input_ref(struct sfs_input_dev *dev); extern void sfs_input_unref(struct sfs_input_dev *dev); typedef int (*sfs_input_callback) (struct sfs_input_dev *dev, void *extra); extern int sfs_input_foreach(const char *path, sfs_input_callback callback, void *extra); extern int sfs_input_list(const char *path, struct sfs_input_dev **first); #endif /* XWII_INTERNAL_H */ xwiimote-0.3+20120630/lib/monitor.c000066400000000000000000000101441177363750100165250ustar00rootroot00000000000000/* * XWiimote - lib * Written 2010, 2011 by David Herrmann * Dedicated to the Public Domain */ /* * Device Enumeration and Monitorig * Use libudev to enumerate all currently connected devices and allow * monitoring the system for new devices. * Normal applications should integrate this into their own udev-monitor. * However, smaller applications might not use udev on their own so this API * wraps the udev API in a small easy xwiimote API. */ #include #include #include #include #include #include #include "xwiimote.h" struct xwii_monitor { size_t ref; struct udev *udev; struct udev_enumerate *enumerate; struct udev_list_entry *entry; struct udev_monitor *monitor; }; struct xwii_monitor *xwii_monitor_new(bool poll, bool direct) { struct udev *udev; struct udev_enumerate *enumerate = NULL; struct udev_list_entry *entry; struct udev_monitor *monitor = NULL; struct xwii_monitor *mon; udev = udev_new(); if (!udev) return NULL; enumerate = udev_enumerate_new(udev); if (!enumerate) goto out; if (0 != udev_enumerate_add_match_subsystem(enumerate, "hid")) goto out; if (0 != udev_enumerate_scan_devices(enumerate)) goto out; entry = udev_enumerate_get_list_entry(enumerate); if (poll) { monitor = udev_monitor_new_from_netlink(udev, direct ? "kernel" : "udev"); if (!monitor) goto out; if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "hid", NULL)) goto out; if (udev_monitor_enable_receiving(monitor)) goto out; } mon = malloc(sizeof(*mon)); if (!mon) goto out; mon->ref = 1; mon->udev = udev; mon->enumerate = enumerate; mon->entry = entry; mon->monitor = monitor; return mon; out: if (monitor) udev_monitor_unref(monitor); if (enumerate) udev_enumerate_unref(enumerate); udev_unref(udev); return NULL; } void xwii_monitor_ref(struct xwii_monitor *mon) { if (!mon || !mon->ref) return; mon->ref++; } static inline void free_enum(struct xwii_monitor *monitor) { if (monitor->enumerate) { udev_enumerate_unref(monitor->enumerate); monitor->enumerate = NULL; monitor->entry = NULL; } } void xwii_monitor_unref(struct xwii_monitor *monitor) { if (!monitor || !monitor->ref) return; if (--monitor->ref) return; free_enum(monitor); if (monitor->monitor) udev_monitor_unref(monitor->monitor); udev_unref(monitor->udev); free(monitor); } int xwii_monitor_get_fd(struct xwii_monitor *monitor, bool blocking) { signed int fd, set; if (!monitor || !monitor->monitor) return -1; fd = udev_monitor_get_fd(monitor->monitor); if (fd < 0) return -1; set = fcntl(fd, F_GETFL); if (set < 0) return -1; if (blocking) set &= ~O_NONBLOCK; else set |= O_NONBLOCK; if (0 != fcntl(fd, F_SETFL, set)) return -1; return fd; } static struct udev_device *next_enum(struct xwii_monitor *monitor) { struct udev_list_entry *e; struct udev_device *dev; const char *path; while (monitor->entry) { e = monitor->entry; monitor->entry = udev_list_entry_get_next(e); path = udev_list_entry_get_name(e); dev = udev_device_new_from_syspath(monitor->udev, path); if (dev) return dev; } free_enum(monitor); return NULL; } static char *make_device(struct udev_device *dev) { const char *tmp; char *ret = NULL; tmp = udev_device_get_action(dev); if (tmp && strcmp(tmp, "add")) goto out; tmp = udev_device_get_property_value(dev, "HID_ID"); if (!tmp || strcmp(tmp, "0005:0000057E:00000306")) goto out; tmp = udev_device_get_syspath(dev); if (tmp) ret = strdup(tmp); out: udev_device_unref(dev); return ret; } char *xwii_monitor_poll(struct xwii_monitor *monitor) { struct udev_device *dev; char *ret; if (!monitor) return NULL; if (monitor->enumerate) { while (1) { dev = next_enum(monitor); if (!dev) /* notify application of end of enum */ return NULL; ret = make_device(dev); if (ret) return ret; } } else if (monitor->monitor) { while (1) { dev = udev_monitor_receive_device(monitor->monitor); if (!dev) return NULL; ret = make_device(dev); if (ret) return ret; } } return NULL; } xwiimote-0.3+20120630/lib/sfs.c000066400000000000000000000211141177363750100156300ustar00rootroot00000000000000/* * Sysfs Helper Library * Written 2011 by David Herrmann * Dedicated to the Public Domain */ #include #include #include #include #include #include #include #include #include #include #include "internal.h" /* * Concatenate two strings * This allocates a new buffer and writes \path and \cat into it. \len is the * length of \path or -1 to use strlen(path). \clen is the length of \cat or -1 * to use strlen(cat). * The resulting size is written to \outlen if it is non-NULL. The resulting * string pointer is stored in \out which must be non-NULL. * On failure, a negative error code is returned and no output variable is * touched. On success 0 is returned. */ static int path_cat(ssize_t len, const char *path, ssize_t clen, const char *cat, size_t *outlen, char **out) { size_t size; char *res; assert(path); assert(cat); assert(out); if (len < 0) len = strlen(path); if (clen < 0) clen = strlen(cat); size = len + clen; res = malloc(size + 1); if (!res) return -ENOMEM; memcpy(res, path, len); memcpy(&res[len], cat, clen); res[size] = 0; if (outlen) *outlen = size; *out = res; return 0; } /* * Read attribute * This reads the whole attribute located at \path into a freshly allocated * buffer and stores a pointer to the buffer into \out. * On failure, a negative error code is returned and \out is not touched. On * success 0 is returned and the pointer stored into \out and the length in * \len. If \len is NULL, the length is not stored. * You need to free the pointer on success if you don't need it anymore with * free(). * If the attribute is empty -ENODATA is returned. * A trailing newline character in \out is removed. This always adds a * terminating zero character to the result so it is safe to be printed with * printf() etc. */ int sfs_attr_read(const char *path, size_t *len, char **out) { FILE *f; int ret = 0; long size; char *tmp; assert(path); assert(out); f = fopen(path, "rb"); if (!f) return -errno; fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); if (size < 0) { ret = -EINVAL; goto err_file; } if (size == 0) { ret = -ENODATA; goto err_file; } tmp = malloc(size + 1); if (!tmp) { ret = -ENOMEM; goto err_file; } ret = fread(tmp, 1, size, f); if (ret < 1) { ret = -EINVAL; free(tmp); goto err_file; } if (tmp[ret - 1] == '\n') --ret; if (ret <= 0) { free(tmp); ret = -ENODATA; goto err_file; } tmp[ret] = 0; if (len) *len = ret; *out = tmp; ret = 0; err_file: fclose(f); return ret; } /* * readdir_r() requires us to allocate the "struct dirent" manually. However, we * cannot allocate it on the stack as we don't know the size of the structure. * See manpage of readdir_r(3) for information on this. This is simply copied * from there. */ static int alloc_dirent(const char *path, struct dirent **ent) { size_t len; struct dirent *tmp; len = offsetof(struct dirent, d_name) + pathconf(path, _PC_NAME_MAX) + 1; tmp = malloc(len); if (!tmp) return -ENOMEM; *ent = tmp; return 0; } /* * Go through directory * This calls \callback for every entry in the directory \path. The \extra * argument is passed untouched to each callback. * If a callback returns non-zero, then the function returns the error code * unchanged. If the directory stream fails or memory allocation fails, then a * negative error code is returned. * Returns 0 if everything went fine. */ int sfs_dir_foreach(const char *path, sfs_dir_callback callback, void *extra) { int ret = 0; DIR *dir; struct dirent *ent, *res; dir = opendir(path); if (!dir) return -errno; ret = alloc_dirent(path, &ent); if (ret) goto err_dir; while (true) { ret = readdir_r(dir, ent, &res); if (ret) { ret = -abs(ret); goto err_ent; } if (!res) break; ret = callback(path, ent, extra); if (ret) goto err_ent; } err_ent: free(ent); err_dir: closedir(dir); return ret; } /* foreach through /sys//input/inputX and find eventY */ static int event_foreach(const char *path, const struct dirent *ent, void *extra) { struct sfs_input_dev *dev = extra; char *npath, *tmp; int ret; if (!strncmp("event", ent->d_name, 5)) { if (dev->event) return 0; dev->event = strdup(ent->d_name); if (!dev->event) return -ENOMEM; } else if (!strcmp("name", ent->d_name)) { if (dev->name) return 0; ret = path_cat(-1, path, -1, "/", NULL, &tmp); if (ret) return ret; ret = path_cat(-1, tmp, -1, ent->d_name, NULL, &npath); free(tmp); if (ret) return ret; ret = sfs_attr_read(npath, NULL, &tmp); free(npath); if (ret) return ret; dev->name = tmp; } return 0; } /* * Read information about input device * \path must point to an input device from /sys/class/input/ * The path \path is copied into a new buffer in \dev->path. The name of the * device is read into \dev->name and the event file name is read into * \dev->event. On failure, \dev is not touched. * On success, it returns 0 and you must free \dev with sfs_input_destroy(). */ int sfs_input_read(const char *path, struct sfs_input_dev **dev) { int ret = 0; struct sfs_input_dev *d; assert(path); assert(dev); d = malloc(sizeof(*d)); if (!d) return -ENOMEM; memset(d, 0, sizeof(*d)); sfs_input_ref(d); d->path = strdup(path); if (!d->path) { ret = -ENOMEM; goto err_dev; } ret = sfs_dir_foreach(path, event_foreach, d); if (ret) goto err_dev; *dev = d; return 0; err_dev: sfs_input_unref(d); return ret; } struct sfs_input_dev *sfs_input_ref(struct sfs_input_dev *dev) { dev->ref++; assert(dev->ref); return dev; } /* frees the result of sfs_input_read() */ void sfs_input_unref(struct sfs_input_dev *dev) { if (!dev) return; assert(dev->ref); if (--dev->ref) return; sfs_input_unref(dev->next); free(dev->path); free(dev->event); free(dev->name); free(dev); } struct input_foreach_extra { void *extra; sfs_input_callback callback; }; /* foreach through /sys//input */ static int input_foreach(const char *path, const struct dirent *ent, void *extra) { struct input_foreach_extra *e = extra; int ret = 0; char *npath; size_t len; struct sfs_input_dev *dev; if (ent->d_type != DT_DIR && ent->d_type != DT_LNK) return 0; if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) return 0; len = strlen(ent->d_name); if (len <= 0) return 0; ret = path_cat(-1, path, len, ent->d_name, NULL, &npath); if (ret) return ret; ret = sfs_input_read(npath, &dev); free(npath); if (ret) return ret; ret = e->callback(dev, e->extra); sfs_input_unref(dev); return ret; } /* * Foreach over all input devices of a single device * Many devices register input devices to report events to userspace. Input * devices are accessible via /dev/input/eventX and similar. However, you need * to find the correct event device first. * This function takes as \path argument the path to the base directory of a * device that has registered input devices. If this device has registered input * devices, then there is an "./input/" subdirectory with several * "./input/input12/" subdirectories and similar. * This iterates over each "./input/inputX" input device and calls the callback * with each device. It also opens "./input/inputX/name" and reads * "./input/inputX/eventX" and passes both information to the callback so you * can immediately check the device name and event file. * Returns 0 on success and negative error code on failure. */ int sfs_input_foreach(const char *path, sfs_input_callback callback, void *extra) { char *npath; int ret; struct input_foreach_extra e; assert(path); assert(callback); ret = path_cat(-1, path, -1, "/input/", NULL, &npath); if (ret) return ret; e.extra = extra; e.callback = callback; ret = sfs_dir_foreach(npath, input_foreach, &e); free(npath); return ret; } /* stuff all input devices into a single linked list */ static int input_list_foreach(struct sfs_input_dev *dev, void *extra) { struct sfs_input_dev **first = extra; assert(!dev->next); dev = sfs_input_ref(dev); dev->next = *first; *first = dev; return 0; } /* * Same as sfs_input_foreach but this creates a single linked list of all input * devices instead of calling a callback on each device. * Calling sfs_input_destroy() on the result frees the whole list recursively. */ int sfs_input_list(const char *path, struct sfs_input_dev **out) { struct sfs_input_dev *first = NULL; int ret; ret = sfs_input_foreach(path, input_list_foreach, &first); if (ret) return ret; *out = first; return 0; } xwiimote-0.3+20120630/lib/xwiimote.h000066400000000000000000000067061177363750100167210ustar00rootroot00000000000000/* * XWiimote - lib * Written 2010, 2011, 2012 by David Herrmann * Dedicated to the Public Domain */ #ifndef XWII_XWIIMOTE_H #define XWII_XWIIMOTE_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #if (__GNUC__ > 3) #define XWII__DEPRECATED __attribute__((__deprecated__)) #else #define XWII__DEPRECATED #endif /* __GNUC__ */ /* * Kernel Interface * This defines kernel interface constants that we use. */ #define XWII_ID_BUS 0x0005 #define XWII_ID_VENDOR 0x057e #define XWII_ID_PRODUCT 0x0306 #define XWII__NAME "Nintendo Wii Remote" #define XWII_NAME_CORE XWII__NAME #define XWII_NAME_ACCEL XWII__NAME " Accelerometer" #define XWII_NAME_IR XWII__NAME " IR" #define XWII_NAME_MP XWII__NAME " Motion+" #define XWII_NAME_EXT XWII__NAME " Extension" /* * Event reader * This is a state machine that reads all wiimote event interfaces and returns * new events to the caller when receiving a sync-event. */ #define XWII_IFACE_CORE 0x000001 /* core interface */ #define XWII_IFACE_ACCEL 0x000002 /* accelerometer interface */ #define XWII_IFACE_IR 0x000004 /* ir interface */ #define XWII_IFACE_MP 0x000008 /* motion+ interface */ #define XWII_IFACE_EXT 0x000010 /* extension interface */ #define XWII_IFACE_ALL 0x00ffff /* all interfaces */ #define XWII_IFACE_WRITABLE 0x010000 /* open iface writable */ enum xwii_event_types { XWII_EVENT_KEY, /* key event */ XWII_EVENT_ACCEL, /* accelerometer event */ XWII_EVENT_IR, /* IR event */ XWII_EVENT_NUM }; enum xwii_event_keys { XWII_KEY_LEFT, XWII_KEY_RIGHT, XWII_KEY_UP, XWII_KEY_DOWN, XWII_KEY_A, XWII_KEY_B, XWII_KEY_PLUS, XWII_KEY_MINUS, XWII_KEY_HOME, XWII_KEY_ONE, XWII_KEY_TWO, XWII_KEY_NUM }; struct xwii_event_key { unsigned int code; unsigned int state; }; struct xwii_event_abs { int32_t x; int32_t y; int32_t z; }; struct xwii_event { struct timeval time; unsigned int type; union xwii_event_union { struct xwii_event_key key; struct xwii_event_abs abs[4]; uint8_t reserved[128]; } v; }; struct xwii_iface; int xwii_iface_new(struct xwii_iface **dev, const char *syspath); void xwii_iface_ref(struct xwii_iface *dev); void xwii_iface_unref(struct xwii_iface *dev); int xwii_iface_get_fd(struct xwii_iface *dev); int xwii_iface_open(struct xwii_iface *dev, unsigned int ifaces); void xwii_iface_close(struct xwii_iface *dev, unsigned int ifaces); unsigned int xwii_iface_opened(struct xwii_iface *dev); int xwii_iface_poll(struct xwii_iface *dev, struct xwii_event *ev); int xwii_iface_rumble(struct xwii_iface *dev, bool on); /* old deprecated functions */ XWII__DEPRECATED int xwii_iface_read(struct xwii_iface *dev, struct xwii_event *ev); /* * Device monitor * This monitor can be used to enumerate all connected wiimote devices and also * monitoring the system for hotplugged wiimote devices. * This is a simple wrapper around libudev and should only be used if your * application does not use udev on its own. * See the implementation of the monitor to integrate wiimote-monitoring into * your own udev routines. */ struct xwii_monitor; struct xwii_monitor *xwii_monitor_new(bool poll, bool direct); void xwii_monitor_ref(struct xwii_monitor *mon); void xwii_monitor_unref(struct xwii_monitor *mon); int xwii_monitor_get_fd(struct xwii_monitor *monitor, bool blocking); char *xwii_monitor_poll(struct xwii_monitor *monitor); #ifdef __cplusplus } #endif #endif /* XWII_XWIIMOTE_H */ xwiimote-0.3+20120630/libxwiimote.pc.in000066400000000000000000000003741177363750100174150ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libxwiimote Description: Library to control Nintendo Wii Remotes Requires: libudev Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lxwiimote Cflags: -I${includedir} xwiimote-0.3+20120630/res/000077500000000000000000000000001177363750100147155ustar00rootroot00000000000000xwiimote-0.3+20120630/res/50-xorg-fix-xwiimote.conf000066400000000000000000000010531177363750100214130ustar00rootroot00000000000000# X11 xorg Wii Remote raw input config # XWiimote reports accelerometer and IR data as absolute axes. Disable them to # avoid weird mouse behaviour. To use IR data as mouse input, use the xwiimote # tools or xf86-input-xwiimote which overwrites this. # This only disables the raw input from the kernel devices. If you use the # xwiimote tools to emulate mouses/keyboards, then they are not affected by # this. Section "InputClass" Identifier "Nintendo Wii Remote Raw Input Blacklist" MatchProduct "Nintendo Wii Remote" Option "Ignore" "on" EndSection xwiimote-0.3+20120630/tools/000077500000000000000000000000001177363750100152645ustar00rootroot00000000000000xwiimote-0.3+20120630/tools/eloop.c000066400000000000000000000311431177363750100165500ustar00rootroot00000000000000/* * XWiimote * * Copyright (c) 2011,2012 David Herrmann * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Event Loop * This provides a basic event loop similar to those provided by glib etc. * It uses linux specific features like signalfd so it may not be easy to port * it to other platforms. */ #include #include #include #include #include #include #include #include #include #include "eloop.h" #include "log.h" struct ev_eloop { int efd; unsigned long ref; struct ev_idle *idle_list; struct ev_idle *cur_idle; struct epoll_event *cur_fds; size_t cur_fds_cnt; }; struct ev_idle { unsigned long ref; struct ev_eloop *loop; struct ev_idle *next; struct ev_idle *prev; ev_idle_cb cb; void *data; }; struct ev_fd { unsigned long ref; struct ev_eloop *loop; ev_fd_cb cb; void *data; int fd; }; struct ev_signal { unsigned long ref; struct ev_fd *fd; ev_signal_cb cb; void *data; }; struct ev_timer { unsigned long ref; struct ev_fd *fd; ev_timer_cb cb; void *data; }; int ev_idle_new(struct ev_idle **out) { struct ev_idle *idle; if (!out) return -EINVAL; idle = malloc(sizeof(*idle)); if (!idle) return -ENOMEM; memset(idle, 0, sizeof(*idle)); idle->ref = 1; *out = idle; return 0; } void ev_idle_ref(struct ev_idle *idle) { if (!idle) return; ++idle->ref; } void ev_idle_unref(struct ev_idle *idle) { if (!idle || !idle->ref) return; if (--idle->ref) return; free(idle); } int ev_eloop_new_idle(struct ev_eloop *loop, struct ev_idle **out, ev_idle_cb cb, void *data) { struct ev_idle *idle; int ret; if (!out) return -EINVAL; ret = ev_idle_new(&idle); if (ret) return ret; ret = ev_eloop_add_idle(loop, idle, cb, data); if (ret) { ev_idle_unref(idle); return ret; } ev_idle_unref(idle); *out = idle; return 0; } int ev_eloop_add_idle(struct ev_eloop *loop, struct ev_idle *idle, ev_idle_cb cb, void *data) { if (!loop || !idle || !cb) return -EINVAL; if (idle->next || idle->prev || idle->loop) return -EALREADY; idle->next = loop->idle_list; if (idle->next) idle->next->prev = idle; loop->idle_list = idle; idle->loop = loop; idle->cb = cb; idle->data = data; ev_idle_ref(idle); ev_eloop_ref(loop); return 0; } void ev_eloop_rm_idle(struct ev_idle *idle) { struct ev_eloop *loop; if (!idle || !idle->loop) return; loop = idle->loop; /* * If the loop is currently dispatching, we need to check whether we are * the current element and correctly set it to the next element. */ if (loop->cur_idle == idle) loop->cur_idle = idle->next; if (idle->prev) idle->prev->next = idle->next; if (idle->next) idle->next->prev = idle->prev; if (loop->idle_list == idle) loop->idle_list = idle->next; idle->next = NULL; idle->prev = NULL; idle->loop = NULL; idle->cb = NULL; idle->data = NULL; ev_idle_unref(idle); ev_eloop_unref(loop); } int ev_fd_new(struct ev_fd **out) { struct ev_fd *fd; if (!out) return -EINVAL; fd = malloc(sizeof(*fd)); if (!fd) return -ENOMEM; memset(fd, 0, sizeof(*fd)); fd->ref = 1; fd->fd = -1; *out = fd; return 0; } void ev_fd_ref(struct ev_fd *fd) { if (!fd) return; ++fd->ref; } void ev_fd_unref(struct ev_fd *fd) { if (!fd || !fd->ref) return; if (--fd->ref) return; free(fd); } int ev_eloop_new_fd(struct ev_eloop *loop, struct ev_fd **out, int rfd, int mask, ev_fd_cb cb, void *data) { struct ev_fd *fd; int ret; if (!out) return -EINVAL; ret = ev_fd_new(&fd); if (ret) return ret; ret = ev_eloop_add_fd(loop, fd, rfd, mask, cb, data); if (ret) { ev_fd_unref(fd); return ret; } ev_fd_unref(fd); *out = fd; return 0; } int ev_eloop_add_fd(struct ev_eloop *loop, struct ev_fd *fd, int rfd, int mask, ev_fd_cb cb, void *data) { struct epoll_event ep; if (!loop || !fd || !cb) return -EINVAL; if (fd->loop) return -EALREADY; memset(&ep, 0, sizeof(ep)); if (mask & EV_READABLE) ep.events |= EPOLLIN; if (mask & EV_WRITEABLE) ep.events |= EPOLLOUT; ep.data.ptr = fd; if (epoll_ctl(loop->efd, EPOLL_CTL_ADD, rfd, &ep) < 0) return -errno; fd->loop = loop; fd->cb = cb; fd->data = data; fd->fd = rfd; ev_fd_ref(fd); ev_eloop_ref(loop); return 0; } void ev_eloop_rm_fd(struct ev_fd *fd) { struct ev_eloop *loop; size_t i; if (!fd || !fd->loop) return; loop = fd->loop; epoll_ctl(loop->efd, EPOLL_CTL_DEL, fd->fd, NULL); /* * If we are currently dispatching events, we need to remove ourself * from the temporary event list. */ for (i = 0; i < loop->cur_fds_cnt; ++i) { if (fd == loop->cur_fds[i].data.ptr) loop->cur_fds[i].data.ptr = NULL; } fd->loop = NULL; fd->cb = NULL; fd->data = NULL; fd->fd = -1; ev_fd_unref(fd); ev_eloop_unref(loop); } int ev_eloop_update_fd(struct ev_fd *fd, int mask) { struct epoll_event ep; if (!fd || !fd->loop) return -EINVAL; memset(&ep, 0, sizeof(ep)); if (mask & EV_READABLE) ep.events |= EPOLLIN; if (mask & EV_WRITEABLE) ep.events |= EPOLLOUT; ep.data.ptr = fd; if (epoll_ctl(fd->loop->efd, EPOLL_CTL_MOD, fd->fd, &ep)) return -errno; return 0; } int ev_signal_new(struct ev_signal **out) { struct ev_signal *sig; int ret; if (!out) return -EINVAL; sig = malloc(sizeof(*sig)); if (!sig) return -ENOMEM; memset(sig, 0, sizeof(*sig)); sig->ref = 1; ret = ev_fd_new(&sig->fd); if (ret) { free(sig); return ret; } *out = sig; return 0; } void ev_signal_ref(struct ev_signal *sig) { if (!sig) return; ++sig->ref; } void ev_signal_unref(struct ev_signal *sig) { if (!sig || !sig->ref) return; if (--sig->ref) return; ev_fd_unref(sig->fd); free(sig); } int ev_eloop_new_signal(struct ev_eloop *loop, struct ev_signal **out, int signum, ev_signal_cb cb, void *data) { struct ev_signal *sig; int ret; if (!out) return -EINVAL; ret = ev_signal_new(&sig); if (ret) return ret; ret = ev_eloop_add_signal(loop, sig, signum, cb, data); if (ret) { ev_signal_unref(sig); return ret; } ev_signal_unref(sig); *out = sig; return 0; } static void signal_cb(struct ev_fd *fd, int mask, void *data) { struct ev_signal *sig = data; struct signalfd_siginfo signal_info; int len; if (mask & EV_READABLE) { len = read(fd->fd, &signal_info, sizeof(signal_info)); if (len != sizeof(signal_info)) log_warn("eloop: cannot read signalfd\n"); else sig->cb(sig, signal_info.ssi_signo, sig->data); } } int ev_eloop_add_signal(struct ev_eloop *loop, struct ev_signal *sig, int signum, ev_signal_cb cb, void *data) { sigset_t mask; int ret, fd; if (!loop || !sig) return -EINVAL; if (sig->fd->loop) return -EALREADY; sigemptyset(&mask); sigaddset(&mask, signum); fd = signalfd(-1, &mask, SFD_CLOEXEC); if (fd < 0) return -errno; ret = ev_eloop_add_fd(loop, sig->fd, fd, EV_READABLE, signal_cb, sig); if (ret) { close(fd); return ret; } sigprocmask(SIG_BLOCK, &mask, NULL); sig->cb = cb; sig->data = data; ev_signal_ref(sig); return 0; } void ev_eloop_rm_signal(struct ev_signal *sig) { int fd; if (!sig || !sig->fd->loop) return; fd = sig->fd->fd; ev_eloop_rm_fd(sig->fd); close(fd); ev_signal_unref(sig); /* * We cannot unblock the signal here because we do not know whether some * other subsystem also added the signal to the sigprocmask. */ } int ev_timer_new(struct ev_timer **out) { struct ev_timer *timer; int ret; if (!out) return -EINVAL; timer = malloc(sizeof(*timer)); if (!timer) return -ENOMEM; memset(timer, 0, sizeof(*timer)); timer->ref = 1; ret = ev_fd_new(&timer->fd); if (ret) { free(timer); return ret; } *out = timer; return 0; } void ev_timer_ref(struct ev_timer *timer) { if (!timer) return; ++timer->ref; } void ev_timer_unref(struct ev_timer *timer) { if (!timer || !timer->ref) return; if (--timer->ref) return; ev_fd_unref(timer->fd); free(timer); } int ev_eloop_new_timer(struct ev_eloop *loop, struct ev_timer **out, const struct itimerspec *spec, ev_timer_cb cb, void *data) { struct ev_timer *timer; int ret; if (!out) return -EINVAL; ret = ev_timer_new(&timer); if (ret) return ret; ret = ev_eloop_add_timer(loop, timer, spec, cb, data); if (ret) { ev_timer_unref(timer); return ret; } ev_timer_unref(timer); *out = timer; return 0; } static void timer_cb(struct ev_fd *fd, int mask, void *data) { struct ev_timer *timer = data; uint64_t expirations; int len; if (mask & EV_READABLE) { len = read(fd->fd, &expirations, sizeof(expirations)); if (len != sizeof(expirations)) log_warn("eloop: cannot read timerfd\n"); else timer->cb(timer, expirations, timer->data); } } int ev_eloop_add_timer(struct ev_eloop *loop, struct ev_timer *timer, const struct itimerspec *spec, ev_timer_cb cb, void *data) { int ret, fd; if (!loop || !timer || !spec || !cb) return -EINVAL; if (timer->fd->loop) return -EALREADY; fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (fd < 0) return -errno; ret = timerfd_settime(fd, 0, spec, NULL); if (ret) { ret = -errno; log_warn("eloop: cannot set timerfd: %m\n"); goto err_fd; } ret = ev_eloop_add_fd(loop, timer->fd, fd, EV_READABLE, timer_cb, timer); if (ret) goto err_fd; timer->cb = cb; timer->data = data; ev_timer_ref(timer); return 0; err_fd: close(fd); return ret; } void ev_eloop_rm_timer(struct ev_timer *timer) { int fd; if (!timer || !timer->fd->loop) return; fd = timer->fd->fd; ev_eloop_rm_fd(timer->fd); close(fd); ev_timer_unref(timer); } int ev_eloop_update_timer(struct ev_timer *timer, const struct itimerspec *spec) { int ret; if (!timer || !timer->fd->loop) return -EINVAL; ret = timerfd_settime(timer->fd->fd, 0, spec, NULL); if (ret) { ret = -errno; log_warn("eloop: cannot set timerfd: %m\n"); return ret; } return 0; } int ev_eloop_new(struct ev_eloop **out) { struct ev_eloop *loop; if (!out) return -EINVAL; loop = malloc(sizeof(*loop)); if (!loop) return -ENOMEM; memset(loop, 0, sizeof(*loop)); loop->ref = 1; loop->efd = epoll_create1(EPOLL_CLOEXEC); if (loop->efd < 0) { free(loop); return -errno; } log_debug("eloop: create eloop object\n"); *out = loop; return 0; } void ev_eloop_ref(struct ev_eloop *loop) { if (!loop) return; ++loop->ref; } void ev_eloop_unref(struct ev_eloop *loop) { if (!loop || !loop->ref) return; if (--loop->ref) return; log_debug("eloop: destroy eloop object\n"); close(loop->efd); free(loop); } int ev_eloop_dispatch(struct ev_eloop *loop, int timeout) { struct epoll_event ep[32]; struct ev_fd *fd; int i, count, mask; if (!loop) return -EINVAL; /* dispatch idle events */ loop->cur_idle = loop->idle_list; while (loop->cur_idle) { loop->cur_idle->cb(loop->cur_idle, loop->cur_idle->data); if (loop->cur_idle) loop->cur_idle = loop->cur_idle->next; } /* dispatch fd events */ count = epoll_wait(loop->efd, ep, 32, timeout); if (count < 0) { log_warn("eloop: epoll_wait dispatching failed: %m\n"); return -errno; } loop->cur_fds = ep; loop->cur_fds_cnt = count; for (i = 0; i < count; ++i) { fd = ep[i].data.ptr; if (!fd || !fd->cb) continue; mask = 0; if (ep[i].events & EPOLLIN) mask |= EV_READABLE; if (ep[i].events & EPOLLOUT) mask |= EV_WRITEABLE; if (ep[i].events & EPOLLHUP) mask |= EV_HUP; if (ep[i].events & EPOLLERR) mask |= EV_ERR; fd->cb(fd, mask, fd->data); } loop->cur_fds = NULL; loop->cur_fds_cnt = 0; return 0; } int ev_eloop_get_fd(struct ev_eloop *loop) { if (!loop) return -EINVAL; return loop->efd; } xwiimote-0.3+20120630/tools/eloop.h000066400000000000000000000077771177363750100165750ustar00rootroot00000000000000/* * XWiimote * * Copyright (c) 2011,2012 David Herrmann * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Event Loop * This provides a basic event loop similar to those provided by glib etc. * It uses linux specific features like signalfd so it may not be easy to port * it to other platforms. */ #ifndef EV_ELOOP_H #define EV_ELOOP_H #include #include #include struct ev_eloop; struct ev_idle; struct ev_fd; struct ev_signal; struct ev_timer; typedef void (*ev_idle_cb) (struct ev_idle *idle, void *data); typedef void (*ev_fd_cb) (struct ev_fd *fd, int mask, void *data); typedef void (*ev_signal_cb) (struct ev_signal *sig, int signum, void *data); typedef void (*ev_timer_cb) (struct ev_timer *timer, uint64_t num, void *data); enum ev_eloop_flags { EV_READABLE = 0x01, EV_WRITEABLE = 0x02, EV_HUP = 0x04, EV_ERR = 0x08, }; int ev_eloop_new(struct ev_eloop **out); void ev_eloop_ref(struct ev_eloop *loop); void ev_eloop_unref(struct ev_eloop *loop); int ev_eloop_get_fd(struct ev_eloop *loop); int ev_eloop_dispatch(struct ev_eloop *loop, int timeout); /* idle sources */ int ev_idle_new(struct ev_idle **out); void ev_idle_ref(struct ev_idle *idle); void ev_idle_unref(struct ev_idle *idle); int ev_eloop_new_idle(struct ev_eloop *loop, struct ev_idle **out, ev_idle_cb cb, void *data); int ev_eloop_add_idle(struct ev_eloop *loop, struct ev_idle *idle, ev_idle_cb cb, void *data); void ev_eloop_rm_idle(struct ev_idle *idle); /* fd sources */ int ev_fd_new(struct ev_fd **out); void ev_fd_ref(struct ev_fd *fd); void ev_fd_unref(struct ev_fd *fd); int ev_eloop_new_fd(struct ev_eloop *loop, struct ev_fd **out, int rfd, int mask, ev_fd_cb cb, void *data); int ev_eloop_add_fd(struct ev_eloop *loop, struct ev_fd *fd, int rfd, int mask, ev_fd_cb cb, void *data); void ev_eloop_rm_fd(struct ev_fd *fd); int ev_eloop_update_fd(struct ev_fd *fd, int mask); /* signal sources */ int ev_signal_new(struct ev_signal **out); void ev_signal_ref(struct ev_signal *sig); void ev_signal_unref(struct ev_signal *sig); int ev_eloop_new_signal(struct ev_eloop *loop, struct ev_signal **out, int signum, ev_signal_cb cb, void *data); int ev_eloop_add_signal(struct ev_eloop *loop, struct ev_signal *sig, int signum, ev_signal_cb cb, void *data); void ev_eloop_rm_signal(struct ev_signal *sig); /* timer sources */ int ev_timer_new(struct ev_timer **out); void ev_timer_ref(struct ev_timer *timer); void ev_timer_unref(struct ev_timer *timer); int ev_eloop_new_timer(struct ev_eloop *loop, struct ev_timer **out, const struct itimerspec *spec, ev_timer_cb cb, void *data); int ev_eloop_add_timer(struct ev_eloop *loop, struct ev_timer *timer, const struct itimerspec *spec, ev_timer_cb cb, void *data); void ev_eloop_rm_timer(struct ev_timer *timer); int ev_eloop_update_timer(struct ev_timer *timer, const struct itimerspec *spec); #endif /* EV_ELOOP_H */ xwiimote-0.3+20120630/tools/log.c000066400000000000000000000032771177363750100162220ustar00rootroot00000000000000/* * XWiimote * * Copyright (c) 2011,2012 David Herrmann * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Log Control * Forward log messages to stderr. We use syslog and printk like severity * prefixes. */ #include #include #include #include #include "log.h" __attribute__ ((format (printf, 1, 2))) void log_printf(const char *format, ...) { va_list list; va_start(list, format); log_vprintf(format, list); va_end(list); } __attribute__ ((format (printf, 1, 0))) void log_vprintf(const char *format, va_list list) { int saved_errno = errno; vfprintf(stderr, format, list); errno = saved_errno; } xwiimote-0.3+20120630/tools/log.h000066400000000000000000000055551177363750100162300ustar00rootroot00000000000000/* * XWiimote * * Copyright (c) 2011,2012 David Herrmann * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Log Control * This is a fairly simply logging API. It forwards all messages to stderr. * They may be prefixed with a priority level like kernel messages. * To forward the messages to syslog simply connect stderr to the syslog daemon * via your init-manager. */ #ifndef LOG_LOG_H #define LOG_LOG_H #include #include #include "config.h" /* LOG_EMERG and LOG_ALERT do not make sense for this application */ #define LOG_CRIT "<2>" /* error that cannot be handled correctly */ #define LOG_ERR "<3>" /* error detected */ #define LOG_WARN "<4>" /* warn about unexpected conditions */ #define LOG_NOTICE "<5>" /* notify about unusual conditions */ #define LOG_INFO "<6>" /* basic inforomational messages */ #define LOG_DEBUG "<7>" /* debug messages */ /* dummy logger which allows gcc to check for printk-format */ static inline __attribute__ ((format (printf, 1, 2))) void log_dummy(const char *format, ...) { } __attribute__ ((format (printf, 1, 2))) void log_printf(const char *format, ...); __attribute__ ((format (printf, 1, 0))) void log_vprintf(const char *format, va_list list); #define log_crit(format, ...) log_printf(LOG_CRIT format, ##__VA_ARGS__) #define log_err(format, ...) log_printf(LOG_ERR format, ##__VA_ARGS__) #define log_warn(format, ...) log_printf(LOG_WARN format, ##__VA_ARGS__) #define log_notice(format, ...) log_printf(LOG_NOTICE format, ##__VA_ARGS__) #define log_info(format, ...) log_printf(LOG_INFO format, ##__VA_ARGS__) /* log_debug() should produce zero code if DEBUG is disabled */ #ifndef NDEBUG #define log_debug(format, ...) log_printf(LOG_DEBUG format, ##__VA_ARGS__) #else #define log_debug(format, ...) log_dummy(LOG_DEBUG format, ##__VA_ARGS__) #endif #endif /* LOG_LOG_H */ xwiimote-0.3+20120630/tools/xwiibind.sh000077500000000000000000000066101177363750100174430ustar00rootroot00000000000000#!/bin/sh # # XWiimote - tools # Written 2011 by David Herrmann # Dedicated to the Public Domain # # # This script enables auto-reconnect on your wiimote. This script should only be # used if you really require auto-reconnect now. There is work going on to get # auto-reconnect of wiimotes into upstream bluez repository. # If you need this feature now, you may read below, but be aware that this # method described here is neither fast nor reliable. It is a small hack to get # it work. # # To run this tool, you need: # - "simple-agent" # - "test-device" # - "test-input" # from the "test" directory of the bluez distribution. They are available here: # http://git.kernel.org/?p=bluetooth/bluez.git;a=tree;f=test # They are GPL licensed and hence not included here. They are simple python # scripts and can be just copied into this directory. # # Please specify your device bdaddr as first argument to this script. # The python scripts need "python2" and are not python3 compatible, so specify # the python interpreter as "PYTHON" below if the default value does not work. # # This script REQUIRES that you have the "wiimote.so" plugin enabled in your # bluetoothd daemon. It is often NOT part of the official distribution package # so check whether it is installed and enabled. # # Please disable gnome-bluetooth, blueman or any similar bluetooth applet to # avoid inter-process conflicts. # # This script does not check for error codes, so if you see errors, abort the # script with ctrl+c. This script first removes the device. Then it connects to # the device without pairing and without connecting to the input service. It # does this just to retrieve SDP values. After that you should disconnect the # device again by pressing the power-button for 3 seconds. # Then press the red-sync button again, the script will now connect to the # device and perform pairing. If the script asks you for PIN input, then you did # not install the "wiimote.so" plugin for bluetoothd. # If you did, bluetoothd chooses the right PIN for you. After pairing it # directly connects to the input device. If this succeeds, the wiimote is ready # for auto-reconnect. # # To test auto-reconnect, disconnect your wiimote. Then invoke # "python2 ./simple-agent" # And you will have an agent that listens for incoming connections. Now a single # key-press on the remote should be enough to make the wiimote connect to your # host. You only need to acknowledge the connection in the simple-agent by # writing "yes" when it prompts you. # PYTHON="python2" DEV=$1 if test x"$1" = "x" ; then echo "Please specify bdaddr of wiimote as first argument" exit 1 fi echo "Removing device..." "$PYTHON" "test-device" remove "$DEV" echo "Device removed, press any key to continue" read echo "Please press red sync-button on the back of the wiimote and press any key to continue" echo "If this asks you for PIN input, then your bluetoothd daemon does not include the wiimote.so plugin. Please install it or contact your distributor." read "$PYTHON" "test-device" create "$DEV" echo "Please disconnect the device by pressing the power button and then press any key to continue" read echo "Now press the red-sync button again and press any key to continue" read echo "Pairing with the remote device..." "$PYTHON" "simple-agent" "hci0" "$DEV" echo "Connecting to input device..." "$PYTHON" "test-input" connect "$DEV" echo "Connected to input device. Autoconnect should be enabled now." xwiimote-0.3+20120630/tools/xwiidump.c000066400000000000000000000033271177363750100173030ustar00rootroot00000000000000/* * XWiimote - tools * Written 2010, 2011 by David Herrmann * Dedicated to the Public Domain */ /* * XWiimote EEPROM Dump * This tool reads the whole eeprom of a wiimote and dumps the output to * stdout. This requires debugfs support and euid 0/root. * Pass as argument the eeprom input file. This requires that debugfs is * mounted and compiled into the kernel. * * Debugfs compiled: * zgrep DEBUG_FS /proc/config.gz * Mount debugfs: * mount -t debugfs debugfs /sys/kernel/debug * Path to eeprom file: * /sys/kernel/debug/hid//eeprom */ #include #include #include #include #include static void show(const char *buf, size_t len) { size_t i; for (i = 0; i < len; ++i) printf(" 0x%02hhx", buf[i]); } static void dump(int fd) { char buf[1]; int ret; size_t off, i; off = 0; while (1) { printf("0x%08lx:", off); for (i = 0; i < 8; ++i) { ret = read(fd, buf, sizeof(buf)); if (ret > 0) { show(buf, ret); } else if (ret < 0) { printf(" (read error %d)", errno); if (lseek(fd, 1, SEEK_CUR) < 0) { printf(" (Seek failed %d)", errno); goto out; } } else { printf(" (eof)"); goto out; } ++off; } printf("\n"); } out: return; } static int open_eeprom(const char *file) { int fd; fd = open(file, O_RDONLY); if (fd < 0) fprintf(stderr, "Cannot open eeprom file %d\n", errno); return fd; } int main(int argc, char **argv) { int fd; if (argc < 2 || !*argv[1]) { fprintf(stderr, "Please give path to eeprom file as first argument\n"); return EXIT_FAILURE; } fd = open_eeprom(argv[1]); if (fd >= 0) { dump(fd); close(fd); } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } xwiimote-0.3+20120630/tools/xwiikeymap.c000066400000000000000000000246161177363750100176300ustar00rootroot00000000000000/* * XWiimote - tools - xwiikeymap * Written 2011,2012 by David Herrmann * Dedicated to the Public Domain */ /* * XWiimote Button Remapper * This tool listens for incoming Wii Remotes and for every connected Wii Remote * it creates a new input device via uinput and maps the keys as given in the * keymap. This allows to map the buttons of the Wii Remote to arbitrary keys. */ #include #include #include #include #include #include #include #include #include #include #include #include "eloop.h" #include "log.h" #include "xwiimote.h" struct app { struct ev_eloop *eloop; struct ev_signal *sig_term; struct ev_signal *sig_int; struct xwii_monitor *monitor; int monitor_fd; struct ev_fd *monitor_fdo; bool daemon; }; struct dev { struct xwii_iface *iface; int iface_fd; struct ev_fd *iface_fdo; int uinput_fd; }; static const char *uinput_path = "/dev/uinput"; static const char *uinput_name = "XWiimote Keyboard"; static uint16_t mapping[] = { [XWII_KEY_LEFT] = KEY_LEFT, [XWII_KEY_RIGHT] = KEY_RIGHT, [XWII_KEY_UP] = KEY_UP, [XWII_KEY_DOWN] = KEY_DOWN, [XWII_KEY_A] = KEY_ENTER, [XWII_KEY_B] = KEY_SPACE, [XWII_KEY_PLUS] = KEY_VOLUMEUP, [XWII_KEY_MINUS] = KEY_VOLUMEDOWN, [XWII_KEY_HOME] = KEY_ESC, [XWII_KEY_ONE] = KEY_1, [XWII_KEY_TWO] = KEY_2, [XWII_KEY_NUM] = 0, }; static volatile sig_atomic_t terminate = 0; static void sig_term(struct ev_signal *sig, int signum, void *data) { terminate = 1; } static void uinput_destroy(struct dev *dev) { if (dev->uinput_fd < 0) return; ioctl(dev->uinput_fd, UI_DEV_DESTROY); close(dev->uinput_fd); } static int uinput_init(struct dev *dev) { int ret, i; struct uinput_user_dev udev; dev->uinput_fd = open(uinput_path, O_RDWR | O_CLOEXEC | O_NONBLOCK); if (dev->uinput_fd < 0) { ret = -errno; log_err("app: cannot open uinput device %s: %m (%d)\n", uinput_path, ret); return ret; } memset(&udev, 0, sizeof(udev)); strncpy(udev.name, uinput_name, UINPUT_MAX_NAME_SIZE); udev.id.bustype = XWII_ID_BUS; udev.id.vendor = XWII_ID_VENDOR; udev.id.product = XWII_ID_PRODUCT; udev.id.version = 0; ret = write(dev->uinput_fd, &udev, sizeof(udev)); if (ret != sizeof(udev)) { ret = -EFAULT; log_err("app: cannot register uinput device\n"); goto err; } ret = ioctl(dev->uinput_fd, UI_SET_EVBIT, EV_KEY); if (ret) { ret = -EFAULT; log_err("app: cannot initialize uinput device\n"); goto err; } for (i = 0; i < XWII_KEY_NUM; ++i) { if (!mapping[i]) continue; ret = ioctl(dev->uinput_fd, UI_SET_KEYBIT, mapping[i]); if (ret) { ret = -EFAULT; log_err("app: cannot initialize uinput device\n"); goto err; } } ret = ioctl(dev->uinput_fd, UI_DEV_CREATE); if (ret) { ret = -EFAULT; log_err("app: cannot create uinput device\n"); goto err; } return 0; err: close(dev->uinput_fd); dev->uinput_fd = -1; return ret; } static void destroy_device(struct dev *dev) { if (!dev) return; uinput_destroy(dev); ev_eloop_rm_fd(dev->iface_fdo); xwii_iface_unref(dev->iface); free(dev); } static void handle_data(struct dev *dev, struct xwii_event *ev) { struct input_event output; if (ev->type != XWII_EVENT_KEY) return; if (ev->v.key.code >= XWII_KEY_NUM || !mapping[ev->v.key.code]) return; memset(&output, 0, sizeof(output)); output.type = EV_KEY; output.code = mapping[ev->v.key.code]; output.value = ev->v.key.state; gettimeofday(&output.time, NULL); if (write(dev->uinput_fd, &output, sizeof(output)) != sizeof(output)) log_warn("app: cannot write to uinput device\n"); } static void device_event(struct ev_fd *fdo, int mask, void *data) { struct dev *dev = data; struct xwii_event event; int ret; struct input_event ev; if (mask & (EV_HUP | EV_ERR)) { log_err("app: Wii Remote device closed\n"); destroy_device(dev); } else if (mask & EV_READABLE) { while (1) { ret = xwii_iface_poll(dev->iface, &event); if (ret != -EAGAIN) { if (ret) { log_err("app: reading Wii Remote " "failed; closing device...\n"); destroy_device(dev); return; } else { handle_data(dev, &event); } } else { break; } } memset(&ev, 0, sizeof(ev)); ev.type = EV_SYN; ev.code = SYN_REPORT; ev.value = 0; gettimeofday(&ev.time, NULL); if (write(dev->uinput_fd, &ev, sizeof(ev)) != sizeof(ev)) log_warn("app: cannot write to uinput device\n"); } } static void monitor_poll(struct app *app) { char *str; struct dev *dev; int ret; while ((str = xwii_monitor_poll(app->monitor))) { /* sleep short time (10ms) to have the device fully setup */ usleep(10000); dev = malloc(sizeof(*dev)); if (!dev) { log_warn("app: cannot create new Wii Remote device\n"); free(str); continue; } memset(dev, 0, sizeof(*dev)); ret = xwii_iface_new(&dev->iface, str); if (ret) { log_warn("app: cannot create new Wii Remote device\n"); free(dev); free(str); continue; } ret = xwii_iface_open(dev->iface, XWII_IFACE_CORE); if (ret) { log_warn("app: cannot open Wii Remote core iface\n"); xwii_iface_unref(dev->iface); free(dev); free(str); continue; } dev->iface_fd = xwii_iface_get_fd(dev->iface); ret = ev_eloop_new_fd(app->eloop, &dev->iface_fdo, dev->iface_fd, EV_READABLE, device_event, dev); if (ret) { log_warn("app: cannot create new Wii Remote device\n"); xwii_iface_unref(dev->iface); free(dev); free(str); continue; } ret = uinput_init(dev); if (ret) { log_warn("app: cannot create new Wii Remote device\n"); ev_eloop_rm_fd(dev->iface_fdo); xwii_iface_unref(dev->iface); free(dev); free(str); continue; } log_info("app: new Wii Remote detected: %s\n", str); free(str); } } static void monitor_event(struct ev_fd *fdo, int mask, void *data) { struct app *app = data; if (mask & (EV_HUP | EV_ERR)) { log_err("app: Wii Remote monitor closed unexpectedly\n"); terminate = 1; } else if (mask & EV_READABLE) { monitor_poll(app); } } static void app_destroy(struct app *app) { ev_eloop_rm_fd(app->monitor_fdo); xwii_monitor_unref(app->monitor); ev_eloop_rm_signal(app->sig_int); ev_eloop_rm_signal(app->sig_term); ev_eloop_unref(app->eloop); } static int app_setup(struct app *app) { int ret; ret = ev_eloop_new(&app->eloop); if (ret) goto err; ret = ev_eloop_new_signal(app->eloop, &app->sig_term, SIGTERM, sig_term, app); if (ret) goto err; ret = ev_eloop_new_signal(app->eloop, &app->sig_int, SIGINT, sig_term, app); if (ret) goto err; app->monitor = xwii_monitor_new(true, false); if (!app->monitor) { ret = -EFAULT; log_err("app: cannot create Wii Remote monitor\n"); goto err; } app->monitor_fd = xwii_monitor_get_fd(app->monitor, false); if (app->monitor_fd < 0) { ret = -EFAULT; log_err("app: cannot get monitor fd\n"); goto err; } ret = ev_eloop_new_fd(app->eloop, &app->monitor_fdo, app->monitor_fd, EV_READABLE, monitor_event, app); if (ret) goto err; return 0; err: app_destroy(app); return ret; } struct arg { char name_s; /* short argument name */ const char *name_l; /* long argument name */ bool need_arg; /* does it require an argument? */ const char *arg; /* the parsed argument or "no_value" */ }; struct arg args[] = { { 'L', "left", true, NULL }, { 'R', "right", true, NULL }, { 'U', "up", true, NULL }, { 'D', "down", true, NULL }, { 'A', "a", true, NULL }, { 'B', "b", true, NULL }, { 'P', "plus", true, NULL }, { 'M', "minus", true, NULL }, { 'H', "home", true, NULL }, { 'O', "one", true, NULL }, { 'T', "two", true, NULL }, { 'u', "uinput", true, NULL }, { 'n', "name", true, NULL }, { 'd', "daemon", false, NULL }, { 0, NULL, false, NULL }, }; static const char *no_value = "no value"; static void parse_args(struct app *app, int argc, char **argv) { int i, j; bool handled; char *v; struct arg *arg; for (i = 0; i < argc; ++i) { if (!argv[i][0]) continue; handled = false; if (argv[i][0] == '-' && argv[i][1] == '-') { v = &argv[i][2]; for (j = 0; args[j].name_s || args[j].name_l; ++j) { arg = &args[j]; if (!arg->name_l) continue; if (strcmp(v, arg->name_l)) continue; handled = true; if (!arg->need_arg) { arg->arg = no_value; break; } ++i; if (i >= argc) log_warn("app: missing arg for %s\n", v); else arg->arg = argv[i]; } } else if (argv[i][0] == '-') { v = &argv[i][1]; for (j = 0; args[j].name_s || args[j].name_l; ++j) { arg = &args[j]; if (arg->name_s != *v) continue; handled = true; if (!arg->need_arg) { arg->arg = no_value; break; } ++i; if (i >= argc) log_warn("app: missing arg for %s\n", v); else arg->arg = argv[i]; } } if (!handled) log_warn("app: unhandled argument '%s'\n", argv[i]); } if (args[0].arg) mapping[XWII_KEY_LEFT] = atoi(args[0].arg); if (args[1].arg) mapping[XWII_KEY_RIGHT] = atoi(args[1].arg); if (args[2].arg) mapping[XWII_KEY_UP] = atoi(args[2].arg); if (args[3].arg) mapping[XWII_KEY_DOWN] = atoi(args[3].arg); if (args[4].arg) mapping[XWII_KEY_A] = atoi(args[4].arg); if (args[5].arg) mapping[XWII_KEY_B] = atoi(args[5].arg); if (args[6].arg) mapping[XWII_KEY_PLUS] = atoi(args[6].arg); if (args[7].arg) mapping[XWII_KEY_MINUS] = atoi(args[7].arg); if (args[8].arg) mapping[XWII_KEY_HOME] = atoi(args[8].arg); if (args[9].arg) mapping[XWII_KEY_ONE] = atoi(args[9].arg); if (args[10].arg) mapping[XWII_KEY_TWO] = atoi(args[10].arg); if (args[11].arg) uinput_path = args[11].arg; if (args[12].arg) uinput_name = args[12].arg; if (args[13].arg) app->daemon = true; } int main(int argc, char **argv) { int ret; struct app app; log_info("app: initializing\n"); memset(&app, 0, sizeof(app)); if (argc > 1) parse_args(&app, argc - 1, &argv[1]); if (app.daemon) { log_info("app: forking into background\n"); daemon(0, 0); } ret = app_setup(&app); if (ret) goto err; log_info("app: starting\n"); monitor_poll(&app); while (!terminate) { ret = ev_eloop_dispatch(app.eloop, -1); if (ret) break; } log_info("app: stopping\n"); /* TODO: add device into global list and remove all devices here */ app_destroy(&app); err: if (ret) { log_info("app: failed with %d\n", ret); return EXIT_FAILURE; } else { log_info("app: terminating\n"); return EXIT_SUCCESS; } } xwiimote-0.3+20120630/tools/xwiishow.c000066400000000000000000000204671177363750100173220ustar00rootroot00000000000000/* * XWiimote - tools - xwiishow * Written 2010, 2011 by David Herrmann * Dedicated to the Public Domain */ /* * Interactive Wiimote Testing Tool * If you run this tool without arguments, then it lists all currently connected * wiimotes and exits. * You need to pass one path as argument and the given wiimote is opened and * printed to the screen. When wiimote events are received, then the screen is * updated correspondingly. You can use the keyboard to control the wiimote: * q: quit the application * a: toggle accelerometer * r: toggle rumble * * Example: * ./xwiishow /sys/bus/hid/devices/ * This will opened the given wiimote device and print it to the screen. */ #include #include #include #include #include #include #include #include #include #include #include #include "xwiimote.h" static struct xwii_iface *iface; static void print_error(const char *format, ...) { va_list list; va_start(list, format); move(23, 22); vw_printw(stdscr, format, list); printw(" "); va_end(list); } static void show_key_event(const struct xwii_event *event) { unsigned int code = event->v.key.code; bool pressed = event->v.key.state; char *str = NULL; if (pressed) str = "X"; else str = " "; if (code == XWII_KEY_LEFT) { mvprintw(4, 7, "%s", str); } else if (code == XWII_KEY_RIGHT) { mvprintw(4, 11, "%s", str); } else if (code == XWII_KEY_UP) { mvprintw(2, 9, "%s", str); } else if (code == XWII_KEY_DOWN) { mvprintw(6, 9, "%s", str); } else if (code == XWII_KEY_A) { if (pressed) str = "A"; mvprintw(10, 5, "%s", str); } else if (code == XWII_KEY_B) { if (pressed) str = "B"; mvprintw(10, 13, "%s", str); } else if (code == XWII_KEY_HOME) { if (pressed) str = "HOME+"; else str = " "; mvprintw(13, 7, "%s", str); } else if (code == XWII_KEY_MINUS) { if (pressed) str = "-"; mvprintw(13, 3, "%s", str); } else if (code == XWII_KEY_PLUS) { if (pressed) str = "+"; mvprintw(13, 15, "%s", str); } else if (code == XWII_KEY_ONE) { if (pressed) str = "1"; mvprintw(20, 9, "%s", str); } else if (code == XWII_KEY_TWO) { if (pressed) str = "2"; mvprintw(21, 9, "%s", str); } } static void show_accel_event(const struct xwii_event *event) { } static void show_ir_event(const struct xwii_event *event) { } static void show_rumble(bool on) { mvprintw(1, 21, on ? "RUMBLE" : " "); } static int setup_window() { size_t i; if (LINES < 24 || COLS < 80) { printw("Error: Screen is too small\n"); return -EINVAL; } i = 0; /* 80x24 Box */ mvprintw(i++, 0, "+-----------------+ +------+ +-------------------------------------------------+"); mvprintw(i++, 0, "| +-+ | | | |"); mvprintw(i++, 0, "| | | | +------+ |"); mvprintw(i++, 0, "| +-+ +-+ | |"); mvprintw(i++, 0, "| | | | |"); mvprintw(i++, 0, "| +-+ +-+ | |"); mvprintw(i++, 0, "| | | | |"); mvprintw(i++, 0, "| +-+ | |"); mvprintw(i++, 0, "| | |"); mvprintw(i++, 0, "| +-+ +-+ | |"); mvprintw(i++, 0, "| | | | | | |"); mvprintw(i++, 0, "| +-+ +-+ | |"); mvprintw(i++, 0, "| | |"); mvprintw(i++, 0, "| ( ) | | ( ) | |"); mvprintw(i++, 0, "| | |"); mvprintw(i++, 0, "| +++++ | |"); mvprintw(i++, 0, "| + + | |"); mvprintw(i++, 0, "| + + | |"); mvprintw(i++, 0, "| +++++ | |"); mvprintw(i++, 0, "| | |"); mvprintw(i++, 0, "| | | | |"); mvprintw(i++, 0, "| | | | |"); mvprintw(i++, 0, "| | +----------------------------------------------------------+"); mvprintw(i++, 0, "+-----------------+ |"); return 0; } static void toggle_accel() { if (xwii_iface_opened(iface) & XWII_IFACE_ACCEL) xwii_iface_close(iface, XWII_IFACE_ACCEL); else xwii_iface_open(iface, XWII_IFACE_ACCEL); } static void toggle_rumble() { static bool on = false; on = !on; xwii_iface_rumble(iface, on); show_rumble(on); } static int keyboard() { int key; key = getch(); if (key == ERR) return 0; switch (key) { case 'a': toggle_accel(); break; case 'r': toggle_rumble(); break; case 'q': return -ECANCELED; } return 0; } static int run_iface(struct xwii_iface *iface) { struct xwii_event event; int ret = 0; ret = setup_window(); if (ret) return ret; while (true) { ret = xwii_iface_poll(iface, &event); if (ret == -EAGAIN) { nanosleep(&(struct timespec) {.tv_sec = 0, .tv_nsec = 5000000 }, NULL); } else if (ret) { print_error("Error: Read failed with err:%d\n", ret); break; } else { switch (event.type) { case XWII_EVENT_KEY: show_key_event(&event); break; case XWII_EVENT_ACCEL: show_accel_event(&event); break; case XWII_EVENT_IR: show_ir_event(&event); break; } } ret = keyboard(); if (ret == -ECANCELED) return 0; else if (ret) return ret; refresh(); } return ret; } static int enumerate() { struct xwii_monitor *mon; char *ent; int num = 0; mon = xwii_monitor_new(false, false); if (!mon) { printf("Cannot create monitor\n"); return -EINVAL; } while ((ent = xwii_monitor_poll(mon))) { printf(" Found device #%d: %s\n", ++num, ent); free(ent); } xwii_monitor_unref(mon); return 0; } static char *get_dev(int num) { struct xwii_monitor *mon; char *ent; int i = 0; mon = xwii_monitor_new(false, false); if (!mon) { printf("Cannot create monitor\n"); return NULL; } while ((ent = xwii_monitor_poll(mon))) { if (++i == num) break; free(ent); } xwii_monitor_unref(mon); if (!ent) printf("Cannot find device with number #%d\n", num); return ent; } int main(int argc, char **argv) { int ret = 0; char *path = NULL; if (argc < 2 || !strcmp(argv[1], "-h")) { printf("Usage:\n"); printf("\txwiishow [-h]: Show help\n"); printf("\txwiishow list: List connected devices\n"); printf("\txwiishow : Show device with number #num\n"); printf("\txwiishow /sys/path/to/device: Show given device\n"); printf("UI commands:\n"); printf("\tq: Quit application\n"); printf("\tr: Toggle rumble motor\n"); printf("\ta: Toggle accelerometer\n"); ret = -1; } else if (!strcmp(argv[1], "list")) { printf("Listing connected Wii Remote devices:\n"); ret = enumerate(); printf("End of device list\n"); } else { if (argv[1][0] != '/') path = get_dev(atoi(argv[1])); ret = xwii_iface_new(&iface, path ? path : argv[1]); free(path); if (ret) { printf("Cannot create xwii_iface '%s' err:%d\n", argv[1], ret); } else { ret = xwii_iface_open(iface, XWII_IFACE_CORE | XWII_IFACE_WRITABLE); if (ret) { printf("Cannot open core iface '%s' err:%d\n", argv[1], ret); } else { initscr(); curs_set(0); raw(); noecho(); timeout(0); ret = run_iface(iface); xwii_iface_unref(iface); if (ret) { printw("Program failed; press any key to exit\n"); refresh(); timeout(-1); getch(); } endwin(); } } } return abs(ret); }