162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> 462306a36Sopenharmony_ci * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * USB/RS232 I-Force joysticks and wheels. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "iforce.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Set the magnitude of a constant force effect 1362306a36Sopenharmony_ci * Return error code 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Note: caller must ensure exclusive access to device 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int make_magnitude_modifier(struct iforce* iforce, 1962306a36Sopenharmony_ci struct resource* mod_chunk, int no_alloc, __s16 level) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci unsigned char data[3]; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (!no_alloc) { 2462306a36Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 2562306a36Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, 2662306a36Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 2762306a36Sopenharmony_ci NULL, NULL)) { 2862306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 2962306a36Sopenharmony_ci return -ENOSPC; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci data[0] = LO(mod_chunk->start); 3562306a36Sopenharmony_ci data[1] = HI(mod_chunk->start); 3662306a36Sopenharmony_ci data[2] = HIFIX80(level); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci iforce_dump_packet(iforce, "magnitude", FF_CMD_MAGNITUDE, data); 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Upload the component of an effect dealing with the period, phase and magnitude 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int make_period_modifier(struct iforce* iforce, 4962306a36Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 5062306a36Sopenharmony_ci __s16 magnitude, __s16 offset, u16 period, u16 phase) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci unsigned char data[7]; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci period = TIME_SCALE(period); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (!no_alloc) { 5762306a36Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 5862306a36Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, 5962306a36Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 6062306a36Sopenharmony_ci NULL, NULL)) { 6162306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 6262306a36Sopenharmony_ci return -ENOSPC; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci data[0] = LO(mod_chunk->start); 6862306a36Sopenharmony_ci data[1] = HI(mod_chunk->start); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci data[2] = HIFIX80(magnitude); 7162306a36Sopenharmony_ci data[3] = HIFIX80(offset); 7262306a36Sopenharmony_ci data[4] = HI(phase); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci data[5] = LO(period); 7562306a36Sopenharmony_ci data[6] = HI(period); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_PERIOD, data); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * Uploads the part of an effect setting the envelope of the force 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int make_envelope_modifier(struct iforce* iforce, 8762306a36Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 8862306a36Sopenharmony_ci u16 attack_duration, __s16 initial_level, 8962306a36Sopenharmony_ci u16 fade_duration, __s16 final_level) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned char data[8]; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci attack_duration = TIME_SCALE(attack_duration); 9462306a36Sopenharmony_ci fade_duration = TIME_SCALE(fade_duration); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!no_alloc) { 9762306a36Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 9862306a36Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, 9962306a36Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 10062306a36Sopenharmony_ci NULL, NULL)) { 10162306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 10262306a36Sopenharmony_ci return -ENOSPC; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci data[0] = LO(mod_chunk->start); 10862306a36Sopenharmony_ci data[1] = HI(mod_chunk->start); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci data[2] = LO(attack_duration); 11162306a36Sopenharmony_ci data[3] = HI(attack_duration); 11262306a36Sopenharmony_ci data[4] = HI(initial_level); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci data[5] = LO(fade_duration); 11562306a36Sopenharmony_ci data[6] = HI(fade_duration); 11662306a36Sopenharmony_ci data[7] = HI(final_level); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Component of spring, friction, inertia... effects 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int make_condition_modifier(struct iforce* iforce, 12862306a36Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 12962306a36Sopenharmony_ci __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci unsigned char data[10]; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!no_alloc) { 13462306a36Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 13562306a36Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, 13662306a36Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 13762306a36Sopenharmony_ci NULL, NULL)) { 13862306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 13962306a36Sopenharmony_ci return -ENOSPC; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci data[0] = LO(mod_chunk->start); 14562306a36Sopenharmony_ci data[1] = HI(mod_chunk->start); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ 14862306a36Sopenharmony_ci data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci center = (500 * center) >> 15; 15162306a36Sopenharmony_ci data[4] = LO(center); 15262306a36Sopenharmony_ci data[5] = HI(center); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci db = (1000 * db) >> 16; 15562306a36Sopenharmony_ci data[6] = LO(db); 15662306a36Sopenharmony_ci data[7] = HI(db); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci data[8] = (100 * rsat) >> 16; 15962306a36Sopenharmony_ci data[9] = (100 * lsat) >> 16; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_CONDITION, data); 16262306a36Sopenharmony_ci iforce_dump_packet(iforce, "condition", FF_CMD_CONDITION, data); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic unsigned char find_button(struct iforce *iforce, signed short button) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int i; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci for (i = 1; iforce->type->btn[i] >= 0; i++) 17262306a36Sopenharmony_ci if (iforce->type->btn[i] == button) 17362306a36Sopenharmony_ci return i + 1; 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* 17862306a36Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an condition 17962306a36Sopenharmony_ci * parameter packet 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic int need_condition_modifier(struct iforce *iforce, 18262306a36Sopenharmony_ci struct ff_effect *old, 18362306a36Sopenharmony_ci struct ff_effect *new) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci int ret = 0; 18662306a36Sopenharmony_ci int i; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (new->type != FF_SPRING && new->type != FF_FRICTION) { 18962306a36Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 19062306a36Sopenharmony_ci __func__); 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 19562306a36Sopenharmony_ci ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation 19662306a36Sopenharmony_ci || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation 19762306a36Sopenharmony_ci || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff 19862306a36Sopenharmony_ci || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff 19962306a36Sopenharmony_ci || old->u.condition[i].deadband != new->u.condition[i].deadband 20062306a36Sopenharmony_ci || old->u.condition[i].center != new->u.condition[i].center; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send a magnitude 20762306a36Sopenharmony_ci * parameter packet 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic int need_magnitude_modifier(struct iforce *iforce, 21062306a36Sopenharmony_ci struct ff_effect *old, 21162306a36Sopenharmony_ci struct ff_effect *effect) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci if (effect->type != FF_CONSTANT) { 21462306a36Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 21562306a36Sopenharmony_ci __func__); 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return old->u.constant.level != effect->u.constant.level; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an envelope 22462306a36Sopenharmony_ci * parameter packet 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic int need_envelope_modifier(struct iforce *iforce, struct ff_effect *old, 22762306a36Sopenharmony_ci struct ff_effect *effect) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci switch (effect->type) { 23062306a36Sopenharmony_ci case FF_CONSTANT: 23162306a36Sopenharmony_ci if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length 23262306a36Sopenharmony_ci || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level 23362306a36Sopenharmony_ci || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length 23462306a36Sopenharmony_ci || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) 23562306a36Sopenharmony_ci return 1; 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci case FF_PERIODIC: 23962306a36Sopenharmony_ci if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length 24062306a36Sopenharmony_ci || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level 24162306a36Sopenharmony_ci || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length 24262306a36Sopenharmony_ci || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) 24362306a36Sopenharmony_ci return 1; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci default: 24762306a36Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 24862306a36Sopenharmony_ci __func__); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send a periodic 25662306a36Sopenharmony_ci * parameter effect 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_cistatic int need_period_modifier(struct iforce *iforce, struct ff_effect *old, 25962306a36Sopenharmony_ci struct ff_effect *new) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci if (new->type != FF_PERIODIC) { 26262306a36Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 26362306a36Sopenharmony_ci __func__); 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci return (old->u.periodic.period != new->u.periodic.period 26762306a36Sopenharmony_ci || old->u.periodic.magnitude != new->u.periodic.magnitude 26862306a36Sopenharmony_ci || old->u.periodic.offset != new->u.periodic.offset 26962306a36Sopenharmony_ci || old->u.periodic.phase != new->u.periodic.phase); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an effect 27462306a36Sopenharmony_ci * packet 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_cistatic int need_core(struct ff_effect *old, struct ff_effect *new) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci if (old->direction != new->direction 27962306a36Sopenharmony_ci || old->trigger.button != new->trigger.button 28062306a36Sopenharmony_ci || old->trigger.interval != new->trigger.interval 28162306a36Sopenharmony_ci || old->replay.length != new->replay.length 28262306a36Sopenharmony_ci || old->replay.delay != new->replay.delay) 28362306a36Sopenharmony_ci return 1; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * Send the part common to all effects to the device 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_cistatic int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, 29162306a36Sopenharmony_ci u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, 29262306a36Sopenharmony_ci u16 interval, u16 direction) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci unsigned char data[14]; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci duration = TIME_SCALE(duration); 29762306a36Sopenharmony_ci delay = TIME_SCALE(delay); 29862306a36Sopenharmony_ci interval = TIME_SCALE(interval); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci data[0] = LO(id); 30162306a36Sopenharmony_ci data[1] = effect_type; 30262306a36Sopenharmony_ci data[2] = LO(axes) | find_button(iforce, button); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci data[3] = LO(duration); 30562306a36Sopenharmony_ci data[4] = HI(duration); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci data[5] = HI(direction); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci data[6] = LO(interval); 31062306a36Sopenharmony_ci data[7] = HI(interval); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci data[8] = LO(mod_id1); 31362306a36Sopenharmony_ci data[9] = HI(mod_id1); 31462306a36Sopenharmony_ci data[10] = LO(mod_id2); 31562306a36Sopenharmony_ci data[11] = HI(mod_id2); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci data[12] = LO(delay); 31862306a36Sopenharmony_ci data[13] = HI(delay); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Stop effect */ 32162306a36Sopenharmony_ci/* iforce_control_playback(iforce, id, 0);*/ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_EFFECT, data); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* If needed, restart effect */ 32662306a36Sopenharmony_ci if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { 32762306a36Sopenharmony_ci /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ 32862306a36Sopenharmony_ci iforce_control_playback(iforce, id, 1); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* 33562306a36Sopenharmony_ci * Upload a periodic effect to the device 33662306a36Sopenharmony_ci * See also iforce_upload_constant. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ciint iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci u8 wave_code; 34162306a36Sopenharmony_ci int core_id = effect->id; 34262306a36Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 34362306a36Sopenharmony_ci struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); 34462306a36Sopenharmony_ci struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); 34562306a36Sopenharmony_ci int param1_err = 1; 34662306a36Sopenharmony_ci int param2_err = 1; 34762306a36Sopenharmony_ci int core_err = 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!old || need_period_modifier(iforce, old, effect)) { 35062306a36Sopenharmony_ci param1_err = make_period_modifier(iforce, mod1_chunk, 35162306a36Sopenharmony_ci old != NULL, 35262306a36Sopenharmony_ci effect->u.periodic.magnitude, effect->u.periodic.offset, 35362306a36Sopenharmony_ci effect->u.periodic.period, effect->u.periodic.phase); 35462306a36Sopenharmony_ci if (param1_err) 35562306a36Sopenharmony_ci return param1_err; 35662306a36Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (!old || need_envelope_modifier(iforce, old, effect)) { 36062306a36Sopenharmony_ci param2_err = make_envelope_modifier(iforce, mod2_chunk, 36162306a36Sopenharmony_ci old !=NULL, 36262306a36Sopenharmony_ci effect->u.periodic.envelope.attack_length, 36362306a36Sopenharmony_ci effect->u.periodic.envelope.attack_level, 36462306a36Sopenharmony_ci effect->u.periodic.envelope.fade_length, 36562306a36Sopenharmony_ci effect->u.periodic.envelope.fade_level); 36662306a36Sopenharmony_ci if (param2_err) 36762306a36Sopenharmony_ci return param2_err; 36862306a36Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci switch (effect->u.periodic.waveform) { 37262306a36Sopenharmony_ci case FF_SQUARE: wave_code = 0x20; break; 37362306a36Sopenharmony_ci case FF_TRIANGLE: wave_code = 0x21; break; 37462306a36Sopenharmony_ci case FF_SINE: wave_code = 0x22; break; 37562306a36Sopenharmony_ci case FF_SAW_UP: wave_code = 0x23; break; 37662306a36Sopenharmony_ci case FF_SAW_DOWN: wave_code = 0x24; break; 37762306a36Sopenharmony_ci default: wave_code = 0x20; break; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (!old || need_core(old, effect)) { 38162306a36Sopenharmony_ci core_err = make_core(iforce, effect->id, 38262306a36Sopenharmony_ci mod1_chunk->start, 38362306a36Sopenharmony_ci mod2_chunk->start, 38462306a36Sopenharmony_ci wave_code, 38562306a36Sopenharmony_ci 0x20, 38662306a36Sopenharmony_ci effect->replay.length, 38762306a36Sopenharmony_ci effect->replay.delay, 38862306a36Sopenharmony_ci effect->trigger.button, 38962306a36Sopenharmony_ci effect->trigger.interval, 39062306a36Sopenharmony_ci effect->direction); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* If one of the parameter creation failed, we already returned an 39462306a36Sopenharmony_ci * error code. 39562306a36Sopenharmony_ci * If the core creation failed, we return its error code. 39662306a36Sopenharmony_ci * Else: if one parameter at least was created, we return 0 39762306a36Sopenharmony_ci * else we return 1; 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci return core_err < 0 ? core_err : (param1_err && param2_err); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * Upload a constant force effect 40462306a36Sopenharmony_ci * Return value: 40562306a36Sopenharmony_ci * <0 Error code 40662306a36Sopenharmony_ci * 0 Ok, effect created or updated 40762306a36Sopenharmony_ci * 1 effect did not change since last upload, and no packet was therefore sent 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ciint iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci int core_id = effect->id; 41262306a36Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 41362306a36Sopenharmony_ci struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); 41462306a36Sopenharmony_ci struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); 41562306a36Sopenharmony_ci int param1_err = 1; 41662306a36Sopenharmony_ci int param2_err = 1; 41762306a36Sopenharmony_ci int core_err = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!old || need_magnitude_modifier(iforce, old, effect)) { 42062306a36Sopenharmony_ci param1_err = make_magnitude_modifier(iforce, mod1_chunk, 42162306a36Sopenharmony_ci old != NULL, 42262306a36Sopenharmony_ci effect->u.constant.level); 42362306a36Sopenharmony_ci if (param1_err) 42462306a36Sopenharmony_ci return param1_err; 42562306a36Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (!old || need_envelope_modifier(iforce, old, effect)) { 42962306a36Sopenharmony_ci param2_err = make_envelope_modifier(iforce, mod2_chunk, 43062306a36Sopenharmony_ci old != NULL, 43162306a36Sopenharmony_ci effect->u.constant.envelope.attack_length, 43262306a36Sopenharmony_ci effect->u.constant.envelope.attack_level, 43362306a36Sopenharmony_ci effect->u.constant.envelope.fade_length, 43462306a36Sopenharmony_ci effect->u.constant.envelope.fade_level); 43562306a36Sopenharmony_ci if (param2_err) 43662306a36Sopenharmony_ci return param2_err; 43762306a36Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!old || need_core(old, effect)) { 44162306a36Sopenharmony_ci core_err = make_core(iforce, effect->id, 44262306a36Sopenharmony_ci mod1_chunk->start, 44362306a36Sopenharmony_ci mod2_chunk->start, 44462306a36Sopenharmony_ci 0x00, 44562306a36Sopenharmony_ci 0x20, 44662306a36Sopenharmony_ci effect->replay.length, 44762306a36Sopenharmony_ci effect->replay.delay, 44862306a36Sopenharmony_ci effect->trigger.button, 44962306a36Sopenharmony_ci effect->trigger.interval, 45062306a36Sopenharmony_ci effect->direction); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* If one of the parameter creation failed, we already returned an 45462306a36Sopenharmony_ci * error code. 45562306a36Sopenharmony_ci * If the core creation failed, we return its error code. 45662306a36Sopenharmony_ci * Else: if one parameter at least was created, we return 0 45762306a36Sopenharmony_ci * else we return 1; 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci return core_err < 0 ? core_err : (param1_err && param2_err); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* 46362306a36Sopenharmony_ci * Upload an condition effect. Those are for example friction, inertia, springs... 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ciint iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int core_id = effect->id; 46862306a36Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 46962306a36Sopenharmony_ci struct resource* mod1_chunk = &(core_effect->mod1_chunk); 47062306a36Sopenharmony_ci struct resource* mod2_chunk = &(core_effect->mod2_chunk); 47162306a36Sopenharmony_ci u8 type; 47262306a36Sopenharmony_ci int param_err = 1; 47362306a36Sopenharmony_ci int core_err = 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci switch (effect->type) { 47662306a36Sopenharmony_ci case FF_SPRING: type = 0x40; break; 47762306a36Sopenharmony_ci case FF_DAMPER: type = 0x41; break; 47862306a36Sopenharmony_ci default: return -1; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!old || need_condition_modifier(iforce, old, effect)) { 48262306a36Sopenharmony_ci param_err = make_condition_modifier(iforce, mod1_chunk, 48362306a36Sopenharmony_ci old != NULL, 48462306a36Sopenharmony_ci effect->u.condition[0].right_saturation, 48562306a36Sopenharmony_ci effect->u.condition[0].left_saturation, 48662306a36Sopenharmony_ci effect->u.condition[0].right_coeff, 48762306a36Sopenharmony_ci effect->u.condition[0].left_coeff, 48862306a36Sopenharmony_ci effect->u.condition[0].deadband, 48962306a36Sopenharmony_ci effect->u.condition[0].center); 49062306a36Sopenharmony_ci if (param_err) 49162306a36Sopenharmony_ci return param_err; 49262306a36Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci param_err = make_condition_modifier(iforce, mod2_chunk, 49562306a36Sopenharmony_ci old != NULL, 49662306a36Sopenharmony_ci effect->u.condition[1].right_saturation, 49762306a36Sopenharmony_ci effect->u.condition[1].left_saturation, 49862306a36Sopenharmony_ci effect->u.condition[1].right_coeff, 49962306a36Sopenharmony_ci effect->u.condition[1].left_coeff, 50062306a36Sopenharmony_ci effect->u.condition[1].deadband, 50162306a36Sopenharmony_ci effect->u.condition[1].center); 50262306a36Sopenharmony_ci if (param_err) 50362306a36Sopenharmony_ci return param_err; 50462306a36Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!old || need_core(old, effect)) { 50962306a36Sopenharmony_ci core_err = make_core(iforce, effect->id, 51062306a36Sopenharmony_ci mod1_chunk->start, mod2_chunk->start, 51162306a36Sopenharmony_ci type, 0xc0, 51262306a36Sopenharmony_ci effect->replay.length, effect->replay.delay, 51362306a36Sopenharmony_ci effect->trigger.button, effect->trigger.interval, 51462306a36Sopenharmony_ci effect->direction); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* If the parameter creation failed, we already returned an 51862306a36Sopenharmony_ci * error code. 51962306a36Sopenharmony_ci * If the core creation failed, we return its error code. 52062306a36Sopenharmony_ci * Else: if a parameter was created, we return 0 52162306a36Sopenharmony_ci * else we return 1; 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci return core_err < 0 ? core_err : param_err; 52462306a36Sopenharmony_ci} 525