xref: /linux/drivers/hid/hid-lg4ff.c (revision 95e9fd10f06cb5642028b6b851e32b8c8afb4571)
1 /*
2  *  Force feedback support for Logitech Gaming Wheels
3  *
4  *  Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
5  *  Speed Force Wireless (WiiWheel)
6  *
7  *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>
8  */
9 
10 /*
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  */
25 
26 
27 #include <linux/input.h>
28 #include <linux/usb.h>
29 #include <linux/hid.h>
30 
31 #include "usbhid/usbhid.h"
32 #include "hid-lg.h"
33 #include "hid-ids.h"
34 
35 #define DFGT_REV_MAJ 0x13
36 #define DFGT_REV_MIN 0x22
37 #define DFP_REV_MAJ 0x11
38 #define DFP_REV_MIN 0x06
39 #define FFEX_REV_MAJ 0x21
40 #define FFEX_REV_MIN 0x00
41 #define G25_REV_MAJ 0x12
42 #define G25_REV_MIN 0x22
43 #define G27_REV_MAJ 0x12
44 #define G27_REV_MIN 0x38
45 
46 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
47 
48 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
49 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
50 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf);
51 static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
52 
53 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
54 
55 struct lg4ff_device_entry {
56 	__u16 range;
57 	__u16 min_range;
58 	__u16 max_range;
59 #ifdef CONFIG_LEDS_CLASS
60 	__u8  led_state;
61 	struct led_classdev *led[5];
62 #endif
63 	struct list_head list;
64 	void (*set_range)(struct hid_device *hid, u16 range);
65 };
66 
67 static const signed short lg4ff_wheel_effects[] = {
68 	FF_CONSTANT,
69 	FF_AUTOCENTER,
70 	-1
71 };
72 
73 struct lg4ff_wheel {
74 	const __u32 product_id;
75 	const signed short *ff_effects;
76 	const __u16 min_range;
77 	const __u16 max_range;
78 	void (*set_range)(struct hid_device *hid, u16 range);
79 };
80 
81 static const struct lg4ff_wheel lg4ff_devices[] = {
82 	{USB_DEVICE_ID_LOGITECH_WHEEL,       lg4ff_wheel_effects, 40, 270, NULL},
83 	{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, NULL},
84 	{USB_DEVICE_ID_LOGITECH_DFP_WHEEL,   lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_dfp},
85 	{USB_DEVICE_ID_LOGITECH_G25_WHEEL,   lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
86 	{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,  lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
87 	{USB_DEVICE_ID_LOGITECH_G27_WHEEL,   lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
88 	{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
89 	{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
90 };
91 
92 struct lg4ff_native_cmd {
93 	const __u8 cmd_num;	/* Number of commands to send */
94 	const __u8 cmd[];
95 };
96 
97 struct lg4ff_usb_revision {
98 	const __u16 rev_maj;
99 	const __u16 rev_min;
100 	const struct lg4ff_native_cmd *command;
101 };
102 
103 static const struct lg4ff_native_cmd native_dfp = {
104 	1,
105 	{0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
106 };
107 
108 static const struct lg4ff_native_cmd native_dfgt = {
109 	2,
110 	{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 1st command */
111 	 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}	/* 2nd command */
112 };
113 
114 static const struct lg4ff_native_cmd native_g25 = {
115 	1,
116 	{0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
117 };
118 
119 static const struct lg4ff_native_cmd native_g27 = {
120 	2,
121 	{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 1st command */
122 	 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}	/* 2nd command */
123 };
124 
125 static const struct lg4ff_usb_revision lg4ff_revs[] = {
126 	{DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt},	/* Driving Force GT */
127 	{DFP_REV_MAJ,  DFP_REV_MIN,  &native_dfp},	/* Driving Force Pro */
128 	{G25_REV_MAJ,  G25_REV_MIN,  &native_g25},	/* G25 */
129 	{G27_REV_MAJ,  G27_REV_MIN,  &native_g27},	/* G27 */
130 };
131 
132 static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
133 {
134 	struct hid_device *hid = input_get_drvdata(dev);
135 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
136 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
137 	int x;
138 
139 #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
140 
141 	switch (effect->type) {
142 	case FF_CONSTANT:
143 		x = effect->u.ramp.start_level + 0x80;	/* 0x80 is no force */
144 		CLAMP(x);
145 		report->field[0]->value[0] = 0x11;	/* Slot 1 */
146 		report->field[0]->value[1] = 0x08;
147 		report->field[0]->value[2] = x;
148 		report->field[0]->value[3] = 0x80;
149 		report->field[0]->value[4] = 0x00;
150 		report->field[0]->value[5] = 0x00;
151 		report->field[0]->value[6] = 0x00;
152 
153 		usbhid_submit_report(hid, report, USB_DIR_OUT);
154 		break;
155 	}
156 	return 0;
157 }
158 
159 /* Sends default autocentering command compatible with
160  * all wheels except Formula Force EX */
161 static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
162 {
163 	struct hid_device *hid = input_get_drvdata(dev);
164 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
165 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
166 
167 	report->field[0]->value[0] = 0xfe;
168 	report->field[0]->value[1] = 0x0d;
169 	report->field[0]->value[2] = magnitude >> 13;
170 	report->field[0]->value[3] = magnitude >> 13;
171 	report->field[0]->value[4] = magnitude >> 8;
172 	report->field[0]->value[5] = 0x00;
173 	report->field[0]->value[6] = 0x00;
174 
175 	usbhid_submit_report(hid, report, USB_DIR_OUT);
176 }
177 
178 /* Sends autocentering command compatible with Formula Force EX */
179 static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
180 {
181 	struct hid_device *hid = input_get_drvdata(dev);
182 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
183 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
184 	magnitude = magnitude * 90 / 65535;
185 
186 
187 	report->field[0]->value[0] = 0xfe;
188 	report->field[0]->value[1] = 0x03;
189 	report->field[0]->value[2] = magnitude >> 14;
190 	report->field[0]->value[3] = magnitude >> 14;
191 	report->field[0]->value[4] = magnitude;
192 	report->field[0]->value[5] = 0x00;
193 	report->field[0]->value[6] = 0x00;
194 
195 	usbhid_submit_report(hid, report, USB_DIR_OUT);
196 }
197 
198 /* Sends command to set range compatible with G25/G27/Driving Force GT */
199 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
200 {
201 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
202 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
203 	dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
204 
205 	report->field[0]->value[0] = 0xf8;
206 	report->field[0]->value[1] = 0x81;
207 	report->field[0]->value[2] = range & 0x00ff;
208 	report->field[0]->value[3] = (range & 0xff00) >> 8;
209 	report->field[0]->value[4] = 0x00;
210 	report->field[0]->value[5] = 0x00;
211 	report->field[0]->value[6] = 0x00;
212 
213 	usbhid_submit_report(hid, report, USB_DIR_OUT);
214 }
215 
216 /* Sends commands to set range compatible with Driving Force Pro wheel */
217 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
218 {
219 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
220 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
221 	int start_left, start_right, full_range;
222 	dbg_hid("Driving Force Pro: setting range to %u\n", range);
223 
224 	/* Prepare "coarse" limit command */
225 	report->field[0]->value[0] = 0xf8;
226 	report->field[0]->value[1] = 0x00; 	/* Set later */
227 	report->field[0]->value[2] = 0x00;
228 	report->field[0]->value[3] = 0x00;
229 	report->field[0]->value[4] = 0x00;
230 	report->field[0]->value[5] = 0x00;
231 	report->field[0]->value[6] = 0x00;
232 
233 	if (range > 200) {
234 		report->field[0]->value[1] = 0x03;
235 		full_range = 900;
236 	} else {
237 		report->field[0]->value[1] = 0x02;
238 		full_range = 200;
239 	}
240 	usbhid_submit_report(hid, report, USB_DIR_OUT);
241 
242 	/* Prepare "fine" limit command */
243 	report->field[0]->value[0] = 0x81;
244 	report->field[0]->value[1] = 0x0b;
245 	report->field[0]->value[2] = 0x00;
246 	report->field[0]->value[3] = 0x00;
247 	report->field[0]->value[4] = 0x00;
248 	report->field[0]->value[5] = 0x00;
249 	report->field[0]->value[6] = 0x00;
250 
251 	if (range == 200 || range == 900) {	/* Do not apply any fine limit */
252 		usbhid_submit_report(hid, report, USB_DIR_OUT);
253 		return;
254 	}
255 
256 	/* Construct fine limit command */
257 	start_left = (((full_range - range + 1) * 2047) / full_range);
258 	start_right = 0xfff - start_left;
259 
260 	report->field[0]->value[2] = start_left >> 4;
261 	report->field[0]->value[3] = start_right >> 4;
262 	report->field[0]->value[4] = 0xff;
263 	report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
264 	report->field[0]->value[6] = 0xff;
265 
266 	usbhid_submit_report(hid, report, USB_DIR_OUT);
267 }
268 
269 static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
270 {
271 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
272 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
273 	__u8 i, j;
274 
275 	j = 0;
276 	while (j < 7*cmd->cmd_num) {
277 		for (i = 0; i < 7; i++)
278 			report->field[0]->value[i] = cmd->cmd[j++];
279 
280 		usbhid_submit_report(hid, report, USB_DIR_OUT);
281 	}
282 }
283 
284 /* Read current range and display it in terminal */
285 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
286 {
287 	struct hid_device *hid = to_hid_device(dev);
288 	struct lg4ff_device_entry *entry;
289 	struct lg_drv_data *drv_data;
290 	size_t count;
291 
292 	drv_data = hid_get_drvdata(hid);
293 	if (!drv_data) {
294 		hid_err(hid, "Private driver data not found!\n");
295 		return 0;
296 	}
297 
298 	entry = drv_data->device_props;
299 	if (!entry) {
300 		hid_err(hid, "Device properties not found!\n");
301 		return 0;
302 	}
303 
304 	count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range);
305 	return count;
306 }
307 
308 /* Set range to user specified value, call appropriate function
309  * according to the type of the wheel */
310 static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
311 {
312 	struct hid_device *hid = to_hid_device(dev);
313 	struct lg4ff_device_entry *entry;
314 	struct lg_drv_data *drv_data;
315 	__u16 range = simple_strtoul(buf, NULL, 10);
316 
317 	drv_data = hid_get_drvdata(hid);
318 	if (!drv_data) {
319 		hid_err(hid, "Private driver data not found!\n");
320 		return 0;
321 	}
322 
323 	entry = drv_data->device_props;
324 	if (!entry) {
325 		hid_err(hid, "Device properties not found!\n");
326 		return 0;
327 	}
328 
329 	if (range == 0)
330 		range = entry->max_range;
331 
332 	/* Check if the wheel supports range setting
333 	 * and that the range is within limits for the wheel */
334 	if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) {
335 		entry->set_range(hid, range);
336 		entry->range = range;
337 	}
338 
339 	return count;
340 }
341 
342 #ifdef CONFIG_LEDS_CLASS
343 static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
344 {
345 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
346 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
347 
348 	report->field[0]->value[0] = 0xf8;
349 	report->field[0]->value[1] = 0x12;
350 	report->field[0]->value[2] = leds;
351 	report->field[0]->value[3] = 0x00;
352 	report->field[0]->value[4] = 0x00;
353 	report->field[0]->value[5] = 0x00;
354 	report->field[0]->value[6] = 0x00;
355 	usbhid_submit_report(hid, report, USB_DIR_OUT);
356 }
357 
358 static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
359 			enum led_brightness value)
360 {
361 	struct device *dev = led_cdev->dev->parent;
362 	struct hid_device *hid = container_of(dev, struct hid_device, dev);
363 	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
364 	struct lg4ff_device_entry *entry;
365 	int i, state = 0;
366 
367 	if (!drv_data) {
368 		hid_err(hid, "Device data not found.");
369 		return;
370 	}
371 
372 	entry = (struct lg4ff_device_entry *)drv_data->device_props;
373 
374 	if (!entry) {
375 		hid_err(hid, "Device properties not found.");
376 		return;
377 	}
378 
379 	for (i = 0; i < 5; i++) {
380 		if (led_cdev != entry->led[i])
381 			continue;
382 		state = (entry->led_state >> i) & 1;
383 		if (value == LED_OFF && state) {
384 			entry->led_state &= ~(1 << i);
385 			lg4ff_set_leds(hid, entry->led_state);
386 		} else if (value != LED_OFF && !state) {
387 			entry->led_state |= 1 << i;
388 			lg4ff_set_leds(hid, entry->led_state);
389 		}
390 		break;
391 	}
392 }
393 
394 static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
395 {
396 	struct device *dev = led_cdev->dev->parent;
397 	struct hid_device *hid = container_of(dev, struct hid_device, dev);
398 	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
399 	struct lg4ff_device_entry *entry;
400 	int i, value = 0;
401 
402 	if (!drv_data) {
403 		hid_err(hid, "Device data not found.");
404 		return LED_OFF;
405 	}
406 
407 	entry = (struct lg4ff_device_entry *)drv_data->device_props;
408 
409 	if (!entry) {
410 		hid_err(hid, "Device properties not found.");
411 		return LED_OFF;
412 	}
413 
414 	for (i = 0; i < 5; i++)
415 		if (led_cdev == entry->led[i]) {
416 			value = (entry->led_state >> i) & 1;
417 			break;
418 		}
419 
420 	return value ? LED_FULL : LED_OFF;
421 }
422 #endif
423 
424 int lg4ff_init(struct hid_device *hid)
425 {
426 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
427 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
428 	struct input_dev *dev = hidinput->input;
429 	struct hid_report *report;
430 	struct hid_field *field;
431 	struct lg4ff_device_entry *entry;
432 	struct lg_drv_data *drv_data;
433 	struct usb_device_descriptor *udesc;
434 	int error, i, j;
435 	__u16 bcdDevice, rev_maj, rev_min;
436 
437 	/* Find the report to use */
438 	if (list_empty(report_list)) {
439 		hid_err(hid, "No output report found\n");
440 		return -1;
441 	}
442 
443 	/* Check that the report looks ok */
444 	report = list_entry(report_list->next, struct hid_report, list);
445 	if (!report) {
446 		hid_err(hid, "NULL output report\n");
447 		return -1;
448 	}
449 
450 	field = report->field[0];
451 	if (!field) {
452 		hid_err(hid, "NULL field\n");
453 		return -1;
454 	}
455 
456 	/* Check what wheel has been connected */
457 	for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
458 		if (hid->product == lg4ff_devices[i].product_id) {
459 			dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
460 			break;
461 		}
462 	}
463 
464 	if (i == ARRAY_SIZE(lg4ff_devices)) {
465 		hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
466 			     "LKML, Simon Wood <simon@mungewell.org> or Michal Maly <madcatxster@gmail.com>\n");
467 		return -1;
468 	}
469 
470 	/* Attempt to switch wheel to native mode when applicable */
471 	udesc = &(hid_to_usb_dev(hid)->descriptor);
472 	if (!udesc) {
473 		hid_err(hid, "NULL USB device descriptor\n");
474 		return -1;
475 	}
476 	bcdDevice = le16_to_cpu(udesc->bcdDevice);
477 	rev_maj = bcdDevice >> 8;
478 	rev_min = bcdDevice & 0xff;
479 
480 	if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_WHEEL) {
481 		dbg_hid("Generic wheel detected, can it do native?\n");
482 		dbg_hid("USB revision: %2x.%02x\n", rev_maj, rev_min);
483 
484 		for (j = 0; j < ARRAY_SIZE(lg4ff_revs); j++) {
485 			if (lg4ff_revs[j].rev_maj == rev_maj && lg4ff_revs[j].rev_min == rev_min) {
486 				hid_lg4ff_switch_native(hid, lg4ff_revs[j].command);
487 				hid_info(hid, "Switched to native mode\n");
488 			}
489 		}
490 	}
491 
492 	/* Set supported force feedback capabilities */
493 	for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
494 		set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
495 
496 	error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
497 
498 	if (error)
499 		return error;
500 
501 	/* Check if autocentering is available and
502 	 * set the centering force to zero by default */
503 	if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
504 		if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN)	/* Formula Force EX expects different autocentering command */
505 			dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
506 		else
507 			dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
508 
509 		dev->ff->set_autocenter(dev, 0);
510 	}
511 
512 	/* Get private driver data */
513 	drv_data = hid_get_drvdata(hid);
514 	if (!drv_data) {
515 		hid_err(hid, "Cannot add device, private driver data not allocated\n");
516 		return -1;
517 	}
518 
519 	/* Initialize device properties */
520 	entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
521 	if (!entry) {
522 		hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
523 		return -ENOMEM;
524 	}
525 	drv_data->device_props = entry;
526 
527 	entry->min_range = lg4ff_devices[i].min_range;
528 	entry->max_range = lg4ff_devices[i].max_range;
529 	entry->set_range = lg4ff_devices[i].set_range;
530 
531 	/* Create sysfs interface */
532 	error = device_create_file(&hid->dev, &dev_attr_range);
533 	if (error)
534 		return error;
535 	dbg_hid("sysfs interface created\n");
536 
537 	/* Set the maximum range to start with */
538 	entry->range = entry->max_range;
539 	if (entry->set_range != NULL)
540 		entry->set_range(hid, entry->range);
541 
542 #ifdef CONFIG_LEDS_CLASS
543 	/* register led subsystem - G27 only */
544 	entry->led_state = 0;
545 	for (j = 0; j < 5; j++)
546 		entry->led[j] = NULL;
547 
548 	if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
549 		struct led_classdev *led;
550 		size_t name_sz;
551 		char *name;
552 
553 		lg4ff_set_leds(hid, 0);
554 
555 		name_sz = strlen(dev_name(&hid->dev)) + 8;
556 
557 		for (j = 0; j < 5; j++) {
558 			led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
559 			if (!led) {
560 				hid_err(hid, "can't allocate memory for LED %d\n", j);
561 				goto err;
562 			}
563 
564 			name = (void *)(&led[1]);
565 			snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
566 			led->name = name;
567 			led->brightness = 0;
568 			led->max_brightness = 1;
569 			led->brightness_get = lg4ff_led_get_brightness;
570 			led->brightness_set = lg4ff_led_set_brightness;
571 
572 			entry->led[j] = led;
573 			error = led_classdev_register(&hid->dev, led);
574 
575 			if (error) {
576 				hid_err(hid, "failed to register LED %d. Aborting.\n", j);
577 err:
578 				/* Deregister LEDs (if any) */
579 				for (j = 0; j < 5; j++) {
580 					led = entry->led[j];
581 					entry->led[j] = NULL;
582 					if (!led)
583 						continue;
584 					led_classdev_unregister(led);
585 					kfree(led);
586 				}
587 				goto out;	/* Let the driver continue without LEDs */
588 			}
589 		}
590 	}
591 out:
592 #endif
593 	hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
594 	return 0;
595 }
596 
597 int lg4ff_deinit(struct hid_device *hid)
598 {
599 	struct lg4ff_device_entry *entry;
600 	struct lg_drv_data *drv_data;
601 
602 	device_remove_file(&hid->dev, &dev_attr_range);
603 
604 	drv_data = hid_get_drvdata(hid);
605 	if (!drv_data) {
606 		hid_err(hid, "Error while deinitializing device, no private driver data.\n");
607 		return -1;
608 	}
609 	entry = drv_data->device_props;
610 	if (!entry) {
611 		hid_err(hid, "Error while deinitializing device, no device properties data.\n");
612 		return -1;
613 	}
614 
615 #ifdef CONFIG_LEDS_CLASS
616 	{
617 		int j;
618 		struct led_classdev *led;
619 
620 		/* Deregister LEDs (if any) */
621 		for (j = 0; j < 5; j++) {
622 
623 			led = entry->led[j];
624 			entry->led[j] = NULL;
625 			if (!led)
626 				continue;
627 			led_classdev_unregister(led);
628 			kfree(led);
629 		}
630 	}
631 #endif
632 
633 	/* Deallocate memory */
634 	kfree(entry);
635 
636 	dbg_hid("Device successfully unregistered\n");
637 	return 0;
638 }
639