hid-lg4ff.c (b3e5ced63e051e8f911b795ac5b06229a5328f7b) | hid-lg4ff.c (2a552c30b2e44578b8d063e55b717ba94df84667) |
---|---|
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 */ --- 58 unchanged lines hidden (view full) --- 67 68#define LG4FF_FFEX_REV_MAJ 0x21 69#define LG4FF_FFEX_REV_MIN 0x00 70 71static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); 72static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); 73 74struct lg4ff_device_entry { | 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 */ --- 58 unchanged lines hidden (view full) --- 67 68#define LG4FF_FFEX_REV_MAJ 0x21 69#define LG4FF_FFEX_REV_MIN 0x00 70 71static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); 72static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); 73 74struct lg4ff_device_entry { |
75 __u32 product_id; 76 __u16 range; 77 __u16 min_range; 78 __u16 max_range; | 75 u32 product_id; 76 u16 range; 77 u16 min_range; 78 u16 max_range; |
79#ifdef CONFIG_LEDS_CLASS | 79#ifdef CONFIG_LEDS_CLASS |
80 __u8 led_state; | 80 u8 led_state; |
81 struct led_classdev *led[5]; 82#endif 83 u32 alternate_modes; 84 const char *real_tag; 85 const char *real_name; 86 u16 real_product_id; 87 struct list_head list; 88 void (*set_range)(struct hid_device *hid, u16 range); 89}; 90 91static const signed short lg4ff_wheel_effects[] = { 92 FF_CONSTANT, 93 FF_AUTOCENTER, 94 -1 95}; 96 97struct lg4ff_wheel { | 81 struct led_classdev *led[5]; 82#endif 83 u32 alternate_modes; 84 const char *real_tag; 85 const char *real_name; 86 u16 real_product_id; 87 struct list_head list; 88 void (*set_range)(struct hid_device *hid, u16 range); 89}; 90 91static const signed short lg4ff_wheel_effects[] = { 92 FF_CONSTANT, 93 FF_AUTOCENTER, 94 -1 95}; 96 97struct lg4ff_wheel { |
98 const __u32 product_id; | 98 const u32 product_id; |
99 const signed short *ff_effects; | 99 const signed short *ff_effects; |
100 const __u16 min_range; 101 const __u16 max_range; | 100 const u16 min_range; 101 const u16 max_range; |
102 void (*set_range)(struct hid_device *hid, u16 range); 103}; 104 105struct lg4ff_compat_mode_switch { | 102 void (*set_range)(struct hid_device *hid, u16 range); 103}; 104 105struct lg4ff_compat_mode_switch { |
106 const __u8 cmd_count; /* Number of commands to send */ 107 const __u8 cmd[]; | 106 const u8 cmd_count; /* Number of commands to send */ 107 const u8 cmd[]; |
108}; 109 110struct lg4ff_wheel_ident_info { 111 const u16 mask; 112 const u16 result; 113 const u16 real_product_id; 114}; 115 --- 124 unchanged lines hidden (view full) --- 240 241/* EXT_CMD16 - Understood by G25 and G27 */ 242static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = { 243 1, 244 {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} 245}; 246 247/* Recalculates X axis value accordingly to currently selected range */ | 108}; 109 110struct lg4ff_wheel_ident_info { 111 const u16 mask; 112 const u16 result; 113 const u16 real_product_id; 114}; 115 --- 124 unchanged lines hidden (view full) --- 240 241/* EXT_CMD16 - Understood by G25 and G27 */ 242static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = { 243 1, 244 {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} 245}; 246 247/* Recalculates X axis value accordingly to currently selected range */ |
248static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) | 248static s32 lg4ff_adjust_dfp_x_axis(s32 value, u16 range) |
249{ | 249{ |
250 __u16 max_range; 251 __s32 new_value; | 250 u16 max_range; 251 s32 new_value; |
252 253 if (range == 900) 254 return value; 255 else if (range == 200) 256 return value; 257 else if (range < 200) 258 max_range = 200; 259 else --- 4 unchanged lines hidden (view full) --- 264 return 0; 265 else if (new_value > 16383) 266 return 16383; 267 else 268 return new_value; 269} 270 271int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, | 252 253 if (range == 900) 254 return value; 255 else if (range == 200) 256 return value; 257 else if (range < 200) 258 max_range = 200; 259 else --- 4 unchanged lines hidden (view full) --- 264 return 0; 265 else if (new_value > 16383) 266 return 16383; 267 else 268 return new_value; 269} 270 271int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, |
272 struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) | 272 struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data) |
273{ 274 struct lg4ff_device_entry *entry = drv_data->device_props; | 273{ 274 struct lg4ff_device_entry *entry = drv_data->device_props; |
275 __s32 new_value = 0; | 275 s32 new_value = 0; |
276 277 if (!entry) { 278 hid_err(hid, "Device properties not found"); 279 return 0; 280 } 281 282 switch (entry->product_id) { 283 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: --- 10 unchanged lines hidden (view full) --- 294 } 295} 296 297static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) 298{ 299 struct hid_device *hid = input_get_drvdata(dev); 300 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 301 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 276 277 if (!entry) { 278 hid_err(hid, "Device properties not found"); 279 return 0; 280 } 281 282 switch (entry->product_id) { 283 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: --- 10 unchanged lines hidden (view full) --- 294 } 295} 296 297static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) 298{ 299 struct hid_device *hid = input_get_drvdata(dev); 300 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 301 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
302 __s32 *value = report->field[0]->value; | 302 s32 *value = report->field[0]->value; |
303 int x; 304 305#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) 306 307 switch (effect->type) { 308 case FF_CONSTANT: 309 x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ 310 CLAMP(x); --- 28 unchanged lines hidden (view full) --- 339 340/* Sends default autocentering command compatible with 341 * all wheels except Formula Force EX */ 342static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) 343{ 344 struct hid_device *hid = input_get_drvdata(dev); 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); | 303 int x; 304 305#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) 306 307 switch (effect->type) { 308 case FF_CONSTANT: 309 x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ 310 CLAMP(x); --- 28 unchanged lines hidden (view full) --- 339 340/* Sends default autocentering command compatible with 341 * all wheels except Formula Force EX */ 342static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) 343{ 344 struct hid_device *hid = input_get_drvdata(dev); 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 __s32 *value = report->field[0]->value; 348 __u32 expand_a, expand_b; | 347 s32 *value = report->field[0]->value; 348 u32 expand_a, expand_b; |
349 struct lg4ff_device_entry *entry; 350 struct lg_drv_data *drv_data; 351 352 drv_data = hid_get_drvdata(hid); 353 if (!drv_data) { 354 hid_err(hid, "Private driver data not found!\n"); 355 return; 356 } --- 59 unchanged lines hidden (view full) --- 416} 417 418/* Sends autocentering command compatible with Formula Force EX */ 419static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) 420{ 421 struct hid_device *hid = input_get_drvdata(dev); 422 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 423 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 349 struct lg4ff_device_entry *entry; 350 struct lg_drv_data *drv_data; 351 352 drv_data = hid_get_drvdata(hid); 353 if (!drv_data) { 354 hid_err(hid, "Private driver data not found!\n"); 355 return; 356 } --- 59 unchanged lines hidden (view full) --- 416} 417 418/* Sends autocentering command compatible with Formula Force EX */ 419static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) 420{ 421 struct hid_device *hid = input_get_drvdata(dev); 422 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 423 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
424 __s32 *value = report->field[0]->value; | 424 s32 *value = report->field[0]->value; |
425 magnitude = magnitude * 90 / 65535; 426 427 value[0] = 0xfe; 428 value[1] = 0x03; 429 value[2] = magnitude >> 14; 430 value[3] = magnitude >> 14; 431 value[4] = magnitude; 432 value[5] = 0x00; 433 value[6] = 0x00; 434 435 hid_hw_request(hid, report, HID_REQ_SET_REPORT); 436} 437 438/* Sends command to set range compatible with G25/G27/Driving Force GT */ 439static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) 440{ 441 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 442 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 425 magnitude = magnitude * 90 / 65535; 426 427 value[0] = 0xfe; 428 value[1] = 0x03; 429 value[2] = magnitude >> 14; 430 value[3] = magnitude >> 14; 431 value[4] = magnitude; 432 value[5] = 0x00; 433 value[6] = 0x00; 434 435 hid_hw_request(hid, report, HID_REQ_SET_REPORT); 436} 437 438/* Sends command to set range compatible with G25/G27/Driving Force GT */ 439static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) 440{ 441 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 442 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
443 __s32 *value = report->field[0]->value; | 443 s32 *value = report->field[0]->value; |
444 445 dbg_hid("G25/G27/DFGT: setting range to %u\n", range); 446 447 value[0] = 0xf8; 448 value[1] = 0x81; 449 value[2] = range & 0x00ff; 450 value[3] = (range & 0xff00) >> 8; 451 value[4] = 0x00; 452 value[5] = 0x00; 453 value[6] = 0x00; 454 455 hid_hw_request(hid, report, HID_REQ_SET_REPORT); 456} 457 458/* Sends commands to set range compatible with Driving Force Pro wheel */ | 444 445 dbg_hid("G25/G27/DFGT: setting range to %u\n", range); 446 447 value[0] = 0xf8; 448 value[1] = 0x81; 449 value[2] = range & 0x00ff; 450 value[3] = (range & 0xff00) >> 8; 451 value[4] = 0x00; 452 value[5] = 0x00; 453 value[6] = 0x00; 454 455 hid_hw_request(hid, report, HID_REQ_SET_REPORT); 456} 457 458/* Sends commands to set range compatible with Driving Force Pro wheel */ |
459static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) | 459static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range) |
460{ 461 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 462 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 463 int start_left, start_right, full_range; | 460{ 461 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 462 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 463 int start_left, start_right, full_range; |
464 __s32 *value = report->field[0]->value; | 464 s32 *value = report->field[0]->value; |
465 466 dbg_hid("Driving Force Pro: setting range to %u\n", range); 467 468 /* Prepare "coarse" limit command */ 469 value[0] = 0xf8; 470 value[1] = 0x00; /* Set later */ 471 value[2] = 0x00; 472 value[3] = 0x00; --- 93 unchanged lines hidden (view full) --- 566 return NULL; 567 } 568} 569 570static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s) 571{ 572 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 573 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 465 466 dbg_hid("Driving Force Pro: setting range to %u\n", range); 467 468 /* Prepare "coarse" limit command */ 469 value[0] = 0xf8; 470 value[1] = 0x00; /* Set later */ 471 value[2] = 0x00; 472 value[3] = 0x00; --- 93 unchanged lines hidden (view full) --- 566 return NULL; 567 } 568} 569 570static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s) 571{ 572 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 573 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
574 __s32 *value = report->field[0]->value; | 574 s32 *value = report->field[0]->value; |
575 u8 i; 576 577 for (i = 0; i < s->cmd_count; i++) { 578 u8 j; 579 580 for (j = 0; j < 7; j++) 581 value[j] = s->cmd[j + (7*i)]; 582 --- 166 unchanged lines hidden (view full) --- 749/* Set range to user specified value, call appropriate function 750 * according to the type of the wheel */ 751static ssize_t range_store(struct device *dev, struct device_attribute *attr, 752 const char *buf, size_t count) 753{ 754 struct hid_device *hid = to_hid_device(dev); 755 struct lg4ff_device_entry *entry; 756 struct lg_drv_data *drv_data; | 575 u8 i; 576 577 for (i = 0; i < s->cmd_count; i++) { 578 u8 j; 579 580 for (j = 0; j < 7; j++) 581 value[j] = s->cmd[j + (7*i)]; 582 --- 166 unchanged lines hidden (view full) --- 749/* Set range to user specified value, call appropriate function 750 * according to the type of the wheel */ 751static ssize_t range_store(struct device *dev, struct device_attribute *attr, 752 const char *buf, size_t count) 753{ 754 struct hid_device *hid = to_hid_device(dev); 755 struct lg4ff_device_entry *entry; 756 struct lg_drv_data *drv_data; |
757 __u16 range = simple_strtoul(buf, NULL, 10); | 757 u16 range = simple_strtoul(buf, NULL, 10); |
758 759 drv_data = hid_get_drvdata(hid); 760 if (!drv_data) { 761 hid_err(hid, "Private driver data not found!\n"); 762 return -EINVAL; 763 } 764 765 entry = drv_data->device_props; --- 47 unchanged lines hidden (view full) --- 813static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 814{ 815 /* Real ID is a read-only value */ 816 return -EPERM; 817} 818static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store); 819 820#ifdef CONFIG_LEDS_CLASS | 758 759 drv_data = hid_get_drvdata(hid); 760 if (!drv_data) { 761 hid_err(hid, "Private driver data not found!\n"); 762 return -EINVAL; 763 } 764 765 entry = drv_data->device_props; --- 47 unchanged lines hidden (view full) --- 813static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 814{ 815 /* Real ID is a read-only value */ 816 return -EPERM; 817} 818static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store); 819 820#ifdef CONFIG_LEDS_CLASS |
821static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) | 821static void lg4ff_set_leds(struct hid_device *hid, u8 leds) |
822{ 823 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 824 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 822{ 823 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 824 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
825 __s32 *value = report->field[0]->value; | 825 s32 *value = report->field[0]->value; |
826 827 value[0] = 0xf8; 828 value[1] = 0x12; 829 value[2] = leds; 830 value[3] = 0x00; 831 value[4] = 0x00; 832 value[5] = 0x00; 833 value[6] = 0x00; --- 378 unchanged lines hidden --- | 826 827 value[0] = 0xf8; 828 value[1] = 0x12; 829 value[2] = leds; 830 value[3] = 0x00; 831 value[4] = 0x00; 832 value[5] = 0x00; 833 value[6] = 0x00; --- 378 unchanged lines hidden --- |