2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-12-30 11:53:54 +03:00
/*
* SEGA Dreamcast controller driver
* Based on drivers / usb / iforce . c
*
* Copyright Yaegashi Takeshi , 2001
2009-02-27 10:07:32 +03:00
* Adrian McMenamin , 2008 - 2009
2008-12-30 11:53:54 +03:00
*/
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/input.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/timer.h>
# include <linux/maple.h>
MODULE_AUTHOR ( " Adrian McMenamin <adrian@mcmen.demon.co.uk> " ) ;
MODULE_DESCRIPTION ( " SEGA Dreamcast controller driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
struct dc_pad {
struct input_dev * dev ;
struct maple_device * mdev ;
} ;
static void dc_pad_callback ( struct mapleq * mq )
{
unsigned short buttons ;
struct maple_device * mapledev = mq - > dev ;
struct dc_pad * pad = maple_get_drvdata ( mapledev ) ;
struct input_dev * dev = pad - > dev ;
2009-02-27 10:07:32 +03:00
unsigned char * res = mq - > recvbuf - > buf ;
2008-12-30 11:53:54 +03:00
buttons = ~ le16_to_cpup ( ( __le16 * ) ( res + 8 ) ) ;
input_report_abs ( dev , ABS_HAT0Y ,
( buttons & 0x0010 ? - 1 : 0 ) + ( buttons & 0x0020 ? 1 : 0 ) ) ;
input_report_abs ( dev , ABS_HAT0X ,
( buttons & 0x0040 ? - 1 : 0 ) + ( buttons & 0x0080 ? 1 : 0 ) ) ;
input_report_abs ( dev , ABS_HAT1Y ,
( buttons & 0x1000 ? - 1 : 0 ) + ( buttons & 0x2000 ? 1 : 0 ) ) ;
input_report_abs ( dev , ABS_HAT1X ,
( buttons & 0x4000 ? - 1 : 0 ) + ( buttons & 0x8000 ? 1 : 0 ) ) ;
input_report_key ( dev , BTN_C , buttons & 0x0001 ) ;
input_report_key ( dev , BTN_B , buttons & 0x0002 ) ;
input_report_key ( dev , BTN_A , buttons & 0x0004 ) ;
input_report_key ( dev , BTN_START , buttons & 0x0008 ) ;
input_report_key ( dev , BTN_Z , buttons & 0x0100 ) ;
input_report_key ( dev , BTN_Y , buttons & 0x0200 ) ;
input_report_key ( dev , BTN_X , buttons & 0x0400 ) ;
input_report_key ( dev , BTN_SELECT , buttons & 0x0800 ) ;
input_report_abs ( dev , ABS_GAS , res [ 10 ] ) ;
input_report_abs ( dev , ABS_BRAKE , res [ 11 ] ) ;
input_report_abs ( dev , ABS_X , res [ 12 ] ) ;
input_report_abs ( dev , ABS_Y , res [ 13 ] ) ;
input_report_abs ( dev , ABS_RX , res [ 14 ] ) ;
input_report_abs ( dev , ABS_RY , res [ 15 ] ) ;
}
static int dc_pad_open ( struct input_dev * dev )
{
2013-08-05 20:13:27 +04:00
struct dc_pad * pad = dev_get_platdata ( & dev - > dev ) ;
2008-12-30 11:53:54 +03:00
maple_getcond_callback ( pad - > mdev , dc_pad_callback , HZ / 20 ,
MAPLE_FUNC_CONTROLLER ) ;
return 0 ;
}
static void dc_pad_close ( struct input_dev * dev )
{
2013-08-05 20:13:27 +04:00
struct dc_pad * pad = dev_get_platdata ( & dev - > dev ) ;
2008-12-30 11:53:54 +03:00
maple_getcond_callback ( pad - > mdev , dc_pad_callback , 0 ,
MAPLE_FUNC_CONTROLLER ) ;
}
/* allow the controller to be used */
2012-11-24 09:38:25 +04:00
static int probe_maple_controller ( struct device * dev )
2008-12-30 11:53:54 +03:00
{
static const short btn_bit [ 32 ] = {
BTN_C , BTN_B , BTN_A , BTN_START , - 1 , - 1 , - 1 , - 1 ,
BTN_Z , BTN_Y , BTN_X , BTN_SELECT , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
} ;
static const short abs_bit [ 32 ] = {
- 1 , - 1 , - 1 , - 1 , ABS_HAT0Y , ABS_HAT0Y , ABS_HAT0X , ABS_HAT0X ,
- 1 , - 1 , - 1 , - 1 , ABS_HAT1Y , ABS_HAT1Y , ABS_HAT1X , ABS_HAT1X ,
ABS_GAS , ABS_BRAKE , ABS_X , ABS_Y , ABS_RX , ABS_RY , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
} ;
struct maple_device * mdev = to_maple_dev ( dev ) ;
struct maple_driver * mdrv = to_maple_driver ( dev - > driver ) ;
int i , error ;
struct dc_pad * pad ;
struct input_dev * idev ;
unsigned long data = be32_to_cpu ( mdev - > devinfo . function_data [ 0 ] ) ;
pad = kzalloc ( sizeof ( struct dc_pad ) , GFP_KERNEL ) ;
idev = input_allocate_device ( ) ;
if ( ! pad | | ! idev ) {
error = - ENOMEM ;
goto fail ;
}
pad - > dev = idev ;
pad - > mdev = mdev ;
idev - > open = dc_pad_open ;
idev - > close = dc_pad_close ;
for ( i = 0 ; i < 32 ; i + + ) {
if ( data & ( 1 < < i ) ) {
if ( btn_bit [ i ] > = 0 )
__set_bit ( btn_bit [ i ] , idev - > keybit ) ;
else if ( abs_bit [ i ] > = 0 )
__set_bit ( abs_bit [ i ] , idev - > absbit ) ;
}
}
if ( idev - > keybit [ BIT_WORD ( BTN_JOYSTICK ) ] )
idev - > evbit [ 0 ] | = BIT_MASK ( EV_KEY ) ;
if ( idev - > absbit [ 0 ] )
idev - > evbit [ 0 ] | = BIT_MASK ( EV_ABS ) ;
for ( i = ABS_X ; i < = ABS_BRAKE ; i + + )
input_set_abs_params ( idev , i , 0 , 255 , 0 , 0 ) ;
for ( i = ABS_HAT0X ; i < = ABS_HAT3Y ; i + + )
input_set_abs_params ( idev , i , 1 , - 1 , 0 , 0 ) ;
idev - > dev . platform_data = pad ;
idev - > dev . parent = & mdev - > dev ;
idev - > name = mdev - > product_name ;
idev - > id . bustype = BUS_HOST ;
error = input_register_device ( idev ) ;
if ( error )
goto fail ;
mdev - > driver = mdrv ;
maple_set_drvdata ( mdev , pad ) ;
return 0 ;
fail :
input_free_device ( idev ) ;
kfree ( pad ) ;
maple_set_drvdata ( mdev , NULL ) ;
return error ;
}
2012-11-24 09:50:47 +04:00
static int remove_maple_controller ( struct device * dev )
2008-12-30 11:53:54 +03:00
{
struct maple_device * mdev = to_maple_dev ( dev ) ;
struct dc_pad * pad = maple_get_drvdata ( mdev ) ;
mdev - > callback = NULL ;
input_unregister_device ( pad - > dev ) ;
maple_set_drvdata ( mdev , NULL ) ;
kfree ( pad ) ;
return 0 ;
}
static struct maple_driver dc_pad_driver = {
. function = MAPLE_FUNC_CONTROLLER ,
. drv = {
. name = " Dreamcast_controller " ,
. probe = probe_maple_controller ,
2012-11-24 09:27:39 +04:00
. remove = remove_maple_controller ,
2008-12-30 11:53:54 +03:00
} ,
} ;
static int __init dc_pad_init ( void )
{
return maple_driver_register ( & dc_pad_driver ) ;
}
static void __exit dc_pad_exit ( void )
{
maple_driver_unregister ( & dc_pad_driver ) ;
}
module_init ( dc_pad_init ) ;
module_exit ( dc_pad_exit ) ;