xref: /OK3568_Linux_fs/kernel/drivers/hid/hid-lg2ff.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Force feedback support for Logitech RumblePad and Rumblepad 2
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/input.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/hid.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "hid-lg.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun struct lg2ff_device {
19*4882a593Smuzhiyun 	struct hid_report *report;
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun 
play_effect(struct input_dev * dev,void * data,struct ff_effect * effect)22*4882a593Smuzhiyun static int play_effect(struct input_dev *dev, void *data,
23*4882a593Smuzhiyun 			 struct ff_effect *effect)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	struct hid_device *hid = input_get_drvdata(dev);
26*4882a593Smuzhiyun 	struct lg2ff_device *lg2ff = data;
27*4882a593Smuzhiyun 	int weak, strong;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	strong = effect->u.rumble.strong_magnitude;
30*4882a593Smuzhiyun 	weak = effect->u.rumble.weak_magnitude;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (weak || strong) {
33*4882a593Smuzhiyun 		weak = weak * 0xff / 0xffff;
34*4882a593Smuzhiyun 		strong = strong * 0xff / 0xffff;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[0] = 0x51;
37*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[2] = weak;
38*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[4] = strong;
39*4882a593Smuzhiyun 	} else {
40*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[0] = 0xf3;
41*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[2] = 0x00;
42*4882a593Smuzhiyun 		lg2ff->report->field[0]->value[4] = 0x00;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
46*4882a593Smuzhiyun 	return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
lg2ff_init(struct hid_device * hid)49*4882a593Smuzhiyun int lg2ff_init(struct hid_device *hid)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct lg2ff_device *lg2ff;
52*4882a593Smuzhiyun 	struct hid_report *report;
53*4882a593Smuzhiyun 	struct hid_input *hidinput;
54*4882a593Smuzhiyun 	struct input_dev *dev;
55*4882a593Smuzhiyun 	int error;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	if (list_empty(&hid->inputs)) {
58*4882a593Smuzhiyun 		hid_err(hid, "no inputs found\n");
59*4882a593Smuzhiyun 		return -ENODEV;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
62*4882a593Smuzhiyun 	dev = hidinput->input;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	/* Check that the report looks ok */
65*4882a593Smuzhiyun 	report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
66*4882a593Smuzhiyun 	if (!report)
67*4882a593Smuzhiyun 		return -ENODEV;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
70*4882a593Smuzhiyun 	if (!lg2ff)
71*4882a593Smuzhiyun 		return -ENOMEM;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	set_bit(FF_RUMBLE, dev->ffbit);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	error = input_ff_create_memless(dev, lg2ff, play_effect);
76*4882a593Smuzhiyun 	if (error) {
77*4882a593Smuzhiyun 		kfree(lg2ff);
78*4882a593Smuzhiyun 		return error;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	lg2ff->report = report;
82*4882a593Smuzhiyun 	report->field[0]->value[0] = 0xf3;
83*4882a593Smuzhiyun 	report->field[0]->value[1] = 0x00;
84*4882a593Smuzhiyun 	report->field[0]->value[2] = 0x00;
85*4882a593Smuzhiyun 	report->field[0]->value[3] = 0x00;
86*4882a593Smuzhiyun 	report->field[0]->value[4] = 0x00;
87*4882a593Smuzhiyun 	report->field[0]->value[5] = 0x00;
88*4882a593Smuzhiyun 	report->field[0]->value[6] = 0x00;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	hid_hw_request(hid, report, HID_REQ_SET_REPORT);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	hid_info(hid, "Force feedback for Logitech variant 2 rumble devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	return 0;
95*4882a593Smuzhiyun }
96