1206b17d7SAlexander Leidinger /*- 248351eafSJoel Dahl * Copyright (c) 2003 Mathew Kanner 3206b17d7SAlexander Leidinger * Copyright (c) 1998 The NetBSD Foundation, Inc. 4206b17d7SAlexander Leidinger * All rights reserved. 5206b17d7SAlexander Leidinger * 6206b17d7SAlexander Leidinger * This code is derived from software contributed to The NetBSD Foundation 7206b17d7SAlexander Leidinger * by Lennart Augustsson (augustss@netbsd.org). 8206b17d7SAlexander Leidinger * 9206b17d7SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 10206b17d7SAlexander Leidinger * modification, are permitted provided that the following conditions 11206b17d7SAlexander Leidinger * are met: 12206b17d7SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 13206b17d7SAlexander Leidinger * notice, this list of conditions and the following disclaimer. 14206b17d7SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 15206b17d7SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 16206b17d7SAlexander Leidinger * documentation and/or other materials provided with the distribution. 17206b17d7SAlexander Leidinger * 18206b17d7SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19206b17d7SAlexander Leidinger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20206b17d7SAlexander Leidinger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21206b17d7SAlexander Leidinger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22206b17d7SAlexander Leidinger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23206b17d7SAlexander Leidinger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24206b17d7SAlexander Leidinger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25206b17d7SAlexander Leidinger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26206b17d7SAlexander Leidinger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27206b17d7SAlexander Leidinger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28206b17d7SAlexander Leidinger * POSSIBILITY OF SUCH DAMAGE. 29206b17d7SAlexander Leidinger */ 30206b17d7SAlexander Leidinger 31206b17d7SAlexander Leidinger /* 32206b17d7SAlexander Leidinger * Parts of this file started out as NetBSD: midi.c 1.31 33206b17d7SAlexander Leidinger * They are mostly gone. Still the most obvious will be the state 34206b17d7SAlexander Leidinger * machine midi_in 35206b17d7SAlexander Leidinger */ 36206b17d7SAlexander Leidinger 37206b17d7SAlexander Leidinger #include <sys/cdefs.h> 38206b17d7SAlexander Leidinger __FBSDID("$FreeBSD$"); 39206b17d7SAlexander Leidinger 40206b17d7SAlexander Leidinger #include <sys/param.h> 41206b17d7SAlexander Leidinger #include <sys/queue.h> 42206b17d7SAlexander Leidinger #include <sys/kernel.h> 43206b17d7SAlexander Leidinger #include <sys/lock.h> 44206b17d7SAlexander Leidinger #include <sys/mutex.h> 45206b17d7SAlexander Leidinger #include <sys/proc.h> 46206b17d7SAlexander Leidinger #include <sys/signalvar.h> 47206b17d7SAlexander Leidinger #include <sys/conf.h> 48206b17d7SAlexander Leidinger #include <sys/selinfo.h> 49206b17d7SAlexander Leidinger #include <sys/sysctl.h> 50206b17d7SAlexander Leidinger #include <sys/types.h> 51206b17d7SAlexander Leidinger #include <sys/malloc.h> 52206b17d7SAlexander Leidinger #include <sys/param.h> 53206b17d7SAlexander Leidinger #include <sys/systm.h> 54206b17d7SAlexander Leidinger #include <sys/proc.h> 55206b17d7SAlexander Leidinger #include <sys/fcntl.h> 56206b17d7SAlexander Leidinger #include <sys/types.h> 57206b17d7SAlexander Leidinger #include <sys/uio.h> 58206b17d7SAlexander Leidinger #include <sys/poll.h> 59206b17d7SAlexander Leidinger #include <sys/sbuf.h> 60206b17d7SAlexander Leidinger #include <sys/kobj.h> 61206b17d7SAlexander Leidinger #include <sys/module.h> 62206b17d7SAlexander Leidinger 6390da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 6490da2b28SAriff Abdullah #include "opt_snd.h" 6590da2b28SAriff Abdullah #endif 6690da2b28SAriff Abdullah 67206b17d7SAlexander Leidinger #include <dev/sound/midi/midi.h> 68206b17d7SAlexander Leidinger #include "mpu_if.h" 69206b17d7SAlexander Leidinger 70206b17d7SAlexander Leidinger #include <dev/sound/midi/midiq.h> 71206b17d7SAlexander Leidinger #include "synth_if.h" 72206b17d7SAlexander Leidinger MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area"); 73206b17d7SAlexander Leidinger 745870e3c9SAriff Abdullah #ifndef KOBJMETHOD_END 755870e3c9SAriff Abdullah #define KOBJMETHOD_END { NULL, NULL } 765870e3c9SAriff Abdullah #endif 77206b17d7SAlexander Leidinger 78206b17d7SAlexander Leidinger #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f)) 79206b17d7SAlexander Leidinger #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c) 80206b17d7SAlexander Leidinger 81206b17d7SAlexander Leidinger #define MIDI_DEV_RAW 2 82206b17d7SAlexander Leidinger #define MIDI_DEV_MIDICTL 12 83206b17d7SAlexander Leidinger 84206b17d7SAlexander Leidinger enum midi_states { 85206b17d7SAlexander Leidinger MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA 86206b17d7SAlexander Leidinger }; 87206b17d7SAlexander Leidinger 88206b17d7SAlexander Leidinger /* 897cbd5addSTai-hwa Liang * The MPU interface current has init() uninit() inqsize() outqsize() 90206b17d7SAlexander Leidinger * callback() : fiddle with the tx|rx status. 91206b17d7SAlexander Leidinger */ 92206b17d7SAlexander Leidinger 93206b17d7SAlexander Leidinger #include "mpu_if.h" 94206b17d7SAlexander Leidinger 95206b17d7SAlexander Leidinger /* 96206b17d7SAlexander Leidinger * /dev/rmidi Structure definitions 97206b17d7SAlexander Leidinger */ 98206b17d7SAlexander Leidinger 99206b17d7SAlexander Leidinger #define MIDI_NAMELEN 16 100206b17d7SAlexander Leidinger struct snd_midi { 101206b17d7SAlexander Leidinger KOBJ_FIELDS; 102206b17d7SAlexander Leidinger struct mtx lock; /* Protects all but queues */ 103206b17d7SAlexander Leidinger void *cookie; 104206b17d7SAlexander Leidinger 105206b17d7SAlexander Leidinger int unit; /* Should only be used in midistat */ 106206b17d7SAlexander Leidinger int channel; /* Should only be used in midistat */ 107206b17d7SAlexander Leidinger 108206b17d7SAlexander Leidinger int busy; 109206b17d7SAlexander Leidinger int flags; /* File flags */ 110206b17d7SAlexander Leidinger char name[MIDI_NAMELEN]; 111206b17d7SAlexander Leidinger struct mtx qlock; /* Protects inq, outq and flags */ 112206b17d7SAlexander Leidinger MIDIQ_HEAD(, char) inq, outq; 113206b17d7SAlexander Leidinger int rchan, wchan; 114206b17d7SAlexander Leidinger struct selinfo rsel, wsel; 1158f981688SAlexander Leidinger int hiwat; /* QLEN(outq)>High-water -> disable 1168f981688SAlexander Leidinger * writes from userland */ 117206b17d7SAlexander Leidinger enum midi_states inq_state; 1188f981688SAlexander Leidinger int inq_status, inq_left; /* Variables for the state machine in 1198f981688SAlexander Leidinger * Midi_in, this is to provide that 1208f981688SAlexander Leidinger * signals only get issued only 121206b17d7SAlexander Leidinger * complete command packets. */ 122206b17d7SAlexander Leidinger struct proc *async; 123206b17d7SAlexander Leidinger struct cdev *dev; 124206b17d7SAlexander Leidinger struct synth_midi *synth; 125206b17d7SAlexander Leidinger int synth_flags; 126206b17d7SAlexander Leidinger TAILQ_ENTRY(snd_midi) link; 127206b17d7SAlexander Leidinger }; 128206b17d7SAlexander Leidinger 129206b17d7SAlexander Leidinger struct synth_midi { 130206b17d7SAlexander Leidinger KOBJ_FIELDS; 131206b17d7SAlexander Leidinger struct snd_midi *m; 132206b17d7SAlexander Leidinger }; 133206b17d7SAlexander Leidinger 134206b17d7SAlexander Leidinger static synth_open_t midisynth_open; 135206b17d7SAlexander Leidinger static synth_close_t midisynth_close; 136206b17d7SAlexander Leidinger static synth_writeraw_t midisynth_writeraw; 137206b17d7SAlexander Leidinger static synth_killnote_t midisynth_killnote; 138206b17d7SAlexander Leidinger static synth_startnote_t midisynth_startnote; 139206b17d7SAlexander Leidinger static synth_setinstr_t midisynth_setinstr; 140206b17d7SAlexander Leidinger static synth_alloc_t midisynth_alloc; 141206b17d7SAlexander Leidinger static synth_controller_t midisynth_controller; 142206b17d7SAlexander Leidinger static synth_bender_t midisynth_bender; 143206b17d7SAlexander Leidinger 144206b17d7SAlexander Leidinger 145206b17d7SAlexander Leidinger static kobj_method_t midisynth_methods[] = { 146206b17d7SAlexander Leidinger KOBJMETHOD(synth_open, midisynth_open), 147206b17d7SAlexander Leidinger KOBJMETHOD(synth_close, midisynth_close), 148206b17d7SAlexander Leidinger KOBJMETHOD(synth_writeraw, midisynth_writeraw), 149206b17d7SAlexander Leidinger KOBJMETHOD(synth_setinstr, midisynth_setinstr), 150206b17d7SAlexander Leidinger KOBJMETHOD(synth_startnote, midisynth_startnote), 151206b17d7SAlexander Leidinger KOBJMETHOD(synth_killnote, midisynth_killnote), 152206b17d7SAlexander Leidinger KOBJMETHOD(synth_alloc, midisynth_alloc), 153206b17d7SAlexander Leidinger KOBJMETHOD(synth_controller, midisynth_controller), 154206b17d7SAlexander Leidinger KOBJMETHOD(synth_bender, midisynth_bender), 15590da2b28SAriff Abdullah KOBJMETHOD_END 156206b17d7SAlexander Leidinger }; 157206b17d7SAlexander Leidinger 158206b17d7SAlexander Leidinger DEFINE_CLASS(midisynth, midisynth_methods, 0); 159206b17d7SAlexander Leidinger 160206b17d7SAlexander Leidinger /* 161206b17d7SAlexander Leidinger * Module Exports & Interface 162206b17d7SAlexander Leidinger * 1637cbd5addSTai-hwa Liang * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan, 1647cbd5addSTai-hwa Liang * void *cookie) 1657cbd5addSTai-hwa Liang * int midi_uninit(struct snd_midi *) 1667cbd5addSTai-hwa Liang * 1677cbd5addSTai-hwa Liang * 0 == no error 1687cbd5addSTai-hwa Liang * EBUSY or other error 1697cbd5addSTai-hwa Liang * 1707cbd5addSTai-hwa Liang * int midi_in(struct snd_midi *, char *buf, int count) 1717cbd5addSTai-hwa Liang * int midi_out(struct snd_midi *, char *buf, int count) 172206b17d7SAlexander Leidinger * 173206b17d7SAlexander Leidinger * midi_{in,out} return actual size transfered 174206b17d7SAlexander Leidinger * 175206b17d7SAlexander Leidinger */ 176206b17d7SAlexander Leidinger 177206b17d7SAlexander Leidinger 178206b17d7SAlexander Leidinger /* 179206b17d7SAlexander Leidinger * midi_devs tailq, holder of all rmidi instances protected by midistat_lock 180206b17d7SAlexander Leidinger */ 181206b17d7SAlexander Leidinger 182206b17d7SAlexander Leidinger TAILQ_HEAD(, snd_midi) midi_devs; 183206b17d7SAlexander Leidinger 184206b17d7SAlexander Leidinger /* 185206b17d7SAlexander Leidinger * /dev/midistat variables and declarations, protected by midistat_lock 186206b17d7SAlexander Leidinger */ 187206b17d7SAlexander Leidinger 188206b17d7SAlexander Leidinger static struct mtx midistat_lock; 189206b17d7SAlexander Leidinger static int midistat_isopen = 0; 190206b17d7SAlexander Leidinger static struct sbuf midistat_sbuf; 191206b17d7SAlexander Leidinger static int midistat_bufptr; 192206b17d7SAlexander Leidinger static struct cdev *midistat_dev; 193206b17d7SAlexander Leidinger 194206b17d7SAlexander Leidinger /* 195206b17d7SAlexander Leidinger * /dev/midistat dev_t declarations 196206b17d7SAlexander Leidinger */ 197206b17d7SAlexander Leidinger 198206b17d7SAlexander Leidinger static d_open_t midistat_open; 199206b17d7SAlexander Leidinger static d_close_t midistat_close; 200206b17d7SAlexander Leidinger static d_read_t midistat_read; 201206b17d7SAlexander Leidinger 202206b17d7SAlexander Leidinger static struct cdevsw midistat_cdevsw = { 203206b17d7SAlexander Leidinger .d_version = D_VERSION, 204206b17d7SAlexander Leidinger .d_open = midistat_open, 205206b17d7SAlexander Leidinger .d_close = midistat_close, 206206b17d7SAlexander Leidinger .d_read = midistat_read, 207206b17d7SAlexander Leidinger .d_name = "midistat", 208206b17d7SAlexander Leidinger }; 209206b17d7SAlexander Leidinger 210206b17d7SAlexander Leidinger 211206b17d7SAlexander Leidinger /* 212206b17d7SAlexander Leidinger * /dev/rmidi dev_t declarations, struct variable access is protected by 213206b17d7SAlexander Leidinger * locks contained within the structure. 214206b17d7SAlexander Leidinger */ 215206b17d7SAlexander Leidinger 216206b17d7SAlexander Leidinger static d_open_t midi_open; 217206b17d7SAlexander Leidinger static d_close_t midi_close; 218206b17d7SAlexander Leidinger static d_ioctl_t midi_ioctl; 219206b17d7SAlexander Leidinger static d_read_t midi_read; 220206b17d7SAlexander Leidinger static d_write_t midi_write; 221206b17d7SAlexander Leidinger static d_poll_t midi_poll; 222206b17d7SAlexander Leidinger 223206b17d7SAlexander Leidinger static struct cdevsw midi_cdevsw = { 224206b17d7SAlexander Leidinger .d_version = D_VERSION, 225206b17d7SAlexander Leidinger .d_open = midi_open, 226206b17d7SAlexander Leidinger .d_close = midi_close, 227206b17d7SAlexander Leidinger .d_read = midi_read, 228206b17d7SAlexander Leidinger .d_write = midi_write, 229206b17d7SAlexander Leidinger .d_ioctl = midi_ioctl, 230206b17d7SAlexander Leidinger .d_poll = midi_poll, 231206b17d7SAlexander Leidinger .d_name = "rmidi", 232206b17d7SAlexander Leidinger }; 233206b17d7SAlexander Leidinger 234206b17d7SAlexander Leidinger /* 235206b17d7SAlexander Leidinger * Prototypes of library functions 236206b17d7SAlexander Leidinger */ 237206b17d7SAlexander Leidinger 238206b17d7SAlexander Leidinger static int midi_destroy(struct snd_midi *, int); 239206b17d7SAlexander Leidinger static int midistat_prepare(struct sbuf * s); 240206b17d7SAlexander Leidinger static int midi_load(void); 241206b17d7SAlexander Leidinger static int midi_unload(void); 242206b17d7SAlexander Leidinger 243206b17d7SAlexander Leidinger /* 244206b17d7SAlexander Leidinger * Misc declr. 245206b17d7SAlexander Leidinger */ 246206b17d7SAlexander Leidinger SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver"); 2476472ac3dSEd Schouten static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device"); 248206b17d7SAlexander Leidinger 249206b17d7SAlexander Leidinger int midi_debug; 250851a904aSAlexander Leidinger /* XXX: should this be moved into debug.midi? */ 251206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); 252206b17d7SAlexander Leidinger 253206b17d7SAlexander Leidinger int midi_dumpraw; 254206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, ""); 255206b17d7SAlexander Leidinger 256206b17d7SAlexander Leidinger int midi_instroff; 257206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, ""); 258206b17d7SAlexander Leidinger 259206b17d7SAlexander Leidinger int midistat_verbose; 260206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW, 261206b17d7SAlexander Leidinger &midistat_verbose, 0, ""); 262206b17d7SAlexander Leidinger 263206b17d7SAlexander Leidinger #define MIDI_DEBUG(l,a) if(midi_debug>=l) a 264206b17d7SAlexander Leidinger /* 265206b17d7SAlexander Leidinger * CODE START 266206b17d7SAlexander Leidinger */ 267206b17d7SAlexander Leidinger 268206b17d7SAlexander Leidinger /* 269206b17d7SAlexander Leidinger * Register a new rmidi device. cls midi_if interface unit == 0 means 270206b17d7SAlexander Leidinger * auto-assign new unit number unit != 0 already assigned a unit number, eg. 271206b17d7SAlexander Leidinger * not the first channel provided by this device. channel, sub-unit 272206b17d7SAlexander Leidinger * cookie is passed back on MPU calls Typical device drivers will call with 273206b17d7SAlexander Leidinger * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care 274206b17d7SAlexander Leidinger * what unit number is used. 275206b17d7SAlexander Leidinger * 276206b17d7SAlexander Leidinger * It is an error to call midi_init with an already used unit/channel combo. 277206b17d7SAlexander Leidinger * 278206b17d7SAlexander Leidinger * Returns NULL on error 279206b17d7SAlexander Leidinger * 280206b17d7SAlexander Leidinger */ 281206b17d7SAlexander Leidinger struct snd_midi * 282206b17d7SAlexander Leidinger midi_init(kobj_class_t cls, int unit, int channel, void *cookie) 283206b17d7SAlexander Leidinger { 284206b17d7SAlexander Leidinger struct snd_midi *m; 285206b17d7SAlexander Leidinger int i; 286206b17d7SAlexander Leidinger int inqsize, outqsize; 287206b17d7SAlexander Leidinger MIDI_TYPE *buf; 288206b17d7SAlexander Leidinger 289206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel)); 290206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 291206b17d7SAlexander Leidinger /* 292206b17d7SAlexander Leidinger * Protect against call with existing unit/channel or auto-allocate a 293206b17d7SAlexander Leidinger * new unit number. 294206b17d7SAlexander Leidinger */ 295206b17d7SAlexander Leidinger i = -1; 296206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) { 297206b17d7SAlexander Leidinger mtx_lock(&m->lock); 298206b17d7SAlexander Leidinger if (unit != 0) { 299206b17d7SAlexander Leidinger if (m->unit == unit && m->channel == channel) { 300206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 301206b17d7SAlexander Leidinger goto err0; 302206b17d7SAlexander Leidinger } 303206b17d7SAlexander Leidinger } else { 304206b17d7SAlexander Leidinger /* 305206b17d7SAlexander Leidinger * Find a better unit number 306206b17d7SAlexander Leidinger */ 307206b17d7SAlexander Leidinger if (m->unit > i) 308206b17d7SAlexander Leidinger i = m->unit; 309206b17d7SAlexander Leidinger } 310206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 311206b17d7SAlexander Leidinger } 312206b17d7SAlexander Leidinger 313206b17d7SAlexander Leidinger if (unit == 0) 314206b17d7SAlexander Leidinger unit = i + 1; 315206b17d7SAlexander Leidinger 316206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel)); 317206b17d7SAlexander Leidinger m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 318206b17d7SAlexander Leidinger if (m == NULL) 319206b17d7SAlexander Leidinger goto err0; 320206b17d7SAlexander Leidinger 321206b17d7SAlexander Leidinger m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO); 322671b5759STai-hwa Liang if (m->synth == NULL) 323671b5759STai-hwa Liang goto err1; 324206b17d7SAlexander Leidinger kobj_init((kobj_t)m->synth, &midisynth_class); 325206b17d7SAlexander Leidinger m->synth->m = m; 326206b17d7SAlexander Leidinger kobj_init((kobj_t)m, cls); 327206b17d7SAlexander Leidinger inqsize = MPU_INQSIZE(m, cookie); 328206b17d7SAlexander Leidinger outqsize = MPU_OUTQSIZE(m, cookie); 329206b17d7SAlexander Leidinger 330206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize)); 331206b17d7SAlexander Leidinger if (!inqsize && !outqsize) 332671b5759STai-hwa Liang goto err2; 333206b17d7SAlexander Leidinger 3348c0a77e3SAriff Abdullah mtx_init(&m->lock, "raw midi", NULL, 0); 3358c0a77e3SAriff Abdullah mtx_init(&m->qlock, "q raw midi", NULL, 0); 336206b17d7SAlexander Leidinger 337206b17d7SAlexander Leidinger mtx_lock(&m->lock); 338206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 339206b17d7SAlexander Leidinger 340206b17d7SAlexander Leidinger if (inqsize) 341206b17d7SAlexander Leidinger buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT); 342206b17d7SAlexander Leidinger else 343206b17d7SAlexander Leidinger buf = NULL; 344206b17d7SAlexander Leidinger 345206b17d7SAlexander Leidinger MIDIQ_INIT(m->inq, buf, inqsize); 346206b17d7SAlexander Leidinger 347206b17d7SAlexander Leidinger if (outqsize) 348206b17d7SAlexander Leidinger buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT); 349206b17d7SAlexander Leidinger else 350206b17d7SAlexander Leidinger buf = NULL; 351206b17d7SAlexander Leidinger m->hiwat = outqsize / 2; 352206b17d7SAlexander Leidinger 353206b17d7SAlexander Leidinger MIDIQ_INIT(m->outq, buf, outqsize); 354206b17d7SAlexander Leidinger 355206b17d7SAlexander Leidinger if ((inqsize && !MIDIQ_BUF(m->inq)) || 356206b17d7SAlexander Leidinger (outqsize && !MIDIQ_BUF(m->outq))) 357671b5759STai-hwa Liang goto err3; 358206b17d7SAlexander Leidinger 359206b17d7SAlexander Leidinger 360206b17d7SAlexander Leidinger m->busy = 0; 361206b17d7SAlexander Leidinger m->flags = 0; 362206b17d7SAlexander Leidinger m->unit = unit; 363206b17d7SAlexander Leidinger m->channel = channel; 364206b17d7SAlexander Leidinger m->cookie = cookie; 365206b17d7SAlexander Leidinger 366206b17d7SAlexander Leidinger if (MPU_INIT(m, cookie)) 367671b5759STai-hwa Liang goto err3; 368206b17d7SAlexander Leidinger 369206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 370206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 371206b17d7SAlexander Leidinger 372206b17d7SAlexander Leidinger TAILQ_INSERT_TAIL(&midi_devs, m, link); 373206b17d7SAlexander Leidinger 374206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 375206b17d7SAlexander Leidinger 376206b17d7SAlexander Leidinger m->dev = make_dev(&midi_cdevsw, 377206b17d7SAlexander Leidinger MIDIMKMINOR(unit, MIDI_DEV_RAW, channel), 378206b17d7SAlexander Leidinger UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel); 379206b17d7SAlexander Leidinger m->dev->si_drv1 = m; 380206b17d7SAlexander Leidinger 381206b17d7SAlexander Leidinger return m; 382206b17d7SAlexander Leidinger 383671b5759STai-hwa Liang err3: mtx_destroy(&m->qlock); 384206b17d7SAlexander Leidinger mtx_destroy(&m->lock); 385206b17d7SAlexander Leidinger 386206b17d7SAlexander Leidinger if (MIDIQ_BUF(m->inq)) 387206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->inq), M_MIDI); 388206b17d7SAlexander Leidinger if (MIDIQ_BUF(m->outq)) 389206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->outq), M_MIDI); 390671b5759STai-hwa Liang err2: free(m->synth, M_MIDI); 391206b17d7SAlexander Leidinger err1: free(m, M_MIDI); 392206b17d7SAlexander Leidinger err0: mtx_unlock(&midistat_lock); 393206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_init ended in error\n")); 394206b17d7SAlexander Leidinger return NULL; 395206b17d7SAlexander Leidinger } 396206b17d7SAlexander Leidinger 397206b17d7SAlexander Leidinger /* 398206b17d7SAlexander Leidinger * midi_uninit does not call MIDI_UNINIT, as since this is the implementors 3997cbd5addSTai-hwa Liang * entry point. midi_uninit if fact, does not send any methods. A call to 400206b17d7SAlexander Leidinger * midi_uninit is a defacto promise that you won't manipulate ch anymore 401206b17d7SAlexander Leidinger * 402206b17d7SAlexander Leidinger */ 403206b17d7SAlexander Leidinger 404206b17d7SAlexander Leidinger int 405206b17d7SAlexander Leidinger midi_uninit(struct snd_midi *m) 406206b17d7SAlexander Leidinger { 407206b17d7SAlexander Leidinger int err; 408206b17d7SAlexander Leidinger 409076cf2ddSTai-hwa Liang err = EBUSY; 410206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 411206b17d7SAlexander Leidinger mtx_lock(&m->lock); 412206b17d7SAlexander Leidinger if (m->busy) { 413206b17d7SAlexander Leidinger if (!(m->rchan || m->wchan)) 414206b17d7SAlexander Leidinger goto err; 415206b17d7SAlexander Leidinger 416206b17d7SAlexander Leidinger if (m->rchan) { 417206b17d7SAlexander Leidinger wakeup(&m->rchan); 418206b17d7SAlexander Leidinger m->rchan = 0; 419206b17d7SAlexander Leidinger } 420206b17d7SAlexander Leidinger if (m->wchan) { 421206b17d7SAlexander Leidinger wakeup(&m->wchan); 422206b17d7SAlexander Leidinger m->wchan = 0; 423206b17d7SAlexander Leidinger } 424206b17d7SAlexander Leidinger } 425206b17d7SAlexander Leidinger err = midi_destroy(m, 0); 426206b17d7SAlexander Leidinger if (!err) 427206b17d7SAlexander Leidinger goto exit; 428206b17d7SAlexander Leidinger 429206b17d7SAlexander Leidinger err: mtx_unlock(&m->lock); 430206b17d7SAlexander Leidinger exit: mtx_unlock(&midistat_lock); 431206b17d7SAlexander Leidinger return err; 432206b17d7SAlexander Leidinger } 433206b17d7SAlexander Leidinger 434206b17d7SAlexander Leidinger /* 435206b17d7SAlexander Leidinger * midi_in: process all data until the queue is full, then discards the rest. 436206b17d7SAlexander Leidinger * Since midi_in is a state machine, data discards can cause it to get out of 437206b17d7SAlexander Leidinger * whack. Process as much as possible. It calls, wakeup, selnotify and 438206b17d7SAlexander Leidinger * psignal at most once. 439206b17d7SAlexander Leidinger */ 440206b17d7SAlexander Leidinger 4412916c293SRuslan Ermilov #ifdef notdef 442206b17d7SAlexander Leidinger static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0}; 4438f981688SAlexander Leidinger 444206b17d7SAlexander Leidinger #endif /* notdef */ 445206b17d7SAlexander Leidinger /* Number of bytes in a MIDI command */ 446206b17d7SAlexander Leidinger #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 447206b17d7SAlexander Leidinger #define MIDI_ACK 0xfe 448206b17d7SAlexander Leidinger #define MIDI_IS_STATUS(d) ((d) >= 0x80) 449206b17d7SAlexander Leidinger #define MIDI_IS_COMMON(d) ((d) >= 0xf0) 450206b17d7SAlexander Leidinger 451206b17d7SAlexander Leidinger #define MIDI_SYSEX_START 0xF0 452206b17d7SAlexander Leidinger #define MIDI_SYSEX_END 0xF7 453206b17d7SAlexander Leidinger 454206b17d7SAlexander Leidinger 455206b17d7SAlexander Leidinger int 456206b17d7SAlexander Leidinger midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size) 457206b17d7SAlexander Leidinger { 458206b17d7SAlexander Leidinger /* int i, sig, enq; */ 459206b17d7SAlexander Leidinger int used; 4608f981688SAlexander Leidinger 461206b17d7SAlexander Leidinger /* MIDI_TYPE data; */ 462206b17d7SAlexander Leidinger MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size)); 463206b17d7SAlexander Leidinger 464206b17d7SAlexander Leidinger /* 465206b17d7SAlexander Leidinger * XXX: locking flub 466206b17d7SAlexander Leidinger */ 467206b17d7SAlexander Leidinger if (!(m->flags & M_RX)) 468206b17d7SAlexander Leidinger return size; 469206b17d7SAlexander Leidinger 470206b17d7SAlexander Leidinger used = 0; 471206b17d7SAlexander Leidinger 472206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 473206b17d7SAlexander Leidinger #if 0 474206b17d7SAlexander Leidinger /* 475206b17d7SAlexander Leidinger * Don't bother queuing if not in read mode. Discard everything and 476206b17d7SAlexander Leidinger * return size so the caller doesn't freak out. 477206b17d7SAlexander Leidinger */ 478206b17d7SAlexander Leidinger 479206b17d7SAlexander Leidinger if (!(m->flags & M_RX)) 480206b17d7SAlexander Leidinger return size; 481206b17d7SAlexander Leidinger 482206b17d7SAlexander Leidinger for (i = sig = 0; i < size; i++) { 483206b17d7SAlexander Leidinger 484206b17d7SAlexander Leidinger data = buf[i]; 485206b17d7SAlexander Leidinger enq = 0; 486206b17d7SAlexander Leidinger if (data == MIDI_ACK) 487206b17d7SAlexander Leidinger continue; 488206b17d7SAlexander Leidinger 489206b17d7SAlexander Leidinger switch (m->inq_state) { 490206b17d7SAlexander Leidinger case MIDI_IN_START: 491206b17d7SAlexander Leidinger if (MIDI_IS_STATUS(data)) { 492206b17d7SAlexander Leidinger switch (data) { 493206b17d7SAlexander Leidinger case 0xf0: /* Sysex */ 494206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_SYSEX; 495206b17d7SAlexander Leidinger break; 496206b17d7SAlexander Leidinger case 0xf1: /* MTC quarter frame */ 497206b17d7SAlexander Leidinger case 0xf3: /* Song select */ 498206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA; 499206b17d7SAlexander Leidinger enq = 1; 500206b17d7SAlexander Leidinger m->inq_left = 1; 501206b17d7SAlexander Leidinger break; 502206b17d7SAlexander Leidinger case 0xf2: /* Song position pointer */ 503206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA; 504206b17d7SAlexander Leidinger enq = 1; 505206b17d7SAlexander Leidinger m->inq_left = 2; 506206b17d7SAlexander Leidinger break; 507206b17d7SAlexander Leidinger default: 508206b17d7SAlexander Leidinger if (MIDI_IS_COMMON(data)) { 509206b17d7SAlexander Leidinger enq = 1; 510206b17d7SAlexander Leidinger sig = 1; 511206b17d7SAlexander Leidinger } else { 512206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA; 513206b17d7SAlexander Leidinger enq = 1; 514206b17d7SAlexander Leidinger m->inq_status = data; 515206b17d7SAlexander Leidinger m->inq_left = MIDI_LENGTH(data); 516206b17d7SAlexander Leidinger } 517206b17d7SAlexander Leidinger break; 518206b17d7SAlexander Leidinger } 519206b17d7SAlexander Leidinger } else if (MIDI_IS_STATUS(m->inq_status)) { 520206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA; 521206b17d7SAlexander Leidinger if (!MIDIQ_FULL(m->inq)) { 522206b17d7SAlexander Leidinger used++; 523206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, &m->inq_status, 1); 524206b17d7SAlexander Leidinger } 525206b17d7SAlexander Leidinger enq = 1; 526206b17d7SAlexander Leidinger m->inq_left = MIDI_LENGTH(m->inq_status) - 1; 527206b17d7SAlexander Leidinger } 528206b17d7SAlexander Leidinger break; 529206b17d7SAlexander Leidinger /* 530206b17d7SAlexander Leidinger * End of case MIDI_IN_START: 531206b17d7SAlexander Leidinger */ 532206b17d7SAlexander Leidinger 533206b17d7SAlexander Leidinger case MIDI_IN_DATA: 534206b17d7SAlexander Leidinger enq = 1; 535206b17d7SAlexander Leidinger if (--m->inq_left <= 0) 536206b17d7SAlexander Leidinger sig = 1;/* deliver data */ 537206b17d7SAlexander Leidinger break; 538206b17d7SAlexander Leidinger case MIDI_IN_SYSEX: 539206b17d7SAlexander Leidinger if (data == MIDI_SYSEX_END) 540206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_START; 541206b17d7SAlexander Leidinger break; 542206b17d7SAlexander Leidinger } 543206b17d7SAlexander Leidinger 544206b17d7SAlexander Leidinger if (enq) 545206b17d7SAlexander Leidinger if (!MIDIQ_FULL(m->inq)) { 546206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, &data, 1); 547206b17d7SAlexander Leidinger used++; 548206b17d7SAlexander Leidinger } 549206b17d7SAlexander Leidinger /* 550206b17d7SAlexander Leidinger * End of the state machines main "for loop" 551206b17d7SAlexander Leidinger */ 552206b17d7SAlexander Leidinger } 553206b17d7SAlexander Leidinger if (sig) { 554206b17d7SAlexander Leidinger #endif 5558f981688SAlexander Leidinger MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n", 5568f981688SAlexander Leidinger (intmax_t)MIDIQ_LEN(m->inq), 5578f981688SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->inq))); 558206b17d7SAlexander Leidinger if (MIDIQ_AVAIL(m->inq) > size) { 559206b17d7SAlexander Leidinger used = size; 560206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, buf, size); 561206b17d7SAlexander Leidinger } else { 562206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n")); 563206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 564206b17d7SAlexander Leidinger return 0; 565206b17d7SAlexander Leidinger } 566206b17d7SAlexander Leidinger if (m->rchan) { 567206b17d7SAlexander Leidinger wakeup(&m->rchan); 568206b17d7SAlexander Leidinger m->rchan = 0; 569206b17d7SAlexander Leidinger } 570206b17d7SAlexander Leidinger selwakeup(&m->rsel); 571206b17d7SAlexander Leidinger if (m->async) { 572206b17d7SAlexander Leidinger PROC_LOCK(m->async); 5738451d0ddSKip Macy kern_psignal(m->async, SIGIO); 574206b17d7SAlexander Leidinger PROC_UNLOCK(m->async); 575206b17d7SAlexander Leidinger } 576206b17d7SAlexander Leidinger #if 0 577206b17d7SAlexander Leidinger } 578206b17d7SAlexander Leidinger #endif 579206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 580206b17d7SAlexander Leidinger return used; 581206b17d7SAlexander Leidinger } 582206b17d7SAlexander Leidinger 583206b17d7SAlexander Leidinger /* 584206b17d7SAlexander Leidinger * midi_out: The only clearer of the M_TXEN flag. 585206b17d7SAlexander Leidinger */ 586206b17d7SAlexander Leidinger int 587206b17d7SAlexander Leidinger midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size) 588206b17d7SAlexander Leidinger { 589206b17d7SAlexander Leidinger int used; 590206b17d7SAlexander Leidinger 591206b17d7SAlexander Leidinger /* 592206b17d7SAlexander Leidinger * XXX: locking flub 593206b17d7SAlexander Leidinger */ 594206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) 595206b17d7SAlexander Leidinger return 0; 596206b17d7SAlexander Leidinger 597206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midi_out: %p\n", m)); 598206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 599206b17d7SAlexander Leidinger used = MIN(size, MIDIQ_LEN(m->outq)); 600206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_out: used %d\n", used)); 601206b17d7SAlexander Leidinger if (used) 602206b17d7SAlexander Leidinger MIDIQ_DEQ(m->outq, buf, used); 603206b17d7SAlexander Leidinger if (MIDIQ_EMPTY(m->outq)) { 604206b17d7SAlexander Leidinger m->flags &= ~M_TXEN; 605206b17d7SAlexander Leidinger MPU_CALLBACKP(m, m->cookie, m->flags); 606206b17d7SAlexander Leidinger } 607206b17d7SAlexander Leidinger if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) { 608206b17d7SAlexander Leidinger if (m->wchan) { 609206b17d7SAlexander Leidinger wakeup(&m->wchan); 610206b17d7SAlexander Leidinger m->wchan = 0; 611206b17d7SAlexander Leidinger } 612206b17d7SAlexander Leidinger selwakeup(&m->wsel); 613206b17d7SAlexander Leidinger if (m->async) { 614206b17d7SAlexander Leidinger PROC_LOCK(m->async); 6158451d0ddSKip Macy kern_psignal(m->async, SIGIO); 616206b17d7SAlexander Leidinger PROC_UNLOCK(m->async); 617206b17d7SAlexander Leidinger } 618206b17d7SAlexander Leidinger } 619206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 620206b17d7SAlexander Leidinger return used; 621206b17d7SAlexander Leidinger } 622206b17d7SAlexander Leidinger 623206b17d7SAlexander Leidinger 624206b17d7SAlexander Leidinger /* 625206b17d7SAlexander Leidinger * /dev/rmidi#.# device access functions 626206b17d7SAlexander Leidinger */ 627206b17d7SAlexander Leidinger int 628206b17d7SAlexander Leidinger midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 629206b17d7SAlexander Leidinger { 630206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1; 631206b17d7SAlexander Leidinger int retval; 632206b17d7SAlexander Leidinger 633206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td, 634206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 635206b17d7SAlexander Leidinger if (m == NULL) 636206b17d7SAlexander Leidinger return ENXIO; 637206b17d7SAlexander Leidinger 638206b17d7SAlexander Leidinger mtx_lock(&m->lock); 639206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 640206b17d7SAlexander Leidinger 641206b17d7SAlexander Leidinger retval = 0; 642206b17d7SAlexander Leidinger 643206b17d7SAlexander Leidinger if (flags & FREAD) { 644206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->inq) == 0) 645206b17d7SAlexander Leidinger retval = ENXIO; 646206b17d7SAlexander Leidinger else if (m->flags & M_RX) 647206b17d7SAlexander Leidinger retval = EBUSY; 648206b17d7SAlexander Leidinger if (retval) 649206b17d7SAlexander Leidinger goto err; 650206b17d7SAlexander Leidinger } 651206b17d7SAlexander Leidinger if (flags & FWRITE) { 652206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->outq) == 0) 653206b17d7SAlexander Leidinger retval = ENXIO; 654206b17d7SAlexander Leidinger else if (m->flags & M_TX) 655206b17d7SAlexander Leidinger retval = EBUSY; 656206b17d7SAlexander Leidinger if (retval) 657206b17d7SAlexander Leidinger goto err; 658206b17d7SAlexander Leidinger } 659206b17d7SAlexander Leidinger m->busy++; 660206b17d7SAlexander Leidinger 661206b17d7SAlexander Leidinger m->rchan = 0; 662206b17d7SAlexander Leidinger m->wchan = 0; 663206b17d7SAlexander Leidinger m->async = 0; 664206b17d7SAlexander Leidinger 665206b17d7SAlexander Leidinger if (flags & FREAD) { 666206b17d7SAlexander Leidinger m->flags |= M_RX | M_RXEN; 667206b17d7SAlexander Leidinger /* 6688f981688SAlexander Leidinger * Only clear the inq, the outq might still have data to drain 6698f981688SAlexander Leidinger * from a previous session 670206b17d7SAlexander Leidinger */ 671206b17d7SAlexander Leidinger MIDIQ_CLEAR(m->inq); 672*74b8d63dSPedro F. Giffuni } 673206b17d7SAlexander Leidinger 674206b17d7SAlexander Leidinger if (flags & FWRITE) 675206b17d7SAlexander Leidinger m->flags |= M_TX; 676206b17d7SAlexander Leidinger 677206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 678206b17d7SAlexander Leidinger 679206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midi_open: opened.\n")); 680206b17d7SAlexander Leidinger 681206b17d7SAlexander Leidinger err: mtx_unlock(&m->qlock); 682206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 683206b17d7SAlexander Leidinger return retval; 684206b17d7SAlexander Leidinger } 685206b17d7SAlexander Leidinger 686206b17d7SAlexander Leidinger int 687206b17d7SAlexander Leidinger midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 688206b17d7SAlexander Leidinger { 689206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1; 690206b17d7SAlexander Leidinger int retval; 691206b17d7SAlexander Leidinger int oldflags; 692206b17d7SAlexander Leidinger 693206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td, 694206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 695206b17d7SAlexander Leidinger 696206b17d7SAlexander Leidinger if (m == NULL) 697206b17d7SAlexander Leidinger return ENXIO; 698206b17d7SAlexander Leidinger 699206b17d7SAlexander Leidinger mtx_lock(&m->lock); 700206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 701206b17d7SAlexander Leidinger 702206b17d7SAlexander Leidinger if ((flags & FREAD && !(m->flags & M_RX)) || 703206b17d7SAlexander Leidinger (flags & FWRITE && !(m->flags & M_TX))) { 704206b17d7SAlexander Leidinger retval = ENXIO; 705206b17d7SAlexander Leidinger goto err; 706206b17d7SAlexander Leidinger } 707206b17d7SAlexander Leidinger m->busy--; 708206b17d7SAlexander Leidinger 709206b17d7SAlexander Leidinger oldflags = m->flags; 710206b17d7SAlexander Leidinger 711206b17d7SAlexander Leidinger if (flags & FREAD) 712206b17d7SAlexander Leidinger m->flags &= ~(M_RX | M_RXEN); 713206b17d7SAlexander Leidinger if (flags & FWRITE) 714206b17d7SAlexander Leidinger m->flags &= ~M_TX; 715206b17d7SAlexander Leidinger 716206b17d7SAlexander Leidinger if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 717206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 718206b17d7SAlexander Leidinger 719206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 720206b17d7SAlexander Leidinger 721206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 722206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 723206b17d7SAlexander Leidinger retval = 0; 724206b17d7SAlexander Leidinger err: return retval; 725206b17d7SAlexander Leidinger } 7268f981688SAlexander Leidinger 727206b17d7SAlexander Leidinger /* 7288f981688SAlexander Leidinger * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon 7298f981688SAlexander Leidinger * as data is available. 730206b17d7SAlexander Leidinger */ 731206b17d7SAlexander Leidinger int 732206b17d7SAlexander Leidinger midi_read(struct cdev *i_dev, struct uio *uio, int ioflag) 733206b17d7SAlexander Leidinger { 734206b17d7SAlexander Leidinger #define MIDI_RSIZE 32 735206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1; 736206b17d7SAlexander Leidinger int retval; 737206b17d7SAlexander Leidinger int used; 738206b17d7SAlexander Leidinger char buf[MIDI_RSIZE]; 739206b17d7SAlexander Leidinger 7408f981688SAlexander Leidinger MIDI_DEBUG(5, printf("midiread: count=%lu\n", 7418f981688SAlexander Leidinger (unsigned long)uio->uio_resid)); 742206b17d7SAlexander Leidinger 743206b17d7SAlexander Leidinger retval = EIO; 744206b17d7SAlexander Leidinger 745206b17d7SAlexander Leidinger if (m == NULL) 746206b17d7SAlexander Leidinger goto err0; 747206b17d7SAlexander Leidinger 748206b17d7SAlexander Leidinger mtx_lock(&m->lock); 749206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 750206b17d7SAlexander Leidinger 751206b17d7SAlexander Leidinger if (!(m->flags & M_RX)) 752206b17d7SAlexander Leidinger goto err1; 753206b17d7SAlexander Leidinger 754206b17d7SAlexander Leidinger while (uio->uio_resid > 0) { 755206b17d7SAlexander Leidinger while (MIDIQ_EMPTY(m->inq)) { 756206b17d7SAlexander Leidinger retval = EWOULDBLOCK; 757206b17d7SAlexander Leidinger if (ioflag & O_NONBLOCK) 758206b17d7SAlexander Leidinger goto err1; 759206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 760206b17d7SAlexander Leidinger m->rchan = 1; 761206b17d7SAlexander Leidinger retval = msleep(&m->rchan, &m->qlock, 762206b17d7SAlexander Leidinger PCATCH | PDROP, "midi RX", 0); 763206b17d7SAlexander Leidinger /* 764206b17d7SAlexander Leidinger * We slept, maybe things have changed since last 765206b17d7SAlexander Leidinger * dying check 766206b17d7SAlexander Leidinger */ 767206b17d7SAlexander Leidinger if (retval == EINTR) 768206b17d7SAlexander Leidinger goto err0; 769206b17d7SAlexander Leidinger if (m != i_dev->si_drv1) 770206b17d7SAlexander Leidinger retval = ENXIO; 771206b17d7SAlexander Leidinger /* if (retval && retval != ERESTART) */ 772206b17d7SAlexander Leidinger if (retval) 773206b17d7SAlexander Leidinger goto err0; 774206b17d7SAlexander Leidinger mtx_lock(&m->lock); 775206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 776206b17d7SAlexander Leidinger m->rchan = 0; 777206b17d7SAlexander Leidinger if (!m->busy) 778206b17d7SAlexander Leidinger goto err1; 779206b17d7SAlexander Leidinger } 780206b17d7SAlexander Leidinger MIDI_DEBUG(6, printf("midi_read start\n")); 781206b17d7SAlexander Leidinger /* 782206b17d7SAlexander Leidinger * At this point, it is certain that m->inq has data 783206b17d7SAlexander Leidinger */ 784206b17d7SAlexander Leidinger 785206b17d7SAlexander Leidinger used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid); 786206b17d7SAlexander Leidinger used = MIN(used, MIDI_RSIZE); 787206b17d7SAlexander Leidinger 788206b17d7SAlexander Leidinger MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used)); 789206b17d7SAlexander Leidinger MIDIQ_DEQ(m->inq, buf, used); 790206b17d7SAlexander Leidinger retval = uiomove(buf, used, uio); 791206b17d7SAlexander Leidinger if (retval) 792206b17d7SAlexander Leidinger goto err1; 793206b17d7SAlexander Leidinger } 794206b17d7SAlexander Leidinger 795206b17d7SAlexander Leidinger /* 796206b17d7SAlexander Leidinger * If we Made it here then transfer is good 797206b17d7SAlexander Leidinger */ 798206b17d7SAlexander Leidinger retval = 0; 799206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock); 800206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 801206b17d7SAlexander Leidinger err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval)); 802206b17d7SAlexander Leidinger return retval; 803206b17d7SAlexander Leidinger } 804206b17d7SAlexander Leidinger 805206b17d7SAlexander Leidinger /* 806206b17d7SAlexander Leidinger * midi_write: The only setter of M_TXEN 807206b17d7SAlexander Leidinger */ 808206b17d7SAlexander Leidinger 809206b17d7SAlexander Leidinger int 810206b17d7SAlexander Leidinger midi_write(struct cdev *i_dev, struct uio *uio, int ioflag) 811206b17d7SAlexander Leidinger { 812206b17d7SAlexander Leidinger #define MIDI_WSIZE 32 813206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1; 814206b17d7SAlexander Leidinger int retval; 815206b17d7SAlexander Leidinger int used; 816206b17d7SAlexander Leidinger char buf[MIDI_WSIZE]; 817206b17d7SAlexander Leidinger 818206b17d7SAlexander Leidinger 819206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midi_write\n")); 820206b17d7SAlexander Leidinger retval = 0; 821206b17d7SAlexander Leidinger if (m == NULL) 822206b17d7SAlexander Leidinger goto err0; 823206b17d7SAlexander Leidinger 824206b17d7SAlexander Leidinger mtx_lock(&m->lock); 825206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 826206b17d7SAlexander Leidinger 827206b17d7SAlexander Leidinger if (!(m->flags & M_TX)) 828206b17d7SAlexander Leidinger goto err1; 829206b17d7SAlexander Leidinger 830206b17d7SAlexander Leidinger while (uio->uio_resid > 0) { 831206b17d7SAlexander Leidinger while (MIDIQ_AVAIL(m->outq) == 0) { 832206b17d7SAlexander Leidinger retval = EWOULDBLOCK; 833206b17d7SAlexander Leidinger if (ioflag & O_NONBLOCK) 834206b17d7SAlexander Leidinger goto err1; 835206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 836206b17d7SAlexander Leidinger m->wchan = 1; 837206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_write msleep\n")); 838206b17d7SAlexander Leidinger retval = msleep(&m->wchan, &m->qlock, 839206b17d7SAlexander Leidinger PCATCH | PDROP, "midi TX", 0); 840206b17d7SAlexander Leidinger /* 841206b17d7SAlexander Leidinger * We slept, maybe things have changed since last 842206b17d7SAlexander Leidinger * dying check 843206b17d7SAlexander Leidinger */ 844206b17d7SAlexander Leidinger if (retval == EINTR) 845206b17d7SAlexander Leidinger goto err0; 846206b17d7SAlexander Leidinger if (m != i_dev->si_drv1) 847206b17d7SAlexander Leidinger retval = ENXIO; 848206b17d7SAlexander Leidinger if (retval) 849206b17d7SAlexander Leidinger goto err0; 850206b17d7SAlexander Leidinger mtx_lock(&m->lock); 851206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 852206b17d7SAlexander Leidinger m->wchan = 0; 853206b17d7SAlexander Leidinger if (!m->busy) 854206b17d7SAlexander Leidinger goto err1; 855206b17d7SAlexander Leidinger } 856206b17d7SAlexander Leidinger 857206b17d7SAlexander Leidinger /* 858206b17d7SAlexander Leidinger * We are certain than data can be placed on the queue 859206b17d7SAlexander Leidinger */ 860206b17d7SAlexander Leidinger 861206b17d7SAlexander Leidinger used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid); 862206b17d7SAlexander Leidinger used = MIN(used, MIDI_WSIZE); 8639f80ce04SKonstantin Belousov MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n", 8648f981688SAlexander Leidinger uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq), 8658f981688SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->outq))); 866206b17d7SAlexander Leidinger 867206b17d7SAlexander Leidinger 868206b17d7SAlexander Leidinger MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used)); 869206b17d7SAlexander Leidinger retval = uiomove(buf, used, uio); 870206b17d7SAlexander Leidinger if (retval) 871206b17d7SAlexander Leidinger goto err1; 872206b17d7SAlexander Leidinger MIDIQ_ENQ(m->outq, buf, used); 873206b17d7SAlexander Leidinger /* 874206b17d7SAlexander Leidinger * Inform the bottom half that data can be written 875206b17d7SAlexander Leidinger */ 876206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) { 877206b17d7SAlexander Leidinger m->flags |= M_TXEN; 878206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 879206b17d7SAlexander Leidinger } 880206b17d7SAlexander Leidinger } 881206b17d7SAlexander Leidinger /* 882206b17d7SAlexander Leidinger * If we Made it here then transfer is good 883206b17d7SAlexander Leidinger */ 884206b17d7SAlexander Leidinger retval = 0; 885206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock); 886206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 887206b17d7SAlexander Leidinger err0: return retval; 888206b17d7SAlexander Leidinger } 889206b17d7SAlexander Leidinger 890206b17d7SAlexander Leidinger int 8918f981688SAlexander Leidinger midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 8928f981688SAlexander Leidinger struct thread *td) 893206b17d7SAlexander Leidinger { 894206b17d7SAlexander Leidinger return ENXIO; 895206b17d7SAlexander Leidinger } 896206b17d7SAlexander Leidinger 897206b17d7SAlexander Leidinger int 898206b17d7SAlexander Leidinger midi_poll(struct cdev *i_dev, int events, struct thread *td) 899206b17d7SAlexander Leidinger { 900206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1; 901206b17d7SAlexander Leidinger int revents; 902206b17d7SAlexander Leidinger 903206b17d7SAlexander Leidinger if (m == NULL) 904206b17d7SAlexander Leidinger return 0; 905206b17d7SAlexander Leidinger 906206b17d7SAlexander Leidinger revents = 0; 907206b17d7SAlexander Leidinger 908206b17d7SAlexander Leidinger mtx_lock(&m->lock); 909206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 910206b17d7SAlexander Leidinger 911206b17d7SAlexander Leidinger if (events & (POLLIN | POLLRDNORM)) 912206b17d7SAlexander Leidinger if (!MIDIQ_EMPTY(m->inq)) 913206b17d7SAlexander Leidinger events |= events & (POLLIN | POLLRDNORM); 914206b17d7SAlexander Leidinger 915206b17d7SAlexander Leidinger if (events & (POLLOUT | POLLWRNORM)) 916206b17d7SAlexander Leidinger if (MIDIQ_AVAIL(m->outq) < m->hiwat) 917206b17d7SAlexander Leidinger events |= events & (POLLOUT | POLLWRNORM); 918206b17d7SAlexander Leidinger 919206b17d7SAlexander Leidinger if (revents == 0) { 920206b17d7SAlexander Leidinger if (events & (POLLIN | POLLRDNORM)) 921206b17d7SAlexander Leidinger selrecord(td, &m->rsel); 922206b17d7SAlexander Leidinger 923206b17d7SAlexander Leidinger if (events & (POLLOUT | POLLWRNORM)) 924206b17d7SAlexander Leidinger selrecord(td, &m->wsel); 925206b17d7SAlexander Leidinger } 926206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 927206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 928206b17d7SAlexander Leidinger 929206b17d7SAlexander Leidinger return (revents); 930206b17d7SAlexander Leidinger } 931206b17d7SAlexander Leidinger 932206b17d7SAlexander Leidinger /* 933206b17d7SAlexander Leidinger * /dev/midistat device functions 934206b17d7SAlexander Leidinger * 935206b17d7SAlexander Leidinger */ 936206b17d7SAlexander Leidinger static int 937206b17d7SAlexander Leidinger midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 938206b17d7SAlexander Leidinger { 939206b17d7SAlexander Leidinger int error; 940206b17d7SAlexander Leidinger 941206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midistat_open\n")); 942206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 943206b17d7SAlexander Leidinger 944206b17d7SAlexander Leidinger if (midistat_isopen) { 945206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 946206b17d7SAlexander Leidinger return EBUSY; 947206b17d7SAlexander Leidinger } 948206b17d7SAlexander Leidinger midistat_isopen = 1; 949d130d865SAriff Abdullah mtx_unlock(&midistat_lock); 950206b17d7SAlexander Leidinger 951d130d865SAriff Abdullah if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) { 952206b17d7SAlexander Leidinger error = ENXIO; 953d130d865SAriff Abdullah mtx_lock(&midistat_lock); 954206b17d7SAlexander Leidinger goto out; 955206b17d7SAlexander Leidinger } 956d130d865SAriff Abdullah mtx_lock(&midistat_lock); 957206b17d7SAlexander Leidinger midistat_bufptr = 0; 958206b17d7SAlexander Leidinger error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM; 959206b17d7SAlexander Leidinger 960206b17d7SAlexander Leidinger out: if (error) 961206b17d7SAlexander Leidinger midistat_isopen = 0; 962206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 963206b17d7SAlexander Leidinger return error; 964206b17d7SAlexander Leidinger } 965206b17d7SAlexander Leidinger 966206b17d7SAlexander Leidinger static int 967206b17d7SAlexander Leidinger midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 968206b17d7SAlexander Leidinger { 969206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midistat_close\n")); 970206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 971206b17d7SAlexander Leidinger if (!midistat_isopen) { 972206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 973206b17d7SAlexander Leidinger return EBADF; 974206b17d7SAlexander Leidinger } 975206b17d7SAlexander Leidinger sbuf_delete(&midistat_sbuf); 976206b17d7SAlexander Leidinger midistat_isopen = 0; 977206b17d7SAlexander Leidinger 978206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 979206b17d7SAlexander Leidinger return 0; 980206b17d7SAlexander Leidinger } 981206b17d7SAlexander Leidinger 982206b17d7SAlexander Leidinger static int 983206b17d7SAlexander Leidinger midistat_read(struct cdev *i_dev, struct uio *buf, int flag) 984206b17d7SAlexander Leidinger { 985206b17d7SAlexander Leidinger int l, err; 986206b17d7SAlexander Leidinger 987206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midistat_read\n")); 988206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 989206b17d7SAlexander Leidinger if (!midistat_isopen) { 990206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 991206b17d7SAlexander Leidinger return EBADF; 992206b17d7SAlexander Leidinger } 993206b17d7SAlexander Leidinger l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr); 994206b17d7SAlexander Leidinger err = 0; 995d130d865SAriff Abdullah if (l > 0) { 996d130d865SAriff Abdullah mtx_unlock(&midistat_lock); 9978f981688SAlexander Leidinger err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l, 9988f981688SAlexander Leidinger buf); 999d130d865SAriff Abdullah mtx_lock(&midistat_lock); 1000d130d865SAriff Abdullah } else 1001206b17d7SAlexander Leidinger l = 0; 1002206b17d7SAlexander Leidinger midistat_bufptr += l; 1003206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 1004206b17d7SAlexander Leidinger return err; 1005206b17d7SAlexander Leidinger } 1006206b17d7SAlexander Leidinger 1007206b17d7SAlexander Leidinger /* 1008206b17d7SAlexander Leidinger * Module library functions 1009206b17d7SAlexander Leidinger */ 1010206b17d7SAlexander Leidinger 1011206b17d7SAlexander Leidinger static int 1012206b17d7SAlexander Leidinger midistat_prepare(struct sbuf *s) 1013206b17d7SAlexander Leidinger { 1014206b17d7SAlexander Leidinger struct snd_midi *m; 1015206b17d7SAlexander Leidinger 1016206b17d7SAlexander Leidinger mtx_assert(&midistat_lock, MA_OWNED); 1017206b17d7SAlexander Leidinger 1018206b17d7SAlexander Leidinger sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n"); 1019206b17d7SAlexander Leidinger if (TAILQ_EMPTY(&midi_devs)) { 1020206b17d7SAlexander Leidinger sbuf_printf(s, "No devices installed.\n"); 1021206b17d7SAlexander Leidinger sbuf_finish(s); 1022206b17d7SAlexander Leidinger return sbuf_len(s); 1023206b17d7SAlexander Leidinger } 1024206b17d7SAlexander Leidinger sbuf_printf(s, "Installed devices:\n"); 1025206b17d7SAlexander Leidinger 1026206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) { 1027206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1028206b17d7SAlexander Leidinger sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel, 1029206b17d7SAlexander Leidinger MPU_PROVIDER(m, m->cookie)); 1030206b17d7SAlexander Leidinger sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose)); 1031206b17d7SAlexander Leidinger sbuf_printf(s, "\n"); 1032206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1033206b17d7SAlexander Leidinger } 1034206b17d7SAlexander Leidinger 1035206b17d7SAlexander Leidinger sbuf_finish(s); 1036206b17d7SAlexander Leidinger return sbuf_len(s); 1037206b17d7SAlexander Leidinger } 1038206b17d7SAlexander Leidinger 10392916c293SRuslan Ermilov #ifdef notdef 1040206b17d7SAlexander Leidinger /* 1041206b17d7SAlexander Leidinger * Convert IOCTL command to string for debugging 1042206b17d7SAlexander Leidinger */ 1043206b17d7SAlexander Leidinger 1044206b17d7SAlexander Leidinger static char * 1045206b17d7SAlexander Leidinger midi_cmdname(int cmd) 1046206b17d7SAlexander Leidinger { 1047206b17d7SAlexander Leidinger static struct { 1048206b17d7SAlexander Leidinger int cmd; 1049206b17d7SAlexander Leidinger char *name; 1050206b17d7SAlexander Leidinger } *tab, cmdtab_midiioctl[] = { 1051206b17d7SAlexander Leidinger #define A(x) {x, ## x} 1052206b17d7SAlexander Leidinger /* 1053206b17d7SAlexander Leidinger * Once we have some real IOCTLs define, the following will 1054206b17d7SAlexander Leidinger * be relavant. 1055206b17d7SAlexander Leidinger * 1056206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE), 1057206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO), 1058206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL), 1059206b17d7SAlexander Leidinger * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE), 1060206b17d7SAlexander Leidinger * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE), 1061206b17d7SAlexander Leidinger * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT), 1062206b17d7SAlexander Leidinger * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC), 1063206b17d7SAlexander Leidinger * A(AIOGCAP), 1064206b17d7SAlexander Leidinger */ 1065206b17d7SAlexander Leidinger #undef A 1066206b17d7SAlexander Leidinger { 1067206b17d7SAlexander Leidinger -1, "unknown" 1068206b17d7SAlexander Leidinger }, 1069206b17d7SAlexander Leidinger }; 1070206b17d7SAlexander Leidinger 10718f981688SAlexander Leidinger for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++); 1072206b17d7SAlexander Leidinger return tab->name; 1073206b17d7SAlexander Leidinger } 10748f981688SAlexander Leidinger 1075206b17d7SAlexander Leidinger #endif /* notdef */ 1076206b17d7SAlexander Leidinger 1077206b17d7SAlexander Leidinger /* 1078206b17d7SAlexander Leidinger * midisynth 1079206b17d7SAlexander Leidinger */ 1080206b17d7SAlexander Leidinger 1081206b17d7SAlexander Leidinger 1082206b17d7SAlexander Leidinger int 1083206b17d7SAlexander Leidinger midisynth_open(void *n, void *arg, int flags) 1084206b17d7SAlexander Leidinger { 1085206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m; 1086206b17d7SAlexander Leidinger int retval; 1087206b17d7SAlexander Leidinger 1088206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midisynth_open %s %s\n", 1089206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 1090206b17d7SAlexander Leidinger 1091206b17d7SAlexander Leidinger if (m == NULL) 1092206b17d7SAlexander Leidinger return ENXIO; 1093206b17d7SAlexander Leidinger 1094206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1095206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 1096206b17d7SAlexander Leidinger 1097206b17d7SAlexander Leidinger retval = 0; 1098206b17d7SAlexander Leidinger 1099206b17d7SAlexander Leidinger if (flags & FREAD) { 1100206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->inq) == 0) 1101206b17d7SAlexander Leidinger retval = ENXIO; 1102206b17d7SAlexander Leidinger else if (m->flags & M_RX) 1103206b17d7SAlexander Leidinger retval = EBUSY; 1104206b17d7SAlexander Leidinger if (retval) 1105206b17d7SAlexander Leidinger goto err; 1106206b17d7SAlexander Leidinger } 1107206b17d7SAlexander Leidinger if (flags & FWRITE) { 1108206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->outq) == 0) 1109206b17d7SAlexander Leidinger retval = ENXIO; 1110206b17d7SAlexander Leidinger else if (m->flags & M_TX) 1111206b17d7SAlexander Leidinger retval = EBUSY; 1112206b17d7SAlexander Leidinger if (retval) 1113206b17d7SAlexander Leidinger goto err; 1114206b17d7SAlexander Leidinger } 1115206b17d7SAlexander Leidinger m->busy++; 1116206b17d7SAlexander Leidinger 1117206b17d7SAlexander Leidinger /* 1118206b17d7SAlexander Leidinger * TODO: Consider m->async = 0; 1119206b17d7SAlexander Leidinger */ 1120206b17d7SAlexander Leidinger 1121206b17d7SAlexander Leidinger if (flags & FREAD) { 1122206b17d7SAlexander Leidinger m->flags |= M_RX | M_RXEN; 1123206b17d7SAlexander Leidinger /* 11248f981688SAlexander Leidinger * Only clear the inq, the outq might still have data to drain 11258f981688SAlexander Leidinger * from a previous session 1126206b17d7SAlexander Leidinger */ 1127206b17d7SAlexander Leidinger MIDIQ_CLEAR(m->inq); 1128206b17d7SAlexander Leidinger m->rchan = 0; 1129*74b8d63dSPedro F. Giffuni } 1130206b17d7SAlexander Leidinger 1131206b17d7SAlexander Leidinger if (flags & FWRITE) { 1132206b17d7SAlexander Leidinger m->flags |= M_TX; 1133206b17d7SAlexander Leidinger m->wchan = 0; 1134206b17d7SAlexander Leidinger } 1135206b17d7SAlexander Leidinger m->synth_flags = flags & (FREAD | FWRITE); 1136206b17d7SAlexander Leidinger 1137206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 1138206b17d7SAlexander Leidinger 1139206b17d7SAlexander Leidinger 1140206b17d7SAlexander Leidinger err: mtx_unlock(&m->qlock); 1141206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1142206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval)); 1143206b17d7SAlexander Leidinger return retval; 1144206b17d7SAlexander Leidinger } 1145206b17d7SAlexander Leidinger 1146206b17d7SAlexander Leidinger int 1147206b17d7SAlexander Leidinger midisynth_close(void *n) 1148206b17d7SAlexander Leidinger { 1149206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m; 1150206b17d7SAlexander Leidinger int retval; 1151206b17d7SAlexander Leidinger int oldflags; 1152206b17d7SAlexander Leidinger 1153206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midisynth_close %s %s\n", 1154206b17d7SAlexander Leidinger m->synth_flags & FREAD ? "M_RX" : "", 1155206b17d7SAlexander Leidinger m->synth_flags & FWRITE ? "M_TX" : "")); 1156206b17d7SAlexander Leidinger 1157206b17d7SAlexander Leidinger if (m == NULL) 1158206b17d7SAlexander Leidinger return ENXIO; 1159206b17d7SAlexander Leidinger 1160206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1161206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 1162206b17d7SAlexander Leidinger 1163206b17d7SAlexander Leidinger if ((m->synth_flags & FREAD && !(m->flags & M_RX)) || 1164206b17d7SAlexander Leidinger (m->synth_flags & FWRITE && !(m->flags & M_TX))) { 1165206b17d7SAlexander Leidinger retval = ENXIO; 1166206b17d7SAlexander Leidinger goto err; 1167206b17d7SAlexander Leidinger } 1168206b17d7SAlexander Leidinger m->busy--; 1169206b17d7SAlexander Leidinger 1170206b17d7SAlexander Leidinger oldflags = m->flags; 1171206b17d7SAlexander Leidinger 1172206b17d7SAlexander Leidinger if (m->synth_flags & FREAD) 1173206b17d7SAlexander Leidinger m->flags &= ~(M_RX | M_RXEN); 1174206b17d7SAlexander Leidinger if (m->synth_flags & FWRITE) 1175206b17d7SAlexander Leidinger m->flags &= ~M_TX; 1176206b17d7SAlexander Leidinger 1177206b17d7SAlexander Leidinger if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 1178206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 1179206b17d7SAlexander Leidinger 1180206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 1181206b17d7SAlexander Leidinger 1182206b17d7SAlexander Leidinger mtx_unlock(&m->qlock); 1183206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1184206b17d7SAlexander Leidinger retval = 0; 1185206b17d7SAlexander Leidinger err: return retval; 1186206b17d7SAlexander Leidinger } 1187206b17d7SAlexander Leidinger 1188206b17d7SAlexander Leidinger /* 1189206b17d7SAlexander Leidinger * Always blocking. 1190206b17d7SAlexander Leidinger */ 1191206b17d7SAlexander Leidinger 1192206b17d7SAlexander Leidinger int 1193206b17d7SAlexander Leidinger midisynth_writeraw(void *n, uint8_t *buf, size_t len) 1194206b17d7SAlexander Leidinger { 1195206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m; 1196206b17d7SAlexander Leidinger int retval; 1197206b17d7SAlexander Leidinger int used; 1198206b17d7SAlexander Leidinger int i; 1199206b17d7SAlexander Leidinger 1200206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midisynth_writeraw\n")); 1201206b17d7SAlexander Leidinger 1202206b17d7SAlexander Leidinger retval = 0; 1203206b17d7SAlexander Leidinger 1204206b17d7SAlexander Leidinger if (m == NULL) 1205206b17d7SAlexander Leidinger return ENXIO; 1206206b17d7SAlexander Leidinger 1207206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1208206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 1209206b17d7SAlexander Leidinger 1210206b17d7SAlexander Leidinger if (!(m->flags & M_TX)) 1211206b17d7SAlexander Leidinger goto err1; 1212206b17d7SAlexander Leidinger 1213206b17d7SAlexander Leidinger if (midi_dumpraw) 1214206b17d7SAlexander Leidinger printf("midi dump: "); 1215206b17d7SAlexander Leidinger 1216206b17d7SAlexander Leidinger while (len > 0) { 1217206b17d7SAlexander Leidinger while (MIDIQ_AVAIL(m->outq) == 0) { 1218206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) { 1219206b17d7SAlexander Leidinger m->flags |= M_TXEN; 1220206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 1221206b17d7SAlexander Leidinger } 1222206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1223206b17d7SAlexander Leidinger m->wchan = 1; 1224206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n")); 1225206b17d7SAlexander Leidinger retval = msleep(&m->wchan, &m->qlock, 1226206b17d7SAlexander Leidinger PCATCH | PDROP, "midi TX", 0); 1227206b17d7SAlexander Leidinger /* 1228206b17d7SAlexander Leidinger * We slept, maybe things have changed since last 1229206b17d7SAlexander Leidinger * dying check 1230206b17d7SAlexander Leidinger */ 1231206b17d7SAlexander Leidinger if (retval == EINTR) 1232206b17d7SAlexander Leidinger goto err0; 1233206b17d7SAlexander Leidinger 1234206b17d7SAlexander Leidinger if (retval) 1235206b17d7SAlexander Leidinger goto err0; 1236206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1237206b17d7SAlexander Leidinger mtx_lock(&m->qlock); 1238206b17d7SAlexander Leidinger m->wchan = 0; 1239206b17d7SAlexander Leidinger if (!m->busy) 1240206b17d7SAlexander Leidinger goto err1; 1241206b17d7SAlexander Leidinger } 1242206b17d7SAlexander Leidinger 1243206b17d7SAlexander Leidinger /* 1244206b17d7SAlexander Leidinger * We are certain than data can be placed on the queue 1245206b17d7SAlexander Leidinger */ 1246206b17d7SAlexander Leidinger 1247206b17d7SAlexander Leidinger used = MIN(MIDIQ_AVAIL(m->outq), len); 1248206b17d7SAlexander Leidinger used = MIN(used, MIDI_WSIZE); 12498f981688SAlexander Leidinger MIDI_DEBUG(5, 12508f981688SAlexander Leidinger printf("midi_synth: resid %zu len %jd avail %jd\n", 1251206b17d7SAlexander Leidinger len, (intmax_t)MIDIQ_LEN(m->outq), 1252206b17d7SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->outq))); 1253206b17d7SAlexander Leidinger 1254206b17d7SAlexander Leidinger if (midi_dumpraw) 12558f981688SAlexander Leidinger for (i = 0; i < used; i++) 12568f981688SAlexander Leidinger printf("%x ", buf[i]); 1257206b17d7SAlexander Leidinger 1258206b17d7SAlexander Leidinger MIDIQ_ENQ(m->outq, buf, used); 1259206b17d7SAlexander Leidinger len -= used; 1260206b17d7SAlexander Leidinger 1261206b17d7SAlexander Leidinger /* 1262206b17d7SAlexander Leidinger * Inform the bottom half that data can be written 1263206b17d7SAlexander Leidinger */ 1264206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) { 1265206b17d7SAlexander Leidinger m->flags |= M_TXEN; 1266206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags); 1267206b17d7SAlexander Leidinger } 1268206b17d7SAlexander Leidinger } 1269206b17d7SAlexander Leidinger /* 1270206b17d7SAlexander Leidinger * If we Made it here then transfer is good 1271206b17d7SAlexander Leidinger */ 1272206b17d7SAlexander Leidinger if (midi_dumpraw) 1273206b17d7SAlexander Leidinger printf("\n"); 1274206b17d7SAlexander Leidinger 1275206b17d7SAlexander Leidinger retval = 0; 1276206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock); 1277206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1278206b17d7SAlexander Leidinger err0: return retval; 1279206b17d7SAlexander Leidinger } 1280206b17d7SAlexander Leidinger 1281206b17d7SAlexander Leidinger static int 1282206b17d7SAlexander Leidinger midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1283206b17d7SAlexander Leidinger { 1284206b17d7SAlexander Leidinger u_char c[3]; 1285206b17d7SAlexander Leidinger 1286206b17d7SAlexander Leidinger 1287206b17d7SAlexander Leidinger if (note > 127 || chn > 15) 1288206b17d7SAlexander Leidinger return (EINVAL); 1289206b17d7SAlexander Leidinger 1290206b17d7SAlexander Leidinger if (vel > 127) 1291206b17d7SAlexander Leidinger vel = 127; 1292206b17d7SAlexander Leidinger 1293206b17d7SAlexander Leidinger if (vel == 64) { 1294206b17d7SAlexander Leidinger c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1295206b17d7SAlexander Leidinger c[1] = (u_char)note; 1296206b17d7SAlexander Leidinger c[2] = 0; 1297206b17d7SAlexander Leidinger } else { 1298206b17d7SAlexander Leidinger c[0] = 0x80 | (chn & 0x0f); /* Note off. */ 1299206b17d7SAlexander Leidinger c[1] = (u_char)note; 1300206b17d7SAlexander Leidinger c[2] = (u_char)vel; 1301206b17d7SAlexander Leidinger } 1302206b17d7SAlexander Leidinger 1303206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3); 1304206b17d7SAlexander Leidinger } 1305206b17d7SAlexander Leidinger 1306206b17d7SAlexander Leidinger static int 1307206b17d7SAlexander Leidinger midisynth_setinstr(void *n, uint8_t chn, uint16_t instr) 1308206b17d7SAlexander Leidinger { 1309206b17d7SAlexander Leidinger u_char c[2]; 1310206b17d7SAlexander Leidinger 1311206b17d7SAlexander Leidinger if (instr > 127 || chn > 15) 1312206b17d7SAlexander Leidinger return EINVAL; 1313206b17d7SAlexander Leidinger 1314206b17d7SAlexander Leidinger c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */ 1315206b17d7SAlexander Leidinger c[1] = instr + midi_instroff; 1316206b17d7SAlexander Leidinger 1317206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 2); 1318206b17d7SAlexander Leidinger } 1319206b17d7SAlexander Leidinger 1320206b17d7SAlexander Leidinger static int 1321206b17d7SAlexander Leidinger midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1322206b17d7SAlexander Leidinger { 1323206b17d7SAlexander Leidinger u_char c[3]; 1324206b17d7SAlexander Leidinger 1325206b17d7SAlexander Leidinger if (note > 127 || chn > 15) 1326206b17d7SAlexander Leidinger return EINVAL; 1327206b17d7SAlexander Leidinger 1328206b17d7SAlexander Leidinger if (vel > 127) 1329206b17d7SAlexander Leidinger vel = 127; 1330206b17d7SAlexander Leidinger 1331206b17d7SAlexander Leidinger c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1332206b17d7SAlexander Leidinger c[1] = (u_char)note; 1333206b17d7SAlexander Leidinger c[2] = (u_char)vel; 1334206b17d7SAlexander Leidinger 1335206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3); 1336206b17d7SAlexander Leidinger } 1337206b17d7SAlexander Leidinger static int 1338206b17d7SAlexander Leidinger midisynth_alloc(void *n, uint8_t chan, uint8_t note) 1339206b17d7SAlexander Leidinger { 1340206b17d7SAlexander Leidinger return chan; 1341206b17d7SAlexander Leidinger } 1342206b17d7SAlexander Leidinger 1343206b17d7SAlexander Leidinger static int 1344206b17d7SAlexander Leidinger midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val) 1345206b17d7SAlexander Leidinger { 1346206b17d7SAlexander Leidinger u_char c[3]; 1347206b17d7SAlexander Leidinger 1348206b17d7SAlexander Leidinger if (ctrlnum > 127 || chn > 15) 1349206b17d7SAlexander Leidinger return EINVAL; 1350206b17d7SAlexander Leidinger 1351206b17d7SAlexander Leidinger c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ 1352206b17d7SAlexander Leidinger c[1] = ctrlnum; 1353206b17d7SAlexander Leidinger c[2] = val; 1354206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3); 1355206b17d7SAlexander Leidinger } 1356206b17d7SAlexander Leidinger 1357206b17d7SAlexander Leidinger static int 1358206b17d7SAlexander Leidinger midisynth_bender(void *n, uint8_t chn, uint16_t val) 1359206b17d7SAlexander Leidinger { 1360206b17d7SAlexander Leidinger u_char c[3]; 1361206b17d7SAlexander Leidinger 1362206b17d7SAlexander Leidinger 1363206b17d7SAlexander Leidinger if (val > 16383 || chn > 15) 1364206b17d7SAlexander Leidinger return EINVAL; 1365206b17d7SAlexander Leidinger 1366206b17d7SAlexander Leidinger c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ 1367206b17d7SAlexander Leidinger c[1] = (u_char)val & 0x7f; 1368206b17d7SAlexander Leidinger c[2] = (u_char)(val >> 7) & 0x7f; 1369206b17d7SAlexander Leidinger 1370206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3); 1371206b17d7SAlexander Leidinger } 1372206b17d7SAlexander Leidinger 1373206b17d7SAlexander Leidinger /* 1374206b17d7SAlexander Leidinger * Single point of midi destructions. 1375206b17d7SAlexander Leidinger */ 1376206b17d7SAlexander Leidinger static int 1377206b17d7SAlexander Leidinger midi_destroy(struct snd_midi *m, int midiuninit) 1378206b17d7SAlexander Leidinger { 1379206b17d7SAlexander Leidinger 1380206b17d7SAlexander Leidinger mtx_assert(&midistat_lock, MA_OWNED); 1381206b17d7SAlexander Leidinger mtx_assert(&m->lock, MA_OWNED); 1382206b17d7SAlexander Leidinger 1383206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_destroy\n")); 1384206b17d7SAlexander Leidinger m->dev->si_drv1 = NULL; 138590da2b28SAriff Abdullah mtx_unlock(&m->lock); /* XXX */ 1386206b17d7SAlexander Leidinger destroy_dev(m->dev); 1387206b17d7SAlexander Leidinger TAILQ_REMOVE(&midi_devs, m, link); 1388206b17d7SAlexander Leidinger if (midiuninit) 1389206b17d7SAlexander Leidinger MPU_UNINIT(m, m->cookie); 1390206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->inq), M_MIDI); 1391206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->outq), M_MIDI); 1392206b17d7SAlexander Leidinger mtx_destroy(&m->qlock); 1393206b17d7SAlexander Leidinger mtx_destroy(&m->lock); 1394671b5759STai-hwa Liang free(m->synth, M_MIDI); 1395206b17d7SAlexander Leidinger free(m, M_MIDI); 1396206b17d7SAlexander Leidinger return 0; 1397206b17d7SAlexander Leidinger } 1398206b17d7SAlexander Leidinger 1399206b17d7SAlexander Leidinger /* 1400206b17d7SAlexander Leidinger * Load and unload functions, creates the /dev/midistat device 1401206b17d7SAlexander Leidinger */ 1402206b17d7SAlexander Leidinger 1403206b17d7SAlexander Leidinger static int 1404206b17d7SAlexander Leidinger midi_load() 1405206b17d7SAlexander Leidinger { 14068c0a77e3SAriff Abdullah mtx_init(&midistat_lock, "midistat lock", NULL, 0); 1407206b17d7SAlexander Leidinger TAILQ_INIT(&midi_devs); /* Initialize the queue. */ 1408206b17d7SAlexander Leidinger 1409206b17d7SAlexander Leidinger midistat_dev = make_dev(&midistat_cdevsw, 1410206b17d7SAlexander Leidinger MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0), 1411206b17d7SAlexander Leidinger UID_ROOT, GID_WHEEL, 0666, "midistat"); 1412206b17d7SAlexander Leidinger 1413206b17d7SAlexander Leidinger return 0; 1414206b17d7SAlexander Leidinger } 1415206b17d7SAlexander Leidinger 1416206b17d7SAlexander Leidinger static int 1417206b17d7SAlexander Leidinger midi_unload() 1418206b17d7SAlexander Leidinger { 1419206b17d7SAlexander Leidinger struct snd_midi *m; 1420206b17d7SAlexander Leidinger int retval; 1421206b17d7SAlexander Leidinger 1422206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_unload()\n")); 1423206b17d7SAlexander Leidinger retval = EBUSY; 1424206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 1425206b17d7SAlexander Leidinger if (midistat_isopen) 1426206b17d7SAlexander Leidinger goto exit0; 1427206b17d7SAlexander Leidinger 1428206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) { 1429206b17d7SAlexander Leidinger mtx_lock(&m->lock); 1430206b17d7SAlexander Leidinger if (m->busy) 1431206b17d7SAlexander Leidinger retval = EBUSY; 1432206b17d7SAlexander Leidinger else 1433206b17d7SAlexander Leidinger retval = midi_destroy(m, 1); 1434206b17d7SAlexander Leidinger if (retval) 1435206b17d7SAlexander Leidinger goto exit1; 1436206b17d7SAlexander Leidinger } 1437206b17d7SAlexander Leidinger 143890da2b28SAriff Abdullah mtx_unlock(&midistat_lock); /* XXX */ 143990da2b28SAriff Abdullah 1440206b17d7SAlexander Leidinger destroy_dev(midistat_dev); 1441206b17d7SAlexander Leidinger /* 1442206b17d7SAlexander Leidinger * Made it here then unload is complete 1443206b17d7SAlexander Leidinger */ 1444206b17d7SAlexander Leidinger mtx_destroy(&midistat_lock); 1445206b17d7SAlexander Leidinger return 0; 1446206b17d7SAlexander Leidinger 1447206b17d7SAlexander Leidinger exit1: 1448206b17d7SAlexander Leidinger mtx_unlock(&m->lock); 1449206b17d7SAlexander Leidinger exit0: 1450206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 14518f981688SAlexander Leidinger if (retval) 14528f981688SAlexander Leidinger MIDI_DEBUG(2, printf("midi_unload: failed\n")); 1453206b17d7SAlexander Leidinger return retval; 1454206b17d7SAlexander Leidinger } 1455206b17d7SAlexander Leidinger 1456206b17d7SAlexander Leidinger extern int seq_modevent(module_t mod, int type, void *data); 1457206b17d7SAlexander Leidinger 1458206b17d7SAlexander Leidinger static int 1459206b17d7SAlexander Leidinger midi_modevent(module_t mod, int type, void *data) 1460206b17d7SAlexander Leidinger { 1461206b17d7SAlexander Leidinger int retval; 1462206b17d7SAlexander Leidinger 1463206b17d7SAlexander Leidinger retval = 0; 1464206b17d7SAlexander Leidinger 1465206b17d7SAlexander Leidinger switch (type) { 1466206b17d7SAlexander Leidinger case MOD_LOAD: 1467206b17d7SAlexander Leidinger retval = midi_load(); 1468ff749957SAriff Abdullah #if 0 1469206b17d7SAlexander Leidinger if (retval == 0) 1470206b17d7SAlexander Leidinger retval = seq_modevent(mod, type, data); 1471ff749957SAriff Abdullah #endif 1472206b17d7SAlexander Leidinger break; 1473206b17d7SAlexander Leidinger 1474206b17d7SAlexander Leidinger case MOD_UNLOAD: 1475206b17d7SAlexander Leidinger retval = midi_unload(); 1476ff749957SAriff Abdullah #if 0 1477206b17d7SAlexander Leidinger if (retval == 0) 1478206b17d7SAlexander Leidinger retval = seq_modevent(mod, type, data); 1479ff749957SAriff Abdullah #endif 1480206b17d7SAlexander Leidinger break; 1481206b17d7SAlexander Leidinger 1482206b17d7SAlexander Leidinger default: 1483206b17d7SAlexander Leidinger break; 1484206b17d7SAlexander Leidinger } 1485206b17d7SAlexander Leidinger 1486206b17d7SAlexander Leidinger return retval; 1487206b17d7SAlexander Leidinger } 1488206b17d7SAlexander Leidinger 1489206b17d7SAlexander Leidinger kobj_t 1490206b17d7SAlexander Leidinger midimapper_addseq(void *arg1, int *unit, void **cookie) 1491206b17d7SAlexander Leidinger { 1492206b17d7SAlexander Leidinger unit = 0; 1493206b17d7SAlexander Leidinger 1494206b17d7SAlexander Leidinger return (kobj_t)arg1; 1495206b17d7SAlexander Leidinger } 1496206b17d7SAlexander Leidinger 1497206b17d7SAlexander Leidinger int 1498206b17d7SAlexander Leidinger midimapper_open(void *arg1, void **cookie) 1499206b17d7SAlexander Leidinger { 1500206b17d7SAlexander Leidinger int retval = 0; 1501206b17d7SAlexander Leidinger struct snd_midi *m; 1502206b17d7SAlexander Leidinger 1503206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 1504206b17d7SAlexander Leidinger 1505206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) { 1506206b17d7SAlexander Leidinger retval++; 1507206b17d7SAlexander Leidinger } 1508206b17d7SAlexander Leidinger 1509206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 1510206b17d7SAlexander Leidinger return retval; 1511206b17d7SAlexander Leidinger } 1512206b17d7SAlexander Leidinger 1513206b17d7SAlexander Leidinger int 1514206b17d7SAlexander Leidinger midimapper_close(void *arg1, void *cookie) 1515206b17d7SAlexander Leidinger { 1516206b17d7SAlexander Leidinger return 0; 1517206b17d7SAlexander Leidinger } 1518206b17d7SAlexander Leidinger 1519206b17d7SAlexander Leidinger kobj_t 1520206b17d7SAlexander Leidinger midimapper_fetch_synth(void *arg, void *cookie, int unit) 1521206b17d7SAlexander Leidinger { 1522206b17d7SAlexander Leidinger struct snd_midi *m; 1523206b17d7SAlexander Leidinger int retval = 0; 1524206b17d7SAlexander Leidinger 1525206b17d7SAlexander Leidinger mtx_lock(&midistat_lock); 1526206b17d7SAlexander Leidinger 1527206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) { 1528206b17d7SAlexander Leidinger if (unit == retval) { 1529206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 1530206b17d7SAlexander Leidinger return (kobj_t)m->synth; 1531206b17d7SAlexander Leidinger } 1532206b17d7SAlexander Leidinger retval++; 1533206b17d7SAlexander Leidinger } 1534206b17d7SAlexander Leidinger 1535206b17d7SAlexander Leidinger mtx_unlock(&midistat_lock); 1536206b17d7SAlexander Leidinger return NULL; 1537206b17d7SAlexander Leidinger } 1538206b17d7SAlexander Leidinger 1539206b17d7SAlexander Leidinger DEV_MODULE(midi, midi_modevent, NULL); 1540206b17d7SAlexander Leidinger MODULE_VERSION(midi, 1); 1541