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