Blame view
drivers/hid/hid-axff.c
4.92 KB
c0dbcc33c HID: add ACRUX ga... |
1 2 3 4 5 6 7 8 |
/* * 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" |
b55ebc27b HID: ACRUX - hand... |
9 |
* - tested with an EXEQ EQ-PCU-02090 game controller. |
c0dbcc33c HID: add ACRUX ga... |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
* * 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> |
8f86a2c3c hid: Add module.h... |
34 |
#include <linux/module.h> |
c0dbcc33c HID: add ACRUX ga... |
35 36 |
#include "hid-ids.h" |
0ae438109 HID: ACRUX - acti... |
37 38 |
#ifdef CONFIG_HID_ACRUX_FF |
c0dbcc33c HID: add ACRUX ga... |
39 40 41 42 43 44 45 46 47 48 |
#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; |
b55ebc27b HID: ACRUX - hand... |
49 50 |
struct hid_report *report = axff->report; int field_count = 0; |
c0dbcc33c HID: add ACRUX ga... |
51 |
int left, right; |
b55ebc27b HID: ACRUX - hand... |
52 |
int i, j; |
c0dbcc33c HID: add ACRUX ga... |
53 54 55 56 57 58 59 60 |
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; |
b55ebc27b HID: ACRUX - hand... |
61 62 63 64 65 66 67 |
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++; } } |
c0dbcc33c HID: add ACRUX ga... |
68 69 70 71 72 73 74 75 76 77 78 79 80 |
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; |
b55ebc27b HID: ACRUX - hand... |
81 82 |
int field_count = 0; int i, j; |
c0dbcc33c HID: add ACRUX ga... |
83 84 85 |
int error; if (list_empty(report_list)) { |
4291ee305 HID: Add and use ... |
86 87 |
hid_err(hid, "no output reports found "); |
c0dbcc33c HID: add ACRUX ga... |
88 89 90 91 |
return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); |
b55ebc27b HID: ACRUX - hand... |
92 93 94 95 96 97 |
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++; } } |
c0dbcc33c HID: add ACRUX ga... |
98 |
|
b55ebc27b HID: ACRUX - hand... |
99 100 101 102 |
if (field_count < 4) { hid_err(hid, "not enough fields in the report: %d ", field_count); |
c0dbcc33c HID: add ACRUX ga... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
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; |
c0dbcc33c HID: add ACRUX ga... |
117 |
usbhid_submit_report(hid, axff->report, USB_DIR_OUT); |
b55ebc27b HID: ACRUX - hand... |
118 119 |
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru> "); |
c0dbcc33c HID: add ACRUX ga... |
120 121 122 123 124 125 126 |
return 0; err_free_mem: kfree(axff); return error; } |
0ae438109 HID: ACRUX - acti... |
127 128 129 130 131 132 |
#else static inline int axff_init(struct hid_device *hid) { return 0; } #endif |
c0dbcc33c HID: add ACRUX ga... |
133 134 135 136 |
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) { int error; |
4291ee305 HID: Add and use ... |
137 138 |
dev_dbg(&hdev->dev, "ACRUX HID hardware probe... "); |
c0dbcc33c HID: add ACRUX ga... |
139 140 141 |
error = hid_parse(hdev); if (error) { |
4291ee305 HID: Add and use ... |
142 143 |
hid_err(hdev, "parse failed "); |
c0dbcc33c HID: add ACRUX ga... |
144 145 146 147 148 |
return error; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (error) { |
4291ee305 HID: Add and use ... |
149 150 |
hid_err(hdev, "hw start failed "); |
c0dbcc33c HID: add ACRUX ga... |
151 152 153 154 155 156 157 158 159 |
return error; } error = axff_init(hdev); if (error) { /* * Do not fail device initialization completely as device * may still be partially operable, just warn. */ |
4291ee305 HID: Add and use ... |
160 |
hid_warn(hdev, |
c0dbcc33c HID: add ACRUX ga... |
161 162 163 164 |
"Failed to enable force feedback support, error: %d ", error); } |
0ae438109 HID: ACRUX - acti... |
165 166 167 168 169 170 171 172 |
/* * 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 "); |
b30d89d10 HID: ACRUX - add ... |
173 |
hid_hw_stop(hdev); |
0ae438109 HID: ACRUX - acti... |
174 175 |
return error; } |
c0dbcc33c HID: add ACRUX ga... |
176 177 |
return 0; } |
0ae438109 HID: ACRUX - acti... |
178 179 180 181 182 |
static void ax_remove(struct hid_device *hdev) { hid_hw_close(hdev); hid_hw_stop(hdev); } |
c0dbcc33c HID: add ACRUX ga... |
183 184 185 186 187 188 189 |
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 = { |
0ae438109 HID: ACRUX - acti... |
190 191 192 193 |
.name = "acrux", .id_table = ax_devices, .probe = ax_probe, .remove = ax_remove, |
c0dbcc33c HID: add ACRUX ga... |
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
}; 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"); |