cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hid-dr.c (9338B)


      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
     27struct drff_device {
     28	struct hid_report *report;
     29};
     30
     31static 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
     74static int drff_init(struct hid_device *hid)
     75{
     76	struct drff_device *drff;
     77	struct hid_report *report;
     78	struct hid_input *hidinput;
     79	struct list_head *report_list =
     80			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
     81	struct input_dev *dev;
     82	int error;
     83
     84	if (list_empty(&hid->inputs)) {
     85		hid_err(hid, "no inputs found\n");
     86		return -ENODEV;
     87	}
     88	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
     89	dev = hidinput->input;
     90
     91	if (list_empty(report_list)) {
     92		hid_err(hid, "no output reports found\n");
     93		return -ENODEV;
     94	}
     95
     96	report = list_first_entry(report_list, struct hid_report, list);
     97	if (report->maxfield < 1) {
     98		hid_err(hid, "no fields in the report\n");
     99		return -ENODEV;
    100	}
    101
    102	if (report->field[0]->report_count < 7) {
    103		hid_err(hid, "not enough values in the field\n");
    104		return -ENODEV;
    105	}
    106
    107	drff = kzalloc(sizeof(struct drff_device), GFP_KERNEL);
    108	if (!drff)
    109		return -ENOMEM;
    110
    111	set_bit(FF_RUMBLE, dev->ffbit);
    112
    113	error = input_ff_create_memless(dev, drff, drff_play);
    114	if (error) {
    115		kfree(drff);
    116		return error;
    117	}
    118
    119	drff->report = report;
    120	drff->report->field[0]->value[0] = 0xf3;
    121	drff->report->field[0]->value[1] = 0x00;
    122	drff->report->field[0]->value[2] = 0x00;
    123	drff->report->field[0]->value[3] = 0x00;
    124	drff->report->field[0]->value[4] = 0x00;
    125	drff->report->field[0]->value[5] = 0x00;
    126	drff->report->field[0]->value[6] = 0x00;
    127	hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
    128
    129	hid_info(hid, "Force Feedback for DragonRise Inc. "
    130		 "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
    131
    132	return 0;
    133}
    134#else
    135static inline int drff_init(struct hid_device *hid)
    136{
    137	return 0;
    138}
    139#endif
    140
    141/*
    142 * The original descriptor of joystick with PID 0x0011, represented by DVTech PC
    143 * JS19. It seems both copied from another device and a result of confusion
    144 * either about the specification or about the program used to create the
    145 * descriptor. In any case, it's a wonder it works on Windows.
    146 *
    147 *  Usage Page (Desktop),             ; Generic desktop controls (01h)
    148 *  Usage (Joystick),                 ; Joystick (04h, application collection)
    149 *  Collection (Application),
    150 *    Collection (Logical),
    151 *      Report Size (8),
    152 *      Report Count (5),
    153 *      Logical Minimum (0),
    154 *      Logical Maximum (255),
    155 *      Physical Minimum (0),
    156 *      Physical Maximum (255),
    157 *      Usage (X),                    ; X (30h, dynamic value)
    158 *      Usage (X),                    ; X (30h, dynamic value)
    159 *      Usage (X),                    ; X (30h, dynamic value)
    160 *      Usage (X),                    ; X (30h, dynamic value)
    161 *      Usage (Y),                    ; Y (31h, dynamic value)
    162 *      Input (Variable),
    163 *      Report Size (4),
    164 *      Report Count (1),
    165 *      Logical Maximum (7),
    166 *      Physical Maximum (315),
    167 *      Unit (Degrees),
    168 *      Usage (00h),
    169 *      Input (Variable, Null State),
    170 *      Unit,
    171 *      Report Size (1),
    172 *      Report Count (10),
    173 *      Logical Maximum (1),
    174 *      Physical Maximum (1),
    175 *      Usage Page (Button),          ; Button (09h)
    176 *      Usage Minimum (01h),
    177 *      Usage Maximum (0Ah),
    178 *      Input (Variable),
    179 *      Usage Page (FF00h),           ; FF00h, vendor-defined
    180 *      Report Size (1),
    181 *      Report Count (10),
    182 *      Logical Maximum (1),
    183 *      Physical Maximum (1),
    184 *      Usage (01h),
    185 *      Input (Variable),
    186 *    End Collection,
    187 *    Collection (Logical),
    188 *      Report Size (8),
    189 *      Report Count (4),
    190 *      Physical Maximum (255),
    191 *      Logical Maximum (255),
    192 *      Usage (02h),
    193 *      Output (Variable),
    194 *    End Collection,
    195 *  End Collection
    196 */
    197
    198/* Size of the original descriptor of the PID 0x0011 joystick */
    199#define PID0011_RDESC_ORIG_SIZE	101
    200
    201/* Fixed report descriptor for PID 0x011 joystick */
    202static __u8 pid0011_rdesc_fixed[] = {
    203	0x05, 0x01,         /*  Usage Page (Desktop),           */
    204	0x09, 0x04,         /*  Usage (Joystick),               */
    205	0xA1, 0x01,         /*  Collection (Application),       */
    206	0xA1, 0x02,         /*      Collection (Logical),       */
    207	0x14,               /*          Logical Minimum (0),    */
    208	0x75, 0x08,         /*          Report Size (8),        */
    209	0x95, 0x03,         /*          Report Count (3),       */
    210	0x81, 0x01,         /*          Input (Constant),       */
    211	0x26, 0xFF, 0x00,   /*          Logical Maximum (255),  */
    212	0x95, 0x02,         /*          Report Count (2),       */
    213	0x09, 0x30,         /*          Usage (X),              */
    214	0x09, 0x31,         /*          Usage (Y),              */
    215	0x81, 0x02,         /*          Input (Variable),       */
    216	0x75, 0x01,         /*          Report Size (1),        */
    217	0x95, 0x04,         /*          Report Count (4),       */
    218	0x81, 0x01,         /*          Input (Constant),       */
    219	0x25, 0x01,         /*          Logical Maximum (1),    */
    220	0x95, 0x0A,         /*          Report Count (10),      */
    221	0x05, 0x09,         /*          Usage Page (Button),    */
    222	0x19, 0x01,         /*          Usage Minimum (01h),    */
    223	0x29, 0x0A,         /*          Usage Maximum (0Ah),    */
    224	0x81, 0x02,         /*          Input (Variable),       */
    225	0x95, 0x0A,         /*          Report Count (10),      */
    226	0x81, 0x01,         /*          Input (Constant),       */
    227	0xC0,               /*      End Collection,             */
    228	0xC0                /*  End Collection                  */
    229};
    230
    231static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
    232				unsigned int *rsize)
    233{
    234	switch (hdev->product) {
    235	case 0x0011:
    236		if (*rsize == PID0011_RDESC_ORIG_SIZE) {
    237			rdesc = pid0011_rdesc_fixed;
    238			*rsize = sizeof(pid0011_rdesc_fixed);
    239		}
    240		break;
    241	}
    242	return rdesc;
    243}
    244
    245#define map_abs(c)      hid_map_usage(hi, usage, bit, max, EV_ABS, (c))
    246#define map_rel(c)      hid_map_usage(hi, usage, bit, max, EV_REL, (c))
    247
    248static int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
    249			    struct hid_field *field, struct hid_usage *usage,
    250			    unsigned long **bit, int *max)
    251{
    252	switch (usage->hid) {
    253	/*
    254	 * revert to the old hid-input behavior where axes
    255	 * can be randomly assigned when hid->usage is reused.
    256	 */
    257	case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
    258	case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
    259		if (field->flags & HID_MAIN_ITEM_RELATIVE)
    260			map_rel(usage->hid & 0xf);
    261		else
    262			map_abs(usage->hid & 0xf);
    263		return 1;
    264	}
    265
    266	return 0;
    267}
    268
    269static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
    270{
    271	int ret;
    272
    273	dev_dbg(&hdev->dev, "DragonRise Inc. HID hardware probe...");
    274
    275	ret = hid_parse(hdev);
    276	if (ret) {
    277		hid_err(hdev, "parse failed\n");
    278		goto err;
    279	}
    280
    281	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
    282	if (ret) {
    283		hid_err(hdev, "hw start failed\n");
    284		goto err;
    285	}
    286
    287	switch (hdev->product) {
    288	case 0x0006:
    289		ret = drff_init(hdev);
    290		if (ret) {
    291			dev_err(&hdev->dev, "force feedback init failed\n");
    292			hid_hw_stop(hdev);
    293			goto err;
    294		}
    295		break;
    296	}
    297
    298	return 0;
    299err:
    300	return ret;
    301}
    302
    303static const struct hid_device_id dr_devices[] = {
    304	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
    305	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011),  },
    306	{ }
    307};
    308MODULE_DEVICE_TABLE(hid, dr_devices);
    309
    310static struct hid_driver dr_driver = {
    311	.name = "dragonrise",
    312	.id_table = dr_devices,
    313	.report_fixup = dr_report_fixup,
    314	.probe = dr_probe,
    315	.input_mapping = dr_input_mapping,
    316};
    317module_hid_driver(dr_driver);
    318
    319MODULE_LICENSE("GPL");