diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/hid-tmff2.c | 69 | ||||
| -rw-r--r-- | src/hid-tmff2.h | 3 | ||||
| -rw-r--r-- | src/tmt248/hid-tmt248.c | 9 | ||||
| -rw-r--r-- | src/tmt300rs/hid-tmt300rs.c | 381 | ||||
| -rw-r--r-- | src/tmtsxw/hid-tmtsxw.c | 324 | ||||
| -rw-r--r-- | src/tmtx/hid-tmtx.c | 9 |
6 files changed, 608 insertions, 187 deletions
diff --git a/src/hid-tmff2.c b/src/hid-tmff2.c index ee4232a..3b51445 100644 --- a/src/hid-tmff2.c +++ b/src/hid-tmff2.c @@ -292,7 +292,7 @@ static void tmff2_work_handler(struct work_struct *w) struct tmff2_effect_state *state; int max_count = 0, effect_id; unsigned long time_now; - __u16 effect_length; + __u16 effect_delay, effect_length; if (!tmff2) @@ -304,17 +304,14 @@ static void tmff2_work_handler(struct work_struct *w) time_now = JIFFIES2MS(jiffies); state = &tmff2->states[effect_id]; + effect_delay = state->effect.replay.delay; effect_length = state->effect.replay.length; if (test_bit(FF_EFFECT_PLAYING, &state->flags) && effect_length) { - if ((time_now - state->start_time) >= effect_length) { + if ((time_now - state->start_time) >= (effect_delay + effect_length) * state->count) { __clear_bit(FF_EFFECT_PLAYING, &state->flags); __clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags); - if (state->count) - state->count--; - - if (state->count) - __set_bit(FF_EFFECT_QUEUE_START, &state->flags); + state->count = 0; } } @@ -359,6 +356,7 @@ static void tmff2_work_handler(struct work_struct *w) max_count = state->count; spin_unlock(&tmff2->lock); + /* wait for each effect update to actually be sent out to avoid * filling up usb output queue */ hid_hw_wait(tmff2->hdev); @@ -368,6 +366,32 @@ static void tmff2_work_handler(struct work_struct *w) schedule_delayed_work(&tmff2->work, msecs_to_jiffies(timer_msecs)); } +static void tmff2_rewrite_rumble(struct ff_effect *effect) +{ + /* this is more or less directly copied from + * https://elixir.bootlin.com/linux/latest/source/drivers/input/ff-core.c#L48 + * except we set the direction to east, to make sure the direction + * scaling doesn't do any funny business */ + int magnitude = 0; + if (effect->type != FF_RUMBLE) + return; + + magnitude = effect->u.rumble.strong_magnitude / 3 + + effect->u.rumble.weak_magnitude / 6; + + effect->type = FF_PERIODIC; + effect->direction = 16384; + effect->u.periodic.waveform = FF_SINE; + effect->u.periodic.period = 50; + effect->u.periodic.magnitude = magnitude; + effect->u.periodic.offset = 0; + effect->u.periodic.phase = 0; + effect->u.periodic.envelope.attack_length = 0; + effect->u.periodic.envelope.attack_level = 0; + effect->u.periodic.envelope.fade_length = 0; + effect->u.periodic.envelope.fade_level = 0; +} + static int tmff2_upload(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { @@ -385,10 +409,13 @@ static int tmff2_upload(struct input_dev *dev, spin_lock(&tmff2->lock); state->effect = *effect; + tmff2_rewrite_rumble(&state->effect); if (old) { - if (!test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) + if (!test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) { state->old = *old; + tmff2_rewrite_rumble(&state->old); + } __set_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags); } else { @@ -555,10 +582,22 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) for (i = 0; tmff2->supported_effects[i] >= 0; ++i) __set_bit(tmff2->supported_effects[i], tmff2->input_dev->ffbit); + /* tell ffb subsystem that we want to handle our own rumble effects, + * this is a (maybe kind of silly) workaround to the ffb subsystem + * setting the direction of rumble to 0, which in our case means 0 + * force. Instead, do exactly what the subsystem would do, but update + * the direction. + * + * It *might* be a good idea to change this in the subsystem proper, but + * I don't know if anyone relies on the rumble to be 0 degrees, consider + * this just a proof of concept for now */ + if (test_bit(FF_PERIODIC, tmff2->input_dev->ffbit)) + __set_bit(FF_RUMBLE, tmff2->input_dev->ffbit); + /* create actual ff device*/ if ((ret = input_ff_create(tmff2->input_dev, tmff2->max_effects))) { hid_err(tmff2->hdev, "could not create input_ff\n"); - goto err; + goto ff_err; } /* set ff callbacks */ @@ -589,12 +628,15 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) /* create files */ if ((ret = tmff2_create_files(tmff2))) - goto err; + goto file_err; tmff2->allow_scheduling = 1; return 0; +file_err: input_ff_destroy(tmff2->input_dev); +ff_err: + kfree(tmff2->states); err: return ret; } @@ -632,7 +674,10 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) if ((ret = tx_populate_api(tmff2))) goto wheel_err; break; - + case TSXW_ACTIVE: + if ((ret = tsxw_populate_api(tmff2))) + goto wheel_err; + break; default: ret = -ENODEV; goto wheel_err; @@ -727,6 +772,8 @@ static const struct hid_device_id tmff2_devices[] = { {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT248_PC_ID)}, /* tx */ {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TX_ACTIVE)}, + /* tsxw */ + {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TSXW_ACTIVE)}, {} }; diff --git a/src/hid-tmff2.h b/src/hid-tmff2.h index 1eb3546..666d249 100644 --- a/src/hid-tmff2.h +++ b/src/hid-tmff2.h @@ -102,6 +102,7 @@ struct tmff2_device_entry { int t300rs_populate_api(struct tmff2_device_entry *tmff2); int t248_populate_api(struct tmff2_device_entry *tmff2); int tx_populate_api(struct tmff2_device_entry *tmff2); +int tsxw_populate_api(struct tmff2_device_entry *tmff2); #define TMT300RS_PS3_NORM_ID 0xb66e #define TMT300RS_PS3_ADV_ID 0xb66f @@ -111,6 +112,8 @@ int tx_populate_api(struct tmff2_device_entry *tmff2); #define TX_ACTIVE 0xb669 +#define TSXW_ACTIVE 0xb692 + /* APIs to different wheel families */ /* T248 and TX at least uses the T300RS api, not sure if there are other wheels * but that's why these functions are given global linkage */ diff --git a/src/tmt248/hid-tmt248.c b/src/tmt248/hid-tmt248.c index af3aaa9..9ac43d9 100644 --- a/src/tmt248/hid-tmt248.c +++ b/src/tmt248/hid-tmt248.c @@ -163,7 +163,7 @@ err: return ret; } -int t248_wheel_destroy(void *data) +static int t248_wheel_destroy(void *data) { struct t300rs_device_entry *t300rs = data; @@ -175,7 +175,7 @@ int t248_wheel_destroy(void *data) return 0; } -int t248_set_range(void *data, uint16_t value) +static int t248_set_range(void *data, uint16_t value) { struct t300rs_device_entry *t248 = data; @@ -251,9 +251,10 @@ static int t248_close(void *data, int open_mode) return 0; } -int t248_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +static int t248_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) { - struct t300rs_device_entry *t248 = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); + struct t300rs_device_entry *t248 = kzalloc(sizeof(struct t300rs_device_entry), + GFP_KERNEL); struct list_head *report_list; int ret; diff --git a/src/tmt300rs/hid-tmt300rs.c b/src/tmt300rs/hid-tmt300rs.c index 0191620..40be801 100644 --- a/src/tmt300rs/hid-tmt300rs.c +++ b/src/tmt300rs/hid-tmt300rs.c @@ -330,19 +330,94 @@ static u8 t300rs_rdesc_ps4_fixed[] = { 0xc0, }; -static u8 spring_values[] = { - 0xa6, 0x6a, 0xa6, 0x6a, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xdf, 0x58, 0xa6, - 0x6a, 0x06 +static u8 condition_values[] = { + 0xfe, 0xff, 0xfe, 0xff, 0xfe, + 0xff, 0xfe, 0xff }; -static u8 damper_values[] = { - 0xfc, 0x7f, 0xfc, 0x7f, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xfc, 0x7f, 0xfc, - 0x7f, 0x07 -}; +static void t300rs_calculate_periodic_values(struct ff_effect *effect) +{ + struct ff_periodic_effect *periodic = &effect->u.periodic; + int16_t headroom; + + effect->replay.length -= 1; + + periodic->magnitude = (periodic->magnitude * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; + + if (periodic->magnitude < 0){ + /* the wheel handles positive magnitudes only */ + periodic->magnitude = -periodic->magnitude; + + /* to give the expected result 180 deg is added to the phase */ + periodic->phase = (periodic->phase + (0x10000 / 2)) % 0x10000; + } + + /* the interval [0; 32677[ is used by the wheel for the [0; 360[ degree phase shift */ + periodic->phase = periodic->phase * 32677 / 0x10000; + + headroom = 0x7fff - periodic->magnitude; + /* magnitude + offset cannot be outside the valid magnitude range, */ + /* otherwise the wheel behaves incorrectly */ + periodic->offset = clamp(periodic->offset, -headroom, headroom); +} + +static uint16_t t300rs_condition_max_saturation(uint16_t effect_type) +{ + if(effect_type == FF_SPRING) + return 0x6aa6; + + return 0x7ffc; +} + +static uint16_t t300rs_condition_effect_type(uint16_t effect_type) +{ + if(effect_type == FF_SPRING) + return 0x06; + + return 0x07; +} + +static int16_t t300rs_calculate_coefficient(int16_t coeff, uint16_t effect_type) +{ + uint8_t input_level; + + switch (effect_type) + { + case FF_SPRING: + input_level = spring_level; + break; + case FF_DAMPER: + input_level = damper_level; + break; + case FF_FRICTION: + input_level = friction_level; + break; + default: + input_level = 100; + break; + } + + return coeff * input_level / 100; +} + +static uint16_t t300rs_calculate_saturation(uint16_t sat, uint16_t effect_type) +{ + uint16_t max = t300rs_condition_max_saturation(effect_type); + + if(sat == 0) + return max; + + return sat * max / 0xffff; +} + +static void t300rs_calculate_deadband(int16_t *out_rband, int16_t *out_lband, + uint16_t deadband, int16_t offset) +{ + /* max deadband value is 0x7fff in either direction */ + /* deadband is the width of the deadzone, one direction is half of it */ + *out_rband = clamp(offset + (deadband / 2), -0x7fff, 0x7fff); + *out_lband = clamp(offset - (deadband / 2), -0x7fff, 0x7fff); +} int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) { @@ -383,14 +458,20 @@ int t300rs_play_effect(void *data, struct tmff2_effect_state *state) struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_play { struct t300rs_packet_header header; - uint8_t value; + uint8_t code; + uint16_t count; } *play_packet = (struct t300rs_packet_play *)t300rs->send_buffer; int ret; t300rs_fill_header(&play_packet->header, state->effect.id, 0x89); - play_packet->value = 0x01; + play_packet->code = 0x41; + + if (state->count == 0 || state->count >= 65535) + play_packet->count = 0; + else + play_packet->count = cpu_to_le16(state->count); ret = t300rs_send_int(t300rs); if (ret) @@ -630,6 +711,8 @@ static int t300rs_update_constant(struct t300rs_device_entry *t300rs, int16_t level; level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + /* the Windows driver uses the range [-16385;16381] */ + level = level / 2; if ((constant.level != constant_old.level) || (effect.direction != old.direction)) { @@ -738,114 +821,108 @@ error: return ret; } -static int t300rs_update_damper(struct t300rs_device_entry *t300rs, +static int t300rs_update_condition(struct t300rs_device_entry *t300rs, struct tmff2_effect_state *state) { struct ff_effect effect = state->effect; struct ff_effect old = state->old; - struct ff_condition_effect damper = effect.u.condition[0]; - struct ff_condition_effect damper_old = old.u.condition[0]; - struct __packed t300rs_packet_mod_damper { + struct ff_condition_effect cond = effect.u.condition[0]; + struct ff_condition_effect cond_old = old.u.condition[0]; + struct __packed t300rs_packet_mod_condition + { struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value0; - uint16_t value1; - } *packet_mod_damper = (struct t300rs_packet_mod_damper *)t300rs->send_buffer; - - int ret, input_level; - - input_level = damper_level; - if (state->effect.type == FF_FRICTION) - input_level = friction_level; + uint16_t right_coeff; + uint16_t left_coeff; + uint16_t right_deadband; + uint16_t left_deadband; + uint16_t right_saturation; + uint16_t left_saturation; + uint8_t effect_type; + uint8_t update_type; + uint16_t duration; + uint16_t delay; + } *packet_mod_condition = (struct t300rs_packet_mod_condition *)t300rs->send_buffer; - if (state->effect.type == FF_SPRING) - input_level = spring_level; + int ret = 0; + uint16_t duration, duration_old; + uint16_t right_sat, right_sat_old, left_sat, left_sat_old; + uint16_t right_coeff, right_coeff_old, left_coeff, left_coeff_old; + int16_t right_deadband, right_deadband_old, left_deadband, left_deadband_old; - if (damper.right_coeff != damper_old.right_coeff) { - int16_t coeff = damper.right_coeff * input_level / 100; + right_coeff = t300rs_calculate_coefficient(cond.right_coeff, effect.type); + right_coeff_old = t300rs_calculate_coefficient(cond_old.right_coeff, old.type); - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x41; - packet_mod_damper->value0 = cpu_to_le16(coeff); + left_coeff = t300rs_calculate_coefficient(cond.left_coeff, effect.type); + left_coeff_old = t300rs_calculate_coefficient(cond_old.left_coeff, old.type); - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper rc\n"); - goto error; - } + t300rs_calculate_deadband(&right_deadband, &left_deadband, + cond.deadband, cond.center); + t300rs_calculate_deadband(&right_deadband_old, &left_deadband_old, + cond_old.deadband, cond_old.center); - } + right_sat = t300rs_calculate_saturation(cond.right_saturation, effect.type); + right_sat_old = t300rs_calculate_saturation(cond_old.right_saturation, old.type); - if (damper.left_coeff != damper_old.left_coeff) { - int16_t coeff = damper.left_coeff * input_level / 100; + left_sat = t300rs_calculate_saturation(cond.left_saturation, effect.type); + left_sat_old = t300rs_calculate_saturation(cond_old.left_saturation, old.type); - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x42; - packet_mod_damper->value0 = cpu_to_le16(coeff); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper lc\n"); - goto error; - } - - } + duration = effect.replay.length - 1; + duration_old = old.replay.length - 1; - if ((damper.deadband != damper_old.deadband) - || (damper.center != damper_old.center)) { + if (right_coeff != right_coeff_old + || left_coeff != left_coeff_old + || right_deadband != right_deadband_old + || left_deadband != left_deadband_old + || right_sat != right_sat_old + || left_sat != left_sat_old + || duration != duration_old + || effect.replay.delay != old.replay.delay) { - uint16_t right_deadband = 0xfffe - damper.deadband - damper.center; - uint16_t left_deadband = 0xfffe - damper.deadband + damper.center; + packet_mod_condition->right_coeff = cpu_to_le16(right_coeff); + packet_mod_condition->left_coeff = cpu_to_le16(left_coeff); + packet_mod_condition->right_deadband = cpu_to_le16(right_deadband); + packet_mod_condition->left_deadband = cpu_to_le16(left_deadband); + packet_mod_condition->right_saturation = cpu_to_le16(right_sat); + packet_mod_condition->left_saturation = cpu_to_le16(left_sat); + packet_mod_condition->effect_type = 0x06; + packet_mod_condition->update_type = 0x45; + packet_mod_condition->duration = cpu_to_le16(duration); + packet_mod_condition->delay = cpu_to_le16(effect.replay.delay); - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x4c; - packet_mod_damper->value0 = cpu_to_le16(right_deadband); - packet_mod_damper->value1 = cpu_to_le16(left_deadband); + t300rs_fill_header(&packet_mod_condition->header, effect.id, 0x4c); ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper deadband\n"); - goto error; - } - - } - - ret = t300rs_update_simple_duration(t300rs, state, 0x06); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper duration\n"); - goto error; + if (ret) + hid_err(t300rs->hdev, "failed modifying condition effect\n"); } -error: return ret; } -static int t300rs_update_spring(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - return t300rs_update_damper(t300rs, state); -} - - static int t300rs_update_periodic(struct t300rs_device_entry *t300rs, struct tmff2_effect_state *state) { struct ff_effect effect = state->effect; struct ff_effect old = state->old; - struct ff_periodic_effect periodic = effect.u.periodic; - struct ff_periodic_effect periodic_old = old.u.periodic; struct __packed t300rs_packet_mod_periodic { struct t300rs_packet_header header; uint8_t attribute; uint16_t value; } *packet_mod_periodic = (struct t300rs_packet_mod_periodic *)t300rs->send_buffer; + struct ff_periodic_effect periodic, periodic_old; int ret; - int16_t magnitude, phase; + uint16_t phase; + int16_t magnitude; - magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + t300rs_calculate_periodic_values(&effect); + periodic = effect.u.periodic; + magnitude = periodic.magnitude; phase = periodic.phase; + t300rs_calculate_periodic_values(&old); + periodic_old = old.u.periodic; + if ((periodic.magnitude != periodic_old.magnitude) || (effect.direction != old.direction)) { @@ -948,6 +1025,8 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, int ret; level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + /* the Windows driver uses the range [-16385;16381] */ + level = level / 2; duration = effect.replay.length - 1; offset = effect.replay.delay; @@ -1020,99 +1099,67 @@ static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs, return ret; } -static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, +static int t300rs_upload_condition(struct t300rs_device_entry *t300rs, struct tmff2_effect_state *state) { struct ff_effect effect = state->effect; /* we only care about the first axis */ - struct ff_condition_effect spring = state->effect.u.condition[0]; - struct __packed t300rs_packet_spring { + struct ff_condition_effect cond = state->effect.u.condition[0]; + struct __packed t300rs_packet_condition { struct t300rs_packet_header header; - uint16_t right_coeff; - uint16_t left_coeff; - uint16_t right_deadband; - uint16_t left_deadband; - uint8_t spring_start[17]; + int16_t right_coeff; + int16_t left_coeff; + int16_t right_deadband; + int16_t left_deadband; + uint16_t right_saturation; + uint16_t left_saturation; + uint8_t hardcoded[ARRAY_SIZE(condition_values)]; + uint16_t max_right_saturation; + uint16_t max_left_saturation; + uint8_t type; struct t300rs_packet_timing timing; - } *packet_spring = (struct t300rs_packet_spring *)t300rs->send_buffer; + } *packet_condition = (struct t300rs_packet_condition *)t300rs->send_buffer; int ret; - uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; - - duration = effect.replay.length - 1; - - right_coeff = spring.right_coeff * spring_level / 100; - left_coeff = spring.left_coeff * spring_level / 100; - - right_deadband = 0xfffe - spring.deadband - spring.center; - left_deadband = 0xfffe - spring.deadband + spring.center; - - offset = effect.replay.delay; + uint16_t duration, right_sat, left_sat, right_coeff, left_coeff, max_sat, offset; + int16_t right_deadband, left_deadband; - t300rs_fill_header(&packet_spring->header, effect.id, 0x64); + right_coeff = t300rs_calculate_coefficient(cond.right_coeff, effect.type); + left_coeff = t300rs_calculate_coefficient(cond.left_coeff, effect.type); - packet_spring->right_coeff = cpu_to_le16(right_coeff); - packet_spring->left_coeff = cpu_to_le16(left_coeff); - packet_spring->right_deadband = cpu_to_le16(right_deadband); - packet_spring->left_deadband = cpu_to_le16(left_deadband); + t300rs_calculate_deadband(&right_deadband, &left_deadband, + cond.deadband, cond.center); - memcpy(&packet_spring->spring_start, spring_values, ARRAY_SIZE(spring_values)); - t300rs_fill_timing(&packet_spring->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading spring\n"); - - return ret; -} - -static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - - struct ff_effect effect = state->effect; - /* we only care about the first axis */ - struct ff_condition_effect spring = state->effect.u.condition[0]; - struct __packed t300rs_packet_damper { - struct t300rs_packet_header header; - uint16_t right_coeff; - uint16_t left_coeff; - uint16_t right_deadband; - uint16_t left_deadband; - uint8_t damper_start[17]; - struct t300rs_packet_timing timing; - } *packet_damper = (struct t300rs_packet_damper *)t300rs->send_buffer; - - int ret, input_level; - uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; + right_sat = t300rs_calculate_saturation(cond.right_saturation, effect.type); + left_sat = t300rs_calculate_saturation(cond.left_saturation, effect.type); duration = effect.replay.length - 1; - input_level = damper_level; - if (state->effect.type == FF_FRICTION) - input_level = friction_level; - - right_coeff = spring.right_coeff * input_level / 100; - left_coeff = spring.left_coeff * input_level / 100; + offset = effect.replay.delay; - right_deadband = 0xfffe - spring.deadband - spring.center; - left_deadband = 0xfffe - spring.deadband + spring.center; + t300rs_fill_header(&packet_condition->header, effect.id, 0x64); - offset = effect.replay.delay; + packet_condition->right_coeff = cpu_to_le16(right_coeff); + packet_condition->left_coeff = cpu_to_le16(left_coeff); + packet_condition->right_deadband = cpu_to_le16(right_deadband); + packet_condition->left_deadband = cpu_to_le16(left_deadband); + packet_condition->right_saturation = cpu_to_le16(right_sat); + packet_condition->left_saturation = cpu_to_le16(left_sat); - t300rs_fill_header(&packet_damper->header, effect.id, 0x64); + memcpy(&packet_condition->hardcoded, condition_values, + ARRAY_SIZE(condition_values)); - packet_damper->right_coeff = cpu_to_le16(right_coeff); - packet_damper->left_coeff = cpu_to_le16(left_coeff); - packet_damper->right_deadband = cpu_to_le16(right_deadband); - packet_damper->left_deadband = cpu_to_le16(left_deadband); + max_sat = t300rs_condition_max_saturation(effect.type); + /* it seems that the maximum values do not affect the wheel. */ + packet_condition->max_right_saturation = cpu_to_le16(max_sat); + packet_condition->max_left_saturation = cpu_to_le16(max_sat); + packet_condition->type = t300rs_condition_effect_type(effect.type); - memcpy(&packet_damper->damper_start, damper_values, ARRAY_SIZE(damper_values)); - t300rs_fill_timing(&packet_damper->timing, duration, offset); + t300rs_fill_timing(&packet_condition->timing, duration, offset); ret = t300rs_send_int(t300rs); if (ret) - hid_err(t300rs->hdev, "failed uploading spring\n"); + hid_err(t300rs->hdev, "failed uploading condition\n"); return ret; } @@ -1121,7 +1168,6 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct tmff2_effect_state *state) { struct ff_effect effect = state->effect; - struct ff_periodic_effect periodic = state->effect.u.periodic; struct __packed t300rs_packet_periodic { struct t300rs_packet_header header; uint16_t magnitude; @@ -1134,19 +1180,20 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t300rs_packet_timing timing; } *packet_periodic = (struct t300rs_packet_periodic *)t300rs->send_buffer; + struct ff_periodic_effect periodic; int ret; - uint16_t duration, period, offset, periodic_offset; - int16_t phase, magnitude; - - duration = effect.replay.length - 1; - magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + uint16_t duration, period, phase, offset, periodic_offset; + int16_t magnitude; + t300rs_calculate_periodic_values(&effect); + periodic = effect.u.periodic; + duration = effect.replay.length; + offset = effect.replay.delay; + magnitude = periodic.magnitude; + period = periodic.period; phase = periodic.phase; periodic_offset = periodic.offset; - period = periodic.period; - offset = effect.replay.delay; - t300rs_fill_header(&packet_periodic->header, effect.id, 0x6b); packet_periodic->magnitude = cpu_to_le16(magnitude); @@ -1179,11 +1226,10 @@ int t300rs_update_effect(void *data, struct tmff2_effect_state *state) case FF_RAMP: return t300rs_update_ramp(t300rs, state); case FF_SPRING: - return t300rs_update_spring(t300rs, state); case FF_DAMPER: case FF_FRICTION: case FF_INERTIA: - return t300rs_update_damper(t300rs, state); + return t300rs_update_condition(t300rs, state); case FF_PERIODIC: return t300rs_update_periodic(t300rs, state); default: @@ -1202,11 +1248,10 @@ int t300rs_upload_effect(void *data, struct tmff2_effect_state *state) case FF_RAMP: return t300rs_upload_ramp(t300rs, state); case FF_SPRING: - return t300rs_upload_spring(t300rs, state); case FF_DAMPER: case FF_FRICTION: case FF_INERTIA: - return t300rs_upload_damper(t300rs, state); + return t300rs_upload_condition(t300rs, state); case FF_PERIODIC: return t300rs_upload_periodic(t300rs, state); default: diff --git a/src/tmtsxw/hid-tmtsxw.c b/src/tmtsxw/hid-tmtsxw.c new file mode 100644 index 0000000..b8ee1fd --- /dev/null +++ b/src/tmtsxw/hid-tmtsxw.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <linux/usb.h> +#include <linux/hid.h> +#include "../hid-tmff2.h" + +#define TMTSXW_MAX_EFFECTS 16 +#define TMTSXW_BUFFER_LENGTH 63 + +static const u8 setup_0[64] = { 0x42, 0x01 }; +static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; +static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; +static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; +static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; +static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; +static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; +static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; +static const unsigned int setup_arr_sizes[] = { + ARRAY_SIZE(setup_0), + ARRAY_SIZE(setup_1), + ARRAY_SIZE(setup_2), + ARRAY_SIZE(setup_3), + ARRAY_SIZE(setup_4), + ARRAY_SIZE(setup_5), + ARRAY_SIZE(setup_6) +}; + +static const unsigned long tsxw_params = + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_RANGE + | PARAM_GAIN + ; + +static const signed short tsxw_effects[] = { + FF_CONSTANT, + FF_RAMP, + FF_SPRING, + FF_DAMPER, + FF_FRICTION, + FF_INERTIA, + FF_PERIODIC, + FF_SINE, + FF_TRIANGLE, + FF_SQUARE, + FF_SAW_UP, + FF_SAW_DOWN, + FF_AUTOCENTER, + FF_GAIN, + -1 +}; + +/* TODO: sort through this stuff */ +static u8 tsxw_pc_rdesc_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x04, /* Usage (Joystick) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x85, 0x07, /* Report ID (7) */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x35, /* Usage (Rz) (Brake) */ + 0x26, 0xff, 0x03, /* Logical maximum (1023) */ + 0x46, 0xff, 0x03, /* Physical maximum (1023) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x32, /* Usage (Z) (Gas) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x31, /* Usage (Y) (Clutch) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x0d, /* Usage maximum (13) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x45, 0x01, /* Physical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x0d, /* Report count (13) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x0b, /* Report size (13) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x25, 0x07, /* Logical maximum (7) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x55, 0x00, /* Unit exponent (0) */ + 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Unit (None) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x85, 0x60, /* Report ID (96), prev 10 */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x60, /* Usage (96), prev 10 */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x3f, /* Report count (63) */ + 0x26, 0xff, 0x7f, /* Logical maximum (32767) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x46, 0xff, 0x7f, /* Physical maximum (32767) */ + 0x36, 0x00, 0x80, /* Physical minimum (-32768) */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x02, /* Report ID (2) */ + 0x09, 0x02, /* Usage (2) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x14, /* Usage (20) */ + 0x85, 0x14, /* Report ID (20) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0xc0, /* End collection */ + 0xc0, /* End collection */ +}; + +static int tsxw_interrupts(struct t300rs_device_entry *tsxw) +{ + u8 *send_buf = kmalloc(256, GFP_KERNEL); + struct usb_interface *usbif = to_usb_interface(tsxw->hdev->dev.parent); + struct usb_host_endpoint *ep; + int ret, trans, b_ep, i; + + if (!send_buf) { + hid_err(tsxw->hdev, "failed allocating send buffer\n"); + return -ENOMEM; + } + + ep = &usbif->cur_altsetting->endpoint[1]; + b_ep = ep->desc.bEndpointAddress; + + for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) { + memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]); + + ret = usb_interrupt_msg(tsxw->usbdev, + usb_sndintpipe(tsxw->usbdev, b_ep), + send_buf, setup_arr_sizes[i], + &trans, + USB_CTRL_SET_TIMEOUT); + + if (ret) { + hid_err(tsxw->hdev, "setup data couldn't be sent\n"); + goto err; + } + } + +err: + kfree(send_buf); + return ret; +} + +static int tsxw_wheel_destroy(void *data) +{ + struct t300rs_device_entry *t300rs = data; + + if (!t300rs) + return -ENODEV; + + kfree(t300rs->send_buffer); + kfree(t300rs); + return 0; +} + +static int tsxw_set_range(void *data, uint16_t value) +{ + struct t300rs_device_entry *tsxw = data; + + if (value < 140) { + hid_info(tsxw->hdev, "value %i too small, clamping to 140\n", value); + value = 140; + } + + if (value > 1080) { + hid_info(tsxw->hdev, "value %i too large, clamping to 1080\n", value); + value = 1080; + } + + return t300rs_set_range(data, value); +} + +static int tsxw_send_open(struct t300rs_device_entry *tsxw) +{ + int r1, r2; + tsxw->send_buffer[0] = 0x01; + tsxw->send_buffer[1] = 0x04; + if ((r1 = t300rs_send_int(tsxw))) + return r1; + + tsxw->send_buffer[0] = 0x01; + tsxw->send_buffer[1] = 0x05; + if ((r2 = t300rs_send_int(tsxw))) + return r2; + + return 0; +} + +static int tsxw_open(void *data, int open_mode) +{ + struct t300rs_device_entry *tsxw = data; + + if (!tsxw) + return -ENODEV; + + if (open_mode) + tsxw_send_open(tsxw); + + return tsxw->open(tsxw->input_dev); +} + +static int tsxw_send_close(struct t300rs_device_entry *tsxw) +{ + int r1, r2; + tsxw->send_buffer[0] = 0x01; + tsxw->send_buffer[1] = 0x05; + if ((r1 = t300rs_send_int(tsxw))) + return r1; + + tsxw->send_buffer[0] = 0x01; + tsxw->send_buffer[1] = 0x00; + if ((r2 = t300rs_send_int(tsxw))) + return r2; + + return 0; +} + +static int tsxw_close(void *data, int open_mode) +{ + struct t300rs_device_entry *tsxw = data; + + if (!tsxw) + return -ENODEV; + + if (open_mode) + tsxw_send_close(tsxw); + + tsxw->close(tsxw->input_dev); + return 0; +} + +static int tsxw_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +{ + struct t300rs_device_entry *tsxw = kzalloc(sizeof(struct t300rs_device_entry), + GFP_KERNEL); + struct list_head *report_list; + int ret; + + + if (!tsxw) { + ret = -ENOMEM; + goto tsxw_err; + } + + tsxw->hdev = tmff2->hdev; + tsxw->input_dev = tmff2->input_dev; + tsxw->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); + tsxw->buffer_length = TMTSXW_BUFFER_LENGTH; + + tsxw->send_buffer = kzalloc(tsxw->buffer_length, GFP_KERNEL); + if (!tsxw->send_buffer) { + ret = -ENOMEM; + goto send_err; + } + + report_list = &tsxw->hdev->report_enum[HID_OUTPUT_REPORT].report_list; + tsxw->report = list_entry(report_list->next, struct hid_report, list); + tsxw->ff_field = tsxw->report->field[0]; + + tsxw->open = tsxw->input_dev->open; + tsxw->close = tsxw->input_dev->close; + + if ((ret = tsxw_interrupts(tsxw))) + goto interrupt_err; + + /* everything went OK */ + tmff2->data = tsxw; + tmff2->params = tsxw_params; + tmff2->max_effects = TMTSXW_MAX_EFFECTS; + memcpy(tmff2->supported_effects, tsxw_effects, sizeof(tsxw_effects)); + + if (!open_mode) + tsxw_send_open(tsxw); + + hid_info(tsxw->hdev, "force feedback for TS-XW\n"); + return 0; + +interrupt_err: +send_err: + kfree(tsxw); +tsxw_err: + hid_err(tmff2->hdev, "failed initializing TS-XW\n"); + return ret; +} + +static __u8 *tsxw_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + rdesc = tsxw_pc_rdesc_fixed; + *rsize = sizeof(tsxw_pc_rdesc_fixed); + return rdesc; +} + +int tsxw_populate_api(struct tmff2_device_entry *tmff2) +{ + tmff2->play_effect = t300rs_play_effect; + tmff2->upload_effect = t300rs_upload_effect; + tmff2->update_effect = t300rs_update_effect; + tmff2->stop_effect = t300rs_stop_effect; + + tmff2->set_gain = t300rs_set_gain; + tmff2->set_autocenter = t300rs_set_autocenter; + /* TS-XW has 1080 degree range, just like T300RS 1080 */ + tmff2->set_range = tsxw_set_range; + tmff2->wheel_fixup = tsxw_wheel_fixup; + + tmff2->open = tsxw_open; + tmff2->close = tsxw_close; + + tmff2->wheel_init = tsxw_wheel_init; + tmff2->wheel_destroy = tsxw_wheel_destroy; + + return 0; +} diff --git a/src/tmtx/hid-tmtx.c b/src/tmtx/hid-tmtx.c index afca799..857886c 100644 --- a/src/tmtx/hid-tmtx.c +++ b/src/tmtx/hid-tmtx.c @@ -151,7 +151,7 @@ err: return ret; } -int tx_wheel_destroy(void *data) +static int tx_wheel_destroy(void *data) { struct t300rs_device_entry *t300rs = data; @@ -163,7 +163,7 @@ int tx_wheel_destroy(void *data) return 0; } -int tx_set_range(void *data, uint16_t value) +static int tx_set_range(void *data, uint16_t value) { struct t300rs_device_entry *tx = data; @@ -239,9 +239,10 @@ static int tx_close(void *data, int open_mode) return 0; } -int tx_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +static int tx_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) { - struct t300rs_device_entry *tx = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); + struct t300rs_device_entry *tx = kzalloc(sizeof(struct t300rs_device_entry), + GFP_KERNEL); struct list_head *report_list; int ret; |
