diff --git a/hid-lg4ff.c b/hid-lg4ff.c index 4e92dd6..7a7a8fe 100644 --- a/hid-lg4ff.c +++ b/hid-lg4ff.c @@ -28,6 +28,9 @@ #define LG4FF_MMODE_SWITCHED 1 #define LG4FF_MMODE_NOT_MULTIMODE 2 +/* Device does not have a working 'friction' effect, play a 'damper' instead */ +#define LG4FF_FLAG_FAKEFRICTION 1 + #define LG4FF_MODE_NATIVE_IDX 0 #define LG4FF_MODE_DFEX_IDX 1 #define LG4FF_MODE_DFP_IDX 2 @@ -146,6 +149,7 @@ struct lg4ff_wheel_data { const char * const real_tag; const char * const real_name; const u16 real_product_id; + const u16 flags; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -192,6 +196,7 @@ struct lg4ff_wheel { const signed short *ff_effects; const u16 min_range; const u16 max_range; + const u16 flags; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -227,18 +232,30 @@ static void lg4ff_set_leds(struct hid_device *hid, u8 leds); #endif static const struct lg4ff_wheel lg4ff_devices[] = { - {USB_DEVICE_ID_LOGITECH_WINGMAN_FG, no_wheel_effects, 40, 180, NULL}, - {USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, lg4ff_wheel_effects, 40, 180, NULL}, - {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_dfp}, - {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_G29_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_G923_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} + {USB_DEVICE_ID_LOGITECH_WINGMAN_FG, + no_wheel_effects, 40, 180, 0, NULL}, + {USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, + lg4ff_wheel_effects, 40, 180, 0, NULL}, + {USB_DEVICE_ID_LOGITECH_WHEEL, + lg4ff_wheel_effects, 40, 270, 0, NULL}, + {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, + lg4ff_wheel_effects, 40, 270, 0, NULL}, + {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, + lg4ff_wheel_effects, 40, 900, 0, lg4ff_set_range_dfp}, + {USB_DEVICE_ID_LOGITECH_G25_WHEEL, + lg4ff_wheel_effects, 40, 900, 0, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, + lg4ff_wheel_effects, 40, 900, 0, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G27_WHEEL, + lg4ff_wheel_effects, 40, 900, 0, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G29_WHEEL, + lg4ff_wheel_effects, 40, 900, 0, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G923_WHEEL, + lg4ff_wheel_effects, 40, 900, LG4FF_FLAG_FAKEFRICTION, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, + lg4ff_wheel_effects, 40, 270, 0, NULL}, + {USB_DEVICE_ID_LOGITECH_WII_WHEEL, + lg4ff_wheel_effects, 40, 270, 0, NULL} }; static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = { @@ -495,7 +512,8 @@ static void lg4ff_send_cmd(struct lg4ff_device_entry *entry, u8 *cmd) DEBUG("send_cmd: %02X %02X %02X %02X %02X %02X %02X", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); } -static void lg4ff_update_slot(struct lg4ff_slot *slot, struct lg4ff_effect_parameters *parameters) +static void lg4ff_update_slot(struct lg4ff_device_entry *entry, + struct lg4ff_slot *slot, struct lg4ff_effect_parameters *parameters) { u8 original_cmd[7]; int d1; @@ -584,12 +602,21 @@ static void lg4ff_update_slot(struct lg4ff_slot *slot, struct lg4ff_effect_param case FF_FRICTION: s1 = parameters->k1 < 0; s2 = parameters->k2 < 0; - slot->current_cmd[1] = 0x0e; - slot->current_cmd[2] = SCALE_COEFF(parameters->k1, 8); - slot->current_cmd[3] = SCALE_COEFF(parameters->k2, 8); - slot->current_cmd[4] = SCALE_VALUE_U16(parameters->clip, 8); - slot->current_cmd[5] = (s2 << 4) + s1; - slot->current_cmd[6] = 0; + if (entry->wdata.flags & LG4FF_FLAG_FAKEFRICTION) { + slot->current_cmd[1] = 0x0c; + slot->current_cmd[2] = SCALE_COEFF(parameters->k1, 4); + slot->current_cmd[3] = s1; + slot->current_cmd[4] = SCALE_COEFF(parameters->k2, 4); + slot->current_cmd[5] = s2; + slot->current_cmd[6] = SCALE_VALUE_U16(parameters->clip, 8); + } else { + slot->current_cmd[1] = 0x0e; + slot->current_cmd[2] = SCALE_COEFF(parameters->k1, 8); + slot->current_cmd[3] = SCALE_COEFF(parameters->k2, 8); + slot->current_cmd[4] = SCALE_VALUE_U16(parameters->clip, 8); + slot->current_cmd[5] = (s2 << 4) + s1; + slot->current_cmd[6] = 0; + } break; } } @@ -890,7 +917,7 @@ static __always_inline int lg4ff_timer(struct lg4ff_device_entry *entry) for (i = 0; i < 4; i++) { slot = &entry->slots[i]; - lg4ff_update_slot(slot, ¶meters[i]); + lg4ff_update_slot(entry, slot, ¶meters[i]); if (slot->is_updated) { lg4ff_send_cmd(entry, slot->current_cmd); slot->is_updated = 0; @@ -987,7 +1014,7 @@ static void lg4ff_init_slots(struct lg4ff_device_entry *entry) for (i = 0; i < 4; i++) { entry->slots[i].id = i; - lg4ff_update_slot(&entry->slots[i], ¶meters); + lg4ff_update_slot(entry, &entry->slots[i], ¶meters); lg4ff_send_cmd(entry, entry->slots[i].current_cmd); entry->slots[i].is_updated = 0; } @@ -1226,7 +1253,8 @@ static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const s .set_range = wheel->set_range, .alternate_modes = alternate_modes, .real_tag = real_tag, - .real_name = real_name }; + .real_name = real_name, + .flags = wheel->flags }; memcpy(wdata, &t_wdata, sizeof(t_wdata)); }