Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
1da177e4 | 3 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> |
598972d4 | 4 | * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com> |
1da177e4 LT |
5 | * |
6 | * USB/RS232 I-Force joysticks and wheels. | |
7 | */ | |
8 | ||
1da177e4 LT |
9 | #include "iforce.h" |
10 | ||
11 | /* | |
12 | * Set the magnitude of a constant force effect | |
13 | * Return error code | |
14 | * | |
15 | * Note: caller must ensure exclusive access to device | |
16 | */ | |
17 | ||
18 | static int make_magnitude_modifier(struct iforce* iforce, | |
19 | struct resource* mod_chunk, int no_alloc, __s16 level) | |
20 | { | |
21 | unsigned char data[3]; | |
22 | ||
23 | if (!no_alloc) { | |
72ba9f0c | 24 | mutex_lock(&iforce->mem_mutex); |
1da177e4 LT |
25 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, |
26 | iforce->device_memory.start, iforce->device_memory.end, 2L, | |
27 | NULL, NULL)) { | |
72ba9f0c | 28 | mutex_unlock(&iforce->mem_mutex); |
fe65b97a | 29 | return -ENOSPC; |
1da177e4 | 30 | } |
72ba9f0c | 31 | mutex_unlock(&iforce->mem_mutex); |
1da177e4 LT |
32 | } |
33 | ||
34 | data[0] = LO(mod_chunk->start); | |
35 | data[1] = HI(mod_chunk->start); | |
36 | data[2] = HIFIX80(level); | |
37 | ||
38 | iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); | |
39 | ||
305180bc | 40 | iforce_dump_packet(iforce, "magnitude", FF_CMD_MAGNITUDE, data); |
1da177e4 LT |
41 | return 0; |
42 | } | |
43 | ||
44 | /* | |
45 | * Upload the component of an effect dealing with the period, phase and magnitude | |
46 | */ | |
47 | ||
48 | static int make_period_modifier(struct iforce* iforce, | |
49 | struct resource* mod_chunk, int no_alloc, | |
50 | __s16 magnitude, __s16 offset, u16 period, u16 phase) | |
51 | { | |
52 | unsigned char data[7]; | |
53 | ||
54 | period = TIME_SCALE(period); | |
55 | ||
56 | if (!no_alloc) { | |
72ba9f0c | 57 | mutex_lock(&iforce->mem_mutex); |
1da177e4 LT |
58 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, |
59 | iforce->device_memory.start, iforce->device_memory.end, 2L, | |
60 | NULL, NULL)) { | |
72ba9f0c | 61 | mutex_unlock(&iforce->mem_mutex); |
fe65b97a | 62 | return -ENOSPC; |
1da177e4 | 63 | } |
72ba9f0c | 64 | mutex_unlock(&iforce->mem_mutex); |
1da177e4 LT |
65 | } |
66 | ||
67 | data[0] = LO(mod_chunk->start); | |
68 | data[1] = HI(mod_chunk->start); | |
69 | ||
70 | data[2] = HIFIX80(magnitude); | |
71 | data[3] = HIFIX80(offset); | |
72 | data[4] = HI(phase); | |
73 | ||
74 | data[5] = LO(period); | |
75 | data[6] = HI(period); | |
76 | ||
77 | iforce_send_packet(iforce, FF_CMD_PERIOD, data); | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
82 | /* | |
83 | * Uploads the part of an effect setting the envelope of the force | |
84 | */ | |
85 | ||
86 | static int make_envelope_modifier(struct iforce* iforce, | |
87 | struct resource* mod_chunk, int no_alloc, | |
88 | u16 attack_duration, __s16 initial_level, | |
89 | u16 fade_duration, __s16 final_level) | |
90 | { | |
91 | unsigned char data[8]; | |
92 | ||
93 | attack_duration = TIME_SCALE(attack_duration); | |
94 | fade_duration = TIME_SCALE(fade_duration); | |
95 | ||
96 | if (!no_alloc) { | |
72ba9f0c | 97 | mutex_lock(&iforce->mem_mutex); |
1da177e4 LT |
98 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, |
99 | iforce->device_memory.start, iforce->device_memory.end, 2L, | |
100 | NULL, NULL)) { | |
72ba9f0c | 101 | mutex_unlock(&iforce->mem_mutex); |
fe65b97a | 102 | return -ENOSPC; |
1da177e4 | 103 | } |
72ba9f0c | 104 | mutex_unlock(&iforce->mem_mutex); |
1da177e4 LT |
105 | } |
106 | ||
107 | data[0] = LO(mod_chunk->start); | |
108 | data[1] = HI(mod_chunk->start); | |
109 | ||
110 | data[2] = LO(attack_duration); | |
111 | data[3] = HI(attack_duration); | |
112 | data[4] = HI(initial_level); | |
113 | ||
114 | data[5] = LO(fade_duration); | |
115 | data[6] = HI(fade_duration); | |
116 | data[7] = HI(final_level); | |
117 | ||
118 | iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); | |
119 | ||
120 | return 0; | |
121 | } | |
122 | ||
123 | /* | |
124 | * Component of spring, friction, inertia... effects | |
125 | */ | |
126 | ||
127 | static int make_condition_modifier(struct iforce* iforce, | |
128 | struct resource* mod_chunk, int no_alloc, | |
129 | __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) | |
130 | { | |
131 | unsigned char data[10]; | |
132 | ||
133 | if (!no_alloc) { | |
72ba9f0c | 134 | mutex_lock(&iforce->mem_mutex); |
1da177e4 LT |
135 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, |
136 | iforce->device_memory.start, iforce->device_memory.end, 2L, | |
137 | NULL, NULL)) { | |
72ba9f0c | 138 | mutex_unlock(&iforce->mem_mutex); |
fe65b97a | 139 | return -ENOSPC; |
1da177e4 | 140 | } |
72ba9f0c | 141 | mutex_unlock(&iforce->mem_mutex); |
1da177e4 LT |
142 | } |
143 | ||
144 | data[0] = LO(mod_chunk->start); | |
145 | data[1] = HI(mod_chunk->start); | |
146 | ||
f6a01c85 AH |
147 | data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ |
148 | data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */ | |
1da177e4 | 149 | |
f6a01c85 | 150 | center = (500 * center) >> 15; |
1da177e4 LT |
151 | data[4] = LO(center); |
152 | data[5] = HI(center); | |
153 | ||
f6a01c85 | 154 | db = (1000 * db) >> 16; |
1da177e4 LT |
155 | data[6] = LO(db); |
156 | data[7] = HI(db); | |
157 | ||
f6a01c85 AH |
158 | data[8] = (100 * rsat) >> 16; |
159 | data[9] = (100 * lsat) >> 16; | |
1da177e4 LT |
160 | |
161 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); | |
305180bc | 162 | iforce_dump_packet(iforce, "condition", FF_CMD_CONDITION, data); |
1da177e4 LT |
163 | |
164 | return 0; | |
165 | } | |
166 | ||
167 | static unsigned char find_button(struct iforce *iforce, signed short button) | |
168 | { | |
169 | int i; | |
f6a01c85 | 170 | |
1da177e4 LT |
171 | for (i = 1; iforce->type->btn[i] >= 0; i++) |
172 | if (iforce->type->btn[i] == button) | |
173 | return i + 1; | |
174 | return 0; | |
175 | } | |
176 | ||
177 | /* | |
178 | * Analyse the changes in an effect, and tell if we need to send an condition | |
179 | * parameter packet | |
180 | */ | |
1817b169 GKH |
181 | static int need_condition_modifier(struct iforce *iforce, |
182 | struct ff_effect *old, | |
183 | struct ff_effect *new) | |
1da177e4 | 184 | { |
f6a01c85 | 185 | int ret = 0; |
1da177e4 LT |
186 | int i; |
187 | ||
188 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { | |
1817b169 GKH |
189 | dev_warn(&iforce->dev->dev, "bad effect type in %s\n", |
190 | __func__); | |
f6a01c85 | 191 | return 0; |
1da177e4 LT |
192 | } |
193 | ||
f6a01c85 | 194 | for (i = 0; i < 2; i++) { |
1da177e4 LT |
195 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation |
196 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | |
197 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | |
198 | || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff | |
199 | || old->u.condition[i].deadband != new->u.condition[i].deadband | |
200 | || old->u.condition[i].center != new->u.condition[i].center; | |
201 | } | |
202 | return ret; | |
203 | } | |
204 | ||
205 | /* | |
206 | * Analyse the changes in an effect, and tell if we need to send a magnitude | |
207 | * parameter packet | |
208 | */ | |
1817b169 GKH |
209 | static int need_magnitude_modifier(struct iforce *iforce, |
210 | struct ff_effect *old, | |
211 | struct ff_effect *effect) | |
1da177e4 | 212 | { |
1da177e4 | 213 | if (effect->type != FF_CONSTANT) { |
1817b169 GKH |
214 | dev_warn(&iforce->dev->dev, "bad effect type in %s\n", |
215 | __func__); | |
f6a01c85 | 216 | return 0; |
1da177e4 LT |
217 | } |
218 | ||
f6a01c85 | 219 | return old->u.constant.level != effect->u.constant.level; |
1da177e4 LT |
220 | } |
221 | ||
222 | /* | |
223 | * Analyse the changes in an effect, and tell if we need to send an envelope | |
224 | * parameter packet | |
225 | */ | |
1817b169 GKH |
226 | static int need_envelope_modifier(struct iforce *iforce, struct ff_effect *old, |
227 | struct ff_effect *effect) | |
1da177e4 | 228 | { |
1da177e4 LT |
229 | switch (effect->type) { |
230 | case FF_CONSTANT: | |
231 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | |
232 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | |
233 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | |
234 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | |
f6a01c85 | 235 | return 1; |
1da177e4 LT |
236 | break; |
237 | ||
238 | case FF_PERIODIC: | |
239 | if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length | |
240 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | |
241 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | |
242 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | |
f6a01c85 | 243 | return 1; |
1da177e4 LT |
244 | break; |
245 | ||
246 | default: | |
1817b169 GKH |
247 | dev_warn(&iforce->dev->dev, "bad effect type in %s\n", |
248 | __func__); | |
1da177e4 LT |
249 | } |
250 | ||
f6a01c85 | 251 | return 0; |
1da177e4 LT |
252 | } |
253 | ||
254 | /* | |
255 | * Analyse the changes in an effect, and tell if we need to send a periodic | |
256 | * parameter effect | |
257 | */ | |
1817b169 GKH |
258 | static int need_period_modifier(struct iforce *iforce, struct ff_effect *old, |
259 | struct ff_effect *new) | |
1da177e4 | 260 | { |
1da177e4 | 261 | if (new->type != FF_PERIODIC) { |
1817b169 GKH |
262 | dev_warn(&iforce->dev->dev, "bad effect type in %s\n", |
263 | __func__); | |
f6a01c85 | 264 | return 0; |
1da177e4 | 265 | } |
1da177e4 LT |
266 | return (old->u.periodic.period != new->u.periodic.period |
267 | || old->u.periodic.magnitude != new->u.periodic.magnitude | |
268 | || old->u.periodic.offset != new->u.periodic.offset | |
269 | || old->u.periodic.phase != new->u.periodic.phase); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Analyse the changes in an effect, and tell if we need to send an effect | |
274 | * packet | |
275 | */ | |
f6a01c85 | 276 | static int need_core(struct ff_effect *old, struct ff_effect *new) |
1da177e4 | 277 | { |
1da177e4 LT |
278 | if (old->direction != new->direction |
279 | || old->trigger.button != new->trigger.button | |
280 | || old->trigger.interval != new->trigger.interval | |
281 | || old->replay.length != new->replay.length | |
282 | || old->replay.delay != new->replay.delay) | |
f6a01c85 | 283 | return 1; |
1da177e4 | 284 | |
f6a01c85 | 285 | return 0; |
1da177e4 LT |
286 | } |
287 | /* | |
288 | * Send the part common to all effects to the device | |
289 | */ | |
290 | static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | |
291 | u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, | |
292 | u16 interval, u16 direction) | |
293 | { | |
294 | unsigned char data[14]; | |
295 | ||
296 | duration = TIME_SCALE(duration); | |
297 | delay = TIME_SCALE(delay); | |
298 | interval = TIME_SCALE(interval); | |
299 | ||
300 | data[0] = LO(id); | |
301 | data[1] = effect_type; | |
302 | data[2] = LO(axes) | find_button(iforce, button); | |
303 | ||
304 | data[3] = LO(duration); | |
305 | data[4] = HI(duration); | |
306 | ||
307 | data[5] = HI(direction); | |
308 | ||
309 | data[6] = LO(interval); | |
310 | data[7] = HI(interval); | |
311 | ||
312 | data[8] = LO(mod_id1); | |
313 | data[9] = HI(mod_id1); | |
314 | data[10] = LO(mod_id2); | |
315 | data[11] = HI(mod_id2); | |
316 | ||
317 | data[12] = LO(delay); | |
318 | data[13] = HI(delay); | |
319 | ||
320 | /* Stop effect */ | |
321 | /* iforce_control_playback(iforce, id, 0);*/ | |
322 | ||
323 | iforce_send_packet(iforce, FF_CMD_EFFECT, data); | |
324 | ||
325 | /* If needed, restart effect */ | |
326 | if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { | |
327 | /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ | |
328 | iforce_control_playback(iforce, id, 1); | |
329 | } | |
330 | ||
331 | return 0; | |
332 | } | |
333 | ||
334 | /* | |
335 | * Upload a periodic effect to the device | |
336 | * See also iforce_upload_constant. | |
337 | */ | |
f6a01c85 | 338 | int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
1da177e4 LT |
339 | { |
340 | u8 wave_code; | |
341 | int core_id = effect->id; | |
342 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
343 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
344 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
345 | int param1_err = 1; | |
346 | int param2_err = 1; | |
347 | int core_err = 0; | |
348 | ||
1817b169 | 349 | if (!old || need_period_modifier(iforce, old, effect)) { |
1da177e4 | 350 | param1_err = make_period_modifier(iforce, mod1_chunk, |
f6a01c85 | 351 | old != NULL, |
1da177e4 LT |
352 | effect->u.periodic.magnitude, effect->u.periodic.offset, |
353 | effect->u.periodic.period, effect->u.periodic.phase); | |
f6a01c85 AH |
354 | if (param1_err) |
355 | return param1_err; | |
1da177e4 LT |
356 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
357 | } | |
358 | ||
1817b169 | 359 | if (!old || need_envelope_modifier(iforce, old, effect)) { |
1da177e4 | 360 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
f6a01c85 | 361 | old !=NULL, |
1da177e4 LT |
362 | effect->u.periodic.envelope.attack_length, |
363 | effect->u.periodic.envelope.attack_level, | |
364 | effect->u.periodic.envelope.fade_length, | |
365 | effect->u.periodic.envelope.fade_level); | |
f6a01c85 AH |
366 | if (param2_err) |
367 | return param2_err; | |
1da177e4 LT |
368 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
369 | } | |
370 | ||
371 | switch (effect->u.periodic.waveform) { | |
43e61fc7 DT |
372 | case FF_SQUARE: wave_code = 0x20; break; |
373 | case FF_TRIANGLE: wave_code = 0x21; break; | |
374 | case FF_SINE: wave_code = 0x22; break; | |
375 | case FF_SAW_UP: wave_code = 0x23; break; | |
376 | case FF_SAW_DOWN: wave_code = 0x24; break; | |
377 | default: wave_code = 0x20; break; | |
1da177e4 LT |
378 | } |
379 | ||
f6a01c85 | 380 | if (!old || need_core(old, effect)) { |
1da177e4 LT |
381 | core_err = make_core(iforce, effect->id, |
382 | mod1_chunk->start, | |
383 | mod2_chunk->start, | |
384 | wave_code, | |
385 | 0x20, | |
386 | effect->replay.length, | |
387 | effect->replay.delay, | |
388 | effect->trigger.button, | |
389 | effect->trigger.interval, | |
390 | effect->direction); | |
391 | } | |
392 | ||
393 | /* If one of the parameter creation failed, we already returned an | |
394 | * error code. | |
395 | * If the core creation failed, we return its error code. | |
396 | * Else: if one parameter at least was created, we return 0 | |
397 | * else we return 1; | |
398 | */ | |
399 | return core_err < 0 ? core_err : (param1_err && param2_err); | |
400 | } | |
401 | ||
402 | /* | |
403 | * Upload a constant force effect | |
404 | * Return value: | |
405 | * <0 Error code | |
406 | * 0 Ok, effect created or updated | |
407 | * 1 effect did not change since last upload, and no packet was therefore sent | |
408 | */ | |
f6a01c85 | 409 | int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
1da177e4 LT |
410 | { |
411 | int core_id = effect->id; | |
412 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
413 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
414 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
415 | int param1_err = 1; | |
416 | int param2_err = 1; | |
417 | int core_err = 0; | |
418 | ||
1817b169 | 419 | if (!old || need_magnitude_modifier(iforce, old, effect)) { |
1da177e4 | 420 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, |
f6a01c85 | 421 | old != NULL, |
1da177e4 | 422 | effect->u.constant.level); |
f6a01c85 AH |
423 | if (param1_err) |
424 | return param1_err; | |
1da177e4 LT |
425 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
426 | } | |
427 | ||
1817b169 | 428 | if (!old || need_envelope_modifier(iforce, old, effect)) { |
1da177e4 | 429 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
f6a01c85 | 430 | old != NULL, |
1da177e4 LT |
431 | effect->u.constant.envelope.attack_length, |
432 | effect->u.constant.envelope.attack_level, | |
433 | effect->u.constant.envelope.fade_length, | |
434 | effect->u.constant.envelope.fade_level); | |
f6a01c85 AH |
435 | if (param2_err) |
436 | return param2_err; | |
1da177e4 LT |
437 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
438 | } | |
439 | ||
f6a01c85 | 440 | if (!old || need_core(old, effect)) { |
1da177e4 LT |
441 | core_err = make_core(iforce, effect->id, |
442 | mod1_chunk->start, | |
443 | mod2_chunk->start, | |
444 | 0x00, | |
445 | 0x20, | |
446 | effect->replay.length, | |
447 | effect->replay.delay, | |
448 | effect->trigger.button, | |
449 | effect->trigger.interval, | |
450 | effect->direction); | |
451 | } | |
452 | ||
453 | /* If one of the parameter creation failed, we already returned an | |
454 | * error code. | |
455 | * If the core creation failed, we return its error code. | |
456 | * Else: if one parameter at least was created, we return 0 | |
457 | * else we return 1; | |
458 | */ | |
459 | return core_err < 0 ? core_err : (param1_err && param2_err); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Upload an condition effect. Those are for example friction, inertia, springs... | |
464 | */ | |
f6a01c85 | 465 | int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
1da177e4 LT |
466 | { |
467 | int core_id = effect->id; | |
468 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
469 | struct resource* mod1_chunk = &(core_effect->mod1_chunk); | |
470 | struct resource* mod2_chunk = &(core_effect->mod2_chunk); | |
471 | u8 type; | |
472 | int param_err = 1; | |
473 | int core_err = 0; | |
474 | ||
475 | switch (effect->type) { | |
43e61fc7 DT |
476 | case FF_SPRING: type = 0x40; break; |
477 | case FF_DAMPER: type = 0x41; break; | |
478 | default: return -1; | |
1da177e4 LT |
479 | } |
480 | ||
1817b169 | 481 | if (!old || need_condition_modifier(iforce, old, effect)) { |
1da177e4 | 482 | param_err = make_condition_modifier(iforce, mod1_chunk, |
f6a01c85 | 483 | old != NULL, |
1da177e4 LT |
484 | effect->u.condition[0].right_saturation, |
485 | effect->u.condition[0].left_saturation, | |
486 | effect->u.condition[0].right_coeff, | |
487 | effect->u.condition[0].left_coeff, | |
488 | effect->u.condition[0].deadband, | |
489 | effect->u.condition[0].center); | |
f6a01c85 AH |
490 | if (param_err) |
491 | return param_err; | |
1da177e4 LT |
492 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
493 | ||
494 | param_err = make_condition_modifier(iforce, mod2_chunk, | |
f6a01c85 | 495 | old != NULL, |
1da177e4 LT |
496 | effect->u.condition[1].right_saturation, |
497 | effect->u.condition[1].left_saturation, | |
498 | effect->u.condition[1].right_coeff, | |
499 | effect->u.condition[1].left_coeff, | |
500 | effect->u.condition[1].deadband, | |
501 | effect->u.condition[1].center); | |
f6a01c85 AH |
502 | if (param_err) |
503 | return param_err; | |
1da177e4 LT |
504 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
505 | ||
506 | } | |
507 | ||
f6a01c85 | 508 | if (!old || need_core(old, effect)) { |
1da177e4 LT |
509 | core_err = make_core(iforce, effect->id, |
510 | mod1_chunk->start, mod2_chunk->start, | |
511 | type, 0xc0, | |
512 | effect->replay.length, effect->replay.delay, | |
513 | effect->trigger.button, effect->trigger.interval, | |
514 | effect->direction); | |
515 | } | |
516 | ||
517 | /* If the parameter creation failed, we already returned an | |
518 | * error code. | |
519 | * If the core creation failed, we return its error code. | |
520 | * Else: if a parameter was created, we return 0 | |
521 | * else we return 1; | |
522 | */ | |
523 | return core_err < 0 ? core_err : param_err; | |
524 | } |