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