diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/sequencer.c | |
download | linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.bz2 linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.zip |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/sequencer.c')
-rw-r--r-- | sound/oss/sequencer.c | 1684 |
1 files changed, 1684 insertions, 0 deletions
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c new file mode 100644 index 000000000000..698614226c9a --- /dev/null +++ b/sound/oss/sequencer.c @@ -0,0 +1,1684 @@ +/* + * sound/sequencer.c + * + * The sequencer personality manager. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + */ +/* + * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Alan Cox : reformatted and fixed a pair of null pointer bugs + */ +#include <linux/kmod.h> +#include <linux/spinlock.h> +#define SEQUENCER_C +#include "sound_config.h" + +#include "midi_ctrl.h" + +static int sequencer_ok; +static struct sound_timer_operations *tmr; +static int tmr_no = -1; /* Currently selected timer */ +static int pending_timer = -1; /* For timer change operation */ +extern unsigned long seq_time; + +static int obsolete_api_used; +static DEFINE_SPINLOCK(lock); + +/* + * Local counts for number of synth and MIDI devices. These are initialized + * by the sequencer_open. + */ +static int max_mididev; +static int max_synthdev; + +/* + * The seq_mode gives the operating mode of the sequencer: + * 1 = level1 (the default) + * 2 = level2 (extended capabilities) + */ + +#define SEQ_1 1 +#define SEQ_2 2 +static int seq_mode = SEQ_1; + +static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper); +static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper); + +static int midi_opened[MAX_MIDI_DEV]; + +static int midi_written[MAX_MIDI_DEV]; + +static unsigned long prev_input_time; +static int prev_event_time; + +#include "tuning.h" + +#define EV_SZ 8 +#define IEV_SZ 8 + +static unsigned char *queue; +static unsigned char *iqueue; + +static volatile int qhead, qtail, qlen; +static volatile int iqhead, iqtail, iqlen; +static volatile int seq_playing; +static volatile int sequencer_busy; +static int output_threshold; +static long pre_event_timeout; +static unsigned synth_open_mask; + +static int seq_queue(unsigned char *note, char nonblock); +static void seq_startplay(void); +static int seq_sync(void); +static void seq_reset(void); + +#if MAX_SYNTH_DEV > 15 +#error Too many synthesizer devices enabled. +#endif + +int sequencer_read(int dev, struct file *file, char __user *buf, int count) +{ + int c = count, p = 0; + int ev_len; + unsigned long flags; + + dev = dev >> 4; + + ev_len = seq_mode == SEQ_1 ? 4 : 8; + + spin_lock_irqsave(&lock,flags); + + if (!iqlen) + { + spin_unlock_irqrestore(&lock,flags); + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + + interruptible_sleep_on_timeout(&midi_sleeper, + pre_event_timeout); + spin_lock_irqsave(&lock,flags); + if (!iqlen) + { + spin_unlock_irqrestore(&lock,flags); + return 0; + } + } + while (iqlen && c >= ev_len) + { + char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; + spin_unlock_irqrestore(&lock,flags); + if (copy_to_user(&(buf)[p], fixit, ev_len)) + return count - c; + p += ev_len; + c -= ev_len; + + spin_lock_irqsave(&lock,flags); + iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; + iqlen--; + } + spin_unlock_irqrestore(&lock,flags); + return count - c; +} + +static void sequencer_midi_output(int dev) +{ + /* + * Currently NOP + */ +} + +void seq_copy_to_input(unsigned char *event_rec, int len) +{ + unsigned long flags; + + /* + * Verify that the len is valid for the current mode. + */ + + if (len != 4 && len != 8) + return; + if ((seq_mode == SEQ_1) != (len == 4)) + return; + + if (iqlen >= (SEQ_MAX_QUEUE - 1)) + return; /* Overflow */ + + spin_lock_irqsave(&lock,flags); + memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); + iqlen++; + iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; + wake_up(&midi_sleeper); + spin_unlock_irqrestore(&lock,flags); +} + +static void sequencer_midi_input(int dev, unsigned char data) +{ + unsigned int tstamp; + unsigned char event_rec[4]; + + if (data == 0xfe) /* Ignore active sensing */ + return; + + tstamp = jiffies - seq_time; + + if (tstamp != prev_input_time) + { + tstamp = (tstamp << 8) | SEQ_WAIT; + seq_copy_to_input((unsigned char *) &tstamp, 4); + prev_input_time = tstamp; + } + event_rec[0] = SEQ_MIDIPUTC; + event_rec[1] = data; + event_rec[2] = dev; + event_rec[3] = 0; + + seq_copy_to_input(event_rec, 4); +} + +void seq_input_event(unsigned char *event_rec, int len) +{ + unsigned long this_time; + + if (seq_mode == SEQ_2) + this_time = tmr->get_time(tmr_no); + else + this_time = jiffies - seq_time; + + if (this_time != prev_input_time) + { + unsigned char tmp_event[8]; + + tmp_event[0] = EV_TIMING; + tmp_event[1] = TMR_WAIT_ABS; + tmp_event[2] = 0; + tmp_event[3] = 0; + *(unsigned int *) &tmp_event[4] = this_time; + + seq_copy_to_input(tmp_event, 8); + prev_input_time = this_time; + } + seq_copy_to_input(event_rec, len); +} + +int sequencer_write(int dev, struct file *file, const char __user *buf, int count) +{ + unsigned char event_rec[EV_SZ], ev_code; + int p = 0, c, ev_size; + int err; + int mode = translate_mode(file); + + dev = dev >> 4; + + DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count)); + + if (mode == OPEN_READ) + return -EIO; + + c = count; + + while (c >= 4) + { + if (copy_from_user((char *) event_rec, &(buf)[p], 4)) + goto out; + ev_code = event_rec[0]; + + if (ev_code == SEQ_FULLSIZE) + { + int err, fmt; + + dev = *(unsigned short *) &event_rec[2]; + if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) + return -ENXIO; + + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + + fmt = (*(short *) &event_rec[0]) & 0xffff; + err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); + if (err < 0) + return err; + + return err; + } + if (ev_code >= 128) + { + if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) + { + printk(KERN_WARNING "Sequencer: Invalid level 2 event %x\n", ev_code); + return -EINVAL; + } + ev_size = 8; + + if (c < ev_size) + { + if (!seq_playing) + seq_startplay(); + return count - c; + } + if (copy_from_user((char *)&event_rec[4], + &(buf)[p + 4], 4)) + goto out; + + } + else + { + if (seq_mode == SEQ_2) + { + printk(KERN_WARNING "Sequencer: 4 byte event in level 2 mode\n"); + return -EINVAL; + } + ev_size = 4; + + if (event_rec[0] != SEQ_MIDIPUTC) + obsolete_api_used = 1; + } + + if (event_rec[0] == SEQ_MIDIPUTC) + { + if (!midi_opened[event_rec[2]]) + { + int mode; + int dev = event_rec[2]; + + if (dev >= max_mididev || midi_devs[dev]==NULL) + { + /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ + return -ENXIO; + } + mode = translate_mode(file); + + if ((err = midi_devs[dev]->open(dev, mode, + sequencer_midi_input, sequencer_midi_output)) < 0) + { + seq_reset(); + printk(KERN_WARNING "Sequencer Error: Unable to open Midi #%d\n", dev); + return err; + } + midi_opened[dev] = 1; + } + } + if (!seq_queue(event_rec, (file->f_flags & (O_NONBLOCK) ? 1 : 0))) + { + int processed = count - c; + + if (!seq_playing) + seq_startplay(); + + if (!processed && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + else + return processed; + } + p += ev_size; + c -= ev_size; + } + + if (!seq_playing) + seq_startplay(); +out: + return count; +} + +static int seq_queue(unsigned char *note, char nonblock) +{ + + /* + * Test if there is space in the queue + */ + + if (qlen >= SEQ_MAX_QUEUE) + if (!seq_playing) + seq_startplay(); /* + * Give chance to drain the queue + */ + + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !waitqueue_active(&seq_sleeper)) { + /* + * Sleep until there is enough space on the queue + */ + interruptible_sleep_on(&seq_sleeper); + } + if (qlen >= SEQ_MAX_QUEUE) + { + return 0; /* + * To be sure + */ + } + memcpy(&queue[qtail * EV_SZ], note, EV_SZ); + + qtail = (qtail + 1) % SEQ_MAX_QUEUE; + qlen++; + + return 1; +} + +static int extended_event(unsigned char *q) +{ + int dev = q[2]; + + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; + + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + + switch (q[1]) + { + case SEQ_NOTEOFF: + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_NOTEON: + if (q[4] > 127 && q[4] != 255) + return 0; + + if (q[5] == 0) + { + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + } + synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_PGMCHANGE: + synth_devs[dev]->set_instr(dev, q[3], q[4]); + break; + + case SEQ_AFTERTOUCH: + synth_devs[dev]->aftertouch(dev, q[3], q[4]); + break; + + case SEQ_BALANCE: + synth_devs[dev]->panning(dev, q[3], (char) q[4]); + break; + + case SEQ_CONTROLLER: + synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); + break; + + case SEQ_VOLMODE: + if (synth_devs[dev]->volume_method != NULL) + synth_devs[dev]->volume_method(dev, q[3]); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int find_voice(int dev, int chn, int note) +{ + unsigned short key; + int i; + + key = (chn << 8) | (note + 1); + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if (synth_devs[dev]->alloc.map[i] == key) + return i; + return -1; +} + +static int alloc_voice(int dev, int chn, int note) +{ + unsigned short key; + int voice; + + key = (chn << 8) | (note + 1); + + voice = synth_devs[dev]->alloc_voice(dev, chn, note, + &synth_devs[dev]->alloc); + synth_devs[dev]->alloc.map[voice] = key; + synth_devs[dev]->alloc.alloc_times[voice] = + synth_devs[dev]->alloc.timestamp++; + return voice; +} + +static void seq_chn_voice_event(unsigned char *event_rec) +{ +#define dev event_rec[1] +#define cmd event_rec[2] +#define chn event_rec[3] +#define note event_rec[4] +#define parm event_rec[5] + + int voice = -1; + + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + if (seq_mode == SEQ_2) + { + if (synth_devs[dev]->alloc_voice) + voice = find_voice(dev, chn, note); + + if (cmd == MIDI_NOTEON && parm == 0) + { + cmd = MIDI_NOTEOFF; + parm = 64; + } + } + + switch (cmd) + { + case MIDI_NOTEON: + if (note > 127 && note != 255) /* Not a seq2 feature */ + return; + + if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) + { + /* Internal synthesizer (FM, GUS, etc) */ + voice = alloc_voice(dev, chn, note); + } + if (voice == -1) + voice = chn; + + if (seq_mode == SEQ_2 && (int) dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr(dev, voice, 128 + note); + synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; + } + synth_devs[dev]->setup_voice(dev, voice, chn); + } + synth_devs[dev]->start_note(dev, voice, note, parm); + break; + + case MIDI_NOTEOFF: + if (voice == -1) + voice = chn; + synth_devs[dev]->kill_note(dev, voice, note, parm); + break; + + case MIDI_KEY_PRESSURE: + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch(dev, voice, parm); + break; + + default:; + } +#undef dev +#undef cmd +#undef chn +#undef note +#undef parm +} + + +static void seq_chn_common_event(unsigned char *event_rec) +{ + unsigned char dev = event_rec[1]; + unsigned char cmd = event_rec[2]; + unsigned char chn = event_rec[3]; + unsigned char p1 = event_rec[4]; + + /* unsigned char p2 = event_rec[5]; */ + unsigned short w14 = *(short *) &event_rec[6]; + + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + switch (cmd) + { + case MIDI_PGM_CHANGE: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].pgm_num = p1; + if ((int) dev >= num_synths) + synth_devs[dev]->set_instr(dev, chn, p1); + } + else + synth_devs[dev]->set_instr(dev, chn, p1); + + break; + + case MIDI_CTL_CHANGE: + if (seq_mode == SEQ_2) + { + if (chn > 15 || p1 > 127) + break; + + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; + + if (p1 < 32) /* Setting MSB should clear LSB to 0 */ + synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; + + if ((int) dev < num_synths) + { + int val = w14 & 0x7f; + int i, key; + + if (p1 < 64) /* Combine MSB and LSB */ + { + val = ((synth_devs[dev]-> + chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) + | (synth_devs[dev]-> + chn_info[chn].controllers[p1 | 32] & 0x7f); + p1 &= ~32; + } + /* Handle all playing notes on this channel */ + + key = ((int) chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller(dev, i, p1, val); + } + else + synth_devs[dev]->controller(dev, chn, p1, w14); + } + else /* Mode 1 */ + synth_devs[dev]->controller(dev, chn, p1, w14); + break; + + case MIDI_PITCH_BEND: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if ((int) dev < num_synths) + { + /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender(dev, i, w14); + } + else + synth_devs[dev]->bender(dev, chn, w14); + } + else /* MODE 1 */ + synth_devs[dev]->bender(dev, chn, w14); + break; + + default:; + } +} + +static int seq_timing_event(unsigned char *event_rec) +{ + unsigned char cmd = event_rec[1]; + unsigned int parm = *(int *) &event_rec[4]; + + if (seq_mode == SEQ_2) + { + int ret; + + if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + wake_up(&seq_sleeper); + return ret; + } + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + + /* + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ + + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + time = parm; + prev_event_time = time; + + seq_playing = 1; + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + wake_up(&seq_sleeper); + return TIMER_ARMED; + } + break; + + case TMR_START: + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + break; + + case TMR_STOP: + break; + + case TMR_CONTINUE: + break; + + case TMR_TEMPO: + break; + + case TMR_ECHO: + if (seq_mode == SEQ_2) + seq_copy_to_input(event_rec, 8); + else + { + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input((unsigned char *) &parm, 4); + } + break; + + default:; + } + + return TIMER_NOT_ARMED; +} + +static void seq_local_event(unsigned char *event_rec) +{ + unsigned char cmd = event_rec[1]; + unsigned int parm = *((unsigned int *) &event_rec[4]); + + switch (cmd) + { + case LOCL_STARTAUDIO: + DMAbuf_start_devices(parm); + break; + + default:; + } +} + +static void seq_sysex_message(unsigned char *event_rec) +{ + int dev = event_rec[1]; + int i, l = 0; + unsigned char *buf = &event_rec[2]; + + if ((int) dev > max_synthdev) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + l = 0; + for (i = 0; i < 6 && buf[i] != 0xff; i++) + l = i + 1; + + if (!synth_devs[dev]->send_sysex) + return; + if (l > 0) + synth_devs[dev]->send_sysex(dev, buf, l); +} + +static int play_event(unsigned char *q) +{ + /* + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer + */ + unsigned int *delay; + + switch (q[0]) + { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note(0, q[1], 255, q[3]); + break; + + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note(0, q[1], q[2], q[3]); + break; + + case SEQ_WAIT: + delay = (unsigned int *) q; /* + * Bytes 1 to 3 are containing the * + * delay in 'ticks' + */ + *delay = (*delay >> 8) & 0xffffff; + + if (*delay > 0) + { + long time; + + seq_playing = 1; + time = *delay; + prev_event_time = time; + + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + wake_up(&seq_sleeper); + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return 1; + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr(0, q[1], q[2]); + break; + + case SEQ_SYNCTIMER: /* + * Reset timer + */ + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + break; + + case SEQ_MIDIPUTC: /* + * Put a midi character + */ + if (midi_opened[q[2]]) + { + int dev; + + dev = q[2]; + + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + break; + + if (!midi_devs[dev]->outputc(dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + seq_playing = 1; + request_sound_timer(-1); + return 2; + } + else + midi_written[dev] = 1; + } + break; + + case SEQ_ECHO: + seq_copy_to_input(q, 4); /* + * Echo back to the process + */ + break; + + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control(q[1], q); + break; + + case SEQ_EXTENDED: + extended_event(q); + break; + + case EV_CHN_VOICE: + seq_chn_voice_event(q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event(q); + break; + + case EV_TIMING: + if (seq_timing_event(q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event(q); + break; + + case EV_SYSEX: + seq_sysex_message(q); + break; + + default:; + } + return 0; +} + +/* called also as timer in irq context */ +static void seq_startplay(void) +{ + int this_one, action; + unsigned long flags; + + while (qlen > 0) + { + + spin_lock_irqsave(&lock,flags); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + spin_unlock_irqrestore(&lock,flags); + + seq_playing = 1; + + if ((action = play_event(&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; + } + } + + seq_playing = 0; + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + wake_up(&seq_sleeper); +} + +static void reset_controllers(int dev, unsigned char *controller, int update_dev) +{ + int i; + for (i = 0; i < 128; i++) + controller[i] = ctrl_def_values[i]; +} + +static void setup_mode2(void) +{ + int dev; + + max_synthdev = num_synths; + + for (dev = 0; dev < num_midis; dev++) + { + if (midi_devs[dev] && midi_devs[dev]->converter != NULL) + { + synth_devs[max_synthdev++] = midi_devs[dev]->converter; + } + } + + for (dev = 0; dev < max_synthdev; dev++) + { + int chn; + + synth_devs[dev]->sysex_ptr = 0; + synth_devs[dev]->emulation = 0; + + for (chn = 0; chn < 16; chn++) + { + synth_devs[dev]->chn_info[chn].pgm_num = 0; + reset_controllers(dev, + synth_devs[dev]->chn_info[chn].controllers,0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ + synth_devs[dev]->chn_info[chn].bender_range = 200; + } + } + max_mididev = 0; + seq_mode = SEQ_2; +} + +int sequencer_open(int dev, struct file *file) +{ + int retval, mode, i; + int level, tmp; + + if (!sequencer_ok) + sequencer_init(); + + level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; + + dev = dev >> 4; + mode = translate_mode(file); + + DEB(printk("sequencer_open(dev=%d)\n", dev)); + + if (!sequencer_ok) + { +/* printk("Sound card: sequencer not initialized\n");*/ + return -ENXIO; + } + if (dev) /* Patch manager device (obsolete) */ + return -ENXIO; + + if(synth_devs[dev] == NULL) + request_module("synth0"); + + if (mode == OPEN_READ) + { + if (!num_midis) + { + /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ + sequencer_busy = 0; + return -ENXIO; + } + } + if (sequencer_busy) + { + return -EBUSY; + } + sequencer_busy = 1; + obsolete_api_used = 0; + + max_mididev = num_midis; + max_synthdev = num_synths; + pre_event_timeout = MAX_SCHEDULE_TIMEOUT; + seq_mode = SEQ_1; + + if (pending_timer != -1) + { + tmr_no = pending_timer; + pending_timer = -1; + } + if (tmr_no == -1) /* Not selected yet */ + { + int i, best; + + best = -1; + for (i = 0; i < num_sound_timers; i++) + if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) + { + tmr_no = i; + best = sound_timer_devs[i]->priority; + } + if (tmr_no == -1) /* Should not be */ + tmr_no = 0; + } + tmr = sound_timer_devs[tmr_no]; + + if (level == 2) + { + if (tmr == NULL) + { + /*printk("sequencer: No timer for level 2\n");*/ + sequencer_busy = 0; + return -ENXIO; + } + setup_mode2(); + } + if (!max_synthdev && !max_mididev) + { + sequencer_busy=0; + return -ENXIO; + } + + synth_open_mask = 0; + + for (i = 0; i < max_mididev; i++) + { + midi_opened[i] = 0; + midi_written[i] = 0; + } + + for (i = 0; i < max_synthdev; i++) + { + if (synth_devs[i]==NULL) + continue; + + if (!try_module_get(synth_devs[i]->owner)) + continue; + + if ((tmp = synth_devs[i]->open(i, mode)) < 0) + { + printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); + if (synth_devs[i]->midi_dev) + printk(KERN_WARNING "(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); + } + else + { + synth_open_mask |= (1 << i); + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 1; + } + } + + seq_time = jiffies; + + prev_input_time = 0; + prev_event_time = 0; + + if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) + { + /* + * Initialize midi input devices + */ + + for (i = 0; i < max_mididev; i++) + if (!midi_opened[i] && midi_devs[i]) + { + if (!try_module_get(midi_devs[i]->owner)) + continue; + + if ((retval = midi_devs[i]->open(i, mode, + sequencer_midi_input, sequencer_midi_output)) >= 0) + { + midi_opened[i] = 1; + } + } + } + + if (seq_mode == SEQ_2) { + if (try_module_get(tmr->owner)) + tmr->open(tmr_no, seq_mode); + } + + init_waitqueue_head(&seq_sleeper); + init_waitqueue_head(&midi_sleeper); + output_threshold = SEQ_MAX_QUEUE / 2; + + return 0; +} + +static void seq_drain_midi_queues(void) +{ + int i, n; + + /* + * Give the Midi drivers time to drain their output queues + */ + + n = 1; + + while (!signal_pending(current) && n) + { + n = 0; + + for (i = 0; i < max_mididev; i++) + if (midi_opened[i] && midi_written[i]) + if (midi_devs[i]->buffer_status != NULL) + if (midi_devs[i]->buffer_status(i)) + n++; + + /* + * Let's have a delay + */ + + if (n) + interruptible_sleep_on_timeout(&seq_sleeper, + HZ/10); + } +} + +void sequencer_release(int dev, struct file *file) +{ + int i; + int mode = translate_mode(file); + + dev = dev >> 4; + + DEB(printk("sequencer_release(dev=%d)\n", dev)); + + /* + * Wait until the queue is empty (if we don't have nonblock) + */ + + if (mode != OPEN_READ && !(file->f_flags & O_NONBLOCK)) + { + while (!signal_pending(current) && qlen > 0) + { + seq_sync(); + interruptible_sleep_on_timeout(&seq_sleeper, + 3*HZ); + /* Extra delay */ + } + } + + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Ensure the output queues are empty + */ + seq_reset(); + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Flush the all notes off messages + */ + + for (i = 0; i < max_synthdev; i++) + { + if (synth_open_mask & (1 << i)) /* + * Actually opened + */ + if (synth_devs[i]) + { + synth_devs[i]->close(i); + + module_put(synth_devs[i]->owner); + + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 0; + } + } + + for (i = 0; i < max_mididev; i++) + { + if (midi_opened[i]) { + midi_devs[i]->close(i); + module_put(midi_devs[i]->owner); + } + } + + if (seq_mode == SEQ_2) { + tmr->close(tmr_no); + module_put(tmr->owner); + } + + if (obsolete_api_used) + printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); + sequencer_busy = 0; +} + +static int seq_sync(void) +{ + if (qlen && !seq_playing && !signal_pending(current)) + seq_startplay(); + + if (qlen > 0) + interruptible_sleep_on_timeout(&seq_sleeper, HZ); + return qlen; +} + +static void midi_outc(int dev, unsigned char data) +{ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ + + int n; + unsigned long flags; + + /* + * This routine sends one byte to the Midi channel. + * If the output FIFO is full, it waits until there + * is space in the queue + */ + + n = 3 * HZ; /* Timeout */ + + spin_lock_irqsave(&lock,flags); + while (n && !midi_devs[dev]->outputc(dev, data)) { + interruptible_sleep_on_timeout(&seq_sleeper, HZ/25); + n--; + } + spin_unlock_irqrestore(&lock,flags); +} + +static void seq_reset(void) +{ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ + + int i; + int chn; + unsigned long flags; + + sound_stop_timer(); + + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + + qlen = qhead = qtail = 0; + iqlen = iqhead = iqtail = 0; + + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + synth_devs[i]->reset(i); + + if (seq_mode == SEQ_2) + { + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ + } + } + else /* seq_mode == SEQ_1 */ + { + for (i = 0; i < max_mididev; i++) + if (midi_written[i]) /* + * Midi used. Some notes may still be playing + */ + { + /* + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ + midi_outc(i, 0xfe); + + for (chn = 0; chn < 16; chn++) + { + midi_outc(i, (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc(i, 0x7b); /* All notes off */ + midi_outc(i, 0); /* Dummy parameter */ + } + + midi_devs[i]->close(i); + + midi_written[i] = 0; + midi_opened[i] = 0; + } + } + + seq_playing = 0; + + spin_lock_irqsave(&lock,flags); + + if (waitqueue_active(&seq_sleeper)) { + /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + wake_up(&seq_sleeper); + } + spin_unlock_irqrestore(&lock,flags); +} + +static void seq_panic(void) +{ + /* + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ + + seq_reset(); + + /* + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ + + /* + * Also return the controllers to their default states + */ +} + +int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) +{ + int midi_dev, orig_dev, val, err; + int mode = translate_mode(file); + struct synth_info inf; + struct seq_event_rec event_rec; + unsigned long flags; + int __user *p = arg; + + orig_dev = dev = dev >> 4; + + switch (cmd) + { + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SOURCE: + if (seq_mode != SEQ_2) + return -EINVAL; + return tmr->ioctl(tmr_no, cmd, arg); + + case SNDCTL_TMR_SELECT: + if (seq_mode != SEQ_2) + return -EINVAL; + if (get_user(pending_timer, p)) + return -EFAULT; + if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) + { + pending_timer = -1; + return -EINVAL; + } + val = pending_timer; + break; + + case SNDCTL_SEQ_PANIC: + seq_panic(); + return -EINVAL; + + case SNDCTL_SEQ_SYNC: + if (mode == OPEN_READ) + return 0; + while (qlen > 0 && !signal_pending(current)) + seq_sync(); + return qlen ? -EINTR : 0; + + case SNDCTL_SEQ_RESET: + seq_reset(); + return 0; + + case SNDCTL_SEQ_TESTMIDI: + if (__get_user(midi_dev, p)) + return -EFAULT; + if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) + return -ENXIO; + + if (!midi_opened[midi_dev] && + (err = midi_devs[midi_dev]->open(midi_dev, mode, sequencer_midi_input, + sequencer_midi_output)) < 0) + return err; + midi_opened[midi_dev] = 1; + return 0; + + case SNDCTL_SEQ_GETINCOUNT: + if (mode == OPEN_WRITE) + return 0; + val = iqlen; + break; + + case SNDCTL_SEQ_GETOUTCOUNT: + if (mode == OPEN_READ) + return 0; + val = SEQ_MAX_QUEUE - qlen; + break; + + case SNDCTL_SEQ_GETTIME: + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + val = jiffies - seq_time; + break; + + case SNDCTL_SEQ_CTRLRATE: + /* + * If *arg == 0, just return the current rate + */ + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + + if (get_user(val, p)) + return -EFAULT; + if (val != 0) + return -EINVAL; + val = HZ; + break; + + case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SYNTH_REMOVESAMPLE: + case SNDCTL_SYNTH_CONTROL: + if (get_user(dev, p)) + return -EFAULT; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; + return synth_devs[dev]->ioctl(dev, cmd, arg); + + case SNDCTL_SEQ_NRSYNTHS: + val = max_synthdev; + break; + + case SNDCTL_SEQ_NRMIDIS: + val = max_mididev; + break; + + case SNDCTL_SYNTH_MEMAVL: + if (get_user(dev, p)) + return -EFAULT; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; + val = synth_devs[dev]->ioctl(dev, cmd, arg); + break; + + case SNDCTL_FM_4OP_ENABLE: + if (get_user(dev, p)) + return -EFAULT; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + synth_devs[dev]->ioctl(dev, cmd, arg); + return 0; + + case SNDCTL_SYNTH_INFO: + if (get_user(dev, &((struct synth_info __user *)arg)->device)) + return -EFAULT; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; + return synth_devs[dev]->ioctl(dev, cmd, arg); + + /* Like SYNTH_INFO but returns ID in the name field */ + case SNDCTL_SYNTH_ID: + if (get_user(dev, &((struct synth_info __user *)arg)->device)) + return -EFAULT; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; + memcpy(&inf, synth_devs[dev]->info, sizeof(inf)); + strlcpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); + inf.device = dev; + return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0; + + case SNDCTL_SEQ_OUTOFBAND: + if (copy_from_user(&event_rec, arg, sizeof(event_rec))) + return -EFAULT; + spin_lock_irqsave(&lock,flags); + play_event(event_rec.arr); + spin_unlock_irqrestore(&lock,flags); + return 0; + + case SNDCTL_MIDI_INFO: + if (get_user(dev, &((struct midi_info __user *)arg)->device)) + return -EFAULT; + if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) + return -ENXIO; + midi_devs[dev]->info.device = dev; + return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; + + case SNDCTL_SEQ_THRESHOLD: + if (get_user(val, p)) + return -EFAULT; + if (val < 1) + val = 1; + if (val >= SEQ_MAX_QUEUE) + val = SEQ_MAX_QUEUE - 1; + output_threshold = val; + return 0; + + case SNDCTL_MIDI_PRETIME: + if (get_user(val, p)) + return -EFAULT; + if (val < 0) + val = 0; + val = (HZ * val) / 10; + pre_event_timeout = val; + break; + + default: + if (mode == OPEN_READ) + return -EIO; + if (!synth_devs[0]) + return -ENXIO; + if (!(synth_open_mask & (1 << 0))) + return -ENXIO; + if (!synth_devs[0]->ioctl) + return -EINVAL; + return synth_devs[0]->ioctl(0, cmd, arg); + } + return put_user(val, p); +} + +/* No kernel lock - we're using the global irq lock here */ +unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait) +{ + unsigned long flags; + unsigned int mask = 0; + + dev = dev >> 4; + + spin_lock_irqsave(&lock,flags); + /* input */ + poll_wait(file, &midi_sleeper, wait); + if (iqlen) + mask |= POLLIN | POLLRDNORM; + + /* output */ + poll_wait(file, &seq_sleeper, wait); + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + mask |= POLLOUT | POLLWRNORM; + spin_unlock_irqrestore(&lock,flags); + return mask; +} + + +void sequencer_timer(unsigned long dummy) +{ + seq_startplay(); +} + +int note_to_freq(int note_num) +{ + + /* + * This routine converts a midi note to a frequency (multiplied by 1000) + */ + + int note, octave, note_freq; + static int notes[] = + { + 261632, 277189, 293671, 311132, 329632, 349232, + 369998, 391998, 415306, 440000, 466162, 493880 + }; + +#define BASE_OCTAVE 5 + + octave = note_num / 12; + note = note_num % 12; + + note_freq = notes[note]; + + if (octave < BASE_OCTAVE) + note_freq >>= (BASE_OCTAVE - octave); + else if (octave > BASE_OCTAVE) + note_freq <<= (octave - BASE_OCTAVE); + + /* + * note_freq >>= 1; + */ + + return note_freq; +} + +unsigned long compute_finetune(unsigned long base_freq, int bend, int range, + int vibrato_cents) +{ + unsigned long amount; + int negative, semitones, cents, multiplier = 1; + + if (!bend) + return base_freq; + if (!range) + return base_freq; + + if (!base_freq) + return base_freq; + + if (range >= 8192) + range = 8192; + + bend = bend * range / 8192; /* Convert to cents */ + bend += vibrato_cents; + + if (!bend) + return base_freq; + + negative = bend < 0 ? 1 : 0; + + if (bend < 0) + bend *= -1; + if (bend > range) + bend = range; + + /* + if (bend > 2399) + bend = 2399; + */ + while (bend > 2399) + { + multiplier *= 4; + bend -= 2400; + } + + semitones = bend / 100; + if (semitones > 99) + semitones = 99; + cents = bend % 100; + + amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000; + + if (negative) + return (base_freq * 10000) / amount; /* Bend down */ + else + return (base_freq * amount) / 10000; /* Bend up */ +} + + +void sequencer_init(void) +{ + /* drag in sequencer_syms.o */ + { + extern char sequencer_syms_symbol; + sequencer_syms_symbol = 0; + } + + if (sequencer_ok) + return; + MIDIbuf_init(); + queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); + if (queue == NULL) + { + printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); + return; + } + iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ); + if (iqueue == NULL) + { + printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); + vfree(queue); + return; + } + sequencer_ok = 1; +} + +void sequencer_unload(void) +{ + if(queue) + { + vfree(queue); + queue=NULL; + } + if(iqueue) + { + vfree(iqueue); + iqueue=NULL; + } +} |