162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Force feedback support for DragonRise Inc. game controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * From what I have gathered, these devices are mass produced in China and are
662306a36Sopenharmony_ci * distributed under several vendors. They often share the same design as
762306a36Sopenharmony_ci * the original PlayStation DualShock controller.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * 0079:0006 "DragonRise Inc.   Generic   USB  Joystick  "
1062306a36Sopenharmony_ci *  - tested with a Tesun USB-703 game controller.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Copyright (c) 2009 Richard Walmsley <richwalm@gmail.com>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/input.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/hid.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "hid-ids.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifdef CONFIG_DRAGONRISE_FF
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct drff_device {
2862306a36Sopenharmony_ci	struct hid_report *report;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int drff_play(struct input_dev *dev, void *data,
3262306a36Sopenharmony_ci				 struct ff_effect *effect)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct hid_device *hid = input_get_drvdata(dev);
3562306a36Sopenharmony_ci	struct drff_device *drff = data;
3662306a36Sopenharmony_ci	int strong, weak;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	strong = effect->u.rumble.strong_magnitude;
3962306a36Sopenharmony_ci	weak = effect->u.rumble.weak_magnitude;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	dbg_hid("called with 0x%04x 0x%04x", strong, weak);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (strong || weak) {
4462306a36Sopenharmony_ci		strong = strong * 0xff / 0xffff;
4562306a36Sopenharmony_ci		weak = weak * 0xff / 0xffff;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		/* While reverse engineering this device, I found that when
4862306a36Sopenharmony_ci		   this value is set, it causes the strong rumble to function
4962306a36Sopenharmony_ci		   at a near maximum speed, so we'll bypass it. */
5062306a36Sopenharmony_ci		if (weak == 0x0a)
5162306a36Sopenharmony_ci			weak = 0x0b;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		drff->report->field[0]->value[0] = 0x51;
5462306a36Sopenharmony_ci		drff->report->field[0]->value[1] = 0x00;
5562306a36Sopenharmony_ci		drff->report->field[0]->value[2] = weak;
5662306a36Sopenharmony_ci		drff->report->field[0]->value[4] = strong;
5762306a36Sopenharmony_ci		hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		drff->report->field[0]->value[0] = 0xfa;
6062306a36Sopenharmony_ci		drff->report->field[0]->value[1] = 0xfe;
6162306a36Sopenharmony_ci	} else {
6262306a36Sopenharmony_ci		drff->report->field[0]->value[0] = 0xf3;
6362306a36Sopenharmony_ci		drff->report->field[0]->value[1] = 0x00;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	drff->report->field[0]->value[2] = 0x00;
6762306a36Sopenharmony_ci	drff->report->field[0]->value[4] = 0x00;
6862306a36Sopenharmony_ci	dbg_hid("running with 0x%02x 0x%02x", strong, weak);
6962306a36Sopenharmony_ci	hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return 0;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int drff_init(struct hid_device *hid)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct drff_device *drff;
7762306a36Sopenharmony_ci	struct hid_report *report;
7862306a36Sopenharmony_ci	struct hid_input *hidinput;
7962306a36Sopenharmony_ci	struct list_head *report_list =
8062306a36Sopenharmony_ci			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
8162306a36Sopenharmony_ci	struct input_dev *dev;
8262306a36Sopenharmony_ci	int error;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (list_empty(&hid->inputs)) {
8562306a36Sopenharmony_ci		hid_err(hid, "no inputs found\n");
8662306a36Sopenharmony_ci		return -ENODEV;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
8962306a36Sopenharmony_ci	dev = hidinput->input;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (list_empty(report_list)) {
9262306a36Sopenharmony_ci		hid_err(hid, "no output reports found\n");
9362306a36Sopenharmony_ci		return -ENODEV;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	report = list_first_entry(report_list, struct hid_report, list);
9762306a36Sopenharmony_ci	if (report->maxfield < 1) {
9862306a36Sopenharmony_ci		hid_err(hid, "no fields in the report\n");
9962306a36Sopenharmony_ci		return -ENODEV;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (report->field[0]->report_count < 7) {
10362306a36Sopenharmony_ci		hid_err(hid, "not enough values in the field\n");
10462306a36Sopenharmony_ci		return -ENODEV;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	drff = kzalloc(sizeof(struct drff_device), GFP_KERNEL);
10862306a36Sopenharmony_ci	if (!drff)
10962306a36Sopenharmony_ci		return -ENOMEM;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	set_bit(FF_RUMBLE, dev->ffbit);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	error = input_ff_create_memless(dev, drff, drff_play);
11462306a36Sopenharmony_ci	if (error) {
11562306a36Sopenharmony_ci		kfree(drff);
11662306a36Sopenharmony_ci		return error;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	drff->report = report;
12062306a36Sopenharmony_ci	drff->report->field[0]->value[0] = 0xf3;
12162306a36Sopenharmony_ci	drff->report->field[0]->value[1] = 0x00;
12262306a36Sopenharmony_ci	drff->report->field[0]->value[2] = 0x00;
12362306a36Sopenharmony_ci	drff->report->field[0]->value[3] = 0x00;
12462306a36Sopenharmony_ci	drff->report->field[0]->value[4] = 0x00;
12562306a36Sopenharmony_ci	drff->report->field[0]->value[5] = 0x00;
12662306a36Sopenharmony_ci	drff->report->field[0]->value[6] = 0x00;
12762306a36Sopenharmony_ci	hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	hid_info(hid, "Force Feedback for DragonRise Inc. "
13062306a36Sopenharmony_ci		 "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci#else
13562306a36Sopenharmony_cistatic inline int drff_init(struct hid_device *hid)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * The original descriptor of joystick with PID 0x0011, represented by DVTech PC
14362306a36Sopenharmony_ci * JS19. It seems both copied from another device and a result of confusion
14462306a36Sopenharmony_ci * either about the specification or about the program used to create the
14562306a36Sopenharmony_ci * descriptor. In any case, it's a wonder it works on Windows.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci *  Usage Page (Desktop),             ; Generic desktop controls (01h)
14862306a36Sopenharmony_ci *  Usage (Joystick),                 ; Joystick (04h, application collection)
14962306a36Sopenharmony_ci *  Collection (Application),
15062306a36Sopenharmony_ci *    Collection (Logical),
15162306a36Sopenharmony_ci *      Report Size (8),
15262306a36Sopenharmony_ci *      Report Count (5),
15362306a36Sopenharmony_ci *      Logical Minimum (0),
15462306a36Sopenharmony_ci *      Logical Maximum (255),
15562306a36Sopenharmony_ci *      Physical Minimum (0),
15662306a36Sopenharmony_ci *      Physical Maximum (255),
15762306a36Sopenharmony_ci *      Usage (X),                    ; X (30h, dynamic value)
15862306a36Sopenharmony_ci *      Usage (X),                    ; X (30h, dynamic value)
15962306a36Sopenharmony_ci *      Usage (X),                    ; X (30h, dynamic value)
16062306a36Sopenharmony_ci *      Usage (X),                    ; X (30h, dynamic value)
16162306a36Sopenharmony_ci *      Usage (Y),                    ; Y (31h, dynamic value)
16262306a36Sopenharmony_ci *      Input (Variable),
16362306a36Sopenharmony_ci *      Report Size (4),
16462306a36Sopenharmony_ci *      Report Count (1),
16562306a36Sopenharmony_ci *      Logical Maximum (7),
16662306a36Sopenharmony_ci *      Physical Maximum (315),
16762306a36Sopenharmony_ci *      Unit (Degrees),
16862306a36Sopenharmony_ci *      Usage (00h),
16962306a36Sopenharmony_ci *      Input (Variable, Null State),
17062306a36Sopenharmony_ci *      Unit,
17162306a36Sopenharmony_ci *      Report Size (1),
17262306a36Sopenharmony_ci *      Report Count (10),
17362306a36Sopenharmony_ci *      Logical Maximum (1),
17462306a36Sopenharmony_ci *      Physical Maximum (1),
17562306a36Sopenharmony_ci *      Usage Page (Button),          ; Button (09h)
17662306a36Sopenharmony_ci *      Usage Minimum (01h),
17762306a36Sopenharmony_ci *      Usage Maximum (0Ah),
17862306a36Sopenharmony_ci *      Input (Variable),
17962306a36Sopenharmony_ci *      Usage Page (FF00h),           ; FF00h, vendor-defined
18062306a36Sopenharmony_ci *      Report Size (1),
18162306a36Sopenharmony_ci *      Report Count (10),
18262306a36Sopenharmony_ci *      Logical Maximum (1),
18362306a36Sopenharmony_ci *      Physical Maximum (1),
18462306a36Sopenharmony_ci *      Usage (01h),
18562306a36Sopenharmony_ci *      Input (Variable),
18662306a36Sopenharmony_ci *    End Collection,
18762306a36Sopenharmony_ci *    Collection (Logical),
18862306a36Sopenharmony_ci *      Report Size (8),
18962306a36Sopenharmony_ci *      Report Count (4),
19062306a36Sopenharmony_ci *      Physical Maximum (255),
19162306a36Sopenharmony_ci *      Logical Maximum (255),
19262306a36Sopenharmony_ci *      Usage (02h),
19362306a36Sopenharmony_ci *      Output (Variable),
19462306a36Sopenharmony_ci *    End Collection,
19562306a36Sopenharmony_ci *  End Collection
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* Size of the original descriptor of the PID 0x0011 joystick */
19962306a36Sopenharmony_ci#define PID0011_RDESC_ORIG_SIZE	101
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Fixed report descriptor for PID 0x011 joystick */
20262306a36Sopenharmony_cistatic __u8 pid0011_rdesc_fixed[] = {
20362306a36Sopenharmony_ci	0x05, 0x01,         /*  Usage Page (Desktop),           */
20462306a36Sopenharmony_ci	0x09, 0x04,         /*  Usage (Joystick),               */
20562306a36Sopenharmony_ci	0xA1, 0x01,         /*  Collection (Application),       */
20662306a36Sopenharmony_ci	0xA1, 0x02,         /*      Collection (Logical),       */
20762306a36Sopenharmony_ci	0x14,               /*          Logical Minimum (0),    */
20862306a36Sopenharmony_ci	0x75, 0x08,         /*          Report Size (8),        */
20962306a36Sopenharmony_ci	0x95, 0x03,         /*          Report Count (3),       */
21062306a36Sopenharmony_ci	0x81, 0x01,         /*          Input (Constant),       */
21162306a36Sopenharmony_ci	0x26, 0xFF, 0x00,   /*          Logical Maximum (255),  */
21262306a36Sopenharmony_ci	0x95, 0x02,         /*          Report Count (2),       */
21362306a36Sopenharmony_ci	0x09, 0x30,         /*          Usage (X),              */
21462306a36Sopenharmony_ci	0x09, 0x31,         /*          Usage (Y),              */
21562306a36Sopenharmony_ci	0x81, 0x02,         /*          Input (Variable),       */
21662306a36Sopenharmony_ci	0x75, 0x01,         /*          Report Size (1),        */
21762306a36Sopenharmony_ci	0x95, 0x04,         /*          Report Count (4),       */
21862306a36Sopenharmony_ci	0x81, 0x01,         /*          Input (Constant),       */
21962306a36Sopenharmony_ci	0x25, 0x01,         /*          Logical Maximum (1),    */
22062306a36Sopenharmony_ci	0x95, 0x0A,         /*          Report Count (10),      */
22162306a36Sopenharmony_ci	0x05, 0x09,         /*          Usage Page (Button),    */
22262306a36Sopenharmony_ci	0x19, 0x01,         /*          Usage Minimum (01h),    */
22362306a36Sopenharmony_ci	0x29, 0x0A,         /*          Usage Maximum (0Ah),    */
22462306a36Sopenharmony_ci	0x81, 0x02,         /*          Input (Variable),       */
22562306a36Sopenharmony_ci	0x95, 0x0A,         /*          Report Count (10),      */
22662306a36Sopenharmony_ci	0x81, 0x01,         /*          Input (Constant),       */
22762306a36Sopenharmony_ci	0xC0,               /*      End Collection,             */
22862306a36Sopenharmony_ci	0xC0                /*  End Collection                  */
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
23262306a36Sopenharmony_ci				unsigned int *rsize)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	switch (hdev->product) {
23562306a36Sopenharmony_ci	case 0x0011:
23662306a36Sopenharmony_ci		if (*rsize == PID0011_RDESC_ORIG_SIZE) {
23762306a36Sopenharmony_ci			rdesc = pid0011_rdesc_fixed;
23862306a36Sopenharmony_ci			*rsize = sizeof(pid0011_rdesc_fixed);
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci		break;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci	return rdesc;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#define map_abs(c)      hid_map_usage(hi, usage, bit, max, EV_ABS, (c))
24662306a36Sopenharmony_ci#define map_rel(c)      hid_map_usage(hi, usage, bit, max, EV_REL, (c))
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
24962306a36Sopenharmony_ci			    struct hid_field *field, struct hid_usage *usage,
25062306a36Sopenharmony_ci			    unsigned long **bit, int *max)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	switch (usage->hid) {
25362306a36Sopenharmony_ci	/*
25462306a36Sopenharmony_ci	 * revert to the old hid-input behavior where axes
25562306a36Sopenharmony_ci	 * can be randomly assigned when hid->usage is reused.
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
25862306a36Sopenharmony_ci	case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
25962306a36Sopenharmony_ci		if (field->flags & HID_MAIN_ITEM_RELATIVE)
26062306a36Sopenharmony_ci			map_rel(usage->hid & 0xf);
26162306a36Sopenharmony_ci		else
26262306a36Sopenharmony_ci			map_abs(usage->hid & 0xf);
26362306a36Sopenharmony_ci		return 1;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	int ret;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	dev_dbg(&hdev->dev, "DragonRise Inc. HID hardware probe...");
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ret = hid_parse(hdev);
27662306a36Sopenharmony_ci	if (ret) {
27762306a36Sopenharmony_ci		hid_err(hdev, "parse failed\n");
27862306a36Sopenharmony_ci		goto err;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
28262306a36Sopenharmony_ci	if (ret) {
28362306a36Sopenharmony_ci		hid_err(hdev, "hw start failed\n");
28462306a36Sopenharmony_ci		goto err;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	switch (hdev->product) {
28862306a36Sopenharmony_ci	case 0x0006:
28962306a36Sopenharmony_ci		ret = drff_init(hdev);
29062306a36Sopenharmony_ci		if (ret) {
29162306a36Sopenharmony_ci			dev_err(&hdev->dev, "force feedback init failed\n");
29262306a36Sopenharmony_ci			hid_hw_stop(hdev);
29362306a36Sopenharmony_ci			goto err;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_cierr:
30062306a36Sopenharmony_ci	return ret;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic const struct hid_device_id dr_devices[] = {
30462306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
30562306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011),  },
30662306a36Sopenharmony_ci	{ }
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, dr_devices);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic struct hid_driver dr_driver = {
31162306a36Sopenharmony_ci	.name = "dragonrise",
31262306a36Sopenharmony_ci	.id_table = dr_devices,
31362306a36Sopenharmony_ci	.report_fixup = dr_report_fixup,
31462306a36Sopenharmony_ci	.probe = dr_probe,
31562306a36Sopenharmony_ci	.input_mapping = dr_input_mapping,
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_cimodule_hid_driver(dr_driver);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
320