Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fake friction effect using damper effect #107

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 50 additions & 17 deletions hid-lg4ff.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#define LG4FF_MMODE_SWITCHED 1
#define LG4FF_MMODE_NOT_MULTIMODE 2

/* Device has a "friction" effect in firmware */
#define LG4FF_CAP_FRICTION 1

#define LG4FF_MODE_NATIVE_IDX 0
#define LG4FF_MODE_DFEX_IDX 1
#define LG4FF_MODE_DFP_IDX 2
Expand Down Expand Up @@ -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 capabilities;

void (*set_range)(struct hid_device *hid, u16 range);
};
Expand Down Expand Up @@ -192,6 +196,7 @@ struct lg4ff_wheel {
const signed short *ff_effects;
const u16 min_range;
const u16 max_range;
const u16 capabilities;
void (*set_range)(struct hid_device *hid, u16 range);
};

Expand Down Expand Up @@ -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, LG4FF_CAP_FRICTION, lg4ff_set_range_dfp},
{USB_DEVICE_ID_LOGITECH_G25_WHEEL,
lg4ff_wheel_effects, 40, 900, LG4FF_CAP_FRICTION, lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,
lg4ff_wheel_effects, 40, 900, LG4FF_CAP_FRICTION, lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_G27_WHEEL,
lg4ff_wheel_effects, 40, 900, LG4FF_CAP_FRICTION, 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, 0, 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[] = {
Expand Down Expand Up @@ -436,6 +453,11 @@ static int friction_level = 30;
module_param(friction_level, int, 0);
MODULE_PARM_DESC(friction_level, "Level of friction force (0-100).");

static int always_fake_friction = 0;
module_param(always_fake_friction, int, 0);
MODULE_PARM_DESC(always_fake_friction, "Play FF_FRICTION as a damper hardware effect, "
"even for wheels that do have a friction hardware effect");

static struct lg4ff_device_entry *lg4ff_get_device_entry(struct hid_device *hid)
{
struct lg_drv_data *drv_data;
Expand All @@ -459,7 +481,7 @@ static struct lg4ff_device_entry *lg4ff_get_device_entry(struct hid_device *hid)
return entry;
}

void lg4ff_send_cmd_with_id(struct lg4ff_device_entry *entry, u8 *cmd, u8 id) {
static void lg4ff_send_cmd_with_id(struct lg4ff_device_entry *entry, u8 *cmd, u8 id) {
unsigned long flags;
s32 *value = entry->report->field[0]->value;

Expand All @@ -477,7 +499,7 @@ void lg4ff_send_cmd_with_id(struct lg4ff_device_entry *entry, u8 *cmd, u8 id) {
DEBUG("send_cmd: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
}

void lg4ff_send_cmd(struct lg4ff_device_entry *entry, u8 *cmd)
static void lg4ff_send_cmd(struct lg4ff_device_entry *entry, u8 *cmd)
{
unsigned long flags;
s32 *value = entry->report->field[0]->value;
Expand All @@ -495,7 +517,7 @@ 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]);
}

void lg4ff_update_slot(struct lg4ff_slot *slot, struct lg4ff_effect_parameters *parameters)
static void lg4ff_update_slot(struct lg4ff_slot *slot, struct lg4ff_effect_parameters *parameters)
{
u8 original_cmd[7];
int d1;
Expand Down Expand Up @@ -877,6 +899,17 @@ static __always_inline int lg4ff_timer(struct lg4ff_device_entry *entry)
parameters[2].clip = parameters[2].clip * damper_level / 100;
parameters[3].clip = parameters[3].clip * friction_level / 100;

/* Send "friction" input to the "damper" slot if device only has "damper".
* The Windows driver does cast "friction" and "inertia" effect types to "damper".
* This is not physically plausible, but we are working with toy-strength
* wheels that won't let you feel more than "big value = wheel stuck" */
if (!(entry->wdata.capabilities & LG4FF_CAP_FRICTION) || always_fake_friction) {
if (parameters[2].clip == 0) {
memcpy(&parameters[2], &parameters[3], sizeof(parameters[3]));
}
memset(&parameters[3], 0, sizeof(parameters[3]));
}

ffb_level = abs(parameters[0].level);
for (i = 1; i < 4; i++) {
parameters[i].k1 = (long)parameters[i].k1 * gain / 0xffff;
Expand Down Expand Up @@ -984,7 +1017,6 @@ static void lg4ff_init_slots(struct lg4ff_device_entry *entry)
entry->slots[1].effect_type = FF_SPRING;
entry->slots[2].effect_type = FF_DAMPER;
entry->slots[3].effect_type = FF_FRICTION;

for (i = 0; i < 4; i++) {
entry->slots[i].id = i;
lg4ff_update_slot(&entry->slots[i], &parameters);
Expand Down Expand Up @@ -1226,7 +1258,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,
.capabilities = wheel->capabilities };

memcpy(wdata, &t_wdata, sizeof(t_wdata));
}
Expand Down