1158979Snetchild/*- 2166322Sjoel * Copyright (c) 2003 Mathew Kanner 3158979Snetchild * Copyright (c) 1998 The NetBSD Foundation, Inc. 4158979Snetchild * All rights reserved. 5158979Snetchild * 6158979Snetchild * This code is derived from software contributed to The NetBSD Foundation 7158979Snetchild * by Lennart Augustsson (augustss@netbsd.org). 8158979Snetchild * 9158979Snetchild * Redistribution and use in source and binary forms, with or without 10158979Snetchild * modification, are permitted provided that the following conditions 11158979Snetchild * are met: 12158979Snetchild * 1. Redistributions of source code must retain the above copyright 13158979Snetchild * notice, this list of conditions and the following disclaimer. 14158979Snetchild * 2. Redistributions in binary form must reproduce the above copyright 15158979Snetchild * notice, this list of conditions and the following disclaimer in the 16158979Snetchild * documentation and/or other materials provided with the distribution. 17158979Snetchild * 18158979Snetchild * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19158979Snetchild * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20158979Snetchild * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21158979Snetchild * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22158979Snetchild * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23158979Snetchild * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24158979Snetchild * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25158979Snetchild * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26158979Snetchild * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27158979Snetchild * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28158979Snetchild * POSSIBILITY OF SUCH DAMAGE. 29158979Snetchild */ 30158979Snetchild 31158979Snetchild /* 32158979Snetchild * Parts of this file started out as NetBSD: midi.c 1.31 33158979Snetchild * They are mostly gone. Still the most obvious will be the state 34158979Snetchild * machine midi_in 35158979Snetchild */ 36158979Snetchild 37158979Snetchild#include <sys/cdefs.h> 38158979Snetchild__FBSDID("$FreeBSD$"); 39158979Snetchild 40158979Snetchild#include <sys/param.h> 41158979Snetchild#include <sys/queue.h> 42158979Snetchild#include <sys/kernel.h> 43158979Snetchild#include <sys/lock.h> 44158979Snetchild#include <sys/mutex.h> 45158979Snetchild#include <sys/proc.h> 46158979Snetchild#include <sys/signalvar.h> 47158979Snetchild#include <sys/conf.h> 48158979Snetchild#include <sys/selinfo.h> 49158979Snetchild#include <sys/sysctl.h> 50158979Snetchild#include <sys/types.h> 51158979Snetchild#include <sys/malloc.h> 52158979Snetchild#include <sys/param.h> 53158979Snetchild#include <sys/systm.h> 54158979Snetchild#include <sys/proc.h> 55158979Snetchild#include <sys/fcntl.h> 56158979Snetchild#include <sys/types.h> 57158979Snetchild#include <sys/uio.h> 58158979Snetchild#include <sys/poll.h> 59158979Snetchild#include <sys/sbuf.h> 60158979Snetchild#include <sys/kobj.h> 61158979Snetchild#include <sys/module.h> 62158979Snetchild 63193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 64193640Sariff#include "opt_snd.h" 65193640Sariff#endif 66193640Sariff 67158979Snetchild#include <dev/sound/midi/midi.h> 68158979Snetchild#include "mpu_if.h" 69158979Snetchild 70158979Snetchild#include <dev/sound/midi/midiq.h> 71158979Snetchild#include "synth_if.h" 72158979SnetchildMALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area"); 73158979Snetchild 74193979Sariff#ifndef KOBJMETHOD_END 75193979Sariff#define KOBJMETHOD_END { NULL, NULL } 76193979Sariff#endif 77158979Snetchild 78158979Snetchild#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f)) 79158979Snetchild#define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c) 80158979Snetchild 81158979Snetchild#define MIDI_DEV_RAW 2 82158979Snetchild#define MIDI_DEV_MIDICTL 12 83158979Snetchild 84158979Snetchildenum midi_states { 85158979Snetchild MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA 86158979Snetchild}; 87158979Snetchild 88158979Snetchild/* 89158979Snetchild * The MPU interface current has init() uninit() inqsize(( outqsize() 90158979Snetchild * callback() : fiddle with the tx|rx status. 91158979Snetchild */ 92158979Snetchild 93158979Snetchild#include "mpu_if.h" 94158979Snetchild 95158979Snetchild/* 96158979Snetchild * /dev/rmidi Structure definitions 97158979Snetchild */ 98158979Snetchild 99158979Snetchild#define MIDI_NAMELEN 16 100158979Snetchildstruct snd_midi { 101158979Snetchild KOBJ_FIELDS; 102166971Snetchild struct mtx lock; /* Protects all but queues */ 103166971Snetchild void *cookie; 104158979Snetchild 105166971Snetchild int unit; /* Should only be used in midistat */ 106166971Snetchild int channel; /* Should only be used in midistat */ 107158979Snetchild 108166971Snetchild int busy; 109166971Snetchild int flags; /* File flags */ 110166971Snetchild char name[MIDI_NAMELEN]; 111166971Snetchild struct mtx qlock; /* Protects inq, outq and flags */ 112166971Snetchild MIDIQ_HEAD(, char) inq, outq; 113166971Snetchild int rchan, wchan; 114166971Snetchild struct selinfo rsel, wsel; 115166971Snetchild int hiwat; /* QLEN(outq)>High-water -> disable 116166971Snetchild * writes from userland */ 117158979Snetchild enum midi_states inq_state; 118166971Snetchild int inq_status, inq_left; /* Variables for the state machine in 119166971Snetchild * Midi_in, this is to provide that 120166971Snetchild * signals only get issued only 121166971Snetchild * complete command packets. */ 122166971Snetchild struct proc *async; 123166971Snetchild struct cdev *dev; 124158979Snetchild struct synth_midi *synth; 125166971Snetchild int synth_flags; 126158979Snetchild TAILQ_ENTRY(snd_midi) link; 127158979Snetchild}; 128158979Snetchild 129158979Snetchildstruct synth_midi { 130166971Snetchild KOBJ_FIELDS; 131166971Snetchild struct snd_midi *m; 132158979Snetchild}; 133158979Snetchild 134158979Snetchildstatic synth_open_t midisynth_open; 135158979Snetchildstatic synth_close_t midisynth_close; 136158979Snetchildstatic synth_writeraw_t midisynth_writeraw; 137158979Snetchildstatic synth_killnote_t midisynth_killnote; 138158979Snetchildstatic synth_startnote_t midisynth_startnote; 139158979Snetchildstatic synth_setinstr_t midisynth_setinstr; 140158979Snetchildstatic synth_alloc_t midisynth_alloc; 141158979Snetchildstatic synth_controller_t midisynth_controller; 142158979Snetchildstatic synth_bender_t midisynth_bender; 143158979Snetchild 144158979Snetchild 145158979Snetchildstatic kobj_method_t midisynth_methods[] = { 146166971Snetchild KOBJMETHOD(synth_open, midisynth_open), 147166971Snetchild KOBJMETHOD(synth_close, midisynth_close), 148166971Snetchild KOBJMETHOD(synth_writeraw, midisynth_writeraw), 149166971Snetchild KOBJMETHOD(synth_setinstr, midisynth_setinstr), 150166971Snetchild KOBJMETHOD(synth_startnote, midisynth_startnote), 151166971Snetchild KOBJMETHOD(synth_killnote, midisynth_killnote), 152166971Snetchild KOBJMETHOD(synth_alloc, midisynth_alloc), 153166971Snetchild KOBJMETHOD(synth_controller, midisynth_controller), 154166971Snetchild KOBJMETHOD(synth_bender, midisynth_bender), 155193640Sariff KOBJMETHOD_END 156158979Snetchild}; 157158979Snetchild 158158979SnetchildDEFINE_CLASS(midisynth, midisynth_methods, 0); 159158979Snetchild 160158979Snetchild/* 161158979Snetchild * Module Exports & Interface 162166971Snetchild * 163158979Snetchild * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan) int 164158979Snetchild * midi_uninit(struct snd_midi *) 0 == no error EBUSY or other error int 165158979Snetchild * Midi_in(struct midi_chan *, char *buf, int count) int Midi_out(struct 166158979Snetchild * midi_chan *, char *buf, int count) 167166971Snetchild * 168158979Snetchild * midi_{in,out} return actual size transfered 169166971Snetchild * 170158979Snetchild */ 171158979Snetchild 172158979Snetchild 173158979Snetchild/* 174158979Snetchild * midi_devs tailq, holder of all rmidi instances protected by midistat_lock 175158979Snetchild */ 176158979Snetchild 177158979SnetchildTAILQ_HEAD(, snd_midi) midi_devs; 178158979Snetchild 179158979Snetchild/* 180158979Snetchild * /dev/midistat variables and declarations, protected by midistat_lock 181158979Snetchild */ 182158979Snetchild 183158979Snetchildstatic struct mtx midistat_lock; 184158979Snetchildstatic int midistat_isopen = 0; 185158979Snetchildstatic struct sbuf midistat_sbuf; 186158979Snetchildstatic int midistat_bufptr; 187158979Snetchildstatic struct cdev *midistat_dev; 188158979Snetchild 189158979Snetchild/* 190158979Snetchild * /dev/midistat dev_t declarations 191158979Snetchild */ 192158979Snetchild 193158979Snetchildstatic d_open_t midistat_open; 194158979Snetchildstatic d_close_t midistat_close; 195158979Snetchildstatic d_read_t midistat_read; 196158979Snetchild 197158979Snetchildstatic struct cdevsw midistat_cdevsw = { 198158979Snetchild .d_version = D_VERSION, 199158979Snetchild .d_open = midistat_open, 200158979Snetchild .d_close = midistat_close, 201158979Snetchild .d_read = midistat_read, 202158979Snetchild .d_name = "midistat", 203158979Snetchild}; 204158979Snetchild 205158979Snetchild 206158979Snetchild/* 207158979Snetchild * /dev/rmidi dev_t declarations, struct variable access is protected by 208158979Snetchild * locks contained within the structure. 209158979Snetchild */ 210158979Snetchild 211158979Snetchildstatic d_open_t midi_open; 212158979Snetchildstatic d_close_t midi_close; 213158979Snetchildstatic d_ioctl_t midi_ioctl; 214158979Snetchildstatic d_read_t midi_read; 215158979Snetchildstatic d_write_t midi_write; 216158979Snetchildstatic d_poll_t midi_poll; 217158979Snetchild 218158979Snetchildstatic struct cdevsw midi_cdevsw = { 219158979Snetchild .d_version = D_VERSION, 220158979Snetchild .d_open = midi_open, 221158979Snetchild .d_close = midi_close, 222158979Snetchild .d_read = midi_read, 223158979Snetchild .d_write = midi_write, 224158979Snetchild .d_ioctl = midi_ioctl, 225158979Snetchild .d_poll = midi_poll, 226158979Snetchild .d_name = "rmidi", 227158979Snetchild}; 228158979Snetchild 229158979Snetchild/* 230158979Snetchild * Prototypes of library functions 231158979Snetchild */ 232158979Snetchild 233158979Snetchildstatic int midi_destroy(struct snd_midi *, int); 234158979Snetchildstatic int midistat_prepare(struct sbuf * s); 235158979Snetchildstatic int midi_load(void); 236158979Snetchildstatic int midi_unload(void); 237158979Snetchild 238158979Snetchild/* 239158979Snetchild * Misc declr. 240158979Snetchild */ 241158979SnetchildSYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver"); 242248085Smariusstatic SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device"); 243158979Snetchild 244158979Snetchildint midi_debug; 245159732Snetchild/* XXX: should this be moved into debug.midi? */ 246158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); 247158979Snetchild 248158979Snetchildint midi_dumpraw; 249158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, ""); 250158979Snetchild 251158979Snetchildint midi_instroff; 252158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, ""); 253158979Snetchild 254158979Snetchildint midistat_verbose; 255158979SnetchildSYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW, 256158979Snetchild &midistat_verbose, 0, ""); 257158979Snetchild 258158979Snetchild#define MIDI_DEBUG(l,a) if(midi_debug>=l) a 259158979Snetchild/* 260158979Snetchild * CODE START 261158979Snetchild */ 262158979Snetchild 263158979Snetchild/* 264158979Snetchild * Register a new rmidi device. cls midi_if interface unit == 0 means 265158979Snetchild * auto-assign new unit number unit != 0 already assigned a unit number, eg. 266158979Snetchild * not the first channel provided by this device. channel, sub-unit 267158979Snetchild * cookie is passed back on MPU calls Typical device drivers will call with 268158979Snetchild * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care 269158979Snetchild * what unit number is used. 270166971Snetchild * 271158979Snetchild * It is an error to call midi_init with an already used unit/channel combo. 272166971Snetchild * 273158979Snetchild * Returns NULL on error 274166971Snetchild * 275158979Snetchild */ 276158979Snetchildstruct snd_midi * 277158979Snetchildmidi_init(kobj_class_t cls, int unit, int channel, void *cookie) 278158979Snetchild{ 279158979Snetchild struct snd_midi *m; 280166971Snetchild int i; 281166971Snetchild int inqsize, outqsize; 282166971Snetchild MIDI_TYPE *buf; 283158979Snetchild 284166971Snetchild MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel)); 285158979Snetchild mtx_lock(&midistat_lock); 286158979Snetchild /* 287158979Snetchild * Protect against call with existing unit/channel or auto-allocate a 288158979Snetchild * new unit number. 289158979Snetchild */ 290158979Snetchild i = -1; 291158979Snetchild TAILQ_FOREACH(m, &midi_devs, link) { 292166971Snetchild mtx_lock(&m->lock); 293166971Snetchild if (unit != 0) { 294166971Snetchild if (m->unit == unit && m->channel == channel) { 295166971Snetchild mtx_unlock(&m->lock); 296166971Snetchild goto err0; 297166971Snetchild } 298166971Snetchild } else { 299166971Snetchild /* 300166971Snetchild * Find a better unit number 301166971Snetchild */ 302166971Snetchild if (m->unit > i) 303166971Snetchild i = m->unit; 304158979Snetchild } 305166971Snetchild mtx_unlock(&m->lock); 306158979Snetchild } 307158979Snetchild 308158979Snetchild if (unit == 0) 309166971Snetchild unit = i + 1; 310158979Snetchild 311158979Snetchild MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel)); 312158979Snetchild m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 313158979Snetchild if (m == NULL) 314166971Snetchild goto err0; 315158979Snetchild 316158979Snetchild m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO); 317158979Snetchild kobj_init((kobj_t)m->synth, &midisynth_class); 318158979Snetchild m->synth->m = m; 319158979Snetchild kobj_init((kobj_t)m, cls); 320158979Snetchild inqsize = MPU_INQSIZE(m, cookie); 321158979Snetchild outqsize = MPU_OUTQSIZE(m, cookie); 322158979Snetchild 323158979Snetchild MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize)); 324158979Snetchild if (!inqsize && !outqsize) 325166971Snetchild goto err1; 326158979Snetchild 327167604Sariff mtx_init(&m->lock, "raw midi", NULL, 0); 328167604Sariff mtx_init(&m->qlock, "q raw midi", NULL, 0); 329158979Snetchild 330158979Snetchild mtx_lock(&m->lock); 331158979Snetchild mtx_lock(&m->qlock); 332158979Snetchild 333158979Snetchild if (inqsize) 334166971Snetchild buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT); 335158979Snetchild else 336166971Snetchild buf = NULL; 337158979Snetchild 338158979Snetchild MIDIQ_INIT(m->inq, buf, inqsize); 339158979Snetchild 340158979Snetchild if (outqsize) 341166971Snetchild buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT); 342158979Snetchild else 343166971Snetchild buf = NULL; 344158979Snetchild m->hiwat = outqsize / 2; 345158979Snetchild 346158979Snetchild MIDIQ_INIT(m->outq, buf, outqsize); 347158979Snetchild 348158979Snetchild if ((inqsize && !MIDIQ_BUF(m->inq)) || 349158979Snetchild (outqsize && !MIDIQ_BUF(m->outq))) 350166971Snetchild goto err2; 351158979Snetchild 352158979Snetchild 353158979Snetchild m->busy = 0; 354158979Snetchild m->flags = 0; 355158979Snetchild m->unit = unit; 356158979Snetchild m->channel = channel; 357158979Snetchild m->cookie = cookie; 358158979Snetchild 359158979Snetchild if (MPU_INIT(m, cookie)) 360166971Snetchild goto err2; 361158979Snetchild 362158979Snetchild mtx_unlock(&m->lock); 363158979Snetchild mtx_unlock(&m->qlock); 364158979Snetchild 365158979Snetchild TAILQ_INSERT_TAIL(&midi_devs, m, link); 366158979Snetchild 367158979Snetchild mtx_unlock(&midistat_lock); 368158979Snetchild 369158979Snetchild m->dev = make_dev(&midi_cdevsw, 370166971Snetchild MIDIMKMINOR(unit, MIDI_DEV_RAW, channel), 371166971Snetchild UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel); 372158979Snetchild m->dev->si_drv1 = m; 373158979Snetchild 374158979Snetchild return m; 375158979Snetchild 376158979Snetchilderr2: mtx_destroy(&m->qlock); 377158979Snetchild mtx_destroy(&m->lock); 378158979Snetchild 379158979Snetchild if (MIDIQ_BUF(m->inq)) 380166971Snetchild free(MIDIQ_BUF(m->inq), M_MIDI); 381158979Snetchild if (MIDIQ_BUF(m->outq)) 382166971Snetchild free(MIDIQ_BUF(m->outq), M_MIDI); 383158979Snetchilderr1: free(m, M_MIDI); 384158979Snetchilderr0: mtx_unlock(&midistat_lock); 385158979Snetchild MIDI_DEBUG(1, printf("midi_init ended in error\n")); 386158979Snetchild return NULL; 387158979Snetchild} 388158979Snetchild 389158979Snetchild/* 390158979Snetchild * midi_uninit does not call MIDI_UNINIT, as since this is the implementors 391158979Snetchild * entry point. midi_unint if fact, does not send any methods. A call to 392158979Snetchild * midi_uninit is a defacto promise that you won't manipulate ch anymore 393166971Snetchild * 394158979Snetchild */ 395158979Snetchild 396158979Snetchildint 397166971Snetchildmidi_uninit(struct snd_midi *m) 398158979Snetchild{ 399166971Snetchild int err; 400158979Snetchild 401158979Snetchild err = ENXIO; 402158979Snetchild mtx_lock(&midistat_lock); 403158979Snetchild mtx_lock(&m->lock); 404158979Snetchild if (m->busy) { 405166971Snetchild if (!(m->rchan || m->wchan)) 406166971Snetchild goto err; 407158979Snetchild 408166971Snetchild if (m->rchan) { 409166971Snetchild wakeup(&m->rchan); 410166971Snetchild m->rchan = 0; 411166971Snetchild } 412166971Snetchild if (m->wchan) { 413166971Snetchild wakeup(&m->wchan); 414166971Snetchild m->wchan = 0; 415166971Snetchild } 416158979Snetchild } 417158979Snetchild err = midi_destroy(m, 0); 418166971Snetchild if (!err) 419158979Snetchild goto exit; 420158979Snetchild 421158979Snetchilderr: mtx_unlock(&m->lock); 422158979Snetchildexit: mtx_unlock(&midistat_lock); 423158979Snetchild return err; 424158979Snetchild} 425158979Snetchild 426158979Snetchild/* 427158979Snetchild * midi_in: process all data until the queue is full, then discards the rest. 428158979Snetchild * Since midi_in is a state machine, data discards can cause it to get out of 429158979Snetchild * whack. Process as much as possible. It calls, wakeup, selnotify and 430158979Snetchild * psignal at most once. 431158979Snetchild */ 432158979Snetchild 433159042Sru#ifdef notdef 434166971Snetchildstatic int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0}; 435166971Snetchild 436166971Snetchild#endif /* notdef */ 437158979Snetchild/* Number of bytes in a MIDI command */ 438158979Snetchild#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 439158979Snetchild#define MIDI_ACK 0xfe 440158979Snetchild#define MIDI_IS_STATUS(d) ((d) >= 0x80) 441158979Snetchild#define MIDI_IS_COMMON(d) ((d) >= 0xf0) 442158979Snetchild 443158979Snetchild#define MIDI_SYSEX_START 0xF0 444158979Snetchild#define MIDI_SYSEX_END 0xF7 445158979Snetchild 446158979Snetchild 447158979Snetchildint 448166971Snetchildmidi_in(struct snd_midi *m, MIDI_TYPE *buf, int size) 449158979Snetchild{ 450158979Snetchild /* int i, sig, enq; */ 451166971Snetchild int used; 452166971Snetchild 453158979Snetchild /* MIDI_TYPE data; */ 454158979Snetchild MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size)); 455158979Snetchild 456158979Snetchild/* 457158979Snetchild * XXX: locking flub 458158979Snetchild */ 459158979Snetchild if (!(m->flags & M_RX)) 460166971Snetchild return size; 461158979Snetchild 462158979Snetchild used = 0; 463158979Snetchild 464158979Snetchild mtx_lock(&m->qlock); 465158979Snetchild#if 0 466158979Snetchild /* 467158979Snetchild * Don't bother queuing if not in read mode. Discard everything and 468158979Snetchild * return size so the caller doesn't freak out. 469158979Snetchild */ 470158979Snetchild 471158979Snetchild if (!(m->flags & M_RX)) 472166971Snetchild return size; 473158979Snetchild 474158979Snetchild for (i = sig = 0; i < size; i++) { 475158979Snetchild 476166971Snetchild data = buf[i]; 477166971Snetchild enq = 0; 478166971Snetchild if (data == MIDI_ACK) 479166971Snetchild continue; 480158979Snetchild 481166971Snetchild switch (m->inq_state) { 482166971Snetchild case MIDI_IN_START: 483166971Snetchild if (MIDI_IS_STATUS(data)) { 484166971Snetchild switch (data) { 485166971Snetchild case 0xf0: /* Sysex */ 486166971Snetchild m->inq_state = MIDI_IN_SYSEX; 487166971Snetchild break; 488166971Snetchild case 0xf1: /* MTC quarter frame */ 489166971Snetchild case 0xf3: /* Song select */ 490166971Snetchild m->inq_state = MIDI_IN_DATA; 491166971Snetchild enq = 1; 492166971Snetchild m->inq_left = 1; 493166971Snetchild break; 494166971Snetchild case 0xf2: /* Song position pointer */ 495166971Snetchild m->inq_state = MIDI_IN_DATA; 496166971Snetchild enq = 1; 497166971Snetchild m->inq_left = 2; 498166971Snetchild break; 499166971Snetchild default: 500166971Snetchild if (MIDI_IS_COMMON(data)) { 501166971Snetchild enq = 1; 502166971Snetchild sig = 1; 503166971Snetchild } else { 504166971Snetchild m->inq_state = MIDI_IN_DATA; 505166971Snetchild enq = 1; 506166971Snetchild m->inq_status = data; 507166971Snetchild m->inq_left = MIDI_LENGTH(data); 508166971Snetchild } 509166971Snetchild break; 510166971Snetchild } 511166971Snetchild } else if (MIDI_IS_STATUS(m->inq_status)) { 512166971Snetchild m->inq_state = MIDI_IN_DATA; 513166971Snetchild if (!MIDIQ_FULL(m->inq)) { 514166971Snetchild used++; 515166971Snetchild MIDIQ_ENQ(m->inq, &m->inq_status, 1); 516166971Snetchild } 517166971Snetchild enq = 1; 518166971Snetchild m->inq_left = MIDI_LENGTH(m->inq_status) - 1; 519166971Snetchild } 520158979Snetchild break; 521166971Snetchild /* 522166971Snetchild * End of case MIDI_IN_START: 523166971Snetchild */ 524166971Snetchild 525166971Snetchild case MIDI_IN_DATA: 526158979Snetchild enq = 1; 527166971Snetchild if (--m->inq_left <= 0) 528166971Snetchild sig = 1;/* deliver data */ 529158979Snetchild break; 530166971Snetchild case MIDI_IN_SYSEX: 531166971Snetchild if (data == MIDI_SYSEX_END) 532166971Snetchild m->inq_state = MIDI_IN_START; 533158979Snetchild break; 534166971Snetchild } 535166971Snetchild 536166971Snetchild if (enq) 537166971Snetchild if (!MIDIQ_FULL(m->inq)) { 538166971Snetchild MIDIQ_ENQ(m->inq, &data, 1); 539166971Snetchild used++; 540158979Snetchild } 541158979Snetchild /* 542166971Snetchild * End of the state machines main "for loop" 543166971Snetchild */ 544158979Snetchild } 545158979Snetchild if (sig) { 546158979Snetchild#endif 547166971Snetchild MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n", 548166971Snetchild (intmax_t)MIDIQ_LEN(m->inq), 549166971Snetchild (intmax_t)MIDIQ_AVAIL(m->inq))); 550166971Snetchild if (MIDIQ_AVAIL(m->inq) > size) { 551166971Snetchild used = size; 552166971Snetchild MIDIQ_ENQ(m->inq, buf, size); 553166971Snetchild } else { 554166971Snetchild MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n")); 555166971Snetchild mtx_unlock(&m->qlock); 556166971Snetchild return 0; 557166971Snetchild } 558166971Snetchild if (m->rchan) { 559166971Snetchild wakeup(&m->rchan); 560166971Snetchild m->rchan = 0; 561166971Snetchild } 562166971Snetchild selwakeup(&m->rsel); 563166971Snetchild if (m->async) { 564166971Snetchild PROC_LOCK(m->async); 565225617Skmacy kern_psignal(m->async, SIGIO); 566166971Snetchild PROC_UNLOCK(m->async); 567166971Snetchild } 568158979Snetchild#if 0 569158979Snetchild } 570158979Snetchild#endif 571158979Snetchild mtx_unlock(&m->qlock); 572158979Snetchild return used; 573158979Snetchild} 574158979Snetchild 575158979Snetchild/* 576158979Snetchild * midi_out: The only clearer of the M_TXEN flag. 577158979Snetchild */ 578158979Snetchildint 579166971Snetchildmidi_out(struct snd_midi *m, MIDI_TYPE *buf, int size) 580158979Snetchild{ 581166971Snetchild int used; 582158979Snetchild 583158979Snetchild/* 584158979Snetchild * XXX: locking flub 585158979Snetchild */ 586158979Snetchild if (!(m->flags & M_TXEN)) 587158979Snetchild return 0; 588158979Snetchild 589166971Snetchild MIDI_DEBUG(2, printf("midi_out: %p\n", m)); 590158979Snetchild mtx_lock(&m->qlock); 591158979Snetchild used = MIN(size, MIDIQ_LEN(m->outq)); 592158979Snetchild MIDI_DEBUG(3, printf("midi_out: used %d\n", used)); 593158979Snetchild if (used) 594166971Snetchild MIDIQ_DEQ(m->outq, buf, used); 595158979Snetchild if (MIDIQ_EMPTY(m->outq)) { 596166971Snetchild m->flags &= ~M_TXEN; 597166971Snetchild MPU_CALLBACKP(m, m->cookie, m->flags); 598158979Snetchild } 599166971Snetchild if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) { 600158979Snetchild if (m->wchan) { 601158979Snetchild wakeup(&m->wchan); 602158979Snetchild m->wchan = 0; 603158979Snetchild } 604158979Snetchild selwakeup(&m->wsel); 605166971Snetchild if (m->async) { 606158979Snetchild PROC_LOCK(m->async); 607225617Skmacy kern_psignal(m->async, SIGIO); 608158979Snetchild PROC_UNLOCK(m->async); 609158979Snetchild } 610158979Snetchild } 611158979Snetchild mtx_unlock(&m->qlock); 612158979Snetchild return used; 613158979Snetchild} 614158979Snetchild 615158979Snetchild 616158979Snetchild/* 617158979Snetchild * /dev/rmidi#.# device access functions 618158979Snetchild */ 619158979Snetchildint 620166971Snetchildmidi_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 621158979Snetchild{ 622158979Snetchild struct snd_midi *m = i_dev->si_drv1; 623166971Snetchild int retval; 624158979Snetchild 625166971Snetchild MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td, 626166971Snetchild flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 627158979Snetchild if (m == NULL) 628166971Snetchild return ENXIO; 629158979Snetchild 630158979Snetchild mtx_lock(&m->lock); 631158979Snetchild mtx_lock(&m->qlock); 632158979Snetchild 633158979Snetchild retval = 0; 634158979Snetchild 635158979Snetchild if (flags & FREAD) { 636166971Snetchild if (MIDIQ_SIZE(m->inq) == 0) 637166971Snetchild retval = ENXIO; 638166971Snetchild else if (m->flags & M_RX) 639166971Snetchild retval = EBUSY; 640166971Snetchild if (retval) 641166971Snetchild goto err; 642158979Snetchild } 643158979Snetchild if (flags & FWRITE) { 644166971Snetchild if (MIDIQ_SIZE(m->outq) == 0) 645166971Snetchild retval = ENXIO; 646166971Snetchild else if (m->flags & M_TX) 647166971Snetchild retval = EBUSY; 648166971Snetchild if (retval) 649166971Snetchild goto err; 650158979Snetchild } 651158979Snetchild m->busy++; 652158979Snetchild 653158979Snetchild m->rchan = 0; 654158979Snetchild m->wchan = 0; 655158979Snetchild m->async = 0; 656158979Snetchild 657158979Snetchild if (flags & FREAD) { 658166971Snetchild m->flags |= M_RX | M_RXEN; 659166971Snetchild /* 660166971Snetchild * Only clear the inq, the outq might still have data to drain 661166971Snetchild * from a previous session 662166971Snetchild */ 663166971Snetchild MIDIQ_CLEAR(m->inq); 664158979Snetchild }; 665158979Snetchild 666158979Snetchild if (flags & FWRITE) 667166971Snetchild m->flags |= M_TX; 668158979Snetchild 669158979Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 670158979Snetchild 671158979Snetchild MIDI_DEBUG(2, printf("midi_open: opened.\n")); 672158979Snetchild 673158979Snetchilderr: mtx_unlock(&m->qlock); 674158979Snetchild mtx_unlock(&m->lock); 675158979Snetchild return retval; 676158979Snetchild} 677158979Snetchild 678158979Snetchildint 679166971Snetchildmidi_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 680158979Snetchild{ 681158979Snetchild struct snd_midi *m = i_dev->si_drv1; 682166971Snetchild int retval; 683166971Snetchild int oldflags; 684158979Snetchild 685158979Snetchild MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td, 686166971Snetchild flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 687158979Snetchild 688158979Snetchild if (m == NULL) 689166971Snetchild return ENXIO; 690158979Snetchild 691158979Snetchild mtx_lock(&m->lock); 692158979Snetchild mtx_lock(&m->qlock); 693158979Snetchild 694166971Snetchild if ((flags & FREAD && !(m->flags & M_RX)) || 695166971Snetchild (flags & FWRITE && !(m->flags & M_TX))) { 696166971Snetchild retval = ENXIO; 697166971Snetchild goto err; 698158979Snetchild } 699158979Snetchild m->busy--; 700158979Snetchild 701158979Snetchild oldflags = m->flags; 702158979Snetchild 703158979Snetchild if (flags & FREAD) 704166971Snetchild m->flags &= ~(M_RX | M_RXEN); 705158979Snetchild if (flags & FWRITE) 706166971Snetchild m->flags &= ~M_TX; 707158979Snetchild 708166971Snetchild if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 709158979Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 710158979Snetchild 711158979Snetchild MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 712158979Snetchild 713158979Snetchild mtx_unlock(&m->qlock); 714158979Snetchild mtx_unlock(&m->lock); 715158979Snetchild retval = 0; 716158979Snetchilderr: return retval; 717158979Snetchild} 718166971Snetchild 719158979Snetchild/* 720166971Snetchild * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon 721166971Snetchild * as data is available. 722158979Snetchild */ 723158979Snetchildint 724166971Snetchildmidi_read(struct cdev *i_dev, struct uio *uio, int ioflag) 725158979Snetchild{ 726158979Snetchild#define MIDI_RSIZE 32 727158979Snetchild struct snd_midi *m = i_dev->si_drv1; 728166971Snetchild int retval; 729166971Snetchild int used; 730166971Snetchild char buf[MIDI_RSIZE]; 731158979Snetchild 732166971Snetchild MIDI_DEBUG(5, printf("midiread: count=%lu\n", 733166971Snetchild (unsigned long)uio->uio_resid)); 734158979Snetchild 735158979Snetchild retval = EIO; 736158979Snetchild 737158979Snetchild if (m == NULL) 738166971Snetchild goto err0; 739158979Snetchild 740158979Snetchild mtx_lock(&m->lock); 741158979Snetchild mtx_lock(&m->qlock); 742158979Snetchild 743158979Snetchild if (!(m->flags & M_RX)) 744166971Snetchild goto err1; 745158979Snetchild 746158979Snetchild while (uio->uio_resid > 0) { 747166971Snetchild while (MIDIQ_EMPTY(m->inq)) { 748166971Snetchild retval = EWOULDBLOCK; 749166971Snetchild if (ioflag & O_NONBLOCK) 750166971Snetchild goto err1; 751166971Snetchild mtx_unlock(&m->lock); 752166971Snetchild m->rchan = 1; 753166971Snetchild retval = msleep(&m->rchan, &m->qlock, 754166971Snetchild PCATCH | PDROP, "midi RX", 0); 755166971Snetchild /* 756166971Snetchild * We slept, maybe things have changed since last 757166971Snetchild * dying check 758166971Snetchild */ 759166971Snetchild if (retval == EINTR) 760166971Snetchild goto err0; 761166971Snetchild if (m != i_dev->si_drv1) 762166971Snetchild retval = ENXIO; 763166971Snetchild /* if (retval && retval != ERESTART) */ 764166971Snetchild if (retval) 765166971Snetchild goto err0; 766166971Snetchild mtx_lock(&m->lock); 767166971Snetchild mtx_lock(&m->qlock); 768166971Snetchild m->rchan = 0; 769166971Snetchild if (!m->busy) 770166971Snetchild goto err1; 771166971Snetchild } 772166971Snetchild MIDI_DEBUG(6, printf("midi_read start\n")); 773158979Snetchild /* 774166971Snetchild * At this point, it is certain that m->inq has data 775166971Snetchild */ 776158979Snetchild 777166971Snetchild used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid); 778166971Snetchild used = MIN(used, MIDI_RSIZE); 779158979Snetchild 780166971Snetchild MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used)); 781166971Snetchild MIDIQ_DEQ(m->inq, buf, used); 782166971Snetchild retval = uiomove(buf, used, uio); 783166971Snetchild if (retval) 784166971Snetchild goto err1; 785158979Snetchild } 786158979Snetchild 787158979Snetchild /* 788158979Snetchild * If we Made it here then transfer is good 789158979Snetchild */ 790158979Snetchild retval = 0; 791158979Snetchilderr1: mtx_unlock(&m->qlock); 792158979Snetchild mtx_unlock(&m->lock); 793166971Snetchilderr0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval)); 794158979Snetchild return retval; 795158979Snetchild} 796158979Snetchild 797158979Snetchild/* 798158979Snetchild * midi_write: The only setter of M_TXEN 799158979Snetchild */ 800158979Snetchild 801158979Snetchildint 802166971Snetchildmidi_write(struct cdev *i_dev, struct uio *uio, int ioflag) 803158979Snetchild{ 804158979Snetchild#define MIDI_WSIZE 32 805158979Snetchild struct snd_midi *m = i_dev->si_drv1; 806166971Snetchild int retval; 807166971Snetchild int used; 808166971Snetchild char buf[MIDI_WSIZE]; 809158979Snetchild 810158979Snetchild 811166971Snetchild MIDI_DEBUG(4, printf("midi_write\n")); 812158979Snetchild retval = 0; 813158979Snetchild if (m == NULL) 814166971Snetchild goto err0; 815158979Snetchild 816158979Snetchild mtx_lock(&m->lock); 817158979Snetchild mtx_lock(&m->qlock); 818158979Snetchild 819158979Snetchild if (!(m->flags & M_TX)) 820166971Snetchild goto err1; 821158979Snetchild 822158979Snetchild while (uio->uio_resid > 0) { 823166971Snetchild while (MIDIQ_AVAIL(m->outq) == 0) { 824166971Snetchild retval = EWOULDBLOCK; 825166971Snetchild if (ioflag & O_NONBLOCK) 826166971Snetchild goto err1; 827166971Snetchild mtx_unlock(&m->lock); 828166971Snetchild m->wchan = 1; 829166971Snetchild MIDI_DEBUG(3, printf("midi_write msleep\n")); 830166971Snetchild retval = msleep(&m->wchan, &m->qlock, 831166971Snetchild PCATCH | PDROP, "midi TX", 0); 832166971Snetchild /* 833166971Snetchild * We slept, maybe things have changed since last 834166971Snetchild * dying check 835166971Snetchild */ 836166971Snetchild if (retval == EINTR) 837166971Snetchild goto err0; 838166971Snetchild if (m != i_dev->si_drv1) 839166971Snetchild retval = ENXIO; 840166971Snetchild if (retval) 841166971Snetchild goto err0; 842166971Snetchild mtx_lock(&m->lock); 843166971Snetchild mtx_lock(&m->qlock); 844166971Snetchild m->wchan = 0; 845166971Snetchild if (!m->busy) 846166971Snetchild goto err1; 847166971Snetchild } 848166971Snetchild 849158979Snetchild /* 850166971Snetchild * We are certain than data can be placed on the queue 851166971Snetchild */ 852158979Snetchild 853166971Snetchild used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid); 854166971Snetchild used = MIN(used, MIDI_WSIZE); 855194990Skib MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n", 856166971Snetchild uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq), 857166971Snetchild (intmax_t)MIDIQ_AVAIL(m->outq))); 858158979Snetchild 859158979Snetchild 860166971Snetchild MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used)); 861166971Snetchild retval = uiomove(buf, used, uio); 862166971Snetchild if (retval) 863166971Snetchild goto err1; 864166971Snetchild MIDIQ_ENQ(m->outq, buf, used); 865166971Snetchild /* 866166971Snetchild * Inform the bottom half that data can be written 867166971Snetchild */ 868166971Snetchild if (!(m->flags & M_TXEN)) { 869166971Snetchild m->flags |= M_TXEN; 870166971Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 871166971Snetchild } 872158979Snetchild } 873158979Snetchild /* 874158979Snetchild * If we Made it here then transfer is good 875158979Snetchild */ 876158979Snetchild retval = 0; 877158979Snetchilderr1: mtx_unlock(&m->qlock); 878158979Snetchild mtx_unlock(&m->lock); 879158979Snetchilderr0: return retval; 880158979Snetchild} 881158979Snetchild 882158979Snetchildint 883166971Snetchildmidi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 884166971Snetchild struct thread *td) 885158979Snetchild{ 886158979Snetchild return ENXIO; 887158979Snetchild} 888158979Snetchild 889158979Snetchildint 890166971Snetchildmidi_poll(struct cdev *i_dev, int events, struct thread *td) 891158979Snetchild{ 892158979Snetchild struct snd_midi *m = i_dev->si_drv1; 893166971Snetchild int revents; 894158979Snetchild 895158979Snetchild if (m == NULL) 896166971Snetchild return 0; 897158979Snetchild 898158979Snetchild revents = 0; 899158979Snetchild 900158979Snetchild mtx_lock(&m->lock); 901158979Snetchild mtx_lock(&m->qlock); 902158979Snetchild 903158979Snetchild if (events & (POLLIN | POLLRDNORM)) 904166971Snetchild if (!MIDIQ_EMPTY(m->inq)) 905166971Snetchild events |= events & (POLLIN | POLLRDNORM); 906158979Snetchild 907158979Snetchild if (events & (POLLOUT | POLLWRNORM)) 908166971Snetchild if (MIDIQ_AVAIL(m->outq) < m->hiwat) 909166971Snetchild events |= events & (POLLOUT | POLLWRNORM); 910158979Snetchild 911158979Snetchild if (revents == 0) { 912166971Snetchild if (events & (POLLIN | POLLRDNORM)) 913166971Snetchild selrecord(td, &m->rsel); 914158979Snetchild 915166971Snetchild if (events & (POLLOUT | POLLWRNORM)) 916166971Snetchild selrecord(td, &m->wsel); 917158979Snetchild } 918158979Snetchild mtx_unlock(&m->lock); 919158979Snetchild mtx_unlock(&m->qlock); 920158979Snetchild 921158979Snetchild return (revents); 922158979Snetchild} 923158979Snetchild 924158979Snetchild/* 925158979Snetchild * /dev/midistat device functions 926166971Snetchild * 927158979Snetchild */ 928158979Snetchildstatic int 929166971Snetchildmidistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 930158979Snetchild{ 931166971Snetchild int error; 932158979Snetchild 933166971Snetchild MIDI_DEBUG(1, printf("midistat_open\n")); 934158979Snetchild mtx_lock(&midistat_lock); 935158979Snetchild 936158979Snetchild if (midistat_isopen) { 937166971Snetchild mtx_unlock(&midistat_lock); 938166971Snetchild return EBUSY; 939158979Snetchild } 940158979Snetchild midistat_isopen = 1; 941166280Sariff mtx_unlock(&midistat_lock); 942158979Snetchild 943166280Sariff if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) { 944166971Snetchild error = ENXIO; 945166971Snetchild mtx_lock(&midistat_lock); 946166971Snetchild goto out; 947158979Snetchild } 948166280Sariff mtx_lock(&midistat_lock); 949158979Snetchild midistat_bufptr = 0; 950158979Snetchild error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM; 951158979Snetchild 952158979Snetchildout: if (error) 953166971Snetchild midistat_isopen = 0; 954158979Snetchild mtx_unlock(&midistat_lock); 955158979Snetchild return error; 956158979Snetchild} 957158979Snetchild 958158979Snetchildstatic int 959166971Snetchildmidistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 960158979Snetchild{ 961166971Snetchild MIDI_DEBUG(1, printf("midistat_close\n")); 962158979Snetchild mtx_lock(&midistat_lock); 963158979Snetchild if (!midistat_isopen) { 964166971Snetchild mtx_unlock(&midistat_lock); 965166971Snetchild return EBADF; 966158979Snetchild } 967158979Snetchild sbuf_delete(&midistat_sbuf); 968158979Snetchild midistat_isopen = 0; 969158979Snetchild 970158979Snetchild mtx_unlock(&midistat_lock); 971158979Snetchild return 0; 972158979Snetchild} 973158979Snetchild 974158979Snetchildstatic int 975166971Snetchildmidistat_read(struct cdev *i_dev, struct uio *buf, int flag) 976158979Snetchild{ 977166971Snetchild int l, err; 978158979Snetchild 979166971Snetchild MIDI_DEBUG(4, printf("midistat_read\n")); 980158979Snetchild mtx_lock(&midistat_lock); 981158979Snetchild if (!midistat_isopen) { 982166971Snetchild mtx_unlock(&midistat_lock); 983166971Snetchild return EBADF; 984158979Snetchild } 985158979Snetchild l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr); 986158979Snetchild err = 0; 987166280Sariff if (l > 0) { 988166971Snetchild mtx_unlock(&midistat_lock); 989166971Snetchild err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l, 990166971Snetchild buf); 991166971Snetchild mtx_lock(&midistat_lock); 992166280Sariff } else 993166971Snetchild l = 0; 994158979Snetchild midistat_bufptr += l; 995158979Snetchild mtx_unlock(&midistat_lock); 996158979Snetchild return err; 997158979Snetchild} 998158979Snetchild 999158979Snetchild/* 1000158979Snetchild * Module library functions 1001158979Snetchild */ 1002158979Snetchild 1003158979Snetchildstatic int 1004166971Snetchildmidistat_prepare(struct sbuf *s) 1005158979Snetchild{ 1006158979Snetchild struct snd_midi *m; 1007158979Snetchild 1008158979Snetchild mtx_assert(&midistat_lock, MA_OWNED); 1009158979Snetchild 1010158979Snetchild sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n"); 1011158979Snetchild if (TAILQ_EMPTY(&midi_devs)) { 1012166971Snetchild sbuf_printf(s, "No devices installed.\n"); 1013166971Snetchild sbuf_finish(s); 1014166971Snetchild return sbuf_len(s); 1015158979Snetchild } 1016158979Snetchild sbuf_printf(s, "Installed devices:\n"); 1017158979Snetchild 1018158979Snetchild TAILQ_FOREACH(m, &midi_devs, link) { 1019166971Snetchild mtx_lock(&m->lock); 1020166971Snetchild sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel, 1021158979Snetchild MPU_PROVIDER(m, m->cookie)); 1022166971Snetchild sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose)); 1023166971Snetchild sbuf_printf(s, "\n"); 1024166971Snetchild mtx_unlock(&m->lock); 1025158979Snetchild } 1026158979Snetchild 1027158979Snetchild sbuf_finish(s); 1028158979Snetchild return sbuf_len(s); 1029158979Snetchild} 1030158979Snetchild 1031159042Sru#ifdef notdef 1032158979Snetchild/* 1033158979Snetchild * Convert IOCTL command to string for debugging 1034158979Snetchild */ 1035158979Snetchild 1036166971Snetchildstatic char * 1037158979Snetchildmidi_cmdname(int cmd) 1038158979Snetchild{ 1039158979Snetchild static struct { 1040166971Snetchild int cmd; 1041166971Snetchild char *name; 1042166971Snetchild } *tab, cmdtab_midiioctl[] = { 1043158979Snetchild#define A(x) {x, ## x} 1044166971Snetchild /* 1045166971Snetchild * Once we have some real IOCTLs define, the following will 1046166971Snetchild * be relavant. 1047166971Snetchild * 1048166971Snetchild * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE), 1049166971Snetchild * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO), 1050166971Snetchild * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL), 1051166971Snetchild * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE), 1052166971Snetchild * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE), 1053166971Snetchild * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT), 1054166971Snetchild * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC), 1055166971Snetchild * A(AIOGCAP), 1056166971Snetchild */ 1057158979Snetchild#undef A 1058166971Snetchild { 1059166971Snetchild -1, "unknown" 1060166971Snetchild }, 1061158979Snetchild }; 1062158979Snetchild 1063166971Snetchild for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++); 1064158979Snetchild return tab->name; 1065158979Snetchild} 1066158979Snetchild 1067166971Snetchild#endif /* notdef */ 1068166971Snetchild 1069158979Snetchild/* 1070158979Snetchild * midisynth 1071158979Snetchild */ 1072158979Snetchild 1073158979Snetchild 1074158979Snetchildint 1075158979Snetchildmidisynth_open(void *n, void *arg, int flags) 1076158979Snetchild{ 1077166971Snetchild struct snd_midi *m = ((struct synth_midi *)n)->m; 1078166971Snetchild int retval; 1079158979Snetchild 1080166971Snetchild MIDI_DEBUG(1, printf("midisynth_open %s %s\n", 1081166971Snetchild flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 1082158979Snetchild 1083158979Snetchild if (m == NULL) 1084166971Snetchild return ENXIO; 1085158979Snetchild 1086158979Snetchild mtx_lock(&m->lock); 1087158979Snetchild mtx_lock(&m->qlock); 1088158979Snetchild 1089158979Snetchild retval = 0; 1090158979Snetchild 1091158979Snetchild if (flags & FREAD) { 1092166971Snetchild if (MIDIQ_SIZE(m->inq) == 0) 1093166971Snetchild retval = ENXIO; 1094166971Snetchild else if (m->flags & M_RX) 1095166971Snetchild retval = EBUSY; 1096166971Snetchild if (retval) 1097166971Snetchild goto err; 1098158979Snetchild } 1099158979Snetchild if (flags & FWRITE) { 1100166971Snetchild if (MIDIQ_SIZE(m->outq) == 0) 1101166971Snetchild retval = ENXIO; 1102166971Snetchild else if (m->flags & M_TX) 1103166971Snetchild retval = EBUSY; 1104166971Snetchild if (retval) 1105166971Snetchild goto err; 1106158979Snetchild } 1107158979Snetchild m->busy++; 1108158979Snetchild 1109158979Snetchild /* 1110158979Snetchild * TODO: Consider m->async = 0; 1111158979Snetchild */ 1112158979Snetchild 1113158979Snetchild if (flags & FREAD) { 1114166971Snetchild m->flags |= M_RX | M_RXEN; 1115166971Snetchild /* 1116166971Snetchild * Only clear the inq, the outq might still have data to drain 1117166971Snetchild * from a previous session 1118166971Snetchild */ 1119166971Snetchild MIDIQ_CLEAR(m->inq); 1120166971Snetchild m->rchan = 0; 1121158979Snetchild }; 1122158979Snetchild 1123158979Snetchild if (flags & FWRITE) { 1124166971Snetchild m->flags |= M_TX; 1125166971Snetchild m->wchan = 0; 1126158979Snetchild } 1127166971Snetchild m->synth_flags = flags & (FREAD | FWRITE); 1128158979Snetchild 1129158979Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 1130158979Snetchild 1131158979Snetchild 1132158979Snetchilderr: mtx_unlock(&m->qlock); 1133158979Snetchild mtx_unlock(&m->lock); 1134158979Snetchild MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval)); 1135158979Snetchild return retval; 1136158979Snetchild} 1137158979Snetchild 1138158979Snetchildint 1139158979Snetchildmidisynth_close(void *n) 1140158979Snetchild{ 1141158979Snetchild struct snd_midi *m = ((struct synth_midi *)n)->m; 1142166971Snetchild int retval; 1143166971Snetchild int oldflags; 1144158979Snetchild 1145158979Snetchild MIDI_DEBUG(1, printf("midisynth_close %s %s\n", 1146166971Snetchild m->synth_flags & FREAD ? "M_RX" : "", 1147166971Snetchild m->synth_flags & FWRITE ? "M_TX" : "")); 1148158979Snetchild 1149158979Snetchild if (m == NULL) 1150166971Snetchild return ENXIO; 1151158979Snetchild 1152158979Snetchild mtx_lock(&m->lock); 1153158979Snetchild mtx_lock(&m->qlock); 1154158979Snetchild 1155166971Snetchild if ((m->synth_flags & FREAD && !(m->flags & M_RX)) || 1156166971Snetchild (m->synth_flags & FWRITE && !(m->flags & M_TX))) { 1157166971Snetchild retval = ENXIO; 1158166971Snetchild goto err; 1159158979Snetchild } 1160158979Snetchild m->busy--; 1161158979Snetchild 1162158979Snetchild oldflags = m->flags; 1163158979Snetchild 1164158979Snetchild if (m->synth_flags & FREAD) 1165166971Snetchild m->flags &= ~(M_RX | M_RXEN); 1166158979Snetchild if (m->synth_flags & FWRITE) 1167166971Snetchild m->flags &= ~M_TX; 1168158979Snetchild 1169166971Snetchild if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 1170158979Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 1171158979Snetchild 1172158979Snetchild MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 1173158979Snetchild 1174158979Snetchild mtx_unlock(&m->qlock); 1175158979Snetchild mtx_unlock(&m->lock); 1176158979Snetchild retval = 0; 1177158979Snetchilderr: return retval; 1178158979Snetchild} 1179158979Snetchild 1180158979Snetchild/* 1181158979Snetchild * Always blocking. 1182158979Snetchild */ 1183158979Snetchild 1184158979Snetchildint 1185158979Snetchildmidisynth_writeraw(void *n, uint8_t *buf, size_t len) 1186158979Snetchild{ 1187166971Snetchild struct snd_midi *m = ((struct synth_midi *)n)->m; 1188166971Snetchild int retval; 1189166971Snetchild int used; 1190158979Snetchild int i; 1191158979Snetchild 1192166971Snetchild MIDI_DEBUG(4, printf("midisynth_writeraw\n")); 1193158979Snetchild 1194158979Snetchild retval = 0; 1195158979Snetchild 1196158979Snetchild if (m == NULL) 1197166971Snetchild return ENXIO; 1198158979Snetchild 1199158979Snetchild mtx_lock(&m->lock); 1200158979Snetchild mtx_lock(&m->qlock); 1201158979Snetchild 1202158979Snetchild if (!(m->flags & M_TX)) 1203166971Snetchild goto err1; 1204158979Snetchild 1205158979Snetchild if (midi_dumpraw) 1206166971Snetchild printf("midi dump: "); 1207158979Snetchild 1208158979Snetchild while (len > 0) { 1209166971Snetchild while (MIDIQ_AVAIL(m->outq) == 0) { 1210166971Snetchild if (!(m->flags & M_TXEN)) { 1211166971Snetchild m->flags |= M_TXEN; 1212166971Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 1213166971Snetchild } 1214166971Snetchild mtx_unlock(&m->lock); 1215166971Snetchild m->wchan = 1; 1216166971Snetchild MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n")); 1217166971Snetchild retval = msleep(&m->wchan, &m->qlock, 1218166971Snetchild PCATCH | PDROP, "midi TX", 0); 1219166971Snetchild /* 1220166971Snetchild * We slept, maybe things have changed since last 1221166971Snetchild * dying check 1222166971Snetchild */ 1223166971Snetchild if (retval == EINTR) 1224166971Snetchild goto err0; 1225158979Snetchild 1226166971Snetchild if (retval) 1227166971Snetchild goto err0; 1228166971Snetchild mtx_lock(&m->lock); 1229166971Snetchild mtx_lock(&m->qlock); 1230166971Snetchild m->wchan = 0; 1231166971Snetchild if (!m->busy) 1232166971Snetchild goto err1; 1233166971Snetchild } 1234158979Snetchild 1235166971Snetchild /* 1236166971Snetchild * We are certain than data can be placed on the queue 1237166971Snetchild */ 1238158979Snetchild 1239166971Snetchild used = MIN(MIDIQ_AVAIL(m->outq), len); 1240166971Snetchild used = MIN(used, MIDI_WSIZE); 1241166971Snetchild MIDI_DEBUG(5, 1242166971Snetchild printf("midi_synth: resid %zu len %jd avail %jd\n", 1243166971Snetchild len, (intmax_t)MIDIQ_LEN(m->outq), 1244166971Snetchild (intmax_t)MIDIQ_AVAIL(m->outq))); 1245158979Snetchild 1246166971Snetchild if (midi_dumpraw) 1247166971Snetchild for (i = 0; i < used; i++) 1248166971Snetchild printf("%x ", buf[i]); 1249158979Snetchild 1250166971Snetchild MIDIQ_ENQ(m->outq, buf, used); 1251166971Snetchild len -= used; 1252158979Snetchild 1253166971Snetchild /* 1254166971Snetchild * Inform the bottom half that data can be written 1255166971Snetchild */ 1256166971Snetchild if (!(m->flags & M_TXEN)) { 1257166971Snetchild m->flags |= M_TXEN; 1258166971Snetchild MPU_CALLBACK(m, m->cookie, m->flags); 1259166971Snetchild } 1260158979Snetchild } 1261158979Snetchild /* 1262158979Snetchild * If we Made it here then transfer is good 1263158979Snetchild */ 1264158979Snetchild if (midi_dumpraw) 1265166971Snetchild printf("\n"); 1266158979Snetchild 1267158979Snetchild retval = 0; 1268158979Snetchilderr1: mtx_unlock(&m->qlock); 1269158979Snetchild mtx_unlock(&m->lock); 1270158979Snetchilderr0: return retval; 1271158979Snetchild} 1272158979Snetchild 1273158979Snetchildstatic int 1274158979Snetchildmidisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1275158979Snetchild{ 1276158979Snetchild u_char c[3]; 1277158979Snetchild 1278158979Snetchild 1279158979Snetchild if (note > 127 || chn > 15) 1280158979Snetchild return (EINVAL); 1281158979Snetchild 1282158979Snetchild if (vel > 127) 1283166971Snetchild vel = 127; 1284158979Snetchild 1285158979Snetchild if (vel == 64) { 1286166971Snetchild c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1287158979Snetchild c[1] = (u_char)note; 1288158979Snetchild c[2] = 0; 1289158979Snetchild } else { 1290166971Snetchild c[0] = 0x80 | (chn & 0x0f); /* Note off. */ 1291158979Snetchild c[1] = (u_char)note; 1292158979Snetchild c[2] = (u_char)vel; 1293158979Snetchild } 1294158979Snetchild 1295158979Snetchild return midisynth_writeraw(n, c, 3); 1296158979Snetchild} 1297158979Snetchild 1298158979Snetchildstatic int 1299158979Snetchildmidisynth_setinstr(void *n, uint8_t chn, uint16_t instr) 1300158979Snetchild{ 1301158979Snetchild u_char c[2]; 1302158979Snetchild 1303158979Snetchild if (instr > 127 || chn > 15) 1304158979Snetchild return EINVAL; 1305158979Snetchild 1306166971Snetchild c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */ 1307158979Snetchild c[1] = instr + midi_instroff; 1308158979Snetchild 1309158979Snetchild return midisynth_writeraw(n, c, 2); 1310158979Snetchild} 1311158979Snetchild 1312158979Snetchildstatic int 1313158979Snetchildmidisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1314158979Snetchild{ 1315158979Snetchild u_char c[3]; 1316158979Snetchild 1317158979Snetchild if (note > 127 || chn > 15) 1318158979Snetchild return EINVAL; 1319158979Snetchild 1320158979Snetchild if (vel > 127) 1321166971Snetchild vel = 127; 1322158979Snetchild 1323166971Snetchild c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1324158979Snetchild c[1] = (u_char)note; 1325158979Snetchild c[2] = (u_char)vel; 1326158979Snetchild 1327158979Snetchild return midisynth_writeraw(n, c, 3); 1328158979Snetchild} 1329158979Snetchildstatic int 1330158979Snetchildmidisynth_alloc(void *n, uint8_t chan, uint8_t note) 1331158979Snetchild{ 1332158979Snetchild return chan; 1333158979Snetchild} 1334158979Snetchild 1335158979Snetchildstatic int 1336158979Snetchildmidisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val) 1337158979Snetchild{ 1338158979Snetchild u_char c[3]; 1339158979Snetchild 1340158979Snetchild if (ctrlnum > 127 || chn > 15) 1341166971Snetchild return EINVAL; 1342158979Snetchild 1343166971Snetchild c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ 1344158979Snetchild c[1] = ctrlnum; 1345158979Snetchild c[2] = val; 1346158979Snetchild return midisynth_writeraw(n, c, 3); 1347158979Snetchild} 1348158979Snetchild 1349158979Snetchildstatic int 1350158979Snetchildmidisynth_bender(void *n, uint8_t chn, uint16_t val) 1351158979Snetchild{ 1352158979Snetchild u_char c[3]; 1353158979Snetchild 1354158979Snetchild 1355158979Snetchild if (val > 16383 || chn > 15) 1356166971Snetchild return EINVAL; 1357158979Snetchild 1358166971Snetchild c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ 1359158979Snetchild c[1] = (u_char)val & 0x7f; 1360158979Snetchild c[2] = (u_char)(val >> 7) & 0x7f; 1361158979Snetchild 1362158979Snetchild return midisynth_writeraw(n, c, 3); 1363158979Snetchild} 1364158979Snetchild 1365158979Snetchild/* 1366158979Snetchild * Single point of midi destructions. 1367158979Snetchild */ 1368158979Snetchildstatic int 1369166971Snetchildmidi_destroy(struct snd_midi *m, int midiuninit) 1370158979Snetchild{ 1371158979Snetchild 1372158979Snetchild mtx_assert(&midistat_lock, MA_OWNED); 1373158979Snetchild mtx_assert(&m->lock, MA_OWNED); 1374158979Snetchild 1375166971Snetchild MIDI_DEBUG(3, printf("midi_destroy\n")); 1376158979Snetchild m->dev->si_drv1 = NULL; 1377193640Sariff mtx_unlock(&m->lock); /* XXX */ 1378158979Snetchild destroy_dev(m->dev); 1379158979Snetchild TAILQ_REMOVE(&midi_devs, m, link); 1380158979Snetchild if (midiuninit) 1381166971Snetchild MPU_UNINIT(m, m->cookie); 1382158979Snetchild free(MIDIQ_BUF(m->inq), M_MIDI); 1383158979Snetchild free(MIDIQ_BUF(m->outq), M_MIDI); 1384158979Snetchild mtx_destroy(&m->qlock); 1385158979Snetchild mtx_destroy(&m->lock); 1386158979Snetchild free(m, M_MIDI); 1387158979Snetchild return 0; 1388158979Snetchild} 1389158979Snetchild 1390158979Snetchild/* 1391158979Snetchild * Load and unload functions, creates the /dev/midistat device 1392158979Snetchild */ 1393158979Snetchild 1394158979Snetchildstatic int 1395158979Snetchildmidi_load() 1396158979Snetchild{ 1397167604Sariff mtx_init(&midistat_lock, "midistat lock", NULL, 0); 1398166971Snetchild TAILQ_INIT(&midi_devs); /* Initialize the queue. */ 1399158979Snetchild 1400158979Snetchild midistat_dev = make_dev(&midistat_cdevsw, 1401166971Snetchild MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0), 1402166971Snetchild UID_ROOT, GID_WHEEL, 0666, "midistat"); 1403158979Snetchild 1404158979Snetchild return 0; 1405158979Snetchild} 1406158979Snetchild 1407158979Snetchildstatic int 1408158979Snetchildmidi_unload() 1409158979Snetchild{ 1410158979Snetchild struct snd_midi *m; 1411166971Snetchild int retval; 1412158979Snetchild 1413166971Snetchild MIDI_DEBUG(1, printf("midi_unload()\n")); 1414158979Snetchild retval = EBUSY; 1415158979Snetchild mtx_lock(&midistat_lock); 1416158979Snetchild if (midistat_isopen) 1417166971Snetchild goto exit0; 1418158979Snetchild 1419158979Snetchild TAILQ_FOREACH(m, &midi_devs, link) { 1420166971Snetchild mtx_lock(&m->lock); 1421166971Snetchild if (m->busy) 1422166971Snetchild retval = EBUSY; 1423166971Snetchild else 1424166971Snetchild retval = midi_destroy(m, 1); 1425166971Snetchild if (retval) 1426166971Snetchild goto exit1; 1427158979Snetchild } 1428158979Snetchild 1429193640Sariff mtx_unlock(&midistat_lock); /* XXX */ 1430193640Sariff 1431158979Snetchild destroy_dev(midistat_dev); 1432158979Snetchild /* 1433158979Snetchild * Made it here then unload is complete 1434158979Snetchild */ 1435158979Snetchild mtx_destroy(&midistat_lock); 1436158979Snetchild return 0; 1437158979Snetchild 1438158979Snetchildexit1: 1439158979Snetchild mtx_unlock(&m->lock); 1440158979Snetchildexit0: 1441158979Snetchild mtx_unlock(&midistat_lock); 1442166971Snetchild if (retval) 1443166971Snetchild MIDI_DEBUG(2, printf("midi_unload: failed\n")); 1444158979Snetchild return retval; 1445158979Snetchild} 1446158979Snetchild 1447158979Snetchildextern int seq_modevent(module_t mod, int type, void *data); 1448158979Snetchild 1449158979Snetchildstatic int 1450158979Snetchildmidi_modevent(module_t mod, int type, void *data) 1451158979Snetchild{ 1452166971Snetchild int retval; 1453158979Snetchild 1454158979Snetchild retval = 0; 1455158979Snetchild 1456158979Snetchild switch (type) { 1457158979Snetchild case MOD_LOAD: 1458166971Snetchild retval = midi_load(); 1459168253Sariff#if 0 1460166971Snetchild if (retval == 0) 1461166971Snetchild retval = seq_modevent(mod, type, data); 1462168253Sariff#endif 1463166971Snetchild break; 1464158979Snetchild 1465158979Snetchild case MOD_UNLOAD: 1466166971Snetchild retval = midi_unload(); 1467168253Sariff#if 0 1468166971Snetchild if (retval == 0) 1469166971Snetchild retval = seq_modevent(mod, type, data); 1470168253Sariff#endif 1471166971Snetchild break; 1472158979Snetchild 1473158979Snetchild default: 1474166971Snetchild break; 1475158979Snetchild } 1476158979Snetchild 1477158979Snetchild return retval; 1478158979Snetchild} 1479158979Snetchild 1480158979Snetchildkobj_t 1481158979Snetchildmidimapper_addseq(void *arg1, int *unit, void **cookie) 1482158979Snetchild{ 1483158979Snetchild unit = 0; 1484158979Snetchild 1485166971Snetchild return (kobj_t)arg1; 1486158979Snetchild} 1487158979Snetchild 1488158979Snetchildint 1489158979Snetchildmidimapper_open(void *arg1, void **cookie) 1490158979Snetchild{ 1491158979Snetchild int retval = 0; 1492158979Snetchild struct snd_midi *m; 1493158979Snetchild 1494166971Snetchild mtx_lock(&midistat_lock); 1495158979Snetchild 1496166971Snetchild TAILQ_FOREACH(m, &midi_devs, link) { 1497166971Snetchild retval++; 1498166971Snetchild } 1499158979Snetchild 1500166971Snetchild mtx_unlock(&midistat_lock); 1501166971Snetchild return retval; 1502158979Snetchild} 1503158979Snetchild 1504158979Snetchildint 1505158979Snetchildmidimapper_close(void *arg1, void *cookie) 1506158979Snetchild{ 1507158979Snetchild return 0; 1508158979Snetchild} 1509158979Snetchild 1510158979Snetchildkobj_t 1511158979Snetchildmidimapper_fetch_synth(void *arg, void *cookie, int unit) 1512158979Snetchild{ 1513158979Snetchild struct snd_midi *m; 1514158979Snetchild int retval = 0; 1515158979Snetchild 1516158979Snetchild mtx_lock(&midistat_lock); 1517158979Snetchild 1518158979Snetchild TAILQ_FOREACH(m, &midi_devs, link) { 1519166971Snetchild if (unit == retval) { 1520166971Snetchild mtx_unlock(&midistat_lock); 1521166971Snetchild return (kobj_t)m->synth; 1522166971Snetchild } 1523166971Snetchild retval++; 1524158979Snetchild } 1525158979Snetchild 1526158979Snetchild mtx_unlock(&midistat_lock); 1527158979Snetchild return NULL; 1528158979Snetchild} 1529158979Snetchild 1530158979SnetchildDEV_MODULE(midi, midi_modevent, NULL); 1531158979SnetchildMODULE_VERSION(midi, 1); 1532