static int zpff_init(struct hid_device *hid) { struct zpff_device *zpff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev = hidinput->input; int error; if (list_empty(report_list)) { hid_err(hid, "no output report found\n"); return -ENODEV; } report = list_entry(report_list->next, struct hid_report, list); if (report->maxfield < 4) { hid_err(hid, "not enough fields in report\n"); return -ENODEV; } zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); if (!zpff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, zpff, zpff_play); if (error) { kfree(zpff); return error; } zpff->report = report; zpff->report->field[0]->value[0] = 0x00; zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT); hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <*****@*****.**>\n"); return 0; }
static int axff_init(struct hid_device *hid) { struct axff_device *axff; struct hid_report *report; struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev = hidinput->input; int error; if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 4) { hid_err(hid, "no fields in the report: %d\n", report->maxfield); return -ENODEV; } axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL); if (!axff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, axff, axff_play); if (error) goto err_free_mem; axff->report = report; axff->report->field[0]->value[0] = 0x00; axff->report->field[1]->value[0] = 0x00; axff->report->field[2]->value[0] = 0x00; axff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, axff->report, USB_DIR_OUT); hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<*****@*****.**>\n"); return 0; err_free_mem: kfree(axff); return error; }
static __u8 *acer_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize){ /* Check that the descriptor size matches what we expect */ if (*rsize == ACER_KBD_RDESC_SIZE) { __u64 check = be64_to_cpu(*(__be64 *)(rdesc + ACER_KBD_RDESC_CHECK_POS)); /* check for invalid max usages */ if (check == ACER_KBD_RDESC_CHECK_DATA) { hid_info(hdev, "fixing up acer keyboard report descriptor\n"); /* change max values to 0xFF00 */ rdesc[ACER_KBD_RDESC_FIX_POS1] = 0x00; rdesc[ACER_KBD_RDESC_FIX_POS2] = 0x00; } } return rdesc; }
static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize, int offset, const char *device_name) { /* * the fixup that need to be done: * - change Usage Maximum in the Comsumer Control * (report ID 3) to a reasonable value */ if (*rsize >= offset + 31 && /* Usage Page (Consumer Devices) */ rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c && /* Usage (Consumer Control) */ rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 && /* Usage Maximum > 12287 */ rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) { hid_info(hdev, "fixing up %s report descriptor\n", device_name); rdesc[offset + 12] = 0x2f; } return rdesc; }
static void sixaxis_set_led_bt(struct hid_device *hdev) { /* set first LED on BT connection */ unsigned char led_data[] = { 0x01, /* rumble values */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* LED settings 0x02=LED1 .. 0x10=LED4 */ 0x02, 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 4 */ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 3 */ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 2 */ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED 1 */ 0x00, 0x00, 0x00, 0x00, 0x00 }; hid_info(hdev, "set LED BT\n"); hdev->hid_output_raw_report(hdev, led_data, sizeof(led_data), HID_OUTPUT_REPORT); }
static __u8 *acer_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { /* check for invalid descriptor */ if (*rsize == ACER_KBD_RDESC_ORIG_SIZE) { __u64 check = be64_to_cpu(*(__be64 *)(rdesc + ACER_KBD_RDESC_CHECK_POS)); /* check for invalid max usages and logical 0xFFFF (2^16) */ if (check == ACER_KBD_RDESC_CHECK_DATA) { hid_info(hdev, "fixing up acer keybaord report descriptor\n"); /* fix max values with 0xFF00 (2^8) */ rdesc[ACER_KBD_RDESC_FIX_POS1] = 0x00; rdesc[ACER_KBD_RDESC_FIX_POS2] = 0x00; } } return rdesc; }
static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { switch (hdev->product) { case USB_DEVICE_ID_KYE_ERGO_525V: if (*rsize >= 74 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && rdesc[71] == 0x75 && rdesc[72] == 0x08 && rdesc[73] == 0x95 && rdesc[74] == 0x01) { hid_info(hdev, "fixing up Kye/Genius Ergo Mouse " "report descriptor\n"); rdesc[62] = 0x09; rdesc[64] = 0x04; rdesc[66] = 0x07; rdesc[72] = 0x01; rdesc[74] = 0x08; } break; case USB_DEVICE_ID_KYE_EASYPEN_I405X: if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) { rdesc = easypen_i405x_rdesc_fixed; *rsize = sizeof(easypen_i405x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) { rdesc = mousepen_i608x_rdesc_fixed; *rsize = sizeof(mousepen_i608x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_EASYPEN_M610X: if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) { rdesc = easypen_m610x_rdesc_fixed; *rsize = sizeof(easypen_m610x_rdesc_fixed); } break; } return rdesc; }
/* * Microsoft Wireless Desktop Receiver (Model 1028) has * 'Usage Min/Max' where it ought to have 'Physical Min/Max' */ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); rdesc[557] = 0x35; rdesc[559] = 0x45; } /* the same as above (s/usage/physical/) */ if ((quirks & MS_RDESC_3K) && *rsize == 106 && rdesc[94] == 0x19 && rdesc[95] == 0x00 && rdesc[96] == 0x29 && rdesc[97] == 0xff) { rdesc[94] = 0x35; rdesc[96] = 0x45; } return rdesc; }
static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33 && rdesc[94] == 0x81 && rdesc[95] == 0x03 && rdesc[110] == 0x81 && rdesc[111] == 0x03) { hid_info(hdev, "Fixing up Saitek PS1000 report descriptor\n"); /* convert spurious axis to a "noop" Logical Minimum (0) */ rdesc[20] = 0x15; rdesc[21] = 0x00; /* clear constant bit on buttons and d-pad */ rdesc[95] = 0x02; rdesc[111] = 0x02; } return rdesc; }
static int px_raw_event(struct hid_device *hid, struct hid_report *report, u8 *data, int size) { int idx = size; switch (report->id) { case 0: /* keyboard input */ /* * Convert in-band modifier key values into out of band * modifier bits and pull the key strokes from the report. * Thus a report data set which looked like: * * [00][00][E0][30][00][00][00][00] * (no modifier bits + "Left Shift" key + "1" key) * * Would be converted to: * * [01][00][00][30][00][00][00][00] * (Left Shift modifier bit + "1" key) * * As long as it's in the size range, the upper level * drivers don't particularly care if there are in-band * 0-valued keys, so they don't stop parsing. */ while (--idx > 1) { if (data[idx] < 0xE0 || data[idx] > 0xE7) continue; data[0] |= (1 << (data[idx] - 0xE0)); data[idx] = 0; } hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0); return 1; default: /* unknown report */ /* Unknown report type; pass upstream */ hid_info(hid, "unknown report type %d\n", report->id); break; } return 0; }
int lg2ff_init(struct hid_device *hid) { struct lg2ff_device *lg2ff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; int error; /* Check that the report looks ok */ report = hid_validate_report(hid, HID_OUTPUT_REPORT, 0, 1, 7); if (!report) return -ENODEV; lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); if (!lg2ff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, lg2ff, play_effect); if (error) { kfree(lg2ff); return error; } lg2ff->report = report; report->field[0]->value[0] = 0xf3; report->field[0]->value[1] = 0x00; report->field[0]->value[2] = 0x00; report->field[0]->value[3] = 0x00; report->field[0]->value[4] = 0x00; report->field[0]->value[5] = 0x00; report->field[0]->value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <*****@*****.**>\n"); return 0; }
static int zpff_init(struct hid_device *hid) { struct zpff_device *zpff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; int i, error; for (i = 0; i < 4; i++) { report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); if (!report) return -ENODEV; } zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); if (!zpff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, zpff, zpff_play); if (error) { kfree(zpff); return error; } zpff->report = report; zpff->report->field[0]->value[0] = 0x00; zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <*****@*****.**>\n"); return 0; }
static int px_raw_event(struct hid_device *hid, struct hid_report *report, u8 *data, int size) { int idx = size; switch (report->id) { case 0: while (--idx > 1) { if (data[idx] < 0xE0 || data[idx] > 0xE7) continue; data[0] |= (1 << (data[idx] - 0xE0)); data[idx] = 0; } hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0); return 1; default: hid_info(hid, "unknown report type %d\n", report->id); break; } return 0; }
/* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends * the original value of 0x28c of logical maximum to 0x104d */ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct lg_drv_data *drv_data = hid_get_drvdata(hdev); if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { hid_info(hdev, "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { hid_info(hdev, "fixing up rel/abs in Logitech report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } switch (hdev->product) { case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: if (*rsize == FFG_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Wingman Formula Force GP report descriptor\n"); rdesc = ffg_rdesc_fixed; *rsize = sizeof(ffg_rdesc_fixed); } break; /* Several wheels report as this id when operating in emulation mode. */ case USB_DEVICE_ID_LOGITECH_WHEEL: if (*rsize == DF_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force report descriptor\n"); rdesc = df_rdesc_fixed; *rsize = sizeof(df_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: if (*rsize == MOMO_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Force (Red) report descriptor\n"); rdesc = momo_rdesc_fixed; *rsize = sizeof(momo_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: if (*rsize == MOMO2_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Racing Force (Black) report descriptor\n"); rdesc = momo2_rdesc_fixed; *rsize = sizeof(momo2_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL: if (*rsize == FV_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Formula Vibration report descriptor\n"); rdesc = fv_rdesc_fixed; *rsize = sizeof(fv_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: if (*rsize == DFP_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force Pro report descriptor\n"); rdesc = dfp_rdesc_fixed; *rsize = sizeof(dfp_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_WII_WHEEL: if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B && rdesc[47] == 0x05 && rdesc[48] == 0x09) { hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n"); rdesc[41] = 0x05; rdesc[42] = 0x09; rdesc[47] = 0x95; rdesc[48] = 0x0B; } break; } return rdesc; }
static int valve_sc_init_device(struct valve_sc_device *sc) { int ret; struct hid_device *hdev = sc->hdev; struct input_dev *input; u8 params[6]; u8 feature; u8 serial[64]; int serial_len; char *name, *uniq; int name_sz, uniq_sz; hid_info(hdev, "Initializing device.\n"); /* Retrieve controller serial */ serial[0] = 1; ret = valve_sc_send_request(sc, SC_FEATURE_GET_SERIAL, serial, 21, serial, &serial_len); if (ret < 0 || serial_len < 1 || serial_len > 62) { hid_warn(hdev, "Error while get controller serial: %d\n", -ret); serial[1] = '\0'; } else { serial[serial_len] = '\0'; } /* Set mouse mode for right pad */ params[0] = SC_SETTINGS_AUTOMOUSE; if (sc->automouse) params[1] = SC_SETTINGS_AUTOMOUSE_ON; else params[1] = SC_SETTINGS_AUTOMOUSE_OFF; params[2] = 0; params[3] = SC_SETTINGS_ORIENTATION; params[4] = sc->orientation; params[5] = 0; ret = valve_sc_send_request(sc, SC_FEATURE_SETTINGS, params, 6, NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while disabling mouse: %d\n", -ret); /* Disable buttons acting as keys */ if (sc->autobuttons) feature = SC_FEATURE_ENABLE_AUTO_BUTTONS; else feature = SC_FEATURE_DISABLE_AUTO_BUTTONS; ret = valve_sc_send_request(sc, feature, NULL, 0, NULL, NULL); if (ret < 0) hid_warn(hdev, "Error while setting auto buttons: %d\n", -ret); /* Create input device */ input = input_allocate_device(); if (!input) { hid_err(hdev, "Failed to allocate input device.\n"); return -ENOMEM; } sc->input = input; input->dev.parent = &hdev->dev; input->id.bustype = hdev->bus; input->id.vendor = hdev->vendor; input->id.product = hdev->product; input->id.version = hdev->version; name_sz = strlen(hdev->name) + 1; name = devm_kzalloc(&input->dev, name_sz, GFP_KERNEL); strncpy(name, hdev->name, name_sz); input->name = name; uniq_sz = serial_len + 1; uniq = devm_kzalloc(&input->dev, uniq_sz, GFP_KERNEL); strncpy(uniq, &serial[1], serial_len); uniq[serial_len] = '\0'; input->uniq = uniq; valve_sc_setup_input(input); ret = input_register_device(input); if (ret != 0) { hid_err(hdev, "Failed to register input device: %d.\n", -ret); input_free_device(input); sc->input = NULL; return ret; } return 0; }
static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { switch (hdev->product) { case USB_DEVICE_ID_KYE_ERGO_525V: /* the fixups that need to be done: * - change led usage page to button for extra buttons * - report size 8 count 1 must be size 1 count 8 for button * bitfield * - change the button usage range to 4-7 for the extra * buttons */ if (*rsize >= 75 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && rdesc[71] == 0x75 && rdesc[72] == 0x08 && rdesc[73] == 0x95 && rdesc[74] == 0x01) { hid_info(hdev, "fixing up Kye/Genius Ergo Mouse " "report descriptor\n"); rdesc[62] = 0x09; rdesc[64] = 0x04; rdesc[66] = 0x07; rdesc[72] = 0x01; rdesc[74] = 0x08; } break; case USB_DEVICE_ID_KYE_EASYPEN_I405X: if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) { rdesc = easypen_i405x_rdesc_fixed; *rsize = sizeof(easypen_i405x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) { rdesc = mousepen_i608x_rdesc_fixed; *rsize = sizeof(mousepen_i608x_rdesc_fixed); } break; case USB_DEVICE_ID_KYE_EASYPEN_M610X: if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) { rdesc = easypen_m610x_rdesc_fixed; *rsize = sizeof(easypen_m610x_rdesc_fixed); } break; case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, "Genius Gila Gaming Mouse"); break; case USB_DEVICE_ID_GENIUS_GX_IMPERATOR: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83, "Genius Gx Imperator Keyboard"); break; case USB_DEVICE_ID_GENIUS_MANTICORE: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, "Genius Manticore Keyboard"); break; } return rdesc; }
/* * There are several variants for 0419:0001: * * 1. 184 byte report descriptor * Vendor specific report #4 has a size of 48 bit, * and therefore is not accepted when inspecting the descriptors. * As a workaround we reinterpret the report as: * Variable type, count 6, size 8 bit, log. maximum 255 * The burden to reconstruct the data is moved into user space. * * 2. 203 byte report descriptor * Report #4 has an array field with logical range 0..18 instead of 1..15. * * 3. 135 byte report descriptor * Report #4 has an array field with logical range 0..17 instead of 1..14. * * 4. 171 byte report descriptor * Report #3 has an array field with logical range 0..1 instead of 1..3. */ static inline void samsung_irda_dev_trace(struct hid_device *hdev, unsigned int rsize) { hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n", rsize); }
/* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends * the original value of 0x28c of logical maximum to 0x104d */ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct lg_drv_data *drv_data = hid_get_drvdata(hdev); struct usb_device_descriptor *udesc; __u16 bcdDevice, rev_maj, rev_min; if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { hid_info(hdev, "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { hid_info(hdev, "fixing up rel/abs in Logitech report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } switch (hdev->product) { /* Several wheels report as this id when operating in emulation mode. */ case USB_DEVICE_ID_LOGITECH_WHEEL: udesc = &(hid_to_usb_dev(hdev)->descriptor); if (!udesc) { hid_err(hdev, "NULL USB device descriptor\n"); break; } bcdDevice = le16_to_cpu(udesc->bcdDevice); rev_maj = bcdDevice >> 8; rev_min = bcdDevice & 0xff; /* Update the report descriptor for only the Driving Force wheel */ if (rev_maj == 1 && rev_min == 2 && *rsize == DF_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force report descriptor\n"); rdesc = df_rdesc_fixed; *rsize = sizeof(df_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: if (*rsize == MOMO_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Force (Red) report descriptor\n"); rdesc = momo_rdesc_fixed; *rsize = sizeof(momo_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: if (*rsize == MOMO2_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Momo Racing Force (Black) report descriptor\n"); rdesc = momo2_rdesc_fixed; *rsize = sizeof(momo2_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL: if (*rsize == FV_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Formula Vibration report descriptor\n"); rdesc = fv_rdesc_fixed; *rsize = sizeof(fv_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: if (*rsize == DFP_RDESC_ORIG_SIZE) { hid_info(hdev, "fixing up Logitech Driving Force Pro report descriptor\n"); rdesc = dfp_rdesc_fixed; *rsize = sizeof(dfp_rdesc_fixed); } break; case USB_DEVICE_ID_LOGITECH_WII_WHEEL: if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B && rdesc[47] == 0x05 && rdesc[48] == 0x09) { hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n"); rdesc[41] = 0x05; rdesc[42] = 0x09; rdesc[47] = 0x95; rdesc[48] = 0x0B; } break; } return rdesc; }