2010-07-19 14:13:23 +04:00
/*
* Force feedback support for ACRUX game controllers
*
* From what I have gathered , these devices are mass produced in China
* by several vendors . They often share the same design as the original
* Xbox 360 controller .
*
* 1 a34 : 0802 " ACRUX USB GAMEPAD 8116 "
2011-08-04 11:25:57 +04:00
* - tested with an EXEQ EQ - PCU - 020 90 game controller .
2010-07-19 14:13:23 +04:00
*
* Copyright ( c ) 2010 Sergei Kolzun < x0r @ dv - life . ru >
*/
/*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/input.h>
# include <linux/slab.h>
# include <linux/hid.h>
2011-07-03 21:39:48 +04:00
# include <linux/module.h>
2010-07-19 14:13:23 +04:00
# include "hid-ids.h"
2011-03-11 11:27:34 +03:00
# ifdef CONFIG_HID_ACRUX_FF
2010-07-19 14:13:23 +04:00
struct axff_device {
struct hid_report * report ;
} ;
static int axff_play ( struct input_dev * dev , void * data , struct ff_effect * effect )
{
struct hid_device * hid = input_get_drvdata ( dev ) ;
struct axff_device * axff = data ;
2011-08-04 11:25:57 +04:00
struct hid_report * report = axff - > report ;
int field_count = 0 ;
2010-07-19 14:13:23 +04:00
int left , right ;
2011-08-04 11:25:57 +04:00
int i , j ;
2010-07-19 14:13:23 +04:00
left = effect - > u . rumble . strong_magnitude ;
right = effect - > u . rumble . weak_magnitude ;
dbg_hid ( " called with 0x%04x 0x%04x " , left , right ) ;
left = left * 0xff / 0xffff ;
right = right * 0xff / 0xffff ;
2011-08-04 11:25:57 +04:00
for ( i = 0 ; i < report - > maxfield ; i + + ) {
for ( j = 0 ; j < report - > field [ i ] - > report_count ; j + + ) {
report - > field [ i ] - > value [ j ] =
field_count % 2 ? right : left ;
field_count + + ;
}
}
2010-07-19 14:13:23 +04:00
dbg_hid ( " running with 0x%02x 0x%02x " , left , right ) ;
2013-02-25 14:31:46 +04:00
hid_hw_request ( hid , axff - > report , HID_REQ_SET_REPORT ) ;
2010-07-19 14:13:23 +04:00
return 0 ;
}
static int axff_init ( struct hid_device * hid )
{
struct axff_device * axff ;
struct hid_report * report ;
struct hid_input * hidinput = list_first_entry ( & hid - > inputs , struct hid_input , list ) ;
struct list_head * report_list = & hid - > report_enum [ HID_OUTPUT_REPORT ] . report_list ;
struct input_dev * dev = hidinput - > input ;
2011-08-04 11:25:57 +04:00
int field_count = 0 ;
int i , j ;
2010-07-19 14:13:23 +04:00
int error ;
if ( list_empty ( report_list ) ) {
2010-12-10 06:29:03 +03:00
hid_err ( hid , " no output reports found \n " ) ;
2010-07-19 14:13:23 +04:00
return - ENODEV ;
}
report = list_first_entry ( report_list , struct hid_report , list ) ;
2011-08-04 11:25:57 +04:00
for ( i = 0 ; i < report - > maxfield ; i + + ) {
for ( j = 0 ; j < report - > field [ i ] - > report_count ; j + + ) {
report - > field [ i ] - > value [ j ] = 0x00 ;
field_count + + ;
}
}
2010-07-19 14:13:23 +04:00
2013-11-12 22:06:23 +04:00
if ( field_count < 4 & & hid - > product ! = 0xf705 ) {
2011-08-04 11:25:57 +04:00
hid_err ( hid , " not enough fields in the report: %d \n " ,
field_count ) ;
2010-07-19 14:13:23 +04:00
return - ENODEV ;
}
axff = kzalloc ( sizeof ( struct axff_device ) , GFP_KERNEL ) ;
if ( ! axff )
return - ENOMEM ;
set_bit ( FF_RUMBLE , dev - > ffbit ) ;
error = input_ff_create_memless ( dev , axff , axff_play ) ;
if ( error )
goto err_free_mem ;
axff - > report = report ;
2013-02-25 14:31:46 +04:00
hid_hw_request ( hid , axff - > report , HID_REQ_SET_REPORT ) ;
2010-07-19 14:13:23 +04:00
2011-08-04 11:25:57 +04:00
hid_info ( hid , " Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru> \n " ) ;
2010-07-19 14:13:23 +04:00
return 0 ;
err_free_mem :
kfree ( axff ) ;
return error ;
}
2011-03-11 11:27:34 +03:00
# else
static inline int axff_init ( struct hid_device * hid )
{
return 0 ;
}
# endif
2010-07-19 14:13:23 +04:00
static int ax_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
int error ;
2010-12-10 06:29:03 +03:00
dev_dbg ( & hdev - > dev , " ACRUX HID hardware probe... \n " ) ;
2010-07-19 14:13:23 +04:00
error = hid_parse ( hdev ) ;
if ( error ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " parse failed \n " ) ;
2010-07-19 14:13:23 +04:00
return error ;
}
error = hid_hw_start ( hdev , HID_CONNECT_DEFAULT & ~ HID_CONNECT_FF ) ;
if ( error ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " hw start failed \n " ) ;
2010-07-19 14:13:23 +04:00
return error ;
}
error = axff_init ( hdev ) ;
if ( error ) {
/*
* Do not fail device initialization completely as device
* may still be partially operable , just warn .
*/
2010-12-10 06:29:03 +03:00
hid_warn ( hdev ,
2010-07-19 14:13:23 +04:00
" Failed to enable force feedback support, error: %d \n " ,
error ) ;
}
2011-03-11 11:27:34 +03:00
/*
* We need to start polling device right away , otherwise
* it will go into a coma .
*/
error = hid_hw_open ( hdev ) ;
if ( error ) {
dev_err ( & hdev - > dev , " hw open failed \n " ) ;
2011-07-14 09:07:51 +04:00
hid_hw_stop ( hdev ) ;
2011-03-11 11:27:34 +03:00
return error ;
}
2010-07-19 14:13:23 +04:00
return 0 ;
}
2011-03-11 11:27:34 +03:00
static void ax_remove ( struct hid_device * hdev )
{
hid_hw_close ( hdev ) ;
hid_hw_stop ( hdev ) ;
}
2010-07-19 14:13:23 +04:00
static const struct hid_device_id ax_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_ACRUX , 0x0802 ) , } ,
2013-11-12 22:06:23 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_ACRUX , 0xf705 ) , } ,
2010-07-19 14:13:23 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( hid , ax_devices ) ;
static struct hid_driver ax_driver = {
2011-03-11 11:27:34 +03:00
. name = " acrux " ,
. id_table = ax_devices ,
. probe = ax_probe ,
. remove = ax_remove ,
2010-07-19 14:13:23 +04:00
} ;
2012-12-18 02:28:26 +04:00
module_hid_driver ( ax_driver ) ;
2010-07-19 14:13:23 +04:00
MODULE_AUTHOR ( " Sergei Kolzun " ) ;
MODULE_DESCRIPTION ( " Force feedback support for ACRUX game controllers " ) ;
MODULE_LICENSE ( " GPL " ) ;