• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Force feedback support for EMS Trio Linker Plus II
3  *
4  *  Copyright (c) 2010 Ignaz Forster <ignaz.forster@gmx.de>
5  */
6 
7 /*
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22 
23 
24 #include <linux/hid.h>
25 #include <linux/input.h>
26 #include <linux/module.h>
27 
28 #include "hid-ids.h"
29 
30 struct emsff_device {
31 	struct hid_report *report;
32 };
33 
emsff_play(struct input_dev * dev,void * data,struct ff_effect * effect)34 static int emsff_play(struct input_dev *dev, void *data,
35 			 struct ff_effect *effect)
36 {
37 	struct hid_device *hid = input_get_drvdata(dev);
38 	struct emsff_device *emsff = data;
39 	int weak, strong;
40 
41 	weak = effect->u.rumble.weak_magnitude;
42 	strong = effect->u.rumble.strong_magnitude;
43 
44 	dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
45 
46 	weak = weak * 0xff / 0xffff;
47 	strong = strong * 0xff / 0xffff;
48 
49 	emsff->report->field[0]->value[1] = weak;
50 	emsff->report->field[0]->value[2] = strong;
51 
52 	dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
53 	hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
54 
55 	return 0;
56 }
57 
emsff_init(struct hid_device * hid)58 static int emsff_init(struct hid_device *hid)
59 {
60 	struct emsff_device *emsff;
61 	struct hid_report *report;
62 	struct hid_input *hidinput;
63 	struct list_head *report_list =
64 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
65 	struct input_dev *dev;
66 	int error;
67 
68 	if (list_empty(&hid->inputs)) {
69 		hid_err(hid, "no inputs found\n");
70 		return -ENODEV;
71 	}
72 	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
73 	dev = hidinput->input;
74 
75 	if (list_empty(report_list)) {
76 		hid_err(hid, "no output reports found\n");
77 		return -ENODEV;
78 	}
79 
80 	report = list_first_entry(report_list, struct hid_report, list);
81 	if (report->maxfield < 1) {
82 		hid_err(hid, "no fields in the report\n");
83 		return -ENODEV;
84 	}
85 
86 	if (report->field[0]->report_count < 7) {
87 		hid_err(hid, "not enough values in the field\n");
88 		return -ENODEV;
89 	}
90 
91 	emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL);
92 	if (!emsff)
93 		return -ENOMEM;
94 
95 	set_bit(FF_RUMBLE, dev->ffbit);
96 
97 	error = input_ff_create_memless(dev, emsff, emsff_play);
98 	if (error) {
99 		kfree(emsff);
100 		return error;
101 	}
102 
103 	emsff->report = report;
104 	emsff->report->field[0]->value[0] = 0x01;
105 	emsff->report->field[0]->value[1] = 0x00;
106 	emsff->report->field[0]->value[2] = 0x00;
107 	emsff->report->field[0]->value[3] = 0x00;
108 	emsff->report->field[0]->value[4] = 0x00;
109 	emsff->report->field[0]->value[5] = 0x00;
110 	emsff->report->field[0]->value[6] = 0x00;
111 	hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
112 
113 	hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
114 
115 	return 0;
116 }
117 
ems_probe(struct hid_device * hdev,const struct hid_device_id * id)118 static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
119 {
120 	int ret;
121 
122 	ret = hid_parse(hdev);
123 	if (ret) {
124 		hid_err(hdev, "parse failed\n");
125 		goto err;
126 	}
127 
128 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
129 	if (ret) {
130 		hid_err(hdev, "hw start failed\n");
131 		goto err;
132 	}
133 
134 	ret = emsff_init(hdev);
135 	if (ret) {
136 		dev_err(&hdev->dev, "force feedback init failed\n");
137 		hid_hw_stop(hdev);
138 		goto err;
139 	}
140 
141 	return 0;
142 err:
143 	return ret;
144 }
145 
146 static const struct hid_device_id ems_devices[] = {
147 	{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
148 	{ }
149 };
150 MODULE_DEVICE_TABLE(hid, ems_devices);
151 
152 static struct hid_driver ems_driver = {
153 	.name = "hkems",
154 	.id_table = ems_devices,
155 	.probe = ems_probe,
156 };
157 module_hid_driver(ems_driver);
158 
159 MODULE_LICENSE("GPL");
160 
161