summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/sound/sequencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/sound/sequencer.c')
-rw-r--r--sys/i386/isa/sound/sequencer.c1137
1 files changed, 1137 insertions, 0 deletions
diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c
new file mode 100644
index 0000000..2d4ef37
--- /dev/null
+++ b/sys/i386/isa/sound/sequencer.c
@@ -0,0 +1,1137 @@
+/*
+ * linux/kernel/chr_drv/sound/sequencer.c
+ *
+ * The sequencer personality manager.
+ *
+ * (C) 1992 Hannu Savolainen (hsavolai@cs.helsinki.fi) See COPYING for further
+ * details. Should be distributed with this file.
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#ifndef EXCLUDE_SEQUENCER
+
+static int sequencer_ok = 0;
+
+DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+
+static int midi_opened[MAX_MIDI_DEV] =
+{0}; /* 1 if the process has opened MIDI */
+static int midi_written[MAX_MIDI_DEV] =
+{0};
+
+long seq_time = 0; /* Reference point for the timer */
+
+#include "tuning.h"
+
+#define EV_SZ 8
+static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ];
+static unsigned char iqueue[SEQ_MAX_QUEUE][4];
+static volatile int qhead = 0, qtail = 0, qlen = 0;
+static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
+static volatile int seq_playing = 0;
+static int sequencer_busy = 0;
+static int output_treshold;
+static unsigned synth_open_mask;
+
+static int seq_queue (unsigned char *note);
+static void seq_startplay (void);
+static int seq_sync (void);
+static void seq_reset (void);
+static int pmgr_present[MAX_SYNTH_DEV] =
+{0};
+
+#if MAX_SYNTH_DEV > 15
+#error Too many synthesizer devices
+#endif
+
+int
+sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c = count, p = 0;
+
+ dev = dev >> 4;
+
+ if (dev) /* Patch manager device */
+ return pmgr_read (dev - 1, file, buf, count);
+
+ while (c > 3)
+ {
+ if (!iqlen)
+ {
+ INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag);
+
+ if (!iqlen)
+ return count - c;
+ }
+
+ COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4);
+ p += 4;
+ c -= 4;
+
+ iqhead = (iqhead + 1) % SEQ_MAX_QUEUE;
+ iqlen--;
+ }
+
+ return count - c;
+}
+
+void
+sequencer_midi_output (int dev)
+{
+ /* Currently NOP */
+}
+
+static void
+copy_to_input (unsigned char *event)
+{
+ unsigned long flags;
+
+ if (iqlen >= (SEQ_MAX_QUEUE - 1))
+ return; /* Overflow */
+
+ memcpy (iqueue[iqtail], event, 4);
+ iqlen++;
+ iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
+
+ DISABLE_INTR (flags);
+ if (midi_sleep_flag)
+ {
+ WAKE_UP (midi_sleeper);
+ }
+ RESTORE_INTR (flags);
+}
+
+void
+sequencer_midi_input (int dev, unsigned char data)
+{
+ int tstamp;
+ unsigned char event[4];
+
+ if (data == 0xfe) /* Active sensing */
+ return; /* Ignore */
+
+ tstamp = GET_TIME () - seq_time; /* Time since open() */
+ tstamp = (tstamp << 8) | SEQ_WAIT;
+
+ copy_to_input ((unsigned char *) &tstamp);
+
+ event[0] = SEQ_MIDIPUTC;
+ event[1] = data;
+ event[2] = dev;
+ event[3] = 0;
+
+ copy_to_input (event);
+}
+
+int
+sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ unsigned char event[EV_SZ], ev_code;
+ int p = 0, c, ev_size;
+ int err;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count));
+
+ if (mode == OPEN_READ)
+ return RET_ERROR (EIO);
+
+ if (dev) /* Patch manager device */
+ return pmgr_write (dev - 1, file, buf, count);
+
+ c = count;
+
+ while (c >= 4)
+ {
+ COPY_FROM_USER (event, buf, p, 4);
+ ev_code = event[0];
+
+ if (ev_code == SEQ_FULLSIZE)
+ {
+ int err;
+
+ dev = *(unsigned short *) &event[2];
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ err = synth_devs[dev]->load_patch (dev, *(short *) &event[0], buf, p + 4, c, 0);
+ if (err < 0)
+ return err;
+
+ return err;
+ }
+
+ if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE)
+ {
+
+ ev_size = 8;
+
+ if (c < ev_size)
+ {
+ if (!seq_playing)
+ seq_startplay ();
+ return count - c;
+ }
+
+ COPY_FROM_USER (&event[4], buf, p + 4, 4);
+
+ }
+ else
+ ev_size = 4;
+
+ if (event[0] == SEQ_MIDIPUTC)
+ {
+
+ if (!midi_opened[event[2]])
+ {
+ int mode;
+ int dev = event[2];
+
+ if (dev >= num_midis)
+ {
+ printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ mode = file->mode & O_ACCMODE;
+
+ if ((err = midi_devs[dev]->open (dev, mode)) < 0)
+ {
+ seq_reset ();
+ printk ("Sequencer Error: Unable to open Midi #%d\n", dev);
+ return err;
+ }
+
+ midi_opened[dev] = 1;
+ }
+
+ }
+
+ if (!seq_queue (event))
+ {
+
+ if (!seq_playing)
+ seq_startplay ();
+ return count - c;
+ }
+
+ p += ev_size;
+ c -= ev_size;
+ }
+
+ if (!seq_playing)
+ seq_startplay ();
+
+ return count;
+}
+
+static int
+seq_queue (unsigned char *note)
+{
+
+ /* 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 (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag)
+ {
+ /* Sleep until there is enough space on the queue */
+ INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ }
+
+ if (qlen >= SEQ_MAX_QUEUE)
+ return 0; /* To be sure */
+
+ memcpy (&queue[qtail][0], 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 >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ switch (q[1])
+ {
+ case SEQ_NOTEOFF:
+ synth_devs[dev]->kill_note (dev, q[3], q[5]);
+ break;
+
+ case SEQ_NOTEON:
+ if (q[4] > 127 && q[4] != 255)
+ return 0;
+
+ 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]);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return 0;
+}
+
+static void
+seq_startplay (void)
+{
+ int this_one;
+ unsigned long *delay;
+ unsigned char *q;
+
+ while (qlen > 0)
+ {
+ qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
+ qlen--;
+
+ q = &queue[this_one][0];
+
+ switch (q[0])
+ {
+ case SEQ_NOTEOFF:
+ if (synth_open_mask & (1 << 0))
+ if (synth_devs[0])
+ synth_devs[0]->kill_note (0, q[1], 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 long *) q; /* Bytes 1 to 3 are containing the
+ * delay in GET_TIME() */
+ *delay = (*delay >> 8) & 0xffffff;
+
+ if (*delay > 0)
+ {
+ long time;
+
+ seq_playing = 1;
+ time = *delay;
+
+ request_sound_timer (time);
+
+ if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+ {
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ if (seq_sleep_flag)
+ {
+ seq_sleep_flag = 0;
+ WAKE_UP (seq_sleeper);
+ }
+ RESTORE_INTR (flags);
+ }
+ return; /* Stop here. Timer routine will continue
+ * playing after the delay */
+ }
+ 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 = GET_TIME ();
+ break;
+
+ case SEQ_MIDIPUTC: /* Put a midi character */
+ if (midi_opened[q[2]])
+ {
+ int dev;
+
+ dev = q[2];
+
+ if (!midi_devs[dev]->putc (dev, q[1]))
+ {
+ /*
+ * Output FIFO is full. Wait one timer cycle and try again.
+ */
+
+ qlen++;
+ qhead = this_one; /* Restore queue */
+ seq_playing = 1;
+ request_sound_timer (-1);
+ return;
+ }
+ else
+ midi_written[dev] = 1;
+ }
+ break;
+
+ case SEQ_ECHO:
+ copy_to_input (q); /* Echo back to the process */
+ break;
+
+ case SEQ_PRIVATE:
+ if (q[1] < num_synths)
+ synth_devs[q[1]]->hw_control (q[1], q);
+ break;
+
+ case SEQ_EXTENDED:
+ extended_event (q);
+ break;
+
+ default:;
+ }
+
+ }
+
+ seq_playing = 0;
+
+ if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+ {
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ if (seq_sleep_flag)
+ {
+ seq_sleep_flag = 0;
+ WAKE_UP (seq_sleeper);
+ }
+ RESTORE_INTR (flags);
+ }
+
+}
+
+int
+sequencer_open (int dev, struct fileinfo *file)
+ {
+ int retval, mode, i;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ DEB (printk ("sequencer_open(dev=%d)\n", dev));
+
+ if (!sequencer_ok)
+ {
+ printk ("Soundcard: Sequencer not initialized\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (dev) /* Patch manager device */
+ {
+ int err;
+
+ dev--;
+ if (pmgr_present[dev])
+ return RET_ERROR (EBUSY);
+ if ((err = pmgr_open (dev)) < 0)
+ return err; /* Failed */
+
+ pmgr_present[dev] = 1;
+ return err;
+ }
+
+ if (sequencer_busy)
+ {
+ printk ("Sequencer busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (!(num_synths + num_midis))
+ return RET_ERROR (ENXIO);
+
+ synth_open_mask = 0;
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++) /* Open synth devices */
+ if (synth_devs[i]->open (i, mode) < 0)
+ printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
+ else
+ synth_open_mask |= (1 << i);
+
+ seq_time = GET_TIME ();
+
+ for (i = 0; i < num_midis; i++)
+ {
+ midi_opened[i] = 0;
+ midi_written[i] = 0;
+ }
+
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ { /* Initialize midi input devices */
+ if (!num_midis)
+ {
+ printk ("Sequencer: No Midi devices. Input not possible\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ for (i = 0; i < num_midis; i++)
+ {
+ if ((retval = midi_devs[i]->open (i, mode)) >= 0)
+ midi_opened[i] = 1;
+ }
+ }
+
+ sequencer_busy = 1;
+ seq_sleep_flag = midi_sleep_flag = 0;
+ output_treshold = SEQ_MAX_QUEUE / 2;
+
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
+
+ return 0;
+ }
+
+void
+seq_drain_midi_queues (void)
+{
+ int i, n;
+
+ /*
+ * Give the Midi drivers time to drain their output queues
+ */
+
+ n = 1;
+
+ while (!PROCESS_ABORTING && n)
+ {
+ n = 0;
+
+ for (i = 0; i < num_midis; 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)
+ {
+ REQUEST_TIMEOUT (HZ / 10, seq_sleeper);
+ INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ }
+ }
+}
+
+void
+sequencer_release (int dev, struct fileinfo *file)
+ {
+ int i;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ DEB (printk ("sequencer_release(dev=%d)\n", dev));
+
+ if (dev) /* Patch manager device */
+ {
+ dev--;
+ pmgr_release (dev);
+ pmgr_present[dev] = 0;
+ return;
+ }
+
+ /*
+ * Wait until the queue is empty
+ */
+ while (!PROCESS_ABORTING && qlen)
+ {
+ seq_sync ();
+ }
+
+ 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 < num_midis; i++)
+ if (midi_opened[i])
+ midi_devs[i]->close (i);
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++)
+ if (synth_open_mask & (1 << i)) /* Actually opened */
+ if (synth_devs[i])
+ synth_devs[i]->close (i);
+
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+
+ sequencer_busy = 0;
+ }
+
+static int
+seq_sync (void)
+{
+ if (qlen && !seq_playing && !PROCESS_ABORTING)
+ seq_startplay ();
+
+ if (qlen && !seq_sleep_flag) /* Queue not empty */
+ {
+ INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ }
+
+ return qlen;
+}
+
+static void
+midi_outc (int dev, unsigned char data)
+{
+ /*
+ * NOTE! Calls sleep(). Don't call this from interrupt.
+ */
+
+ int n;
+
+ /* 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 = 300; /* Timeout in jiffies */
+
+ while (n && !midi_devs[dev]->putc (dev, data))
+ {
+ REQUEST_TIMEOUT (1, seq_sleeper);
+ INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ n--;
+ }
+}
+
+static void
+seq_reset (void)
+{
+ /*
+ * NOTE! Calls sleep(). Don't call this from interrupt.
+ */
+
+ int i, chn;
+
+ sound_stop_timer ();
+
+ qlen = qhead = qtail = 0;
+ iqlen = iqhead = iqtail = 0;
+
+ for (i = 0; i < num_synths; i++)
+ if (synth_open_mask & (1 << i))
+ if (synth_devs[i])
+ synth_devs[i]->reset (i);
+
+ for (i = 0; i < num_midis; i++)
+ if (midi_written[i]) /* Midi used. Some notes may still be playing */
+ {
+ for (chn = 0; chn < 16; chn++)
+ {
+ midi_outc (i, 0xb0 + chn); /* Channel message */
+ 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;
+
+ if (seq_sleep_flag)
+ printk ("Sequencer Warning: Unexpected sleeping process\n");
+
+}
+
+int
+sequencer_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ int midi_dev, orig_dev;
+ int mode = file->mode & O_ACCMODE;
+
+ orig_dev = dev = dev >> 4;
+
+ switch (cmd)
+ {
+
+ case SNDCTL_SEQ_SYNC:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_READ)
+ return 0;
+ while (qlen && !PROCESS_ABORTING)
+ seq_sync ();
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_RESET:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ seq_reset ();
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_TESTMIDI:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ midi_dev = IOCTL_IN (arg);
+ if (midi_dev >= num_midis)
+ return RET_ERROR (ENXIO);
+
+ if (!midi_opened[midi_dev])
+ {
+ int err, mode;
+
+ mode = file->mode & O_ACCMODE;
+ if ((err = midi_devs[midi_dev]->open (midi_dev, mode)) < 0)
+ return err;
+ }
+
+ midi_opened[midi_dev] = 1;
+
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_GETINCOUNT:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_WRITE)
+ return 0;
+ return IOCTL_OUT (arg, iqlen);
+ break;
+
+ case SNDCTL_SEQ_GETOUTCOUNT:
+
+ if (mode == OPEN_READ)
+ return 0;
+ return IOCTL_OUT (arg, SEQ_MAX_QUEUE - qlen);
+ break;
+
+ case SNDCTL_SEQ_CTRLRATE:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ /* If *arg == 0, just return the current rate */
+ return IOCTL_OUT (arg, HZ);
+ break;
+
+ case SNDCTL_SEQ_RESETSAMPLES:
+ dev = IOCTL_IN (arg);
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ if (!orig_dev && pmgr_present[dev])
+ pmgr_inform (dev, PM_E_PATCH_RESET, 0, 0, 0, 0);
+
+ return synth_devs[dev]->ioctl (dev, cmd, arg);
+ break;
+
+ case SNDCTL_SEQ_NRSYNTHS:
+ return IOCTL_OUT (arg, num_synths);
+ break;
+
+ case SNDCTL_SEQ_NRMIDIS:
+ return IOCTL_OUT (arg, num_midis);
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ {
+ int dev = IOCTL_IN (arg);
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ return IOCTL_OUT (arg, synth_devs[dev]->ioctl (dev, cmd, arg));
+ }
+ break;
+
+ case SNDCTL_FM_4OP_ENABLE:
+ {
+ int dev = IOCTL_IN (arg);
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ synth_devs[dev]->ioctl (dev, cmd, arg);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_SYNTH_INFO:
+ {
+ struct synth_info inf;
+ int dev;
+
+ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
+ dev = inf.device;
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ return synth_devs[dev]->ioctl (dev, cmd, arg);
+ }
+ break;
+
+ case SNDCTL_MIDI_INFO:
+ {
+ struct midi_info inf;
+ int dev;
+
+ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
+ dev = inf.device;
+
+ if (dev < 0 || dev >= num_midis)
+ return RET_ERROR (ENXIO);
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf));
+ return 0;
+ }
+ break;
+
+ case SNDCTL_PMGR_IFACE:
+ {
+ struct patmgr_info *inf;
+ int dev, err;
+
+ inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+
+ IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
+ dev = inf->device;
+
+ if (dev < 0 || dev >= num_synths)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if (!synth_devs[dev]->pmgr_interface)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1)
+ {
+ KERNEL_FREE (inf);
+ return err;
+ }
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf));
+ KERNEL_FREE (inf);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_PMGR_ACCESS:
+ {
+ struct patmgr_info *inf;
+ int dev, err;
+
+ inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+
+ IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
+ dev = inf->device;
+
+ if (dev < 0 || dev >= num_synths)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if (!pmgr_present[dev])
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ESRCH);
+ }
+
+ if ((err = pmgr_access (dev, inf)) < 0)
+ {
+ KERNEL_FREE (inf);
+ return err;
+ }
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf));
+ KERNEL_FREE (inf);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_SEQ_TRESHOLD:
+ {
+ int tmp = IOCTL_IN (arg);
+
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (tmp < 1)
+ tmp = 1;
+ if (tmp >= SEQ_MAX_QUEUE)
+ tmp = SEQ_MAX_QUEUE - 1;
+ output_treshold = tmp;
+ return 0;
+ }
+ break;
+
+ default:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_READ)
+ return RET_ERROR (EIO);
+
+ if (!synth_devs[0])
+ return RET_ERROR (ENXIO);
+ if (!(synth_open_mask & (1 << 0)))
+ return RET_ERROR (ENXIO);
+ return synth_devs[0]->ioctl (0, cmd, arg);
+ break;
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+#ifdef ALLOW_SELECT
+int
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+ dev = dev >> 4;
+
+ switch (sel_type)
+ {
+ case SEL_IN:
+ if (!iqlen)
+ {
+ midi_sleep_flag = 1;
+ select_wait (&midi_sleeper, wait);
+ return 0;
+ }
+ return 1;
+
+ break;
+
+ case SEL_OUT:
+ if (qlen >= SEQ_MAX_QUEUE)
+ {
+ seq_sleep_flag = 1;
+ select_wait (&seq_sleeper, wait);
+ return 0;
+ }
+ return 1;
+ break;
+
+ case SEL_EX:
+ return 0;
+ }
+
+ return 0;
+}
+
+#endif
+
+void
+sequencer_timer (void)
+{
+ 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;
+ int notes[] =
+ {
+ 261632, 277189, 293671, 311132, 329632, 349232,
+ 369998, 391998, 415306, 440000, 466162, 493880
+ }; /* Note freq*1000 for octave 5 */
+
+#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)
+{
+ unsigned long amount;
+ int negative, semitones, cents;
+
+ if (!bend)
+ return base_freq;
+ if (!range)
+ return base_freq;
+
+ if (!base_freq)
+ return base_freq;
+
+ if (range >= 8192)
+ range = 8191;
+
+ bend = bend * range / 8192;
+ 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;
+
+ semitones = bend / 100;
+ cents = bend % 100;
+
+ amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000;
+
+ if (negative)
+ return (base_freq * 10000) / amount; /* Bend down */
+ else
+ return (base_freq * amount) / 10000; /* Bend up */
+}
+
+
+long
+sequencer_init (long mem_start)
+{
+
+ sequencer_ok = 1;
+ return mem_start;
+}
+
+#else
+/* Stub version */
+int
+sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_open (int dev, struct fileinfo *file)
+ {
+ return RET_ERROR (ENXIO);
+ }
+
+void
+sequencer_release (int dev, struct fileinfo *file)
+ {
+ }
+int
+sequencer_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
+{
+ return RET_ERROR (EIO);
+}
+
+long
+sequencer_init (long mem_start)
+{
+ return mem_start;
+}
+
+void
+sequencer_midi_input (int dev, unsigned char data)
+{
+ return;
+}
+
+void
+sequencer_midi_output (int dev)
+{
+ return;
+}
+
+int
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+ return RET_ERROR (EIO);
+}
+
+#endif
+
+#endif
OpenPOWER on IntegriCloud