diff options
author | peter <peter@FreeBSD.org> | 1999-01-01 08:18:13 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-01-01 08:18:13 +0000 |
commit | d713c6aca4942e88e9afb66a012c176a3b3c93dd (patch) | |
tree | 145a2f9aaed47d75ef5882d97d90e8835c70db2c /sys/i386/isa/sound/midibuf.c | |
parent | cfef427a396353878f1fdad225686030324bda8e (diff) | |
download | FreeBSD-src-d713c6aca4942e88e9afb66a012c176a3b3c93dd.zip FreeBSD-src-d713c6aca4942e88e9afb66a012c176a3b3c93dd.tar.gz |
Part 2 of pcvt/voxware revival. I hope I have not clobbered any other
deltas, but it is possible since I had a few merge conflicts over the last
few days while this has been sitting ready to go.
(Part 1 was committed to the config files, but cvs aborted grrr..)
Approved by: core
Diffstat (limited to 'sys/i386/isa/sound/midibuf.c')
-rw-r--r-- | sys/i386/isa/sound/midibuf.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c new file mode 100644 index 0000000..af5ddc5 --- /dev/null +++ b/sys/i386/isa/sound/midibuf.c @@ -0,0 +1,429 @@ +/* + * sound/midibuf.c + * + * Device file manager for /dev/midi# + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <i386/isa/sound/sound_config.h> + + +#if defined(CONFIG_MIDI) + +/* + * Don't make MAX_QUEUE_SIZE larger than 4000 + */ + +#define MAX_QUEUE_SIZE 4000 +int +MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait); + +static void +drain_midi_queue(int dev); + +static int *midi_sleeper[MAX_MIDI_DEV] = {NULL}; +static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}}; +static int *input_sleeper[MAX_MIDI_DEV] = {NULL}; +static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { {0}}; + +struct midi_buf { + int len, head, tail; + u_char queue[MAX_QUEUE_SIZE]; +}; + +struct midi_parms { + int prech_timeout; /* Timeout before the first ch */ +}; + +static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL}; +static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL}; +static struct midi_parms parms[MAX_MIDI_DEV]; + +static void midi_poll(void *dummy); + +static volatile int open_devs = 0; + +#define DATA_AVAIL(q) (q->len) +#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len) + +#define QUEUE_BYTE(q, data) \ + if (SPACE_AVAIL(q)) { \ + u_long flags; \ + flags = splhigh(); \ + q->queue[q->tail] = (data); \ + q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \ + splx(flags); \ + } + +#define REMOVE_BYTE(q, data) \ + if (DATA_AVAIL(q)) { \ + u_long flags; \ + flags = splhigh(); \ + data = q->queue[q->head]; \ + q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \ + splx(flags); \ + } + +static void +drain_midi_queue(int dev) +{ + + /* + * Give the Midi driver time to drain its output queues + */ + + if (midi_devs[dev]->buffer_status != NULL) + while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) && + midi_devs[dev]->buffer_status(dev)) { + int chn; + + midi_sleeper[dev] = &chn; + DO_SLEEP(chn, midi_sleep_flag[dev], hz / 10); + + }; +} + +static void +midi_input_intr(int dev, u_char data) +{ + if (midi_in_buf[dev] == NULL) + return; + + if (data == 0xfe) /* Active sensing */ + return; /* Ignore */ + + if (SPACE_AVAIL(midi_in_buf[dev])) { + QUEUE_BYTE(midi_in_buf[dev], data); + if ((input_sleep_flag[dev].mode & WK_SLEEP)) { + input_sleep_flag[dev].mode = WK_WAKEUP; + wakeup(input_sleeper[dev]); + }; + } +} + +static void +midi_output_intr(int dev) +{ + /* + * Currently NOP + */ +} + +static void +midi_poll(void *dummy) +{ + u_long flags; + int dev; + + flags = splhigh(); + if (open_devs) { + for (dev = 0; dev < num_midis; dev++) + if (midi_out_buf[dev] != NULL) { + while (DATA_AVAIL(midi_out_buf[dev]) && + midi_devs[dev]->putc(dev, + midi_out_buf[dev]->queue[midi_out_buf[dev]->head])) { + midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; + midi_out_buf[dev]->len--; + } + + if (DATA_AVAIL(midi_out_buf[dev]) < 100 && + (midi_sleep_flag[dev].mode & WK_SLEEP)) { + midi_sleep_flag[dev].mode = WK_WAKEUP; + wakeup(midi_sleeper[dev]); + }; + } + timeout( midi_poll, 0, 1);; /* Come back later */ + } + splx(flags); +} + +int +MIDIbuf_open(int dev, struct fileinfo * file) +{ + int mode, err; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + if (num_midis > MAX_MIDI_DEV) { + printf("Sound: FATAL ERROR: Too many midi interfaces\n"); + num_midis = MAX_MIDI_DEV; + } + if (dev < 0 || dev >= num_midis) { + printf("Sound: Nonexistent MIDI interface %d\n", dev); + return -(ENXIO); + } + /* + * Interrupts disabled. Be careful + */ + + if ((err = midi_devs[dev]->open(dev, mode, + midi_input_intr, midi_output_intr)) < 0) { + return err; + } + parms[dev].prech_timeout = 0; + + midi_in_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK); + + if (midi_in_buf[dev] == NULL) { + printf("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + return -(EIO); + } + midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; + + midi_out_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK); + + if (midi_out_buf[dev] == NULL) { + printf("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + free(midi_in_buf[dev], M_TEMP); + midi_in_buf[dev] = NULL; + return -(EIO); + } + midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; + open_devs++; + + { + midi_sleep_flag[dev].aborting = 0; + midi_sleep_flag[dev].mode = WK_NONE; + }; + { + input_sleep_flag[dev].aborting = 0; + input_sleep_flag[dev].mode = WK_NONE; + }; + + if (open_devs < 2) { /* This was first open */ + { + }; + + timeout( midi_poll, 0, 1);; /* Start polling */ + } + return err; +} + +void +MIDIbuf_release(int dev, struct fileinfo * file) +{ + int mode; + u_long flags; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + if (dev < 0 || dev >= num_midis) + return; + + flags = splhigh(); + + /* + * Wait until the queue is empty + */ + + if (mode != OPEN_READ) { + midi_devs[dev]->putc(dev, 0xfe); /* Active sensing to + * shut the devices */ + + while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) && + DATA_AVAIL(midi_out_buf[dev])) { + int chn; + midi_sleeper[dev] = &chn; + DO_SLEEP(chn, midi_sleep_flag[dev], 0); + + }; /* Sync */ + + drain_midi_queue(dev); /* Ensure the output queues are empty */ + } + splx(flags); + + midi_devs[dev]->close(dev); + + free(midi_in_buf[dev], M_TEMP); + free(midi_out_buf[dev], M_TEMP); + midi_in_buf[dev] = NULL; + midi_out_buf[dev] = NULL; + if (open_devs < 2) { + }; + open_devs--; +} + +int +MIDIbuf_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count) +{ + u_long flags; + int c, n, i; + u_char tmp_data; + + dev = dev >> 4; + + if (!count) + return 0; + + flags = splhigh(); + + c = 0; + + while (c < count) { + n = SPACE_AVAIL(midi_out_buf[dev]); + + if (n == 0) { /* No space just now. We have to sleep */ + + { + int chn; + + midi_sleeper[dev] = &chn; + DO_SLEEP(chn, midi_sleep_flag[dev], 0); + }; + + if (PROCESS_ABORTING(midi_sleep_flag[dev])) { + splx(flags); + return -(EINTR); + } + n = SPACE_AVAIL(midi_out_buf[dev]); + } + if (n > (count - c)) + n = count - c; + + for (i = 0; i < n; i++) { + + if (uiomove((char *) &tmp_data, 1, buf)) { + printf("sb: Bad copyin()!\n"); + }; + QUEUE_BYTE(midi_out_buf[dev], tmp_data); + c++; + } + } + + splx(flags); + + return c; +} + + +int +MIDIbuf_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count) +{ + int n, c = 0; + u_long flags; + u_char tmp_data; + + dev = dev >> 4; + + flags = splhigh(); + + if (!DATA_AVAIL(midi_in_buf[dev])) { /* No data yet, wait */ + + { + int chn; + + + input_sleeper[dev] = &chn; + DO_SLEEP(chn, input_sleep_flag[dev], + parms[dev].prech_timeout); + + }; + if (PROCESS_ABORTING(input_sleep_flag[dev])) + c = -(EINTR); /* The user is getting restless */ + } + if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) { /* Got some bytes */ + n = DATA_AVAIL(midi_in_buf[dev]); + if (n > count) + n = count; + c = 0; + + while (c < n) { + REMOVE_BYTE(midi_in_buf[dev], tmp_data); + + if (uiomove((char *) &tmp_data, 1, buf)) { + printf("sb: Bad copyout()!\n"); + }; + c++; + } + } + splx(flags); + + return c; +} + +int +MIDIbuf_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg) +{ + int val; + + dev = dev >> 4; + + if (((cmd >> 8) & 0xff) == 'C') { + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); + else + printf("/dev/midi%d: No coprocessor for this device\n", dev); + + return -(ENXIO); + } else + switch (cmd) { + + case SNDCTL_MIDI_PRETIME: + val = (int) (*(int *) arg); + if (val < 0) + val = 0; + + val = (hz * val) / 10; + parms[dev].prech_timeout = val; + return *(int *) arg = val; + break; + + default: + return midi_devs[dev]->ioctl(dev, cmd, arg); + } +} + +#ifdef ALLOW_POLL +int +MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait) +{ + int revents = 0; + + dev = dev >> 4; + + if (events & (POLLIN | POLLRDNORM)) + if (!DATA_AVAIL (midi_in_buf[dev])) + selrecord(wait, &selinfo[dev]); + else + revents |= events & (POLLIN | POLLRDNORM); + + if (events & (POLLOUT | POLLWRNORM)) + if (SPACE_AVAIL (midi_out_buf[dev])) + selrecord(wait, &selinfo[dev]); + else + revents |= events & (POLLOUT | POLLWRNORM); + + return revents; +} + +#endif /* ALLOW_SELECT */ + + + +#endif |