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