diff options
Diffstat (limited to 'sys/dev/sound/midi/midi.c')
-rw-r--r-- | sys/dev/sound/midi/midi.c | 1054 |
1 files changed, 0 insertions, 1054 deletions
diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c deleted file mode 100644 index a9d0184..0000000 --- a/sys/dev/sound/midi/midi.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Main midi driver for FreeBSD. This file provides the main - * entry points for probe/attach and all i/o demultiplexing, including - * default routines for generic devices. - * - * (C) 1999 Seigo Tanimura - * - * 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. - * - * - * For each card type a template "mididev_info" structure contains - * all the relevant parameters, both for configuration and runtime. - * - * In this file we build tables of pointers to the descriptors for - * the various supported cards. The generic probe routine scans - * the table(s) looking for a matching entry, then invokes the - * board-specific probe routine. If successful, a pointer to the - * correct mididev_info is stored in mididev_last_probed, for subsequent - * use in the attach routine. The generic attach routine copies - * the template to a permanent descriptor (midi_info and - * friends), initializes all generic parameters, and calls the - * board-specific attach routine. - * - * On device calls, the generic routines do the checks on unit and - * device parameters, then call the board-specific routines if - * available, or try to perform the task using the default code. - * - * $FreeBSD$ - * - */ - -#include <dev/sound/midi/midi.h> - -static devclass_t midi_devclass; - -static d_open_t midiopen; -static d_close_t midiclose; -static d_ioctl_t midiioctl; -static d_read_t midiread; -static d_write_t midiwrite; -static d_poll_t midipoll; - -/* These functions are local. */ -static d_open_t midistat_open; -static d_close_t midistat_close; -static d_read_t midistat_read; -static int midi_initstatus(char *buf, int size); -static int midi_readstatus(char *buf, int *ptr, struct uio *uio); - -#define CDEV_MAJOR MIDI_CDEV_MAJOR -static struct cdevsw midi_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = midiopen, - .d_close = midiclose, - .d_read = midiread, - .d_write = midiwrite, - .d_ioctl = midiioctl, - .d_poll = midipoll, - .d_name = "midi", - .d_maj = CDEV_MAJOR, -}; - -/* - * descriptors for active devices. also used as the public softc - * of a device. - */ -static TAILQ_HEAD(,_mididev_info) midi_info; -static int nmidi, nsynth; -/* Mutex to protect midi_info, nmidi and nsynth. */ -static struct mtx midiinfo_mtx; -static int midiinfo_mtx_init; - -/* These make the buffer for /dev/midistat */ -static int midistatbusy; -static char midistatbuf[4096]; -static int midistatptr; - -SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver"); - -int midi_debug; -SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); - -midi_cmdtab cmdtab_midiioctl[] = { - {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"}, - {SNDCTL_MIDI_MPUMODE, "SNDCTL_MIDI_MPUMODE"}, - {SNDCTL_MIDI_MPUCMD, "SNDCTL_MIDI_MPUCMD"}, - {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"}, - {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"}, - {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"}, - {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"}, - {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"}, - {MIOSPASSTHRU, "MIOSPASSTHRU"}, - {MIOGPASSTHRU, "MIOGPASSTHRU"}, - {AIONWRITE, "AIONWRITE"}, - {AIOGSIZE, "AIOGSIZE"}, - {AIOSSIZE, "AIOSSIZE"}, - {AIOGFMT, "AIOGFMT"}, - {AIOSFMT, "AIOSFMT"}, - {AIOGMIX, "AIOGMIX"}, - {AIOSMIX, "AIOSMIX"}, - {AIOSTOP, "AIOSTOP"}, - {AIOSYNC, "AIOSYNC"}, - {AIOGCAP, "AIOGCAP"}, - {-1, NULL}, -}; - -/* - * This is the generic init routine. - * Must be called after device-specific init. - */ -int -midiinit(mididev_info *d, device_t dev) -{ - int unit; - - /* - * initialize standard parameters for the device. This can be - * overridden by device-specific configurations but better do - * here the generic things. - */ - - MIDI_DEBUG(printf("midiinit: unit %d.\n", d->unit)); - - unit = d->unit; - d->softc = device_get_softc(dev); - d->dev = dev; - d->magic = MAGIC(d->unit); /* debugging... */ - d->flags = 0; - d->fflags = 0; - d->midi_dbuf_in.unit_size = 1; - d->midi_dbuf_out.unit_size = 1; - d->midi_dbuf_passthru.unit_size = 1; - - mtx_unlock(&d->flagqueue_mtx); - - if (midi_devclass == NULL) { - midi_devclass = device_get_devclass(dev); - make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS), - UID_ROOT, GID_WHEEL, 0444, "midistat"); - } - make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN), - UID_ROOT, GID_WHEEL, 0666, "midi%d", unit); - - return 0 ; -} - -/* - * a small utility function which, given a device number, returns - * a pointer to the associated mididev_info struct, and sets the unit - * number. - */ -mididev_info * -get_mididev_info(dev_t i_dev, int *unit) -{ - int u; - - if (MIDIDEV(i_dev) != MIDI_DEV_MIDIN) - return NULL; - u = MIDIUNIT(i_dev); - if (unit) - *unit = u; - - return get_mididev_info_unit(u); -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct. - */ -mididev_info * -get_mididev_info_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->unit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct with MDT_MIDI. - */ -mididev_info * -get_mididev_midi_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->midiunit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct with MDT_SYNTH. - */ -mididev_info * -get_mididev_synth_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->synthunit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* Create a new midi device info structure. */ -/* TODO: lock md, then exit. */ -mididev_info * -create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf) -{ - int unit; - mididev_info *md, *mdnew; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - /* As malloc(9) might block, allocate mididev_info now. */ - mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO); - if (mdnew == NULL) - return NULL; - bcopy(mdinf, mdnew, sizeof(mididev_info)); - bcopy(syninf, &mdnew->synth, sizeof(synthdev_info)); - midibuf_init(&mdnew->midi_dbuf_in); - midibuf_init(&mdnew->midi_dbuf_out); - midibuf_init(&mdnew->midi_dbuf_passthru); - mtx_init(&mdnew->flagqueue_mtx, "midflq", NULL, MTX_DEF); - mtx_init(&mdnew->synth.vc_mtx, "synsvc", NULL, MTX_DEF); - mtx_init(&mdnew->synth.status_mtx, "synsst", NULL, MTX_DEF); - - mtx_lock(&midiinfo_mtx); - - switch (type) { - case MDT_MIDI: - mdnew->midiunit = nmidi; - mdnew->synthunit = nmidi; - nmidi++; - break; - case MDT_SYNTH: - mdnew->midiunit = -1; - mdnew->synthunit = nsynth; - nsynth++; - break; - default: - mtx_unlock(&midiinfo_mtx); - midibuf_destroy(&mdnew->midi_dbuf_in); - midibuf_destroy(&mdnew->midi_dbuf_out); - midibuf_destroy(&mdnew->midi_dbuf_passthru); - mtx_destroy(&mdnew->flagqueue_mtx); - mtx_destroy(&mdnew->synth.vc_mtx); - mtx_destroy(&mdnew->synth.status_mtx); - free(mdnew, M_DEVBUF); - panic("unsupported device type"); - return NULL; - } - mdnew->mdtype = type; - - for (unit = 0 ; ; unit++) { - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->unit == unit) - break; - } - if (md == NULL) - break; - } - - mdnew->unit = unit; - mtx_lock(&mdnew->flagqueue_mtx); - TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link); - - mtx_unlock(&midiinfo_mtx); - - return mdnew; -} - -/* Return the number of configured devices. */ -int -mididev_info_number(void) -{ - return nmidi + nsynth; -} - -/* Return the number of configured midi devices. */ -int -mididev_midi_number(void) -{ - return nmidi; -} - -/* Return the number of configured synth devices. */ -int -mididev_synth_number(void) -{ - return nsynth; -} - -/* - * here are the switches for the main functions. The switches do - * all necessary checks on the device number to make sure - * that the device is configured. They also provide some default - * functionalities so that device-specific drivers have to deal - * only with special cases. - */ - -static int -midiopen(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_open(i_dev, flags, mode, td); - break; - case MIDI_DEV_STATUS: - ret = midistat_open(i_dev, flags, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiclose(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_close(i_dev, flags, mode, td); - break; - case MIDI_DEV_STATUS: - ret = midistat_close(i_dev, flags, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiread(dev_t i_dev, struct uio * buf, int flag) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_read(i_dev, buf, flag); - break; - case MIDI_DEV_STATUS: - ret = midistat_read(i_dev, buf, flag); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiwrite(dev_t i_dev, struct uio * buf, int flag) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_write(i_dev, buf, flag); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_ioctl(i_dev, cmd, arg, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midipoll(dev_t i_dev, int events, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_poll(i_dev, events, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -/* - * Followings are the generic methods in midi drivers. - */ - -int -midi_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int dev, unit, ret; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_open: unit %d, flags 0x%x.\n", unit, flags)); - - if (d == NULL) - return (ENXIO); - - /* Mark this device busy. */ - mtx_lock(&d->flagqueue_mtx); - device_busy(d->dev); - if ((d->flags & MIDI_F_BUSY) != 0) { - mtx_unlock(&d->flagqueue_mtx); - printf("midi_open: unit %d is busy.\n", unit); - return (EBUSY); - } - d->fflags = flags; - d->flags |= MIDI_F_BUSY; - d->flags &= ~(MIDI_F_READING | MIDI_F_WRITING); - if ((d->fflags & O_NONBLOCK) != 0) - d->flags |= MIDI_F_NBIO; - - /* Init the queue. */ - if ((flags & FREAD) != 0) - midibuf_clear(&d->midi_dbuf_in); - if ((flags & FWRITE) != 0) { - midibuf_clear(&d->midi_dbuf_out); - midibuf_clear(&d->midi_dbuf_passthru); - } - - mtx_unlock(&d->flagqueue_mtx); - - if (d->open == NULL) - ret = 0; - else - ret = d->open(i_dev, flags, mode, td); - - mtx_lock(&d->flagqueue_mtx); - - /* Begin recording if nonblocking. */ - if ((d->flags & (MIDI_F_READING | MIDI_F_NBIO)) == MIDI_F_NBIO && (d->fflags & FREAD) != 0) - d->callback(d, MIDI_CB_START | MIDI_CB_RD); - - mtx_unlock(&d->flagqueue_mtx); - - MIDI_DEBUG(printf("midi_open: opened.\n")); - - return (ret); -} - -int -midi_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int dev, unit, ret; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_close: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - mtx_lock(&d->flagqueue_mtx); - - /* Stop recording and playing. */ - if ((d->flags & MIDI_F_READING) != 0) - d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD); - if ((d->flags & MIDI_F_WRITING) != 0) - d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR); - - /* Clear the queues. */ - if ((d->fflags & FREAD) != 0) - midibuf_clear(&d->midi_dbuf_in); - if ((d->fflags & FWRITE) != 0) { - midibuf_clear(&d->midi_dbuf_out); - midibuf_clear(&d->midi_dbuf_passthru); - } - - /* Stop playing and unmark this device busy. */ - d->flags &= ~MIDI_F_BUSY; - d->fflags = 0; - - device_unbusy(d->dev); - - mtx_unlock(&d->flagqueue_mtx); - - if (d->close == NULL) - ret = 0; - else - ret = d->close(i_dev, flags, mode, td); - - MIDI_DEBUG(printf("midi_close: closed.\n")); - - return (ret); -} - -int -midi_read(dev_t i_dev, struct uio * buf, int flag) -{ - int dev, unit, len, lenr, ret; - mididev_info *d ; - u_char *uiobuf; - - dev = minor(i_dev); - - d = get_mididev_info(i_dev, &unit); - MIDI_DEBUG(printf("midi_read: unit %d, resid %d.\n", unit, buf->uio_resid)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - len = buf->uio_resid; - lenr = 0; - - uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (uiobuf == NULL) - return (ENOMEM); - - mtx_lock(&d->flagqueue_mtx); - - /* Begin recording. */ - d->callback(d, MIDI_CB_START | MIDI_CB_RD); - - /* Have we got the data to read? */ - if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0) - ret = EAGAIN; - else { - if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl) - len = d->midi_dbuf_in.rl; - ret = midibuf_seqread(&d->midi_dbuf_in, uiobuf, len, &lenr, - d->callback, d, MIDI_CB_START | MIDI_CB_RD, - &d->flagqueue_mtx); - } - - mtx_unlock(&d->flagqueue_mtx); - - if (lenr > 0) - ret = uiomove(uiobuf, lenr, buf); - - free(uiobuf, M_DEVBUF); - - MIDI_DEBUG(printf("midi_read: ret %d, resid %d.\n", ret, buf->uio_resid)); - - return (ret); -} - -int -midi_write(dev_t i_dev, struct uio * buf, int flag) -{ - int dev, unit, len, len2, lenw, ret; - mididev_info *d; - u_char *uiobuf; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_write: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - len = buf->uio_resid; - lenw = 0; - - uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (uiobuf == NULL) - return (ENOMEM); - - ret = uiomove(uiobuf, len, buf); - if (ret != 0) { - free(uiobuf, M_DEVBUF); - return (ret); - } - - mtx_lock(&d->flagqueue_mtx); - - /* Have we got the data to write? */ - if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) { - /* Begin playing. */ - d->callback(d, MIDI_CB_START | MIDI_CB_WR); - ret = EAGAIN; - } else { - len2 = len; - if ((d->flags & MIDI_F_NBIO) != 0 && len2 > d->midi_dbuf_out.fl) - len2 = d->midi_dbuf_out.fl; - ret = midibuf_seqwrite(&d->midi_dbuf_out, uiobuf, len2, &lenw, - d->callback, d, MIDI_CB_START | MIDI_CB_WR, - &d->flagqueue_mtx); - } - - mtx_unlock(&d->flagqueue_mtx); - - free(uiobuf, M_DEVBUF); - buf->uio_resid = len - lenw; - - return (ret); -} - -/* - * generic midi ioctl. Functions of the default driver can be - * overridden by the device-specific ioctl call. - * If a device-specific call returns ENOSYS (Function not implemented), - * the default driver is called. Otherwise, the returned value - * is passed up. - * - * The default handler, for many parameters, sets the value in the - * descriptor, sets MIDI_F_INIT, and calls the callback function with - * reason INIT. If successful, the callback returns 1 and the caller - * can update the parameter. - */ - -int -midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - int ret = ENOSYS, dev, unit; - mididev_info *d; - struct snd_size *sndsize; - snd_sync_parm *sp; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - if (d == NULL) - return (ENXIO); - - if (d->ioctl) - ret = d->ioctl(i_dev, cmd, arg, mode, td); - if (ret != ENOSYS) - return ret; - - /* - * pass control to the default ioctl handler. Set ret to 0 now. - */ - ret = 0; - - MIDI_DEBUG(printf("midi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - /* - * all routines are called with int. blocked. Make sure that - * ints are re-enabled when calling slow or blocking functions! - */ - switch(cmd) { - - /* - * we start with the new ioctl interface. - */ - case AIONWRITE: /* how many bytes can write ? */ - mtx_lock(&d->flagqueue_mtx); - *(int *)arg = d->midi_dbuf_out.fl; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: fl %d.\n", *(int *)arg)); - break; - - case AIOSSIZE: /* set the current blocksize */ - sndsize = (struct snd_size *)arg; - MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - mtx_lock(&d->flagqueue_mtx); - if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) { - d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size; - d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size; - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - d->flags &= ~MIDI_F_HAS_SIZE; - mtx_unlock(&d->flagqueue_mtx); - } - else { - if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4) - sndsize->play_size = d->midi_dbuf_out.bufsize / 4; - if (sndsize->rec_size > d->midi_dbuf_in.bufsize / 4) - sndsize->rec_size = d->midi_dbuf_in.bufsize / 4; - /* Round up the size to the multiple of EV_SZ. */ - d->midi_dbuf_out.blocksize = - ((sndsize->play_size + d->midi_dbuf_out.unit_size - 1) - / d->midi_dbuf_out.unit_size) * d->midi_dbuf_out.unit_size; - d->midi_dbuf_in.blocksize = - ((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1) - / d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size; - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - d->flags |= MIDI_F_HAS_SIZE; - mtx_unlock(&d->flagqueue_mtx); - } - - ret = 0; - break; - - case AIOGSIZE: /* get the current blocksize */ - sndsize = (struct snd_size *)arg; - mtx_lock(&d->flagqueue_mtx); - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - - ret = 0; - break; - - case AIOSTOP: - mtx_lock(&d->flagqueue_mtx); - if (*(int *)arg == AIOSYNC_PLAY) /* play */ - *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); - else if (*(int *)arg == AIOSYNC_CAPTURE) - *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD); - else { - MIDI_DEBUG(printf("midi_ioctl: bad channel 0x%x.\n", *(int *)arg)); - *(int *)arg = 0 ; - } - mtx_unlock(&d->flagqueue_mtx); - break ; - - case AIOSYNC: - sp = (snd_sync_parm *)arg; - MIDI_DEBUG(printf("midi_ioctl: unimplemented, chan 0x%03lx pos %lu.\n", - sp->chan, - sp->pos)); - break; - /* - * here follow the standard ioctls (filio.h etc.) - */ - case FIONREAD: /* get # bytes to read */ - mtx_lock(&d->flagqueue_mtx); - *(int *)arg = d->midi_dbuf_in.rl; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: rl %d.\n", *(int *)arg)); - break; - - case FIOASYNC: /*set/clear async i/o */ - MIDI_DEBUG(printf("FIOASYNC\n")); - break; - - case FIONBIO: /* set/clear non-blocking i/o */ - mtx_lock(&d->flagqueue_mtx); - if (*(int *)arg == 0) - d->flags &= ~MIDI_F_NBIO ; - else - d->flags |= MIDI_F_NBIO ; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: arg %d.\n", *(int *)arg)); - break ; - - case MIOSPASSTHRU: /* set/clear passthru */ - mtx_lock(&d->flagqueue_mtx); - if (*(int *)arg == 0) - d->flags &= ~MIDI_F_PASSTHRU ; - else - d->flags |= MIDI_F_PASSTHRU ; - - /* Init the queue. */ - midibuf_clear(&d->midi_dbuf_passthru); - - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg)); - - /* FALLTHROUGH */ - case MIOGPASSTHRU: /* get passthru */ - mtx_lock(&d->flagqueue_mtx); - if ((d->flags & MIDI_F_PASSTHRU) != 0) - *(int *)arg = 1; - else - *(int *)arg = 0; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg)); - break; - - default: - MIDI_DEBUG(printf("midi_ioctl: default ioctl midi%d subdev %d fn 0x%08lx fail\n", - unit, dev & 0xf, cmd)); - ret = EINVAL; - break ; - } - return ret ; -} - -int -midi_poll(dev_t i_dev, int events, struct thread *td) -{ - int unit, dev, ret, lim; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_poll: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - mtx_lock(&d->flagqueue_mtx); - - /* Look up the apropriate queue and select it. */ - if ((events & (POLLOUT | POLLWRNORM)) != 0) { - /* Start playing. */ - d->callback(d, MIDI_CB_START | MIDI_CB_WR); - - /* Find out the boundary. */ - if ((d->flags & MIDI_F_HAS_SIZE) != 0) - lim = d->midi_dbuf_out.blocksize; - else - lim = d->midi_dbuf_out.unit_size; - if (d->midi_dbuf_out.fl < lim) - /* No enough space, record select. */ - selrecord(td, &d->midi_dbuf_out.sel); - else - /* We can write now. */ - ret |= events & (POLLOUT | POLLWRNORM); - } - if ((events & (POLLIN | POLLRDNORM)) != 0) { - /* Start recording. */ - d->callback(d, MIDI_CB_START | MIDI_CB_RD); - - /* Find out the boundary. */ - if ((d->flags & MIDI_F_HAS_SIZE) != 0) - lim = d->midi_dbuf_in.blocksize; - else - lim = d->midi_dbuf_in.unit_size; - if (d->midi_dbuf_in.rl < lim) - /* No data ready, record select. */ - selrecord(td, &d->midi_dbuf_in.sel); - else - /* We can write now. */ - ret |= events & (POLLIN | POLLRDNORM); - } - - mtx_unlock(&d->flagqueue_mtx); - - return (ret); -} - -void -midi_intr(mididev_info *d) -{ - if (d->intr != NULL) - d->intr(d->intrarg, d); -} - -/* Flush the output queue. */ -#define MIDI_SYNC_TIMEOUT 1 -int -midi_sync(mididev_info *d) -{ - int i, rl; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - MIDI_DEBUG(printf("midi_sync: unit %d.\n", d->unit)); - - while (d->midi_dbuf_out.rl > 0) { - if ((d->flags & MIDI_F_WRITING) == 0) - d->callback(d, MIDI_CB_START | MIDI_CB_WR); - rl = d->midi_dbuf_out.rl; - i = cv_timedwait_sig(&d->midi_dbuf_out.cv_out, - &d->flagqueue_mtx, - (d->midi_dbuf_out.bufsize * 10 * hz / 38400) - + MIDI_SYNC_TIMEOUT * hz); - if (i == EINTR || i == ERESTART) { - if (i == EINTR) - d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); - return (i); - } - if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) { - /* A queue seems to be stuck up. Give up and clear the queue. */ - d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); - midibuf_clear(&d->midi_dbuf_out); - return (0); - } - } - - return 0; -} - -/* - * These handle the status message of the midi drivers. - */ - -int -midistat_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - if (midistatbusy) - return (EBUSY); - - bzero(midistatbuf, sizeof(midistatbuf)); - midistatptr = 0; - if (midi_initstatus(midistatbuf, sizeof(midistatbuf) - 1)) - return (ENOMEM); - - midistatbusy = 1; - - return (0); -} - -int -midistat_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - midistatbusy = 0; - - return (0); -} - -int -midistat_read(dev_t i_dev, struct uio * buf, int flag) -{ - return midi_readstatus(midistatbuf, &midistatptr, buf); -} - -/* - * finally, some "libraries" - */ - -/* Inits the buffer for /dev/midistat. */ -static int -midi_initstatus(char *buf, int size) -{ - int i, p; - device_t dev; - mididev_info *md; - - p = 0; - p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__); - for (i = 0 ; i < mididev_info_number() ; i++) { - md = get_mididev_info_unit(i); - if (!MIDICONFED(md)) - continue; - dev = devclass_get_device(midi_devclass, i); - if (p < size) - p += snprintf(&buf[p], size - p, "midi%d: <%s> %s\n", i, device_get_desc(dev), md->midistat); - else - return (1); - } - - return (0); -} - -/* Reads the status message. */ -static int -midi_readstatus(char *buf, int *ptr, struct uio *uio) -{ - int len; - - len = min(uio->uio_resid, strlen(&buf[*ptr])); - if (len > 0) { - uiomove(&buf[*ptr], len, uio); - *ptr += len; - } - - return (0); -} - -char -*midi_cmdname(int cmd, midi_cmdtab *tab) -{ - while (tab->name != NULL) { - if (cmd == tab->cmd) - return (tab->name); - tab++; - } - - return ("unknown"); -} |