18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> 48c2ecf20Sopenharmony_ci * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * USB/RS232 I-Force joysticks and wheels. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "iforce.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * Set the magnitude of a constant force effect 138c2ecf20Sopenharmony_ci * Return error code 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Note: caller must ensure exclusive access to device 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int make_magnitude_modifier(struct iforce* iforce, 198c2ecf20Sopenharmony_ci struct resource* mod_chunk, int no_alloc, __s16 level) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci unsigned char data[3]; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (!no_alloc) { 248c2ecf20Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 258c2ecf20Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, 268c2ecf20Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 278c2ecf20Sopenharmony_ci NULL, NULL)) { 288c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 298c2ecf20Sopenharmony_ci return -ENOSPC; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci data[0] = LO(mod_chunk->start); 358c2ecf20Sopenharmony_ci data[1] = HI(mod_chunk->start); 368c2ecf20Sopenharmony_ci data[2] = HIFIX80(level); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci iforce_dump_packet(iforce, "magnitude", FF_CMD_MAGNITUDE, data); 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* 458c2ecf20Sopenharmony_ci * Upload the component of an effect dealing with the period, phase and magnitude 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int make_period_modifier(struct iforce* iforce, 498c2ecf20Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 508c2ecf20Sopenharmony_ci __s16 magnitude, __s16 offset, u16 period, u16 phase) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned char data[7]; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci period = TIME_SCALE(period); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!no_alloc) { 578c2ecf20Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 588c2ecf20Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, 598c2ecf20Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 608c2ecf20Sopenharmony_ci NULL, NULL)) { 618c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 628c2ecf20Sopenharmony_ci return -ENOSPC; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci data[0] = LO(mod_chunk->start); 688c2ecf20Sopenharmony_ci data[1] = HI(mod_chunk->start); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci data[2] = HIFIX80(magnitude); 718c2ecf20Sopenharmony_ci data[3] = HIFIX80(offset); 728c2ecf20Sopenharmony_ci data[4] = HI(phase); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci data[5] = LO(period); 758c2ecf20Sopenharmony_ci data[6] = HI(period); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_PERIOD, data); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * Uploads the part of an effect setting the envelope of the force 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int make_envelope_modifier(struct iforce* iforce, 878c2ecf20Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 888c2ecf20Sopenharmony_ci u16 attack_duration, __s16 initial_level, 898c2ecf20Sopenharmony_ci u16 fade_duration, __s16 final_level) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci unsigned char data[8]; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci attack_duration = TIME_SCALE(attack_duration); 948c2ecf20Sopenharmony_ci fade_duration = TIME_SCALE(fade_duration); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!no_alloc) { 978c2ecf20Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 988c2ecf20Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, 998c2ecf20Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 1008c2ecf20Sopenharmony_ci NULL, NULL)) { 1018c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 1028c2ecf20Sopenharmony_ci return -ENOSPC; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci data[0] = LO(mod_chunk->start); 1088c2ecf20Sopenharmony_ci data[1] = HI(mod_chunk->start); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci data[2] = LO(attack_duration); 1118c2ecf20Sopenharmony_ci data[3] = HI(attack_duration); 1128c2ecf20Sopenharmony_ci data[4] = HI(initial_level); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci data[5] = LO(fade_duration); 1158c2ecf20Sopenharmony_ci data[6] = HI(fade_duration); 1168c2ecf20Sopenharmony_ci data[7] = HI(final_level); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Component of spring, friction, inertia... effects 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int make_condition_modifier(struct iforce* iforce, 1288c2ecf20Sopenharmony_ci struct resource* mod_chunk, int no_alloc, 1298c2ecf20Sopenharmony_ci __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned char data[10]; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!no_alloc) { 1348c2ecf20Sopenharmony_ci mutex_lock(&iforce->mem_mutex); 1358c2ecf20Sopenharmony_ci if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, 1368c2ecf20Sopenharmony_ci iforce->device_memory.start, iforce->device_memory.end, 2L, 1378c2ecf20Sopenharmony_ci NULL, NULL)) { 1388c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 1398c2ecf20Sopenharmony_ci return -ENOSPC; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci mutex_unlock(&iforce->mem_mutex); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci data[0] = LO(mod_chunk->start); 1458c2ecf20Sopenharmony_ci data[1] = HI(mod_chunk->start); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ 1488c2ecf20Sopenharmony_ci data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci center = (500 * center) >> 15; 1518c2ecf20Sopenharmony_ci data[4] = LO(center); 1528c2ecf20Sopenharmony_ci data[5] = HI(center); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci db = (1000 * db) >> 16; 1558c2ecf20Sopenharmony_ci data[6] = LO(db); 1568c2ecf20Sopenharmony_ci data[7] = HI(db); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci data[8] = (100 * rsat) >> 16; 1598c2ecf20Sopenharmony_ci data[9] = (100 * lsat) >> 16; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_CONDITION, data); 1628c2ecf20Sopenharmony_ci iforce_dump_packet(iforce, "condition", FF_CMD_CONDITION, data); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic unsigned char find_button(struct iforce *iforce, signed short button) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int i; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci for (i = 1; iforce->type->btn[i] >= 0; i++) 1728c2ecf20Sopenharmony_ci if (iforce->type->btn[i] == button) 1738c2ecf20Sopenharmony_ci return i + 1; 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an condition 1798c2ecf20Sopenharmony_ci * parameter packet 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int need_condition_modifier(struct iforce *iforce, 1828c2ecf20Sopenharmony_ci struct ff_effect *old, 1838c2ecf20Sopenharmony_ci struct ff_effect *new) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int ret = 0; 1868c2ecf20Sopenharmony_ci int i; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (new->type != FF_SPRING && new->type != FF_FRICTION) { 1898c2ecf20Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 1908c2ecf20Sopenharmony_ci __func__); 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 1958c2ecf20Sopenharmony_ci ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation 1968c2ecf20Sopenharmony_ci || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation 1978c2ecf20Sopenharmony_ci || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff 1988c2ecf20Sopenharmony_ci || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff 1998c2ecf20Sopenharmony_ci || old->u.condition[i].deadband != new->u.condition[i].deadband 2008c2ecf20Sopenharmony_ci || old->u.condition[i].center != new->u.condition[i].center; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send a magnitude 2078c2ecf20Sopenharmony_ci * parameter packet 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic int need_magnitude_modifier(struct iforce *iforce, 2108c2ecf20Sopenharmony_ci struct ff_effect *old, 2118c2ecf20Sopenharmony_ci struct ff_effect *effect) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci if (effect->type != FF_CONSTANT) { 2148c2ecf20Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 2158c2ecf20Sopenharmony_ci __func__); 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return old->u.constant.level != effect->u.constant.level; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* 2238c2ecf20Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an envelope 2248c2ecf20Sopenharmony_ci * parameter packet 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_cistatic int need_envelope_modifier(struct iforce *iforce, struct ff_effect *old, 2278c2ecf20Sopenharmony_ci struct ff_effect *effect) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci switch (effect->type) { 2308c2ecf20Sopenharmony_ci case FF_CONSTANT: 2318c2ecf20Sopenharmony_ci if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length 2328c2ecf20Sopenharmony_ci || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level 2338c2ecf20Sopenharmony_ci || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length 2348c2ecf20Sopenharmony_ci || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) 2358c2ecf20Sopenharmony_ci return 1; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case FF_PERIODIC: 2398c2ecf20Sopenharmony_ci if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length 2408c2ecf20Sopenharmony_ci || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level 2418c2ecf20Sopenharmony_ci || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length 2428c2ecf20Sopenharmony_ci || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) 2438c2ecf20Sopenharmony_ci return 1; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci default: 2478c2ecf20Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 2488c2ecf20Sopenharmony_ci __func__); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* 2558c2ecf20Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send a periodic 2568c2ecf20Sopenharmony_ci * parameter effect 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic int need_period_modifier(struct iforce *iforce, struct ff_effect *old, 2598c2ecf20Sopenharmony_ci struct ff_effect *new) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci if (new->type != FF_PERIODIC) { 2628c2ecf20Sopenharmony_ci dev_warn(&iforce->dev->dev, "bad effect type in %s\n", 2638c2ecf20Sopenharmony_ci __func__); 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci return (old->u.periodic.period != new->u.periodic.period 2678c2ecf20Sopenharmony_ci || old->u.periodic.magnitude != new->u.periodic.magnitude 2688c2ecf20Sopenharmony_ci || old->u.periodic.offset != new->u.periodic.offset 2698c2ecf20Sopenharmony_ci || old->u.periodic.phase != new->u.periodic.phase); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* 2738c2ecf20Sopenharmony_ci * Analyse the changes in an effect, and tell if we need to send an effect 2748c2ecf20Sopenharmony_ci * packet 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic int need_core(struct ff_effect *old, struct ff_effect *new) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci if (old->direction != new->direction 2798c2ecf20Sopenharmony_ci || old->trigger.button != new->trigger.button 2808c2ecf20Sopenharmony_ci || old->trigger.interval != new->trigger.interval 2818c2ecf20Sopenharmony_ci || old->replay.length != new->replay.length 2828c2ecf20Sopenharmony_ci || old->replay.delay != new->replay.delay) 2838c2ecf20Sopenharmony_ci return 1; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * Send the part common to all effects to the device 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, 2918c2ecf20Sopenharmony_ci u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, 2928c2ecf20Sopenharmony_ci u16 interval, u16 direction) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned char data[14]; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci duration = TIME_SCALE(duration); 2978c2ecf20Sopenharmony_ci delay = TIME_SCALE(delay); 2988c2ecf20Sopenharmony_ci interval = TIME_SCALE(interval); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci data[0] = LO(id); 3018c2ecf20Sopenharmony_ci data[1] = effect_type; 3028c2ecf20Sopenharmony_ci data[2] = LO(axes) | find_button(iforce, button); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci data[3] = LO(duration); 3058c2ecf20Sopenharmony_ci data[4] = HI(duration); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci data[5] = HI(direction); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci data[6] = LO(interval); 3108c2ecf20Sopenharmony_ci data[7] = HI(interval); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci data[8] = LO(mod_id1); 3138c2ecf20Sopenharmony_ci data[9] = HI(mod_id1); 3148c2ecf20Sopenharmony_ci data[10] = LO(mod_id2); 3158c2ecf20Sopenharmony_ci data[11] = HI(mod_id2); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci data[12] = LO(delay); 3188c2ecf20Sopenharmony_ci data[13] = HI(delay); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Stop effect */ 3218c2ecf20Sopenharmony_ci/* iforce_control_playback(iforce, id, 0);*/ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci iforce_send_packet(iforce, FF_CMD_EFFECT, data); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* If needed, restart effect */ 3268c2ecf20Sopenharmony_ci if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { 3278c2ecf20Sopenharmony_ci /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ 3288c2ecf20Sopenharmony_ci iforce_control_playback(iforce, id, 1); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * Upload a periodic effect to the device 3368c2ecf20Sopenharmony_ci * See also iforce_upload_constant. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ciint iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci u8 wave_code; 3418c2ecf20Sopenharmony_ci int core_id = effect->id; 3428c2ecf20Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 3438c2ecf20Sopenharmony_ci struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); 3448c2ecf20Sopenharmony_ci struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); 3458c2ecf20Sopenharmony_ci int param1_err = 1; 3468c2ecf20Sopenharmony_ci int param2_err = 1; 3478c2ecf20Sopenharmony_ci int core_err = 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!old || need_period_modifier(iforce, old, effect)) { 3508c2ecf20Sopenharmony_ci param1_err = make_period_modifier(iforce, mod1_chunk, 3518c2ecf20Sopenharmony_ci old != NULL, 3528c2ecf20Sopenharmony_ci effect->u.periodic.magnitude, effect->u.periodic.offset, 3538c2ecf20Sopenharmony_ci effect->u.periodic.period, effect->u.periodic.phase); 3548c2ecf20Sopenharmony_ci if (param1_err) 3558c2ecf20Sopenharmony_ci return param1_err; 3568c2ecf20Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!old || need_envelope_modifier(iforce, old, effect)) { 3608c2ecf20Sopenharmony_ci param2_err = make_envelope_modifier(iforce, mod2_chunk, 3618c2ecf20Sopenharmony_ci old !=NULL, 3628c2ecf20Sopenharmony_ci effect->u.periodic.envelope.attack_length, 3638c2ecf20Sopenharmony_ci effect->u.periodic.envelope.attack_level, 3648c2ecf20Sopenharmony_ci effect->u.periodic.envelope.fade_length, 3658c2ecf20Sopenharmony_ci effect->u.periodic.envelope.fade_level); 3668c2ecf20Sopenharmony_ci if (param2_err) 3678c2ecf20Sopenharmony_ci return param2_err; 3688c2ecf20Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci switch (effect->u.periodic.waveform) { 3728c2ecf20Sopenharmony_ci case FF_SQUARE: wave_code = 0x20; break; 3738c2ecf20Sopenharmony_ci case FF_TRIANGLE: wave_code = 0x21; break; 3748c2ecf20Sopenharmony_ci case FF_SINE: wave_code = 0x22; break; 3758c2ecf20Sopenharmony_ci case FF_SAW_UP: wave_code = 0x23; break; 3768c2ecf20Sopenharmony_ci case FF_SAW_DOWN: wave_code = 0x24; break; 3778c2ecf20Sopenharmony_ci default: wave_code = 0x20; break; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!old || need_core(old, effect)) { 3818c2ecf20Sopenharmony_ci core_err = make_core(iforce, effect->id, 3828c2ecf20Sopenharmony_ci mod1_chunk->start, 3838c2ecf20Sopenharmony_ci mod2_chunk->start, 3848c2ecf20Sopenharmony_ci wave_code, 3858c2ecf20Sopenharmony_ci 0x20, 3868c2ecf20Sopenharmony_ci effect->replay.length, 3878c2ecf20Sopenharmony_ci effect->replay.delay, 3888c2ecf20Sopenharmony_ci effect->trigger.button, 3898c2ecf20Sopenharmony_ci effect->trigger.interval, 3908c2ecf20Sopenharmony_ci effect->direction); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* If one of the parameter creation failed, we already returned an 3948c2ecf20Sopenharmony_ci * error code. 3958c2ecf20Sopenharmony_ci * If the core creation failed, we return its error code. 3968c2ecf20Sopenharmony_ci * Else: if one parameter at least was created, we return 0 3978c2ecf20Sopenharmony_ci * else we return 1; 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci return core_err < 0 ? core_err : (param1_err && param2_err); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/* 4038c2ecf20Sopenharmony_ci * Upload a constant force effect 4048c2ecf20Sopenharmony_ci * Return value: 4058c2ecf20Sopenharmony_ci * <0 Error code 4068c2ecf20Sopenharmony_ci * 0 Ok, effect created or updated 4078c2ecf20Sopenharmony_ci * 1 effect did not change since last upload, and no packet was therefore sent 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ciint iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int core_id = effect->id; 4128c2ecf20Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 4138c2ecf20Sopenharmony_ci struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); 4148c2ecf20Sopenharmony_ci struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); 4158c2ecf20Sopenharmony_ci int param1_err = 1; 4168c2ecf20Sopenharmony_ci int param2_err = 1; 4178c2ecf20Sopenharmony_ci int core_err = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!old || need_magnitude_modifier(iforce, old, effect)) { 4208c2ecf20Sopenharmony_ci param1_err = make_magnitude_modifier(iforce, mod1_chunk, 4218c2ecf20Sopenharmony_ci old != NULL, 4228c2ecf20Sopenharmony_ci effect->u.constant.level); 4238c2ecf20Sopenharmony_ci if (param1_err) 4248c2ecf20Sopenharmony_ci return param1_err; 4258c2ecf20Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (!old || need_envelope_modifier(iforce, old, effect)) { 4298c2ecf20Sopenharmony_ci param2_err = make_envelope_modifier(iforce, mod2_chunk, 4308c2ecf20Sopenharmony_ci old != NULL, 4318c2ecf20Sopenharmony_ci effect->u.constant.envelope.attack_length, 4328c2ecf20Sopenharmony_ci effect->u.constant.envelope.attack_level, 4338c2ecf20Sopenharmony_ci effect->u.constant.envelope.fade_length, 4348c2ecf20Sopenharmony_ci effect->u.constant.envelope.fade_level); 4358c2ecf20Sopenharmony_ci if (param2_err) 4368c2ecf20Sopenharmony_ci return param2_err; 4378c2ecf20Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!old || need_core(old, effect)) { 4418c2ecf20Sopenharmony_ci core_err = make_core(iforce, effect->id, 4428c2ecf20Sopenharmony_ci mod1_chunk->start, 4438c2ecf20Sopenharmony_ci mod2_chunk->start, 4448c2ecf20Sopenharmony_ci 0x00, 4458c2ecf20Sopenharmony_ci 0x20, 4468c2ecf20Sopenharmony_ci effect->replay.length, 4478c2ecf20Sopenharmony_ci effect->replay.delay, 4488c2ecf20Sopenharmony_ci effect->trigger.button, 4498c2ecf20Sopenharmony_ci effect->trigger.interval, 4508c2ecf20Sopenharmony_ci effect->direction); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* If one of the parameter creation failed, we already returned an 4548c2ecf20Sopenharmony_ci * error code. 4558c2ecf20Sopenharmony_ci * If the core creation failed, we return its error code. 4568c2ecf20Sopenharmony_ci * Else: if one parameter at least was created, we return 0 4578c2ecf20Sopenharmony_ci * else we return 1; 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci return core_err < 0 ? core_err : (param1_err && param2_err); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* 4638c2ecf20Sopenharmony_ci * Upload an condition effect. Those are for example friction, inertia, springs... 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ciint iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int core_id = effect->id; 4688c2ecf20Sopenharmony_ci struct iforce_core_effect* core_effect = iforce->core_effects + core_id; 4698c2ecf20Sopenharmony_ci struct resource* mod1_chunk = &(core_effect->mod1_chunk); 4708c2ecf20Sopenharmony_ci struct resource* mod2_chunk = &(core_effect->mod2_chunk); 4718c2ecf20Sopenharmony_ci u8 type; 4728c2ecf20Sopenharmony_ci int param_err = 1; 4738c2ecf20Sopenharmony_ci int core_err = 0; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci switch (effect->type) { 4768c2ecf20Sopenharmony_ci case FF_SPRING: type = 0x40; break; 4778c2ecf20Sopenharmony_ci case FF_DAMPER: type = 0x41; break; 4788c2ecf20Sopenharmony_ci default: return -1; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!old || need_condition_modifier(iforce, old, effect)) { 4828c2ecf20Sopenharmony_ci param_err = make_condition_modifier(iforce, mod1_chunk, 4838c2ecf20Sopenharmony_ci old != NULL, 4848c2ecf20Sopenharmony_ci effect->u.condition[0].right_saturation, 4858c2ecf20Sopenharmony_ci effect->u.condition[0].left_saturation, 4868c2ecf20Sopenharmony_ci effect->u.condition[0].right_coeff, 4878c2ecf20Sopenharmony_ci effect->u.condition[0].left_coeff, 4888c2ecf20Sopenharmony_ci effect->u.condition[0].deadband, 4898c2ecf20Sopenharmony_ci effect->u.condition[0].center); 4908c2ecf20Sopenharmony_ci if (param_err) 4918c2ecf20Sopenharmony_ci return param_err; 4928c2ecf20Sopenharmony_ci set_bit(FF_MOD1_IS_USED, core_effect->flags); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci param_err = make_condition_modifier(iforce, mod2_chunk, 4958c2ecf20Sopenharmony_ci old != NULL, 4968c2ecf20Sopenharmony_ci effect->u.condition[1].right_saturation, 4978c2ecf20Sopenharmony_ci effect->u.condition[1].left_saturation, 4988c2ecf20Sopenharmony_ci effect->u.condition[1].right_coeff, 4998c2ecf20Sopenharmony_ci effect->u.condition[1].left_coeff, 5008c2ecf20Sopenharmony_ci effect->u.condition[1].deadband, 5018c2ecf20Sopenharmony_ci effect->u.condition[1].center); 5028c2ecf20Sopenharmony_ci if (param_err) 5038c2ecf20Sopenharmony_ci return param_err; 5048c2ecf20Sopenharmony_ci set_bit(FF_MOD2_IS_USED, core_effect->flags); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (!old || need_core(old, effect)) { 5098c2ecf20Sopenharmony_ci core_err = make_core(iforce, effect->id, 5108c2ecf20Sopenharmony_ci mod1_chunk->start, mod2_chunk->start, 5118c2ecf20Sopenharmony_ci type, 0xc0, 5128c2ecf20Sopenharmony_ci effect->replay.length, effect->replay.delay, 5138c2ecf20Sopenharmony_ci effect->trigger.button, effect->trigger.interval, 5148c2ecf20Sopenharmony_ci effect->direction); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* If the parameter creation failed, we already returned an 5188c2ecf20Sopenharmony_ci * error code. 5198c2ecf20Sopenharmony_ci * If the core creation failed, we return its error code. 5208c2ecf20Sopenharmony_ci * Else: if a parameter was created, we return 0 5218c2ecf20Sopenharmony_ci * else we return 1; 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci return core_err < 0 ? core_err : param_err; 5248c2ecf20Sopenharmony_ci} 525