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