2011-07-05 15:45:08 +04:00
/*
* 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 .
*/
2011-07-05 15:45:12 +04:00
# include <linux/atomic.h>
2011-07-05 15:45:11 +04:00
# include <linux/device.h>
2011-07-05 15:45:09 +04:00
# include <linux/hid.h>
2011-07-05 15:45:11 +04:00
# include <linux/input.h>
2011-07-05 15:45:08 +04:00
# include <linux/module.h>
2011-07-05 15:45:14 +04:00
# include <linux/spinlock.h>
2011-07-05 15:45:09 +04:00
# include "hid-ids.h"
2011-07-05 15:45:08 +04:00
# define WIIMOTE_VERSION "0.1"
# define WIIMOTE_NAME "Nintendo Wii Remote"
2011-07-05 15:45:14 +04:00
# define WIIMOTE_BUFSIZE 32
struct wiimote_buf {
__u8 data [ HID_MAX_BUFFER_SIZE ] ;
size_t size ;
} ;
2011-07-05 15:45:08 +04:00
2011-07-05 15:45:10 +04:00
struct wiimote_data {
2011-07-05 15:45:12 +04:00
atomic_t ready ;
2011-07-05 15:45:10 +04:00
struct hid_device * hdev ;
2011-07-05 15:45:11 +04:00
struct input_dev * input ;
2011-07-05 15:45:14 +04:00
spinlock_t qlock ;
__u8 head ;
__u8 tail ;
struct wiimote_buf outq [ WIIMOTE_BUFSIZE ] ;
struct work_struct worker ;
2011-07-05 15:45:10 +04:00
} ;
2011-07-05 15:45:16 +04:00
enum wiiproto_reqs {
WIIPROTO_REQ_DRM_K = 0x30 ,
} ;
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 */
} ;
2011-07-05 15:45:13 +04:00
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 ;
}
2011-07-05 15:45:14 +04:00
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 ) ;
}
2011-07-05 15:45:11 +04:00
static int wiimote_input_event ( struct input_dev * dev , unsigned int type ,
unsigned int code , int value )
{
2011-07-05 15:45:12 +04:00
struct wiimote_data * wdata = input_get_drvdata ( dev ) ;
if ( ! atomic_read ( & wdata - > ready ) )
return - EBUSY ;
/* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
smp_rmb ( ) ;
2011-07-05 15:45:11 +04:00
return 0 ;
}
2011-07-05 15:45:16 +04:00
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 ) ;
}
2011-07-05 15:45:15 +04:00
struct wiiproto_handler {
__u8 id ;
size_t size ;
void ( * func ) ( struct wiimote_data * wdata , const __u8 * payload ) ;
} ;
static struct wiiproto_handler handlers [ ] = {
2011-07-05 15:45:16 +04:00
{ . id = WIIPROTO_REQ_DRM_K , . size = 2 , . func = handler_keys } ,
2011-07-05 15:45:15 +04:00
{ . id = 0 }
} ;
2011-07-05 15:45:09 +04:00
static int wiimote_hid_event ( struct hid_device * hdev , struct hid_report * report ,
u8 * raw_data , int size )
{
2011-07-05 15:45:12 +04:00
struct wiimote_data * wdata = hid_get_drvdata ( hdev ) ;
2011-07-05 15:45:15 +04:00
struct wiiproto_handler * h ;
int i ;
2011-07-05 15:45:12 +04:00
if ( ! atomic_read ( & wdata - > ready ) )
return - EBUSY ;
/* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
smp_rmb ( ) ;
2011-07-05 15:45:09 +04:00
if ( size < 1 )
return - EINVAL ;
2011-07-05 15:45:15 +04:00
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 ] ) ;
}
2011-07-05 15:45:09 +04:00
return 0 ;
}
2011-07-05 15:45:10 +04:00
static struct wiimote_data * wiimote_create ( struct hid_device * hdev )
{
struct wiimote_data * wdata ;
2011-07-05 15:45:16 +04:00
int i ;
2011-07-05 15:45:10 +04:00
wdata = kzalloc ( sizeof ( * wdata ) , GFP_KERNEL ) ;
if ( ! wdata )
return NULL ;
2011-07-05 15:45:11 +04:00
wdata - > input = input_allocate_device ( ) ;
if ( ! wdata - > input ) {
kfree ( wdata ) ;
return NULL ;
}
2011-07-05 15:45:10 +04:00
wdata - > hdev = hdev ;
hid_set_drvdata ( hdev , wdata ) ;
2011-07-05 15:45:11 +04:00
input_set_drvdata ( wdata - > input , wdata ) ;
wdata - > input - > event = wiimote_input_event ;
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 ;
2011-07-05 15:45:16 +04:00
set_bit ( EV_KEY , wdata - > input - > evbit ) ;
for ( i = 0 ; i < WIIPROTO_KEY_COUNT ; + + i )
set_bit ( wiiproto_keymap [ i ] , wdata - > input - > keybit ) ;
2011-07-05 15:45:14 +04:00
spin_lock_init ( & wdata - > qlock ) ;
INIT_WORK ( & wdata - > worker , wiimote_worker ) ;
2011-07-05 15:45:10 +04:00
return wdata ;
}
static void wiimote_destroy ( struct wiimote_data * wdata )
{
kfree ( wdata ) ;
}
2011-07-05 15:45:09 +04:00
static int wiimote_hid_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
2011-07-05 15:45:08 +04:00
{
2011-07-05 15:45:10 +04:00
struct wiimote_data * wdata ;
2011-07-05 15:45:09 +04:00
int ret ;
2011-07-05 15:45:10 +04:00
wdata = wiimote_create ( hdev ) ;
if ( ! wdata ) {
hid_err ( hdev , " Can't alloc device \n " ) ;
return - ENOMEM ;
}
2011-07-05 15:45:09 +04:00
ret = hid_parse ( hdev ) ;
if ( ret ) {
hid_err ( hdev , " HID parse failed \n " ) ;
2011-07-05 15:45:10 +04:00
goto err ;
2011-07-05 15:45:09 +04:00
}
ret = hid_hw_start ( hdev , HID_CONNECT_HIDRAW ) ;
if ( ret ) {
hid_err ( hdev , " HW start failed \n " ) ;
2011-07-05 15:45:10 +04:00
goto err ;
2011-07-05 15:45:09 +04:00
}
2011-07-05 15:45:11 +04:00
ret = input_register_device ( wdata - > input ) ;
if ( ret ) {
hid_err ( hdev , " Cannot register input device \n " ) ;
goto err_stop ;
}
2011-07-05 15:45:12 +04:00
/* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
smp_wmb ( ) ;
atomic_set ( & wdata - > ready , 1 ) ;
2011-07-05 15:45:09 +04:00
hid_info ( hdev , " New device registered \n " ) ;
2011-07-05 15:45:08 +04:00
return 0 ;
2011-07-05 15:45:10 +04:00
2011-07-05 15:45:11 +04:00
err_stop :
hid_hw_stop ( hdev ) ;
2011-07-05 15:45:10 +04:00
err :
2011-07-05 15:45:11 +04:00
input_free_device ( wdata - > input ) ;
2011-07-05 15:45:10 +04:00
wiimote_destroy ( wdata ) ;
return ret ;
2011-07-05 15:45:08 +04:00
}
2011-07-05 15:45:09 +04:00
static void wiimote_hid_remove ( struct hid_device * hdev )
{
2011-07-05 15:45:10 +04:00
struct wiimote_data * wdata = hid_get_drvdata ( hdev ) ;
2011-07-05 15:45:09 +04:00
hid_info ( hdev , " Device removed \n " ) ;
2011-07-05 15:45:14 +04:00
2011-07-05 15:45:09 +04:00
hid_hw_stop ( hdev ) ;
2011-07-05 15:45:11 +04:00
input_unregister_device ( wdata - > input ) ;
2011-07-05 15:45:14 +04:00
cancel_work_sync ( & wdata - > worker ) ;
2011-07-05 15:45:10 +04:00
wiimote_destroy ( wdata ) ;
2011-07-05 15:45:09 +04:00
}
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 ;
}
2011-07-05 15:45:08 +04:00
static void __exit wiimote_exit ( void )
{
2011-07-05 15:45:09 +04:00
hid_unregister_driver ( & wiimote_hid_driver ) ;
2011-07-05 15:45:08 +04:00
}
module_init ( wiimote_init ) ;
module_exit ( wiimote_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Herrmann <dh.herrmann@gmail.com> " ) ;
MODULE_DESCRIPTION ( WIIMOTE_NAME " Device Driver " ) ;
MODULE_VERSION ( WIIMOTE_VERSION ) ;