Skip to content

Commit

Permalink
HID: add ACRUX game controller force feedback support
Browse files Browse the repository at this point in the history
Adds force feedback support for ACRUX USB game controllers.
These devices are mass produced in China by several vendors.

Signed-off-by: Sergei Kolzun <x0r@dv-life.ru>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Sergei Kolzun authored and Jiri Kosina committed Jul 19, 2010
1 parent 1c5474a commit c0dbcc3
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
9 changes: 9 additions & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ config HID_A4TECH
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.

config HID_ACRUX_FF
tristate "ACRUX force feedback support"
depends on USB_HID
default !EMBEDDED
select INPUT_FF_MEMLESS
---help---
Say Y here if you want to enable force feedback support for ACRUX
game controllers.

config HID_APPLE
tristate "Apple" if EMBEDDED
depends on (USB_HID || BT_HIDP)
Expand Down
1 change: 1 addition & 0 deletions drivers/hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ endif

obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o
Expand Down
172 changes: 172 additions & 0 deletions drivers/hid/hid-axff.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* 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.
*
* 1a34:0802 "ACRUX USB GAMEPAD 8116"
* - tested with a EXEQ EQ-PCU-02090 game controller.
*
* 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/usb.h>
#include <linux/hid.h>

#include "hid-ids.h"
#include "usbhid/usbhid.h"

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;
int left, right;

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;

axff->report->field[0]->value[0] = left;
axff->report->field[1]->value[0] = right;
axff->report->field[2]->value[0] = left;
axff->report->field[3]->value[0] = right;
dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);

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;
int error;

if (list_empty(report_list)) {
dev_err(&hid->dev, "no output reports found\n");
return -ENODEV;
}

report = list_first_entry(report_list, struct hid_report, list);

if (report->maxfield < 4) {
dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
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;
axff->report->field[0]->value[0] = 0x00;
axff->report->field[1]->value[0] = 0x00;
axff->report->field[2]->value[0] = 0x00;
axff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);

dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");

return 0;

err_free_mem:
kfree(axff);
return error;
}

static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int error;

dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");

error = hid_parse(hdev);
if (error) {
dev_err(&hdev->dev, "parse failed\n");
return error;
}

error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (error) {
dev_err(&hdev->dev, "hw start failed\n");
return error;
}

error = axff_init(hdev);
if (error) {
/*
* Do not fail device initialization completely as device
* may still be partially operable, just warn.
*/
dev_warn(&hdev->dev,
"Failed to enable force feedback support, error: %d\n",
error);
}

return 0;
}

static const struct hid_device_id ax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
{ }
};
MODULE_DEVICE_TABLE(hid, ax_devices);

static struct hid_driver ax_driver = {
.name = "acrux",
.id_table = ax_devices,
.probe = ax_probe,
};

static int __init ax_init(void)
{
return hid_register_driver(&ax_driver);
}

static void __exit ax_exit(void)
{
hid_unregister_driver(&ax_driver);
}

module_init(ax_init);
module_exit(ax_exit);

MODULE_AUTHOR("Sergei Kolzun");
MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers");
MODULE_LICENSE("GPL");
3 changes: 3 additions & 0 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,9 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
Expand Down
2 changes: 2 additions & 0 deletions drivers/hid/hid-ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
#define USB_DEVICE_ID_ACECAD_302 0x0008

#define USB_VENDOR_ID_ACRUX 0x1a34

#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155

Expand Down

0 comments on commit c0dbcc3

Please sign in to comment.