Blame view
drivers/hid/hid-axff.c
4.24 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
c0dbcc33c HID: add ACRUX ga... |
2 3 4 5 6 7 8 9 |
/* * 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... |
10 |
* - tested with an EXEQ EQ-PCU-02090 game controller. |
c0dbcc33c HID: add ACRUX ga... |
11 12 13 14 15 |
* * Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru> */ /* |
c0dbcc33c HID: add ACRUX ga... |
16 17 18 19 |
*/ #include <linux/input.h> #include <linux/slab.h> |
c0dbcc33c HID: add ACRUX ga... |
20 |
#include <linux/hid.h> |
8f86a2c3c hid: Add module.h... |
21 |
#include <linux/module.h> |
c0dbcc33c HID: add ACRUX ga... |
22 23 |
#include "hid-ids.h" |
0ae438109 HID: ACRUX - acti... |
24 25 |
#ifdef CONFIG_HID_ACRUX_FF |
c0dbcc33c HID: add ACRUX ga... |
26 27 28 29 30 31 32 33 34 |
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... |
35 36 |
struct hid_report *report = axff->report; int field_count = 0; |
c0dbcc33c HID: add ACRUX ga... |
37 |
int left, right; |
b55ebc27b HID: ACRUX - hand... |
38 |
int i, j; |
c0dbcc33c HID: add ACRUX ga... |
39 40 41 42 43 44 45 46 |
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... |
47 48 49 50 51 52 53 |
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... |
54 |
dbg_hid("running with 0x%02x 0x%02x", left, right); |
d88142725 HID: use hid_hw_r... |
55 |
hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT); |
c0dbcc33c HID: add ACRUX ga... |
56 57 58 59 60 61 62 63 |
return 0; } static int axff_init(struct hid_device *hid) { struct axff_device *axff; struct hid_report *report; |
d9d4b1e46 HID: Fix assumpti... |
64 |
struct hid_input *hidinput; |
c0dbcc33c HID: add ACRUX ga... |
65 |
struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list; |
d9d4b1e46 HID: Fix assumpti... |
66 |
struct input_dev *dev; |
b55ebc27b HID: ACRUX - hand... |
67 68 |
int field_count = 0; int i, j; |
c0dbcc33c HID: add ACRUX ga... |
69 |
int error; |
d9d4b1e46 HID: Fix assumpti... |
70 71 72 73 74 75 76 |
if (list_empty(&hid->inputs)) { hid_err(hid, "no inputs found "); return -ENODEV; } hidinput = list_first_entry(&hid->inputs, struct hid_input, list); dev = hidinput->input; |
c0dbcc33c HID: add ACRUX ga... |
77 |
if (list_empty(report_list)) { |
4291ee305 HID: Add and use ... |
78 79 |
hid_err(hid, "no output reports found "); |
c0dbcc33c HID: add ACRUX ga... |
80 81 82 83 |
return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); |
b55ebc27b HID: ACRUX - hand... |
84 85 86 87 88 89 |
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... |
90 |
|
e17f5d766 HID: enable Mayfl... |
91 |
if (field_count < 4 && hid->product != 0xf705) { |
b55ebc27b HID: ACRUX - hand... |
92 93 94 |
hid_err(hid, "not enough fields in the report: %d ", field_count); |
c0dbcc33c HID: add ACRUX ga... |
95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
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; |
d88142725 HID: use hid_hw_r... |
109 |
hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT); |
c0dbcc33c HID: add ACRUX ga... |
110 |
|
b55ebc27b HID: ACRUX - hand... |
111 112 |
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru> "); |
c0dbcc33c HID: add ACRUX ga... |
113 114 115 116 117 118 119 |
return 0; err_free_mem: kfree(axff); return error; } |
0ae438109 HID: ACRUX - acti... |
120 121 122 123 124 125 |
#else static inline int axff_init(struct hid_device *hid) { return 0; } #endif |
c0dbcc33c HID: add ACRUX ga... |
126 127 128 129 |
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) { int error; |
4291ee305 HID: Add and use ... |
130 131 |
dev_dbg(&hdev->dev, "ACRUX HID hardware probe... "); |
c0dbcc33c HID: add ACRUX ga... |
132 133 134 |
error = hid_parse(hdev); if (error) { |
4291ee305 HID: Add and use ... |
135 136 |
hid_err(hdev, "parse failed "); |
c0dbcc33c HID: add ACRUX ga... |
137 138 139 140 141 |
return error; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (error) { |
4291ee305 HID: Add and use ... |
142 143 |
hid_err(hdev, "hw start failed "); |
c0dbcc33c HID: add ACRUX ga... |
144 145 146 147 148 149 150 151 152 |
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 ... |
153 |
hid_warn(hdev, |
c0dbcc33c HID: add ACRUX ga... |
154 155 156 157 |
"Failed to enable force feedback support, error: %d ", error); } |
0ae438109 HID: ACRUX - acti... |
158 159 160 161 162 163 164 165 |
/* * 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 ... |
166 |
hid_hw_stop(hdev); |
0ae438109 HID: ACRUX - acti... |
167 168 |
return error; } |
c0dbcc33c HID: add ACRUX ga... |
169 170 |
return 0; } |
0ae438109 HID: ACRUX - acti... |
171 172 173 174 175 |
static void ax_remove(struct hid_device *hdev) { hid_hw_close(hdev); hid_hw_stop(hdev); } |
c0dbcc33c HID: add ACRUX ga... |
176 177 |
static const struct hid_device_id ax_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), }, |
e17f5d766 HID: enable Mayfl... |
178 |
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705), }, |
c0dbcc33c HID: add ACRUX ga... |
179 180 181 182 183 |
{ } }; MODULE_DEVICE_TABLE(hid, ax_devices); static struct hid_driver ax_driver = { |
0ae438109 HID: ACRUX - acti... |
184 185 186 187 |
.name = "acrux", .id_table = ax_devices, .probe = ax_probe, .remove = ax_remove, |
c0dbcc33c HID: add ACRUX ga... |
188 |
}; |
f425458ea HID: Use module_h... |
189 |
module_hid_driver(ax_driver); |
c0dbcc33c HID: add ACRUX ga... |
190 191 192 193 |
MODULE_AUTHOR("Sergei Kolzun"); MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers"); MODULE_LICENSE("GPL"); |