1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Force feedback support for DragonRise Inc. game controllers 4 * 5 * From what I have gathered, these devices are mass produced in China and are 6 * distributed under several vendors. They often share the same design as 7 * the original PlayStation DualShock controller. 8 * 9 * 0079:0006 "DragonRise Inc. Generic USB Joystick " 10 * - tested with a Tesun USB-703 game controller. 11 * 12 * Copyright (c) 2009 Richard Walmsley <richwalm@gmail.com> 13 */ 14 15 /* 16 */ 17 18 #include <linux/input.h> 19 #include <linux/slab.h> 20 #include <linux/hid.h> 21 #include <linux/module.h> 22 23 #include "hid-ids.h" 24 25 #ifdef CONFIG_DRAGONRISE_FF 26 27 struct drff_device { 28 struct hid_report *report; 29 }; 30 31 static int drff_play(struct input_dev *dev, void *data, 32 struct ff_effect *effect) 33 { 34 struct hid_device *hid = input_get_drvdata(dev); 35 struct drff_device *drff = data; 36 int strong, weak; 37 38 strong = effect->u.rumble.strong_magnitude; 39 weak = effect->u.rumble.weak_magnitude; 40 41 dbg_hid("called with 0x%04x 0x%04x", strong, weak); 42 43 if (strong || weak) { 44 strong = strong * 0xff / 0xffff; 45 weak = weak * 0xff / 0xffff; 46 47 /* While reverse engineering this device, I found that when 48 this value is set, it causes the strong rumble to function 49 at a near maximum speed, so we'll bypass it. */ 50 if (weak == 0x0a) 51 weak = 0x0b; 52 53 drff->report->field[0]->value[0] = 0x51; 54 drff->report->field[0]->value[1] = 0x00; 55 drff->report->field[0]->value[2] = weak; 56 drff->report->field[0]->value[4] = strong; 57 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); 58 59 drff->report->field[0]->value[0] = 0xfa; 60 drff->report->field[0]->value[1] = 0xfe; 61 } else { 62 drff->report->field[0]->value[0] = 0xf3; 63 drff->report->field[0]->value[1] = 0x00; 64 } 65 66 drff->report->field[0]->value[2] = 0x00; 67 drff->report->field[0]->value[4] = 0x00; 68 dbg_hid("running with 0x%02x 0x%02x", strong, weak); 69 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); 70 71 return 0; 72 } 73 74 static int dr_input_configured(struct hid_device *hid, struct hid_input *hidinput) 75 { 76 struct drff_device *drff; 77 struct hid_report *report; 78 struct list_head *report_list = 79 &hid->report_enum[HID_OUTPUT_REPORT].report_list; 80 struct input_dev *dev = hidinput->input; 81 int error; 82 83 if (!list_is_first(&hidinput->list, &hid->inputs)) 84 return 0; 85 86 if (hid->product != 0x0006) 87 return 0; 88 89 report = list_first_entry_or_null(report_list, struct hid_report, list); 90 if (!report) { 91 hid_err(hid, "no output reports found\n"); 92 return -ENODEV; 93 } 94 if (report->maxfield < 1) { 95 hid_err(hid, "no fields in the report\n"); 96 return -ENODEV; 97 } 98 99 if (report->field[0]->report_count < 7) { 100 hid_err(hid, "not enough values in the field\n"); 101 return -ENODEV; 102 } 103 104 drff = kzalloc_obj(struct drff_device); 105 if (!drff) 106 return -ENOMEM; 107 108 drff->report = report; 109 set_bit(FF_RUMBLE, dev->ffbit); 110 111 error = input_ff_create_memless(dev, drff, drff_play); 112 if (error) { 113 kfree(drff); 114 return error; 115 } 116 117 drff->report->field[0]->value[0] = 0xf3; 118 drff->report->field[0]->value[1] = 0x00; 119 drff->report->field[0]->value[2] = 0x00; 120 drff->report->field[0]->value[3] = 0x00; 121 drff->report->field[0]->value[4] = 0x00; 122 drff->report->field[0]->value[5] = 0x00; 123 drff->report->field[0]->value[6] = 0x00; 124 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); 125 126 hid_info(hid, "Force Feedback for DragonRise Inc. " 127 "game controllers by Richard Walmsley <richwalm@gmail.com>\n"); 128 129 return 0; 130 } 131 #else 132 static inline int dr_input_configured(struct hid_device *hid, 133 struct hid_input *hidinput) 134 { 135 return 0; 136 } 137 #endif 138 139 /* 140 * The original descriptor of joystick with PID 0x0011, represented by DVTech PC 141 * JS19. It seems both copied from another device and a result of confusion 142 * either about the specification or about the program used to create the 143 * descriptor. In any case, it's a wonder it works on Windows. 144 * 145 * Usage Page (Desktop), ; Generic desktop controls (01h) 146 * Usage (Joystick), ; Joystick (04h, application collection) 147 * Collection (Application), 148 * Collection (Logical), 149 * Report Size (8), 150 * Report Count (5), 151 * Logical Minimum (0), 152 * Logical Maximum (255), 153 * Physical Minimum (0), 154 * Physical Maximum (255), 155 * Usage (X), ; X (30h, dynamic value) 156 * Usage (X), ; X (30h, dynamic value) 157 * Usage (X), ; X (30h, dynamic value) 158 * Usage (X), ; X (30h, dynamic value) 159 * Usage (Y), ; Y (31h, dynamic value) 160 * Input (Variable), 161 * Report Size (4), 162 * Report Count (1), 163 * Logical Maximum (7), 164 * Physical Maximum (315), 165 * Unit (Degrees), 166 * Usage (00h), 167 * Input (Variable, Null State), 168 * Unit, 169 * Report Size (1), 170 * Report Count (10), 171 * Logical Maximum (1), 172 * Physical Maximum (1), 173 * Usage Page (Button), ; Button (09h) 174 * Usage Minimum (01h), 175 * Usage Maximum (0Ah), 176 * Input (Variable), 177 * Usage Page (FF00h), ; FF00h, vendor-defined 178 * Report Size (1), 179 * Report Count (10), 180 * Logical Maximum (1), 181 * Physical Maximum (1), 182 * Usage (01h), 183 * Input (Variable), 184 * End Collection, 185 * Collection (Logical), 186 * Report Size (8), 187 * Report Count (4), 188 * Physical Maximum (255), 189 * Logical Maximum (255), 190 * Usage (02h), 191 * Output (Variable), 192 * End Collection, 193 * End Collection 194 */ 195 196 /* Size of the original descriptor of the PID 0x0011 joystick */ 197 #define PID0011_RDESC_ORIG_SIZE 101 198 199 /* Fixed report descriptor for PID 0x011 joystick */ 200 static const __u8 pid0011_rdesc_fixed[] = { 201 0x05, 0x01, /* Usage Page (Desktop), */ 202 0x09, 0x04, /* Usage (Joystick), */ 203 0xA1, 0x01, /* Collection (Application), */ 204 0xA1, 0x02, /* Collection (Logical), */ 205 0x14, /* Logical Minimum (0), */ 206 0x75, 0x08, /* Report Size (8), */ 207 0x95, 0x03, /* Report Count (3), */ 208 0x81, 0x01, /* Input (Constant), */ 209 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 210 0x95, 0x02, /* Report Count (2), */ 211 0x09, 0x30, /* Usage (X), */ 212 0x09, 0x31, /* Usage (Y), */ 213 0x81, 0x02, /* Input (Variable), */ 214 0x75, 0x01, /* Report Size (1), */ 215 0x95, 0x04, /* Report Count (4), */ 216 0x81, 0x01, /* Input (Constant), */ 217 0x25, 0x01, /* Logical Maximum (1), */ 218 0x95, 0x0A, /* Report Count (10), */ 219 0x05, 0x09, /* Usage Page (Button), */ 220 0x19, 0x01, /* Usage Minimum (01h), */ 221 0x29, 0x0A, /* Usage Maximum (0Ah), */ 222 0x81, 0x02, /* Input (Variable), */ 223 0x95, 0x0A, /* Report Count (10), */ 224 0x81, 0x01, /* Input (Constant), */ 225 0xC0, /* End Collection, */ 226 0xC0 /* End Collection */ 227 }; 228 229 static const __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc, 230 unsigned int *rsize) 231 { 232 switch (hdev->product) { 233 case 0x0011: 234 if (*rsize == PID0011_RDESC_ORIG_SIZE) { 235 *rsize = sizeof(pid0011_rdesc_fixed); 236 return pid0011_rdesc_fixed; 237 } 238 break; 239 } 240 return rdesc; 241 } 242 243 #define map_abs(c) hid_map_usage(hi, usage, bit, max, EV_ABS, (c)) 244 #define map_rel(c) hid_map_usage(hi, usage, bit, max, EV_REL, (c)) 245 246 static int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi, 247 struct hid_field *field, struct hid_usage *usage, 248 unsigned long **bit, int *max) 249 { 250 switch (usage->hid) { 251 /* 252 * revert to the old hid-input behavior where axes 253 * can be randomly assigned when hid->usage is reused. 254 */ 255 case HID_GD_X: case HID_GD_Y: case HID_GD_Z: 256 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: 257 if (field->flags & HID_MAIN_ITEM_RELATIVE) 258 map_rel(usage->hid & 0xf); 259 else 260 map_abs(usage->hid & 0xf); 261 return 1; 262 } 263 264 return 0; 265 } 266 267 static const struct hid_device_id dr_devices[] = { 268 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), }, 269 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), }, 270 { } 271 }; 272 MODULE_DEVICE_TABLE(hid, dr_devices); 273 274 static struct hid_driver dr_driver = { 275 .name = "dragonrise", 276 .id_table = dr_devices, 277 .report_fixup = dr_report_fixup, 278 .input_mapping = dr_input_mapping, 279 .input_configured = dr_input_configured, 280 }; 281 module_hid_driver(dr_driver); 282 283 MODULE_DESCRIPTION("Force feedback support for DragonRise Inc. game controllers"); 284 MODULE_LICENSE("GPL"); 285