]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
f30c2269 | 2 | * sound/oss/midi_synth.c |
1da177e4 LT |
3 | * |
4 | * High level midi sequencer manager for dumb MIDI interfaces. | |
5 | */ | |
6 | /* | |
7 | * Copyright (C) by Hannu Savolainen 1993-1997 | |
8 | * | |
9 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | |
10 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | |
11 | * for more info. | |
12 | */ | |
13 | /* | |
14 | * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) | |
15 | * Andrew Veliath : fixed running status in MIDI input state machine | |
16 | */ | |
17 | #define USE_SEQ_MACROS | |
18 | #define USE_SIMPLE_MACROS | |
19 | ||
20 | #include "sound_config.h" | |
21 | ||
22 | #define _MIDI_SYNTH_C_ | |
23 | ||
24 | #include "midi_synth.h" | |
25 | ||
26 | static int midi2synth[MAX_MIDI_DEV]; | |
27 | static int sysex_state[MAX_MIDI_DEV] = | |
28 | {0}; | |
29 | static unsigned char prev_out_status[MAX_MIDI_DEV]; | |
30 | ||
31 | #define STORE(cmd) \ | |
32 | { \ | |
33 | int len; \ | |
34 | unsigned char obuf[8]; \ | |
35 | cmd; \ | |
36 | seq_input_event(obuf, len); \ | |
37 | } | |
38 | ||
39 | #define _seqbuf obuf | |
40 | #define _seqbufptr 0 | |
41 | #define _SEQ_ADVBUF(x) len=x | |
42 | ||
43 | void | |
44 | do_midi_msg(int synthno, unsigned char *msg, int mlen) | |
45 | { | |
46 | switch (msg[0] & 0xf0) | |
47 | { | |
48 | case 0x90: | |
49 | if (msg[2] != 0) | |
50 | { | |
51 | STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | |
52 | break; | |
53 | } | |
54 | msg[2] = 64; | |
55 | ||
56 | case 0x80: | |
57 | STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | |
58 | break; | |
59 | ||
60 | case 0xA0: | |
61 | STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | |
62 | break; | |
63 | ||
64 | case 0xB0: | |
65 | STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, | |
66 | msg[1], msg[2])); | |
67 | break; | |
68 | ||
69 | case 0xC0: | |
70 | STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); | |
71 | break; | |
72 | ||
73 | case 0xD0: | |
74 | STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); | |
75 | break; | |
76 | ||
77 | case 0xE0: | |
78 | STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, | |
79 | (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); | |
80 | break; | |
81 | ||
82 | default: | |
83 | /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ | |
84 | ; | |
85 | } | |
86 | } | |
ece7f77b | 87 | EXPORT_SYMBOL(do_midi_msg); |
1da177e4 LT |
88 | |
89 | static void | |
90 | midi_outc(int midi_dev, int data) | |
91 | { | |
92 | int timeout; | |
93 | ||
94 | for (timeout = 0; timeout < 3200; timeout++) | |
95 | if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) | |
96 | { | |
97 | if (data & 0x80) /* | |
98 | * Status byte | |
99 | */ | |
100 | prev_out_status[midi_dev] = | |
101 | (unsigned char) (data & 0xff); /* | |
102 | * Store for running status | |
103 | */ | |
104 | return; /* | |
105 | * Mission complete | |
106 | */ | |
107 | } | |
108 | /* | |
109 | * Sorry! No space on buffers. | |
110 | */ | |
111 | printk("Midi send timed out\n"); | |
112 | } | |
113 | ||
114 | static int | |
115 | prefix_cmd(int midi_dev, unsigned char status) | |
116 | { | |
117 | if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) | |
118 | return 1; | |
119 | ||
120 | return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); | |
121 | } | |
122 | ||
123 | static void | |
124 | midi_synth_input(int orig_dev, unsigned char data) | |
125 | { | |
126 | int dev; | |
127 | struct midi_input_info *inc; | |
128 | ||
129 | static unsigned char len_tab[] = /* # of data bytes following a status | |
130 | */ | |
131 | { | |
132 | 2, /* 8x */ | |
133 | 2, /* 9x */ | |
134 | 2, /* Ax */ | |
135 | 2, /* Bx */ | |
136 | 1, /* Cx */ | |
137 | 1, /* Dx */ | |
138 | 2, /* Ex */ | |
139 | 0 /* Fx */ | |
140 | }; | |
141 | ||
142 | if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) | |
143 | return; | |
144 | ||
145 | if (data == 0xfe) /* Ignore active sensing */ | |
146 | return; | |
147 | ||
148 | dev = midi2synth[orig_dev]; | |
149 | inc = &midi_devs[orig_dev]->in_info; | |
150 | ||
151 | switch (inc->m_state) | |
152 | { | |
153 | case MST_INIT: | |
154 | if (data & 0x80) /* MIDI status byte */ | |
155 | { | |
156 | if ((data & 0xf0) == 0xf0) /* Common message */ | |
157 | { | |
158 | switch (data) | |
159 | { | |
160 | case 0xf0: /* Sysex */ | |
161 | inc->m_state = MST_SYSEX; | |
162 | break; /* Sysex */ | |
163 | ||
164 | case 0xf1: /* MTC quarter frame */ | |
165 | case 0xf3: /* Song select */ | |
166 | inc->m_state = MST_DATA; | |
167 | inc->m_ptr = 1; | |
168 | inc->m_left = 1; | |
169 | inc->m_buf[0] = data; | |
170 | break; | |
171 | ||
172 | case 0xf2: /* Song position pointer */ | |
173 | inc->m_state = MST_DATA; | |
174 | inc->m_ptr = 1; | |
175 | inc->m_left = 2; | |
176 | inc->m_buf[0] = data; | |
177 | break; | |
178 | ||
179 | default: | |
180 | inc->m_buf[0] = data; | |
181 | inc->m_ptr = 1; | |
182 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | |
183 | inc->m_ptr = 0; | |
184 | inc->m_left = 0; | |
185 | } | |
186 | } else | |
187 | { | |
188 | inc->m_state = MST_DATA; | |
189 | inc->m_ptr = 1; | |
190 | inc->m_left = len_tab[(data >> 4) - 8]; | |
191 | inc->m_buf[0] = inc->m_prev_status = data; | |
192 | } | |
193 | } else if (inc->m_prev_status & 0x80) { | |
194 | /* Data byte (use running status) */ | |
195 | inc->m_ptr = 2; | |
196 | inc->m_buf[1] = data; | |
197 | inc->m_buf[0] = inc->m_prev_status; | |
198 | inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; | |
199 | if (inc->m_left > 0) | |
200 | inc->m_state = MST_DATA; /* Not done yet */ | |
201 | else { | |
202 | inc->m_state = MST_INIT; | |
203 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | |
204 | inc->m_ptr = 0; | |
205 | } | |
206 | } | |
207 | break; /* MST_INIT */ | |
208 | ||
209 | case MST_DATA: | |
210 | inc->m_buf[inc->m_ptr++] = data; | |
211 | if (--inc->m_left <= 0) | |
212 | { | |
213 | inc->m_state = MST_INIT; | |
214 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | |
215 | inc->m_ptr = 0; | |
216 | } | |
217 | break; /* MST_DATA */ | |
218 | ||
219 | case MST_SYSEX: | |
220 | if (data == 0xf7) /* Sysex end */ | |
221 | { | |
222 | inc->m_state = MST_INIT; | |
223 | inc->m_left = 0; | |
224 | inc->m_ptr = 0; | |
225 | } | |
226 | break; /* MST_SYSEX */ | |
227 | ||
228 | default: | |
229 | printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); | |
230 | inc->m_state = MST_INIT; | |
231 | } | |
232 | } | |
233 | ||
234 | static void | |
235 | leave_sysex(int dev) | |
236 | { | |
237 | int orig_dev = synth_devs[dev]->midi_dev; | |
238 | int timeout = 0; | |
239 | ||
240 | if (!sysex_state[dev]) | |
241 | return; | |
242 | ||
243 | sysex_state[dev] = 0; | |
244 | ||
245 | while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && | |
246 | timeout < 1000) | |
247 | timeout++; | |
248 | ||
249 | sysex_state[dev] = 0; | |
250 | } | |
251 | ||
252 | static void | |
253 | midi_synth_output(int dev) | |
254 | { | |
255 | /* | |
256 | * Currently NOP | |
257 | */ | |
258 | } | |
259 | ||
260 | int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg) | |
261 | { | |
262 | /* | |
263 | * int orig_dev = synth_devs[dev]->midi_dev; | |
264 | */ | |
265 | ||
266 | switch (cmd) { | |
267 | ||
268 | case SNDCTL_SYNTH_INFO: | |
269 | if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) | |
270 | return -EFAULT; | |
271 | return 0; | |
272 | ||
273 | case SNDCTL_SYNTH_MEMAVL: | |
274 | return 0x7fffffff; | |
275 | ||
276 | default: | |
277 | return -EINVAL; | |
278 | } | |
279 | } | |
ece7f77b | 280 | EXPORT_SYMBOL(midi_synth_ioctl); |
1da177e4 LT |
281 | |
282 | int | |
283 | midi_synth_kill_note(int dev, int channel, int note, int velocity) | |
284 | { | |
285 | int orig_dev = synth_devs[dev]->midi_dev; | |
286 | int msg, chn; | |
287 | ||
288 | if (note < 0 || note > 127) | |
289 | return 0; | |
290 | if (channel < 0 || channel > 15) | |
291 | return 0; | |
292 | if (velocity < 0) | |
293 | velocity = 0; | |
294 | if (velocity > 127) | |
295 | velocity = 127; | |
296 | ||
297 | leave_sysex(dev); | |
298 | ||
299 | msg = prev_out_status[orig_dev] & 0xf0; | |
300 | chn = prev_out_status[orig_dev] & 0x0f; | |
301 | ||
302 | if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) | |
303 | { /* | |
304 | * Use running status | |
305 | */ | |
306 | if (!prefix_cmd(orig_dev, note)) | |
307 | return 0; | |
308 | ||
309 | midi_outc(orig_dev, note); | |
310 | ||
311 | if (msg == 0x90) /* | |
312 | * Running status = Note on | |
313 | */ | |
314 | midi_outc(orig_dev, 0); /* | |
315 | * Note on with velocity 0 == note | |
316 | * off | |
317 | */ | |
318 | else | |
319 | midi_outc(orig_dev, velocity); | |
320 | } else | |
321 | { | |
322 | if (velocity == 64) | |
323 | { | |
324 | if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) | |
325 | return 0; | |
326 | midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* | |
327 | * Note on | |
328 | */ | |
329 | midi_outc(orig_dev, note); | |
330 | midi_outc(orig_dev, 0); /* | |
331 | * Zero G | |
332 | */ | |
333 | } else | |
334 | { | |
335 | if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) | |
336 | return 0; | |
337 | midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* | |
338 | * Note off | |
339 | */ | |
340 | midi_outc(orig_dev, note); | |
341 | midi_outc(orig_dev, velocity); | |
342 | } | |
343 | } | |
344 | ||
345 | return 0; | |
346 | } | |
ece7f77b | 347 | EXPORT_SYMBOL(midi_synth_kill_note); |
1da177e4 LT |
348 | |
349 | int | |
350 | midi_synth_set_instr(int dev, int channel, int instr_no) | |
351 | { | |
352 | int orig_dev = synth_devs[dev]->midi_dev; | |
353 | ||
354 | if (instr_no < 0 || instr_no > 127) | |
355 | instr_no = 0; | |
356 | if (channel < 0 || channel > 15) | |
357 | return 0; | |
358 | ||
359 | leave_sysex(dev); | |
360 | ||
361 | if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f))) | |
362 | return 0; | |
363 | midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* | |
364 | * Program change | |
365 | */ | |
366 | midi_outc(orig_dev, instr_no); | |
367 | ||
368 | return 0; | |
369 | } | |
ece7f77b | 370 | EXPORT_SYMBOL(midi_synth_set_instr); |
1da177e4 LT |
371 | |
372 | int | |
373 | midi_synth_start_note(int dev, int channel, int note, int velocity) | |
374 | { | |
375 | int orig_dev = synth_devs[dev]->midi_dev; | |
376 | int msg, chn; | |
377 | ||
378 | if (note < 0 || note > 127) | |
379 | return 0; | |
380 | if (channel < 0 || channel > 15) | |
381 | return 0; | |
382 | if (velocity < 0) | |
383 | velocity = 0; | |
384 | if (velocity > 127) | |
385 | velocity = 127; | |
386 | ||
387 | leave_sysex(dev); | |
388 | ||
389 | msg = prev_out_status[orig_dev] & 0xf0; | |
390 | chn = prev_out_status[orig_dev] & 0x0f; | |
391 | ||
392 | if (chn == channel && msg == 0x90) | |
393 | { /* | |
394 | * Use running status | |
395 | */ | |
396 | if (!prefix_cmd(orig_dev, note)) | |
397 | return 0; | |
398 | midi_outc(orig_dev, note); | |
399 | midi_outc(orig_dev, velocity); | |
400 | } else | |
401 | { | |
402 | if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) | |
403 | return 0; | |
404 | midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* | |
405 | * Note on | |
406 | */ | |
407 | midi_outc(orig_dev, note); | |
408 | midi_outc(orig_dev, velocity); | |
409 | } | |
410 | return 0; | |
411 | } | |
ece7f77b | 412 | EXPORT_SYMBOL(midi_synth_start_note); |
1da177e4 LT |
413 | |
414 | void | |
415 | midi_synth_reset(int dev) | |
416 | { | |
417 | ||
418 | leave_sysex(dev); | |
419 | } | |
ece7f77b | 420 | EXPORT_SYMBOL(midi_synth_reset); |
1da177e4 LT |
421 | |
422 | int | |
423 | midi_synth_open(int dev, int mode) | |
424 | { | |
425 | int orig_dev = synth_devs[dev]->midi_dev; | |
426 | int err; | |
427 | struct midi_input_info *inc; | |
428 | ||
02bb57ae | 429 | if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) |
1da177e4 LT |
430 | return -ENXIO; |
431 | ||
432 | midi2synth[orig_dev] = dev; | |
433 | sysex_state[dev] = 0; | |
434 | prev_out_status[orig_dev] = 0; | |
435 | ||
436 | if ((err = midi_devs[orig_dev]->open(orig_dev, mode, | |
437 | midi_synth_input, midi_synth_output)) < 0) | |
438 | return err; | |
439 | inc = &midi_devs[orig_dev]->in_info; | |
440 | ||
441 | /* save_flags(flags); | |
442 | cli(); | |
443 | don't know against what irqhandler to protect*/ | |
444 | inc->m_busy = 0; | |
445 | inc->m_state = MST_INIT; | |
446 | inc->m_ptr = 0; | |
447 | inc->m_left = 0; | |
448 | inc->m_prev_status = 0x00; | |
449 | /* restore_flags(flags); */ | |
450 | ||
451 | return 1; | |
452 | } | |
ece7f77b | 453 | EXPORT_SYMBOL(midi_synth_open); |
1da177e4 LT |
454 | |
455 | void | |
456 | midi_synth_close(int dev) | |
457 | { | |
458 | int orig_dev = synth_devs[dev]->midi_dev; | |
459 | ||
460 | leave_sysex(dev); | |
461 | ||
462 | /* | |
463 | * Shut up the synths by sending just single active sensing message. | |
464 | */ | |
465 | midi_devs[orig_dev]->outputc(orig_dev, 0xfe); | |
466 | ||
467 | midi_devs[orig_dev]->close(orig_dev); | |
468 | } | |
ece7f77b | 469 | EXPORT_SYMBOL(midi_synth_close); |
1da177e4 LT |
470 | |
471 | void | |
472 | midi_synth_hw_control(int dev, unsigned char *event) | |
473 | { | |
474 | } | |
ece7f77b | 475 | EXPORT_SYMBOL(midi_synth_hw_control); |
1da177e4 LT |
476 | |
477 | int | |
478 | midi_synth_load_patch(int dev, int format, const char __user *addr, | |
b769f494 | 479 | int count, int pmgr_flag) |
1da177e4 LT |
480 | { |
481 | int orig_dev = synth_devs[dev]->midi_dev; | |
482 | ||
483 | struct sysex_info sysex; | |
484 | int i; | |
485 | unsigned long left, src_offs, eox_seen = 0; | |
486 | int first_byte = 1; | |
487 | int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; | |
488 | ||
489 | leave_sysex(dev); | |
490 | ||
491 | if (!prefix_cmd(orig_dev, 0xf0)) | |
492 | return 0; | |
493 | ||
b769f494 | 494 | /* Invalid patch format */ |
1da177e4 | 495 | if (format != SYSEX_PATCH) |
1da177e4 | 496 | return -EINVAL; |
b769f494 DR |
497 | |
498 | /* Patch header too short */ | |
1da177e4 | 499 | if (count < hdr_size) |
1da177e4 | 500 | return -EINVAL; |
b769f494 | 501 | |
1da177e4 LT |
502 | count -= hdr_size; |
503 | ||
504 | /* | |
b769f494 | 505 | * Copy the header from user space |
1da177e4 LT |
506 | */ |
507 | ||
b769f494 | 508 | if (copy_from_user(&sysex, addr, hdr_size)) |
1da177e4 | 509 | return -EFAULT; |
b769f494 DR |
510 | |
511 | /* Sysex record too short */ | |
512 | if ((unsigned)count < (unsigned)sysex.len) | |
1da177e4 | 513 | sysex.len = count; |
b769f494 DR |
514 | |
515 | left = sysex.len; | |
516 | src_offs = 0; | |
1da177e4 LT |
517 | |
518 | for (i = 0; i < left && !signal_pending(current); i++) | |
519 | { | |
520 | unsigned char data; | |
521 | ||
b3390cea KV |
522 | if (get_user(data, |
523 | (unsigned char __user *)(addr + hdr_size + i))) | |
524 | return -EFAULT; | |
1da177e4 LT |
525 | |
526 | eox_seen = (i > 0 && data & 0x80); /* End of sysex */ | |
527 | ||
528 | if (eox_seen && data != 0xf7) | |
529 | data = 0xf7; | |
530 | ||
531 | if (i == 0) | |
532 | { | |
533 | if (data != 0xf0) | |
534 | { | |
535 | printk(KERN_WARNING "midi_synth: Sysex start missing\n"); | |
536 | return -EINVAL; | |
537 | } | |
538 | } | |
539 | while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && | |
540 | !signal_pending(current)) | |
541 | schedule(); | |
542 | ||
543 | if (!first_byte && data & 0x80) | |
544 | return 0; | |
545 | first_byte = 0; | |
546 | } | |
547 | ||
548 | if (!eox_seen) | |
549 | midi_outc(orig_dev, 0xf7); | |
550 | return 0; | |
551 | } | |
ece7f77b AB |
552 | EXPORT_SYMBOL(midi_synth_load_patch); |
553 | ||
1da177e4 LT |
554 | void midi_synth_panning(int dev, int channel, int pressure) |
555 | { | |
556 | } | |
ece7f77b AB |
557 | EXPORT_SYMBOL(midi_synth_panning); |
558 | ||
1da177e4 LT |
559 | void midi_synth_aftertouch(int dev, int channel, int pressure) |
560 | { | |
561 | int orig_dev = synth_devs[dev]->midi_dev; | |
562 | int msg, chn; | |
563 | ||
564 | if (pressure < 0 || pressure > 127) | |
565 | return; | |
566 | if (channel < 0 || channel > 15) | |
567 | return; | |
568 | ||
569 | leave_sysex(dev); | |
570 | ||
571 | msg = prev_out_status[orig_dev] & 0xf0; | |
572 | chn = prev_out_status[orig_dev] & 0x0f; | |
573 | ||
574 | if (msg != 0xd0 || chn != channel) /* | |
575 | * Test for running status | |
576 | */ | |
577 | { | |
578 | if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f))) | |
579 | return; | |
580 | midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* | |
581 | * Channel pressure | |
582 | */ | |
583 | } else if (!prefix_cmd(orig_dev, pressure)) | |
584 | return; | |
585 | ||
586 | midi_outc(orig_dev, pressure); | |
587 | } | |
ece7f77b | 588 | EXPORT_SYMBOL(midi_synth_aftertouch); |
1da177e4 LT |
589 | |
590 | void | |
591 | midi_synth_controller(int dev, int channel, int ctrl_num, int value) | |
592 | { | |
593 | int orig_dev = synth_devs[dev]->midi_dev; | |
594 | int chn, msg; | |
595 | ||
596 | if (ctrl_num < 0 || ctrl_num > 127) | |
597 | return; | |
598 | if (channel < 0 || channel > 15) | |
599 | return; | |
600 | ||
601 | leave_sysex(dev); | |
602 | ||
603 | msg = prev_out_status[orig_dev] & 0xf0; | |
604 | chn = prev_out_status[orig_dev] & 0x0f; | |
605 | ||
606 | if (msg != 0xb0 || chn != channel) | |
607 | { | |
608 | if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f))) | |
609 | return; | |
610 | midi_outc(orig_dev, 0xb0 | (channel & 0x0f)); | |
611 | } else if (!prefix_cmd(orig_dev, ctrl_num)) | |
612 | return; | |
613 | ||
614 | midi_outc(orig_dev, ctrl_num); | |
615 | midi_outc(orig_dev, value & 0x7f); | |
616 | } | |
ece7f77b | 617 | EXPORT_SYMBOL(midi_synth_controller); |
1da177e4 LT |
618 | |
619 | void | |
620 | midi_synth_bender(int dev, int channel, int value) | |
621 | { | |
622 | int orig_dev = synth_devs[dev]->midi_dev; | |
623 | int msg, prev_chn; | |
624 | ||
625 | if (channel < 0 || channel > 15) | |
626 | return; | |
627 | ||
628 | if (value < 0 || value > 16383) | |
629 | return; | |
630 | ||
631 | leave_sysex(dev); | |
632 | ||
633 | msg = prev_out_status[orig_dev] & 0xf0; | |
634 | prev_chn = prev_out_status[orig_dev] & 0x0f; | |
635 | ||
636 | if (msg != 0xd0 || prev_chn != channel) /* | |
637 | * Test for running status | |
638 | */ | |
639 | { | |
640 | if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f))) | |
641 | return; | |
642 | midi_outc(orig_dev, 0xe0 | (channel & 0x0f)); | |
643 | } else if (!prefix_cmd(orig_dev, value & 0x7f)) | |
644 | return; | |
645 | ||
646 | midi_outc(orig_dev, value & 0x7f); | |
647 | midi_outc(orig_dev, (value >> 7) & 0x7f); | |
648 | } | |
ece7f77b | 649 | EXPORT_SYMBOL(midi_synth_bender); |
1da177e4 LT |
650 | |
651 | void | |
652 | midi_synth_setup_voice(int dev, int voice, int channel) | |
653 | { | |
654 | } | |
ece7f77b | 655 | EXPORT_SYMBOL(midi_synth_setup_voice); |
1da177e4 LT |
656 | |
657 | int | |
658 | midi_synth_send_sysex(int dev, unsigned char *bytes, int len) | |
659 | { | |
660 | int orig_dev = synth_devs[dev]->midi_dev; | |
661 | int i; | |
662 | ||
663 | for (i = 0; i < len; i++) | |
664 | { | |
665 | switch (bytes[i]) | |
666 | { | |
667 | case 0xf0: /* Start sysex */ | |
668 | if (!prefix_cmd(orig_dev, 0xf0)) | |
669 | return 0; | |
670 | sysex_state[dev] = 1; | |
671 | break; | |
672 | ||
673 | case 0xf7: /* End sysex */ | |
674 | if (!sysex_state[dev]) /* Orphan sysex end */ | |
675 | return 0; | |
676 | sysex_state[dev] = 0; | |
677 | break; | |
678 | ||
679 | default: | |
680 | if (!sysex_state[dev]) | |
681 | return 0; | |
682 | ||
683 | if (bytes[i] & 0x80) /* Error. Another message before sysex end */ | |
684 | { | |
685 | bytes[i] = 0xf7; /* Sysex end */ | |
686 | sysex_state[dev] = 0; | |
687 | } | |
688 | } | |
689 | ||
690 | if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i])) | |
691 | { | |
692 | /* | |
693 | * Hardware level buffer is full. Abort the sysex message. | |
694 | */ | |
695 | ||
696 | int timeout = 0; | |
697 | ||
698 | bytes[i] = 0xf7; | |
699 | sysex_state[dev] = 0; | |
700 | ||
701 | while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && | |
702 | timeout < 1000) | |
703 | timeout++; | |
704 | } | |
705 | if (!sysex_state[dev]) | |
706 | return 0; | |
707 | } | |
708 | ||
709 | return 0; | |
710 | } | |
ece7f77b AB |
711 | EXPORT_SYMBOL(midi_synth_send_sysex); |
712 |