1 1.101 riastrad /* $NetBSD: midi.c,v 1.101 2022/10/23 23:03:30 riastradh Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.73 jmcneill * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.8 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.73 jmcneill * by Lennart Augustsson (augustss (at) NetBSD.org), (MIDI FST and Active 9 1.73 jmcneill * Sense handling) Chapman Flack (chap (at) NetBSD.org), and Andrew Doran. 10 1.1 augustss * 11 1.1 augustss * Redistribution and use in source and binary forms, with or without 12 1.1 augustss * modification, are permitted provided that the following conditions 13 1.1 augustss * are met: 14 1.1 augustss * 1. Redistributions of source code must retain the above copyright 15 1.1 augustss * notice, this list of conditions and the following disclaimer. 16 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 augustss * notice, this list of conditions and the following disclaimer in the 18 1.1 augustss * documentation and/or other materials provided with the distribution. 19 1.1 augustss * 20 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 31 1.1 augustss */ 32 1.23 lukem 33 1.23 lukem #include <sys/cdefs.h> 34 1.101 riastrad __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.101 2022/10/23 23:03:30 riastradh Exp $"); 35 1.1 augustss 36 1.86 pgoyette #ifdef _KERNEL_OPT 37 1.1 augustss #include "midi.h" 38 1.86 pgoyette #endif 39 1.1 augustss 40 1.1 augustss #include <sys/param.h> 41 1.1 augustss #include <sys/ioctl.h> 42 1.1 augustss #include <sys/fcntl.h> 43 1.1 augustss #include <sys/vnode.h> 44 1.1 augustss #include <sys/select.h> 45 1.1 augustss #include <sys/poll.h> 46 1.1 augustss #include <sys/proc.h> 47 1.1 augustss #include <sys/systm.h> 48 1.15 thorpej #include <sys/callout.h> 49 1.1 augustss #include <sys/syslog.h> 50 1.1 augustss #include <sys/kernel.h> 51 1.1 augustss #include <sys/signalvar.h> 52 1.1 augustss #include <sys/conf.h> 53 1.1 augustss #include <sys/audioio.h> 54 1.1 augustss #include <sys/midiio.h> 55 1.62 tnn #include <sys/device.h> 56 1.56 ad #include <sys/intr.h> 57 1.86 pgoyette #include <sys/module.h> 58 1.1 augustss 59 1.89 isaki #include <dev/audio/audio_if.h> 60 1.4 augustss #include <dev/midi_if.h> 61 1.1 augustss #include <dev/midivar.h> 62 1.1 augustss 63 1.88 riastrad #include "ioconf.h" 64 1.88 riastrad 65 1.10 drochner #if NMIDI > 0 66 1.10 drochner 67 1.1 augustss #ifdef AUDIO_DEBUG 68 1.1 augustss #define DPRINTF(x) if (mididebug) printf x 69 1.1 augustss #define DPRINTFN(n,x) if (mididebug >= (n)) printf x 70 1.1 augustss int mididebug = 0; 71 1.44 chap /* 72 1.44 chap * 1: detected protocol errors and buffer overflows 73 1.44 chap * 2: probe, attach, detach 74 1.44 chap * 3: open, close 75 1.44 chap * 4: data received except realtime 76 1.44 chap * 5: ioctl 77 1.44 chap * 6: read, write, poll 78 1.44 chap * 7: data transmitted 79 1.44 chap * 8: uiomoves, synchronization 80 1.44 chap * 9: realtime data received 81 1.44 chap */ 82 1.1 augustss #else 83 1.1 augustss #define DPRINTF(x) 84 1.1 augustss #define DPRINTFN(n,x) 85 1.1 augustss #endif 86 1.1 augustss 87 1.44 chap static struct midi_softc *hwif_softc = NULL; 88 1.74 mrg static kmutex_t hwif_softc_lock; 89 1.1 augustss 90 1.73 jmcneill static void midi_in(void *, int); 91 1.73 jmcneill static void midi_out(void *); 92 1.73 jmcneill static int midi_poll_out(struct midi_softc *); 93 1.73 jmcneill static int midi_intr_out(struct midi_softc *); 94 1.73 jmcneill static int midi_msg_out(struct midi_softc *, u_char **, u_char **, 95 1.73 jmcneill u_char **, u_char **); 96 1.73 jmcneill static int midi_start_output(struct midi_softc *); 97 1.73 jmcneill static void midi_initbuf(struct midi_buffer *); 98 1.73 jmcneill static void midi_xmt_asense(void *); 99 1.73 jmcneill static void midi_rcv_asense(void *); 100 1.73 jmcneill static void midi_softint(void *); 101 1.73 jmcneill 102 1.73 jmcneill static int midiprobe(device_t, cfdata_t, void *); 103 1.73 jmcneill static void midiattach(device_t, device_t, void *); 104 1.73 jmcneill int mididetach(device_t, int); 105 1.73 jmcneill static int midiactivate(device_t, enum devact); 106 1.73 jmcneill 107 1.73 jmcneill static dev_type_open(midiopen); 108 1.73 jmcneill static dev_type_close(midiclose); 109 1.73 jmcneill static dev_type_read(midiread); 110 1.73 jmcneill static dev_type_write(midiwrite); 111 1.73 jmcneill static dev_type_ioctl(midiioctl); 112 1.73 jmcneill static dev_type_poll(midipoll); 113 1.73 jmcneill static dev_type_kqfilter(midikqfilter); 114 1.25 gehenna 115 1.25 gehenna const struct cdevsw midi_cdevsw = { 116 1.80 dholland .d_open = midiopen, 117 1.80 dholland .d_close = midiclose, 118 1.80 dholland .d_read = midiread, 119 1.80 dholland .d_write = midiwrite, 120 1.80 dholland .d_ioctl = midiioctl, 121 1.80 dholland .d_stop = nostop, 122 1.80 dholland .d_tty = notty, 123 1.80 dholland .d_poll = midipoll, 124 1.80 dholland .d_mmap = nommap, 125 1.80 dholland .d_kqfilter = midikqfilter, 126 1.81 dholland .d_discard = nodiscard, 127 1.80 dholland .d_flag = D_OTHER | D_MPSAFE 128 1.25 gehenna }; 129 1.25 gehenna 130 1.61 cube CFATTACH_DECL_NEW(midi, sizeof(struct midi_softc), 131 1.29 thorpej midiprobe, midiattach, mididetach, midiactivate); 132 1.1 augustss 133 1.44 chap #define MIDI_XMT_ASENSE_PERIOD mstohz(275) 134 1.44 chap #define MIDI_RCV_ASENSE_PERIOD mstohz(300) 135 1.4 augustss 136 1.73 jmcneill static int 137 1.61 cube midiprobe(device_t parent, cfdata_t match, void *aux) 138 1.1 augustss { 139 1.73 jmcneill struct audio_attach_args *sa; 140 1.73 jmcneill 141 1.73 jmcneill sa = aux; 142 1.73 jmcneill 143 1.73 jmcneill DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n", sa->type, sa, 144 1.73 jmcneill sa->hwif)); 145 1.1 augustss 146 1.73 jmcneill return sa->type == AUDIODEV_TYPE_MIDI; 147 1.1 augustss } 148 1.1 augustss 149 1.73 jmcneill static void 150 1.61 cube midiattach(device_t parent, device_t self, void *aux) 151 1.1 augustss { 152 1.78 plunky struct midi_softc *sc = device_private(self); 153 1.78 plunky struct audio_attach_args *sa = aux; 154 1.73 jmcneill const struct midi_hw_if *hwp; 155 1.73 jmcneill void *hdlp; 156 1.73 jmcneill 157 1.73 jmcneill hwp = sa->hwif; 158 1.73 jmcneill hdlp = sa->hdl; 159 1.1 augustss 160 1.57 jmcneill aprint_naive("\n"); 161 1.57 jmcneill 162 1.44 chap DPRINTFN(2, ("MIDI attach\n")); 163 1.1 augustss 164 1.1 augustss #ifdef DIAGNOSTIC 165 1.1 augustss if (hwp == 0 || 166 1.1 augustss hwp->open == 0 || 167 1.1 augustss hwp->close == 0 || 168 1.1 augustss hwp->output == 0 || 169 1.1 augustss hwp->getinfo == 0) { 170 1.85 msaitoh aprint_error_dev(self, "missing method\n"); 171 1.1 augustss return; 172 1.1 augustss } 173 1.1 augustss #endif 174 1.15 thorpej 175 1.63 cube sc->dev = self; 176 1.1 augustss sc->hw_if = hwp; 177 1.1 augustss sc->hw_hdl = hdlp; 178 1.78 plunky midi_attach(sc); 179 1.2 augustss } 180 1.2 augustss 181 1.73 jmcneill static int 182 1.61 cube midiactivate(device_t self, enum devact act) 183 1.18 tshiozak { 184 1.61 cube struct midi_softc *sc = device_private(self); 185 1.18 tshiozak 186 1.18 tshiozak switch (act) { 187 1.18 tshiozak case DVACT_DEACTIVATE: 188 1.73 jmcneill mutex_enter(sc->lock); 189 1.18 tshiozak sc->dying = 1; 190 1.73 jmcneill mutex_exit(sc->lock); 191 1.71 dyoung return 0; 192 1.71 dyoung default: 193 1.71 dyoung return EOPNOTSUPP; 194 1.18 tshiozak } 195 1.18 tshiozak } 196 1.18 tshiozak 197 1.18 tshiozak int 198 1.61 cube mididetach(device_t self, int flags) 199 1.18 tshiozak { 200 1.61 cube struct midi_softc *sc = device_private(self); 201 1.18 tshiozak int maj, mn; 202 1.18 tshiozak 203 1.69 dyoung DPRINTFN(2,("%s: sc=%p flags=%d\n", __func__, sc, flags)); 204 1.18 tshiozak 205 1.59 christos pmf_device_deregister(self); 206 1.59 christos 207 1.73 jmcneill mutex_enter(sc->lock); 208 1.18 tshiozak sc->dying = 1; 209 1.99 riastrad cv_broadcast(&sc->wchan); 210 1.99 riastrad cv_broadcast(&sc->rchan); 211 1.82 mrg 212 1.82 mrg if (--sc->refcnt >= 0) { 213 1.82 mrg (void)cv_timedwait(&sc->detach_cv, sc->lock, hz * 60); 214 1.100 riastrad if (sc->refcnt >= 0) { 215 1.100 riastrad aprint_error_dev(self, "refcnt failed to drain," 216 1.100 riastrad " bashing my brains out anyway\n"); 217 1.100 riastrad } 218 1.82 mrg } 219 1.73 jmcneill mutex_exit(sc->lock); 220 1.18 tshiozak 221 1.18 tshiozak /* locate the major number */ 222 1.25 gehenna maj = cdevsw_lookup_major(&midi_cdevsw); 223 1.18 tshiozak 224 1.73 jmcneill /* 225 1.73 jmcneill * Nuke the vnodes for any open instances (calls close). 226 1.73 jmcneill * Will wait until any activity on the device nodes has ceased. 227 1.73 jmcneill * 228 1.73 jmcneill * XXXAD NOT YET. 229 1.73 jmcneill * 230 1.73 jmcneill * XXXAD NEED TO PREVENT NEW REFERENCES THROUGH AUDIO_ENTER(). 231 1.73 jmcneill */ 232 1.43 thorpej mn = device_unit(self); 233 1.18 tshiozak vdevgone(maj, mn, mn, VCHR); 234 1.85 msaitoh 235 1.73 jmcneill if (!(sc->props & MIDI_PROP_NO_OUTPUT)) { 236 1.44 chap evcnt_detach(&sc->xmt.bytesDiscarded); 237 1.44 chap evcnt_detach(&sc->xmt.incompleteMessages); 238 1.44 chap } 239 1.73 jmcneill if (sc->props & MIDI_PROP_CAN_INPUT) { 240 1.44 chap evcnt_detach(&sc->rcv.bytesDiscarded); 241 1.44 chap evcnt_detach(&sc->rcv.incompleteMessages); 242 1.44 chap } 243 1.18 tshiozak 244 1.73 jmcneill if (sc->sih != NULL) { 245 1.73 jmcneill softint_disestablish(sc->sih); 246 1.73 jmcneill sc->sih = NULL; 247 1.51 ad } 248 1.51 ad 249 1.101 riastrad callout_halt(&sc->xmt_asense_co, NULL); 250 1.101 riastrad callout_halt(&sc->rcv_asense_co, NULL); 251 1.82 mrg 252 1.82 mrg callout_destroy(&sc->xmt_asense_co); 253 1.82 mrg callout_destroy(&sc->rcv_asense_co); 254 1.82 mrg 255 1.73 jmcneill cv_destroy(&sc->wchan); 256 1.73 jmcneill cv_destroy(&sc->rchan); 257 1.82 mrg cv_destroy(&sc->detach_cv); 258 1.73 jmcneill 259 1.18 tshiozak return (0); 260 1.18 tshiozak } 261 1.18 tshiozak 262 1.2 augustss void 263 1.78 plunky midi_attach(struct midi_softc *sc) 264 1.2 augustss { 265 1.2 augustss struct midi_info mi; 266 1.73 jmcneill kmutex_t *dummy; 267 1.74 mrg static int first = 1; 268 1.74 mrg 269 1.74 mrg if (first) { 270 1.74 mrg mutex_init(&hwif_softc_lock, MUTEX_DEFAULT, IPL_NONE); 271 1.74 mrg first = 0; 272 1.74 mrg } 273 1.2 augustss 274 1.73 jmcneill sc->hw_if->get_locks(sc->hw_hdl, &sc->lock, &dummy); 275 1.73 jmcneill 276 1.73 jmcneill callout_init(&sc->xmt_asense_co, CALLOUT_MPSAFE); 277 1.73 jmcneill callout_init(&sc->rcv_asense_co, CALLOUT_MPSAFE); 278 1.44 chap callout_setfunc(&sc->xmt_asense_co, midi_xmt_asense, sc); 279 1.44 chap callout_setfunc(&sc->rcv_asense_co, midi_rcv_asense, sc); 280 1.73 jmcneill 281 1.73 jmcneill sc->sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, 282 1.73 jmcneill midi_softint, sc); 283 1.73 jmcneill 284 1.73 jmcneill cv_init(&sc->rchan, "midird"); 285 1.73 jmcneill cv_init(&sc->wchan, "midiwr"); 286 1.82 mrg cv_init(&sc->detach_cv, "mididet"); 287 1.73 jmcneill 288 1.44 chap sc->dying = 0; 289 1.1 augustss sc->isopen = 0; 290 1.82 mrg sc->refcnt = 0; 291 1.51 ad 292 1.74 mrg mutex_enter(&hwif_softc_lock); 293 1.73 jmcneill mutex_enter(sc->lock); 294 1.74 mrg hwif_softc = sc; 295 1.73 jmcneill sc->hw_if->getinfo(sc->hw_hdl, &mi); 296 1.74 mrg hwif_softc = NULL; 297 1.73 jmcneill mutex_exit(sc->lock); 298 1.74 mrg mutex_exit(&hwif_softc_lock); 299 1.51 ad 300 1.1 augustss sc->props = mi.props; 301 1.73 jmcneill 302 1.73 jmcneill if (!(sc->props & MIDI_PROP_NO_OUTPUT)) { 303 1.44 chap evcnt_attach_dynamic(&sc->xmt.bytesDiscarded, 304 1.44 chap EVCNT_TYPE_MISC, NULL, 305 1.61 cube device_xname(sc->dev), "xmt bytes discarded"); 306 1.44 chap evcnt_attach_dynamic(&sc->xmt.incompleteMessages, 307 1.44 chap EVCNT_TYPE_MISC, NULL, 308 1.61 cube device_xname(sc->dev), "xmt incomplete msgs"); 309 1.44 chap } 310 1.73 jmcneill if (sc->props & MIDI_PROP_CAN_INPUT) { 311 1.44 chap evcnt_attach_dynamic(&sc->rcv.bytesDiscarded, 312 1.44 chap EVCNT_TYPE_MISC, NULL, 313 1.61 cube device_xname(sc->dev), "rcv bytes discarded"); 314 1.44 chap evcnt_attach_dynamic(&sc->rcv.incompleteMessages, 315 1.44 chap EVCNT_TYPE_MISC, NULL, 316 1.61 cube device_xname(sc->dev), "rcv incomplete msgs"); 317 1.44 chap } 318 1.85 msaitoh 319 1.75 njoly aprint_naive("\n"); 320 1.70 jmcneill aprint_normal(": %s\n", mi.name); 321 1.76 plunky 322 1.76 plunky if (!pmf_device_register(sc->dev, NULL, NULL)) 323 1.84 msaitoh aprint_error_dev(sc->dev, "couldn't establish power handler\n"); 324 1.44 chap } 325 1.44 chap 326 1.73 jmcneill void 327 1.73 jmcneill midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) 328 1.73 jmcneill { 329 1.73 jmcneill if (hwif_softc != NULL) /* ignore calls resulting from non-init */ 330 1.44 chap hwif_softc->hw_if_ext = exthw; /* uses of getinfo */ 331 1.1 augustss } 332 1.1 augustss 333 1.1 augustss int 334 1.22 augustss midi_unit_count(void) 335 1.1 augustss { 336 1.44 chap int i; 337 1.73 jmcneill for ( i = 0; i < midi_cd.cd_ndevs; ++i) 338 1.73 jmcneill if (NULL == device_lookup(&midi_cd, i)) 339 1.44 chap break; 340 1.44 chap return i; 341 1.1 augustss } 342 1.1 augustss 343 1.73 jmcneill static void 344 1.22 augustss midi_initbuf(struct midi_buffer *mb) 345 1.1 augustss { 346 1.44 chap mb->idx_producerp = mb->idx_consumerp = mb->idx; 347 1.44 chap mb->buf_producerp = mb->buf_consumerp = mb->buf; 348 1.1 augustss } 349 1.73 jmcneill 350 1.44 chap #define PACK_MB_IDX(cat,len) (((cat)<<4)|(len)) 351 1.44 chap #define MB_IDX_CAT(idx) ((idx)>>4) 352 1.44 chap #define MB_IDX_LEN(idx) ((idx)&0xf) 353 1.1 augustss 354 1.44 chap static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3"; 355 1.44 chap #define MIDI_CAT(d) (midi_cats[((d)>>4)&15]) 356 1.44 chap #define FST_RETURN(offp,endp,ret) \ 357 1.44 chap return (s->pos=s->msg+(offp)), (s->end=s->msg+(endp)), (ret) 358 1.44 chap 359 1.44 chap enum fst_ret { FST_CHN, FST_CHV, FST_COM, FST_SYX, FST_RT, FST_MORE, FST_ERR, 360 1.44 chap FST_HUH, FST_SXP }; 361 1.44 chap enum fst_form { FST_CANON, FST_COMPR, FST_VCOMP }; 362 1.44 chap static struct { 363 1.44 chap int off; 364 1.44 chap enum fst_ret tag; 365 1.44 chap } const midi_forms[] = { 366 1.44 chap [FST_CANON] = { .off=0, .tag=FST_CHN }, 367 1.44 chap [FST_COMPR] = { .off=1, .tag=FST_CHN }, 368 1.44 chap [FST_VCOMP] = { .off=0, .tag=FST_CHV } 369 1.44 chap }; 370 1.44 chap #define FST_CRETURN(endp) \ 371 1.44 chap FST_RETURN(midi_forms[form].off,endp,midi_forms[form].tag) 372 1.44 chap 373 1.44 chap /* 374 1.44 chap * A MIDI finite state transducer suitable for receiving or transmitting. It 375 1.44 chap * will accept correct MIDI input that uses, doesn't use, or sometimes uses the 376 1.44 chap * 'running status' compression technique, and transduce it to fully expanded 377 1.44 chap * (form=FST_CANON) or fully compressed (form=FST_COMPR or FST_VCOMP) form. 378 1.44 chap * 379 1.44 chap * Returns FST_MORE if a complete message has not been parsed yet (SysEx 380 1.44 chap * messages are the exception), FST_ERR or FST_HUH if the input does not 381 1.44 chap * conform to the protocol, or FST_CHN (channel messages), FST_COM (System 382 1.44 chap * Common messages), FST_RT (System Real-Time messages), or FST_SYX (System 383 1.44 chap * Exclusive) to broadly categorize the message parsed. s->pos and s->end 384 1.44 chap * locate the parsed message; while (s->pos<s->end) putchar(*(s->pos++)); 385 1.44 chap * would output it. 386 1.44 chap * 387 1.44 chap * FST_HUH means the character c wasn't valid in the original state, but the 388 1.44 chap * state has now been reset to START and the caller should try again passing 389 1.44 chap * the same c. FST_ERR means c isn't valid in the start state; the caller 390 1.44 chap * should kiss it goodbye and continue to try successive characters from the 391 1.44 chap * input until something other than FST_ERR or FST_HUH is returned, at which 392 1.44 chap * point things are resynchronized. 393 1.44 chap * 394 1.44 chap * A FST_SYX return means that between pos and end are from 1 to 3 395 1.44 chap * bytes of a system exclusive message. A SysEx message will be delivered in 396 1.44 chap * one or more chunks of that form, where the first begins with 0xf0 and the 397 1.44 chap * last (which is the only one that might have length < 3) ends with 0xf7. 398 1.44 chap * 399 1.44 chap * Messages corrupted by a protocol error are discarded and won't be seen at 400 1.44 chap * all; again SysEx is the exception, as one or more chunks of it may already 401 1.44 chap * have been parsed. 402 1.44 chap * 403 1.44 chap * For FST_CHN messages, s->msg[0] always contains the status byte even if 404 1.44 chap * FST_COMPR form was requested (pos then points to msg[1]). That way, the 405 1.44 chap * caller can always identify the exact message if there is a need to do so. 406 1.44 chap * For all other message types except FST_SYX, the status byte is at *pos 407 1.44 chap * (which may not necessarily be msg[0]!). There is only one SysEx status 408 1.44 chap * byte, so the return value FST_SYX is sufficient to identify it. 409 1.44 chap * 410 1.44 chap * To simplify some use cases, compression can also be requested with 411 1.44 chap * form=FST_VCOMP. In this form a compressible channel message is indicated 412 1.44 chap * by returning a classification of FST_CHV instead of FST_CHN, and pos points 413 1.44 chap * to the status byte rather than being advanced past it. If the caller in this 414 1.44 chap * case saves the bytes from pos to end, it will have saved the entire message, 415 1.44 chap * and can act on the FST_CHV tag to drop the first byte later. In this form, 416 1.44 chap * unlike FST_CANON, hidden note-off (i.e. note-on with velocity 0) may occur. 417 1.44 chap * 418 1.44 chap * Two obscure points in the MIDI protocol complicate things further, both to 419 1.44 chap * do with the EndSysEx code, 0xf7. First, this code is permitted (and 420 1.44 chap * meaningless) outside of a System Exclusive message, anywhere a status byte 421 1.44 chap * could appear. Second, it is allowed to be absent at the end of a System 422 1.44 chap * Exclusive message (!) - any status byte at all (non-realtime) is allowed to 423 1.97 andvar * terminate the message. Both require accommodation in the interface to 424 1.44 chap * midi_fst's caller. A stray 0xf7 should be ignored BUT should count as a 425 1.44 chap * message received for purposes of Active Sense timeout; the case is 426 1.44 chap * represented by a return of FST_COM with a length of zero (pos == end). A 427 1.44 chap * status byte other than 0xf7 during a system exclusive message will cause an 428 1.44 chap * FST_SXP (sysex plus) return; the bytes from pos to end are the end of the 429 1.44 chap * system exclusive message, and after handling those the caller should call 430 1.44 chap * midi_fst again with the same input byte. 431 1.44 chap * 432 1.44 chap * midi(4) will never produce either such form of rubbish. 433 1.44 chap */ 434 1.44 chap static enum fst_ret 435 1.44 chap midi_fst(struct midi_state *s, u_char c, enum fst_form form) 436 1.44 chap { 437 1.44 chap int syxpos = 0; 438 1.44 chap 439 1.73 jmcneill if (c >= 0xf8) { /* All realtime messages bypass state machine */ 440 1.73 jmcneill if (c == 0xf9 || c == 0xfd) { 441 1.85 msaitoh DPRINTF( ("midi_fst: s=%p c=0x%02x undefined\n", 442 1.73 jmcneill s, c)); 443 1.44 chap s->bytesDiscarded.ev_count++; 444 1.44 chap return FST_ERR; 445 1.44 chap } 446 1.85 msaitoh DPRINTFN(9, ("midi_fst: s=%p System Real-Time data=0x%02x\n", 447 1.73 jmcneill s, c)); 448 1.44 chap s->msg[2] = c; 449 1.44 chap FST_RETURN(2,3,FST_RT); 450 1.44 chap } 451 1.44 chap 452 1.85 msaitoh DPRINTFN(4, ("midi_fst: s=%p data=0x%02x state=%d\n", 453 1.73 jmcneill s, c, s->state)); 454 1.44 chap 455 1.73 jmcneill switch (s->state | MIDI_CAT(c)) { /* break ==> return FST_MORE */ 456 1.44 chap case MIDI_IN_START | MIDI_CAT_COMMON: 457 1.44 chap case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON: 458 1.44 chap case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON: 459 1.44 chap case MIDI_IN_RXX2_2 | MIDI_CAT_COMMON: 460 1.44 chap s->msg[0] = c; 461 1.73 jmcneill switch ( c) { 462 1.44 chap case 0xf0: s->state = MIDI_IN_SYX1_3; break; 463 1.44 chap case 0xf1: s->state = MIDI_IN_COM0_1; break; 464 1.44 chap case 0xf2: s->state = MIDI_IN_COM0_2; break; 465 1.44 chap case 0xf3: s->state = MIDI_IN_COM0_1; break; 466 1.44 chap case 0xf6: s->state = MIDI_IN_START; FST_RETURN(0,1,FST_COM); 467 1.44 chap case 0xf7: s->state = MIDI_IN_START; FST_RETURN(0,0,FST_COM); 468 1.44 chap default: goto protocol_violation; 469 1.44 chap } 470 1.44 chap break; 471 1.85 msaitoh 472 1.44 chap case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1: 473 1.73 jmcneill if (c == s->msg[0]) { 474 1.44 chap s->state = MIDI_IN_RNX0_1; 475 1.44 chap break; 476 1.44 chap } 477 1.44 chap /* FALLTHROUGH */ 478 1.44 chap case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1: 479 1.44 chap case MIDI_IN_RXX2_2 | MIDI_CAT_STATUS1: 480 1.44 chap case MIDI_IN_START | MIDI_CAT_STATUS1: 481 1.44 chap s->state = MIDI_IN_RUN0_1; 482 1.44 chap s->msg[0] = c; 483 1.44 chap break; 484 1.85 msaitoh 485 1.44 chap case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2: 486 1.44 chap case MIDI_IN_RXX2_2 | MIDI_CAT_STATUS2: 487 1.73 jmcneill if (c == s->msg[0]) { 488 1.44 chap s->state = MIDI_IN_RNX0_2; 489 1.44 chap break; 490 1.44 chap } 491 1.73 jmcneill if ((c ^ s->msg[0]) == 0x10 && (c & 0xe0) == 0x80) { 492 1.44 chap s->state = MIDI_IN_RXX0_2; 493 1.44 chap s->msg[0] = c; 494 1.44 chap break; 495 1.44 chap } 496 1.44 chap /* FALLTHROUGH */ 497 1.44 chap case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2: 498 1.44 chap case MIDI_IN_START | MIDI_CAT_STATUS2: 499 1.44 chap s->state = MIDI_IN_RUN0_2; 500 1.44 chap s->msg[0] = c; 501 1.44 chap break; 502 1.44 chap 503 1.44 chap case MIDI_IN_COM0_1 | MIDI_CAT_DATA: 504 1.44 chap s->state = MIDI_IN_START; 505 1.44 chap s->msg[1] = c; 506 1.44 chap FST_RETURN(0,2,FST_COM); 507 1.44 chap 508 1.44 chap case MIDI_IN_COM0_2 | MIDI_CAT_DATA: 509 1.44 chap s->state = MIDI_IN_COM1_2; 510 1.44 chap s->msg[1] = c; 511 1.44 chap break; 512 1.44 chap 513 1.44 chap case MIDI_IN_COM1_2 | MIDI_CAT_DATA: 514 1.44 chap s->state = MIDI_IN_START; 515 1.44 chap s->msg[2] = c; 516 1.44 chap FST_RETURN(0,3,FST_COM); 517 1.44 chap 518 1.44 chap case MIDI_IN_RUN0_1 | MIDI_CAT_DATA: 519 1.44 chap s->state = MIDI_IN_RUN1_1; 520 1.44 chap s->msg[1] = c; 521 1.44 chap FST_RETURN(0,2,FST_CHN); 522 1.44 chap 523 1.44 chap case MIDI_IN_RUN1_1 | MIDI_CAT_DATA: 524 1.44 chap case MIDI_IN_RNX0_1 | MIDI_CAT_DATA: 525 1.44 chap s->state = MIDI_IN_RUN1_1; 526 1.44 chap s->msg[1] = c; 527 1.44 chap FST_CRETURN(2); 528 1.44 chap 529 1.44 chap case MIDI_IN_RUN0_2 | MIDI_CAT_DATA: 530 1.44 chap s->state = MIDI_IN_RUN1_2; 531 1.44 chap s->msg[1] = c; 532 1.44 chap break; 533 1.44 chap 534 1.44 chap case MIDI_IN_RUN1_2 | MIDI_CAT_DATA: 535 1.73 jmcneill if (FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90) { 536 1.44 chap s->state = MIDI_IN_RXX2_2; 537 1.44 chap s->msg[0] ^= 0x10; 538 1.44 chap s->msg[2] = 64; 539 1.44 chap } else { 540 1.44 chap s->state = MIDI_IN_RUN2_2; 541 1.44 chap s->msg[2] = c; 542 1.44 chap } 543 1.44 chap FST_RETURN(0,3,FST_CHN); 544 1.44 chap 545 1.44 chap case MIDI_IN_RUN2_2 | MIDI_CAT_DATA: 546 1.44 chap s->state = MIDI_IN_RNX1_2; 547 1.44 chap s->msg[1] = c; 548 1.44 chap break; 549 1.44 chap 550 1.44 chap case MIDI_IN_RXX2_2 | MIDI_CAT_DATA: 551 1.44 chap s->state = MIDI_IN_RXX1_2; 552 1.44 chap s->msg[0] ^= 0x10; 553 1.44 chap s->msg[1] = c; 554 1.44 chap break; 555 1.44 chap 556 1.44 chap case MIDI_IN_RNX0_2 | MIDI_CAT_DATA: 557 1.44 chap s->state = MIDI_IN_RNY1_2; 558 1.44 chap s->msg[1] = c; 559 1.44 chap break; 560 1.44 chap 561 1.44 chap case MIDI_IN_RXX0_2 | MIDI_CAT_DATA: 562 1.44 chap s->state = MIDI_IN_RXY1_2; 563 1.44 chap s->msg[1] = c; 564 1.44 chap break; 565 1.44 chap 566 1.44 chap case MIDI_IN_RNX1_2 | MIDI_CAT_DATA: 567 1.44 chap case MIDI_IN_RNY1_2 | MIDI_CAT_DATA: 568 1.73 jmcneill if (FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90) { 569 1.44 chap s->state = MIDI_IN_RXX2_2; 570 1.44 chap s->msg[0] ^= 0x10; 571 1.44 chap s->msg[2] = 64; 572 1.44 chap FST_RETURN(0,3,FST_CHN); 573 1.44 chap } 574 1.44 chap s->state = MIDI_IN_RUN2_2; 575 1.44 chap s->msg[2] = c; 576 1.44 chap FST_CRETURN(3); 577 1.44 chap 578 1.44 chap case MIDI_IN_RXX1_2 | MIDI_CAT_DATA: 579 1.44 chap case MIDI_IN_RXY1_2 | MIDI_CAT_DATA: 580 1.73 jmcneill if (( 0 == c && (s->msg[0]&0xf0) == 0x90) 581 1.44 chap || (64 == c && (s->msg[0]&0xf0) == 0x80 582 1.73 jmcneill && FST_CANON != form)) { 583 1.44 chap s->state = MIDI_IN_RXX2_2; 584 1.44 chap s->msg[0] ^= 0x10; 585 1.44 chap s->msg[2] = 64 - c; 586 1.44 chap FST_CRETURN(3); 587 1.44 chap } 588 1.44 chap s->state = MIDI_IN_RUN2_2; 589 1.44 chap s->msg[2] = c; 590 1.44 chap FST_RETURN(0,3,FST_CHN); 591 1.44 chap 592 1.44 chap case MIDI_IN_SYX1_3 | MIDI_CAT_DATA: 593 1.44 chap s->state = MIDI_IN_SYX2_3; 594 1.44 chap s->msg[1] = c; 595 1.44 chap break; 596 1.44 chap 597 1.44 chap case MIDI_IN_SYX2_3 | MIDI_CAT_DATA: 598 1.44 chap s->state = MIDI_IN_SYX0_3; 599 1.44 chap s->msg[2] = c; 600 1.44 chap FST_RETURN(0,3,FST_SYX); 601 1.44 chap 602 1.44 chap case MIDI_IN_SYX0_3 | MIDI_CAT_DATA: 603 1.44 chap s->state = MIDI_IN_SYX1_3; 604 1.44 chap s->msg[0] = c; 605 1.44 chap break; 606 1.44 chap 607 1.44 chap case MIDI_IN_SYX2_3 | MIDI_CAT_COMMON: 608 1.44 chap case MIDI_IN_SYX2_3 | MIDI_CAT_STATUS1: 609 1.44 chap case MIDI_IN_SYX2_3 | MIDI_CAT_STATUS2: 610 1.44 chap ++ syxpos; 611 1.44 chap /* FALLTHROUGH */ 612 1.44 chap case MIDI_IN_SYX1_3 | MIDI_CAT_COMMON: 613 1.44 chap case MIDI_IN_SYX1_3 | MIDI_CAT_STATUS1: 614 1.44 chap case MIDI_IN_SYX1_3 | MIDI_CAT_STATUS2: 615 1.44 chap ++ syxpos; 616 1.44 chap /* FALLTHROUGH */ 617 1.44 chap case MIDI_IN_SYX0_3 | MIDI_CAT_COMMON: 618 1.44 chap case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS1: 619 1.44 chap case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS2: 620 1.44 chap s->state = MIDI_IN_START; 621 1.73 jmcneill if (c == 0xf7) { 622 1.44 chap s->msg[syxpos] = c; 623 1.44 chap FST_RETURN(0,1+syxpos,FST_SYX); 624 1.44 chap } 625 1.44 chap s->msg[syxpos] = 0xf7; 626 1.44 chap FST_RETURN(0,1+syxpos,FST_SXP); 627 1.44 chap 628 1.44 chap default: 629 1.44 chap protocol_violation: 630 1.44 chap DPRINTF(("midi_fst: unexpected %#02x in state %u\n", 631 1.73 jmcneill c, s->state)); 632 1.73 jmcneill switch ( s->state) { 633 1.44 chap case MIDI_IN_RUN1_1: /* can only get here by seeing an */ 634 1.44 chap case MIDI_IN_RUN2_2: /* INVALID System Common message */ 635 1.44 chap case MIDI_IN_RXX2_2: 636 1.44 chap s->state = MIDI_IN_START; 637 1.44 chap /* FALLTHROUGH */ 638 1.44 chap case MIDI_IN_START: 639 1.44 chap s->bytesDiscarded.ev_count++; 640 1.44 chap return FST_ERR; 641 1.44 chap case MIDI_IN_COM1_2: 642 1.44 chap case MIDI_IN_RUN1_2: 643 1.44 chap case MIDI_IN_RNY1_2: 644 1.44 chap case MIDI_IN_RXY1_2: 645 1.44 chap s->bytesDiscarded.ev_count++; 646 1.44 chap /* FALLTHROUGH */ 647 1.44 chap case MIDI_IN_COM0_1: 648 1.44 chap case MIDI_IN_RUN0_1: 649 1.44 chap case MIDI_IN_RNX0_1: 650 1.44 chap case MIDI_IN_COM0_2: 651 1.44 chap case MIDI_IN_RUN0_2: 652 1.44 chap case MIDI_IN_RNX0_2: 653 1.44 chap case MIDI_IN_RXX0_2: 654 1.44 chap case MIDI_IN_RNX1_2: 655 1.44 chap case MIDI_IN_RXX1_2: 656 1.44 chap s->bytesDiscarded.ev_count++; 657 1.44 chap s->incompleteMessages.ev_count++; 658 1.44 chap break; 659 1.44 chap default: 660 1.73 jmcneill DPRINTF(("midi_fst: mishandled %#02x(%u) in state %u?!\n", 661 1.73 jmcneill c, MIDI_CAT(c), s->state)); 662 1.73 jmcneill break; 663 1.44 chap } 664 1.44 chap s->state = MIDI_IN_START; 665 1.44 chap return FST_HUH; 666 1.44 chap } 667 1.44 chap return FST_MORE; 668 1.44 chap } 669 1.1 augustss 670 1.73 jmcneill static void 671 1.73 jmcneill midi_softint(void *cookie) 672 1.51 ad { 673 1.73 jmcneill struct midi_softc *sc; 674 1.73 jmcneill proc_t *p; 675 1.73 jmcneill pid_t pid; 676 1.51 ad 677 1.73 jmcneill sc = cookie; 678 1.51 ad 679 1.90 ad mutex_enter(&proc_lock); 680 1.73 jmcneill pid = sc->async; 681 1.73 jmcneill if (pid != 0 && (p = proc_find(pid)) != NULL) 682 1.73 jmcneill psignal(p, SIGIO); 683 1.90 ad mutex_exit(&proc_lock); 684 1.51 ad } 685 1.51 ad 686 1.73 jmcneill static void 687 1.22 augustss midi_in(void *addr, int data) 688 1.1 augustss { 689 1.73 jmcneill struct midi_softc *sc; 690 1.73 jmcneill struct midi_buffer *mb; 691 1.73 jmcneill int i, count; 692 1.44 chap enum fst_ret got; 693 1.44 chap MIDI_BUF_DECLARE(idx); 694 1.44 chap MIDI_BUF_DECLARE(buf); 695 1.1 augustss 696 1.73 jmcneill sc = addr; 697 1.73 jmcneill mb = &sc->inbuf; 698 1.73 jmcneill 699 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 700 1.73 jmcneill 701 1.3 augustss if (!sc->isopen) 702 1.3 augustss return; 703 1.14 augustss 704 1.73 jmcneill if ((sc->flags & FREAD) == 0) 705 1.1 augustss return; /* discard data if not reading */ 706 1.85 msaitoh 707 1.44 chap sxp_again: 708 1.73 jmcneill do { 709 1.44 chap got = midi_fst(&sc->rcv, data, FST_CANON); 710 1.73 jmcneill } while (got == FST_HUH); 711 1.85 msaitoh 712 1.73 jmcneill switch (got) { 713 1.44 chap case FST_MORE: 714 1.44 chap case FST_ERR: 715 1.1 augustss return; 716 1.44 chap case FST_CHN: 717 1.44 chap case FST_COM: 718 1.44 chap case FST_RT: 719 1.1 augustss #if NSEQUENCER > 0 720 1.44 chap if (sc->seqopen) { 721 1.44 chap extern void midiseq_in(struct midi_dev *,u_char *,int); 722 1.44 chap count = sc->rcv.end - sc->rcv.pos; 723 1.44 chap midiseq_in(sc->seq_md, sc->rcv.pos, count); 724 1.44 chap return; 725 1.44 chap } 726 1.1 augustss #endif 727 1.44 chap /* 728 1.44 chap * Pass Active Sense to the sequencer if it's open, but not to 729 1.44 chap * a raw reader. (Really should do something intelligent with 730 1.44 chap * it then, though....) 731 1.44 chap */ 732 1.73 jmcneill if (got == FST_RT && MIDI_ACK == sc->rcv.pos[0]) { 733 1.73 jmcneill if (!sc->rcv_expect_asense) { 734 1.44 chap sc->rcv_expect_asense = 1; 735 1.44 chap callout_schedule(&sc->rcv_asense_co, 736 1.73 jmcneill MIDI_RCV_ASENSE_PERIOD); 737 1.44 chap } 738 1.44 chap sc->rcv_quiescent = 0; 739 1.44 chap sc->rcv_eof = 0; 740 1.44 chap return; 741 1.44 chap } 742 1.44 chap /* FALLTHROUGH */ 743 1.44 chap /* 744 1.44 chap * Ultimately SysEx msgs should be offered to the sequencer also; the 745 1.44 chap * sequencer API addresses them - but maybe our sequencer can't handle 746 1.44 chap * them yet, so offer only to raw reader. (Which means, ultimately, 747 1.44 chap * discard them if the sequencer's open, as it's not doing reads!) 748 1.44 chap * -> When SysEx support is added to the sequencer, be sure to handle 749 1.44 chap * FST_SXP there too. 750 1.44 chap */ 751 1.44 chap case FST_SYX: 752 1.44 chap case FST_SXP: 753 1.44 chap count = sc->rcv.end - sc->rcv.pos; 754 1.44 chap sc->rcv_quiescent = 0; 755 1.44 chap sc->rcv_eof = 0; 756 1.73 jmcneill if (0 == count) 757 1.44 chap break; 758 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,idx); 759 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,buf); 760 1.44 chap if (count > buf_lim - buf_cur 761 1.44 chap || 1 > idx_lim - idx_cur) { 762 1.44 chap sc->rcv.bytesDiscarded.ev_count += count; 763 1.85 msaitoh DPRINTF(("midi_in: buffer full, discard data=0x%02x\n", 764 1.44 chap sc->rcv.pos[0])); 765 1.44 chap return; 766 1.44 chap } 767 1.44 chap for (i = 0; i < count; i++) { 768 1.44 chap *buf_cur++ = sc->rcv.pos[i]; 769 1.44 chap MIDI_BUF_WRAP(buf); 770 1.44 chap } 771 1.44 chap *idx_cur++ = PACK_MB_IDX(got,count); 772 1.44 chap MIDI_BUF_WRAP(idx); 773 1.44 chap MIDI_BUF_PRODUCER_WBACK(mb,buf); 774 1.44 chap MIDI_BUF_PRODUCER_WBACK(mb,idx); 775 1.73 jmcneill cv_broadcast(&sc->rchan); 776 1.73 jmcneill selnotify(&sc->rsel, 0, NOTE_SUBMIT); 777 1.73 jmcneill if (sc->async != 0) 778 1.73 jmcneill softint_schedule(sc->sih); 779 1.44 chap break; 780 1.44 chap default: /* don't #ifdef this away, gcc will say FST_HUH not handled */ 781 1.44 chap printf("midi_in: midi_fst returned %d?!\n", got); 782 1.1 augustss } 783 1.73 jmcneill if (FST_SXP == got) 784 1.44 chap goto sxp_again; 785 1.1 augustss } 786 1.1 augustss 787 1.73 jmcneill static void 788 1.22 augustss midi_out(void *addr) 789 1.1 augustss { 790 1.1 augustss struct midi_softc *sc = addr; 791 1.3 augustss 792 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 793 1.73 jmcneill 794 1.3 augustss if (!sc->isopen) 795 1.3 augustss return; 796 1.44 chap DPRINTFN(8, ("midi_out: %p\n", sc)); 797 1.44 chap midi_intr_out(sc); 798 1.1 augustss } 799 1.1 augustss 800 1.73 jmcneill static int 801 1.50 christos midiopen(dev_t dev, int flags, int ifmt, struct lwp *l) 802 1.1 augustss { 803 1.1 augustss struct midi_softc *sc; 804 1.38 yamt const struct midi_hw_if *hw; 805 1.1 augustss int error; 806 1.1 augustss 807 1.67 cegger sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 808 1.17 thorpej if (sc == NULL) 809 1.17 thorpej return (ENXIO); 810 1.44 chap DPRINTFN(3,("midiopen %p\n", sc)); 811 1.1 augustss 812 1.73 jmcneill mutex_enter(sc->lock); 813 1.73 jmcneill if (sc->dying) { 814 1.73 jmcneill mutex_exit(sc->lock); 815 1.73 jmcneill return (EIO); 816 1.73 jmcneill } 817 1.1 augustss hw = sc->hw_if; 818 1.73 jmcneill if (hw == NULL) { 819 1.73 jmcneill mutex_exit(sc->lock); 820 1.1 augustss return ENXIO; 821 1.73 jmcneill } 822 1.73 jmcneill if (sc->isopen) { 823 1.73 jmcneill mutex_exit(sc->lock); 824 1.1 augustss return EBUSY; 825 1.73 jmcneill } 826 1.44 chap 827 1.44 chap /* put both state machines into known states */ 828 1.44 chap sc->rcv.state = MIDI_IN_START; 829 1.44 chap sc->rcv.pos = sc->rcv.msg; 830 1.44 chap sc->rcv.end = sc->rcv.msg; 831 1.44 chap sc->xmt.state = MIDI_IN_START; 832 1.44 chap sc->xmt.pos = sc->xmt.msg; 833 1.44 chap sc->xmt.end = sc->xmt.msg; 834 1.85 msaitoh 835 1.44 chap /* copy error counters so an ioctl (TBA) can give since-open stats */ 836 1.44 chap sc->rcv.atOpen.bytesDiscarded = sc->rcv.bytesDiscarded.ev_count; 837 1.44 chap sc->rcv.atQuery.bytesDiscarded = sc->rcv.bytesDiscarded.ev_count; 838 1.85 msaitoh 839 1.44 chap sc->xmt.atOpen.bytesDiscarded = sc->xmt.bytesDiscarded.ev_count; 840 1.44 chap sc->xmt.atQuery.bytesDiscarded = sc->xmt.bytesDiscarded.ev_count; 841 1.85 msaitoh 842 1.44 chap /* and the buffers */ 843 1.44 chap midi_initbuf(&sc->outbuf); 844 1.44 chap midi_initbuf(&sc->inbuf); 845 1.85 msaitoh 846 1.44 chap /* and the receive flags */ 847 1.44 chap sc->rcv_expect_asense = 0; 848 1.44 chap sc->rcv_quiescent = 0; 849 1.44 chap sc->rcv_eof = 0; 850 1.1 augustss sc->isopen++; 851 1.1 augustss sc->flags = flags; 852 1.1 augustss sc->pbus = 0; 853 1.1 augustss sc->async = 0; 854 1.1 augustss 855 1.4 augustss #ifdef MIDI_SAVE 856 1.4 augustss if (midicnt != 0) { 857 1.4 augustss midisave.cnt = midicnt; 858 1.4 augustss midicnt = 0; 859 1.4 augustss } 860 1.4 augustss #endif 861 1.4 augustss 862 1.73 jmcneill error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc); 863 1.73 jmcneill if (error) { 864 1.73 jmcneill mutex_exit(sc->lock); 865 1.73 jmcneill return error; 866 1.73 jmcneill } 867 1.73 jmcneill 868 1.73 jmcneill mutex_exit(sc->lock); 869 1.1 augustss return 0; 870 1.1 augustss } 871 1.1 augustss 872 1.73 jmcneill static int 873 1.73 jmcneill midiclose(dev_t dev, int flags, int ifmt, struct lwp *l) 874 1.1 augustss { 875 1.73 jmcneill struct midi_softc *sc; 876 1.73 jmcneill const struct midi_hw_if *hw; 877 1.73 jmcneill 878 1.73 jmcneill sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 879 1.73 jmcneill hw = sc->hw_if; 880 1.1 augustss 881 1.44 chap DPRINTFN(3,("midiclose %p\n", sc)); 882 1.1 augustss 883 1.73 jmcneill mutex_enter(sc->lock); 884 1.44 chap /* midi_start_output(sc); anything buffered => pbus already set! */ 885 1.44 chap while (sc->pbus) { 886 1.83 mrg if (sc->dying) 887 1.83 mrg break; 888 1.44 chap DPRINTFN(8,("midiclose sleep ...\n")); 889 1.73 jmcneill cv_wait(&sc->wchan, sc->lock); 890 1.1 augustss } 891 1.3 augustss sc->isopen = 0; 892 1.73 jmcneill callout_halt(&sc->xmt_asense_co, sc->lock); 893 1.73 jmcneill callout_halt(&sc->rcv_asense_co, sc->lock); 894 1.1 augustss hw->close(sc->hw_hdl); 895 1.1 augustss sc->seqopen = 0; 896 1.7 augustss sc->seq_md = 0; 897 1.73 jmcneill mutex_exit(sc->lock); 898 1.73 jmcneill 899 1.1 augustss return 0; 900 1.1 augustss } 901 1.1 augustss 902 1.73 jmcneill static int 903 1.22 augustss midiread(dev_t dev, struct uio *uio, int ioflag) 904 1.1 augustss { 905 1.73 jmcneill struct midi_softc *sc; 906 1.73 jmcneill struct midi_buffer *mb; 907 1.73 jmcneill int appetite, error, first; 908 1.44 chap MIDI_BUF_DECLARE(idx); 909 1.44 chap MIDI_BUF_DECLARE(buf); 910 1.73 jmcneill 911 1.73 jmcneill sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 912 1.73 jmcneill mb = &sc->inbuf; 913 1.73 jmcneill first = 1; 914 1.1 augustss 915 1.44 chap DPRINTFN(6,("midiread: %p, count=%lu\n", sc, 916 1.73 jmcneill (unsigned long)uio->uio_resid)); 917 1.1 augustss 918 1.73 jmcneill mutex_enter(sc->lock); 919 1.73 jmcneill if (sc->dying) { 920 1.73 jmcneill mutex_exit(sc->lock); 921 1.18 tshiozak return EIO; 922 1.73 jmcneill } 923 1.73 jmcneill if ((sc->props & MIDI_PROP_CAN_INPUT) == 0) { 924 1.73 jmcneill mutex_exit(sc->lock); 925 1.73 jmcneill return ENXIO; 926 1.73 jmcneill } 927 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,idx); 928 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,buf); 929 1.1 augustss error = 0; 930 1.73 jmcneill for (;;) { 931 1.44 chap /* 932 1.44 chap * If the used portion of idx wraps around the end, just take 933 1.44 chap * the first part on this iteration, and we'll get the rest on 934 1.44 chap * the next. 935 1.44 chap */ 936 1.73 jmcneill if (idx_lim > idx_end) 937 1.44 chap idx_lim = idx_end; 938 1.44 chap /* 939 1.44 chap * Count bytes through the last complete message that will 940 1.44 chap * fit in the requested read. 941 1.44 chap */ 942 1.44 chap for (appetite = uio->uio_resid; idx_cur < idx_lim; ++idx_cur) { 943 1.73 jmcneill if (appetite < MB_IDX_LEN(*idx_cur)) 944 1.44 chap break; 945 1.44 chap appetite -= MB_IDX_LEN(*idx_cur); 946 1.44 chap } 947 1.44 chap appetite = uio->uio_resid - appetite; 948 1.73 jmcneill 949 1.44 chap /* 950 1.44 chap * Only if the read is too small to hold even the first 951 1.44 chap * complete message will we return a partial one (updating idx 952 1.44 chap * to reflect the remaining length of the message). 953 1.44 chap */ 954 1.73 jmcneill if (appetite == 0 && idx_cur < idx_lim) { 955 1.73 jmcneill if (!first) 956 1.73 jmcneill break; 957 1.44 chap appetite = uio->uio_resid; 958 1.44 chap *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur), 959 1.73 jmcneill MB_IDX_LEN(*idx_cur) - appetite); 960 1.44 chap } 961 1.44 chap KASSERT(buf_cur + appetite <= buf_lim); 962 1.85 msaitoh 963 1.44 chap /* move the bytes */ 964 1.85 msaitoh if (appetite > 0) { 965 1.44 chap first = 0; /* we know we won't return empty-handed */ 966 1.44 chap /* do two uiomoves if data wrap around end of buf */ 967 1.73 jmcneill if (buf_cur + appetite > buf_end) { 968 1.44 chap DPRINTFN(8, 969 1.54 pavel ("midiread: uiomove cc=%td (prewrap)\n", 970 1.44 chap buf_end - buf_cur)); 971 1.73 jmcneill mutex_exit(sc->lock); 972 1.73 jmcneill error = uiomove(buf_cur, buf_end - buf_cur, uio); 973 1.73 jmcneill mutex_enter(sc->lock); 974 1.73 jmcneill if (error) 975 1.73 jmcneill break; 976 1.82 mrg if (sc->dying) { 977 1.82 mrg error = EIO; 978 1.82 mrg break; 979 1.82 mrg } 980 1.44 chap appetite -= buf_end - buf_cur; 981 1.44 chap buf_cur = mb->buf; 982 1.44 chap } 983 1.44 chap DPRINTFN(8, ("midiread: uiomove cc=%d\n", appetite)); 984 1.73 jmcneill mutex_exit(sc->lock); 985 1.44 chap error = uiomove(buf_cur, appetite, uio); 986 1.73 jmcneill mutex_enter(sc->lock); 987 1.73 jmcneill if (error) 988 1.73 jmcneill break; 989 1.82 mrg if (sc->dying) { 990 1.82 mrg error = EIO; 991 1.82 mrg break; 992 1.82 mrg } 993 1.44 chap buf_cur += appetite; 994 1.44 chap } 995 1.85 msaitoh 996 1.44 chap MIDI_BUF_WRAP(idx); 997 1.44 chap MIDI_BUF_WRAP(buf); 998 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,idx); 999 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,buf); 1000 1.73 jmcneill if (0 == uio->uio_resid) /* if read satisfied, we're done */ 1001 1.44 chap break; 1002 1.44 chap MIDI_BUF_CONSUMER_REFRESH(mb,idx); 1003 1.73 jmcneill if (idx_cur == idx_lim) { /* need to wait for data? */ 1004 1.73 jmcneill if (!first || sc->rcv_eof) /* never block reader if */ 1005 1.44 chap break; /* any data already in hand */ 1006 1.1 augustss if (ioflag & IO_NDELAY) { 1007 1.44 chap error = EWOULDBLOCK; 1008 1.44 chap break; 1009 1.1 augustss } 1010 1.73 jmcneill error = cv_wait_sig(&sc->rchan, sc->lock); 1011 1.73 jmcneill if (error) 1012 1.44 chap break; 1013 1.44 chap MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* what'd we get? */ 1014 1.1 augustss } 1015 1.44 chap MIDI_BUF_CONSUMER_REFRESH(mb,buf); 1016 1.73 jmcneill if (sc->dying) { 1017 1.73 jmcneill error = EIO; 1018 1.73 jmcneill break; 1019 1.73 jmcneill } 1020 1.1 augustss } 1021 1.73 jmcneill mutex_exit(sc->lock); 1022 1.44 chap 1023 1.1 augustss return error; 1024 1.1 augustss } 1025 1.1 augustss 1026 1.73 jmcneill static void 1027 1.44 chap midi_rcv_asense(void *arg) 1028 1.1 augustss { 1029 1.73 jmcneill struct midi_softc *sc; 1030 1.73 jmcneill 1031 1.73 jmcneill sc = arg; 1032 1.73 jmcneill 1033 1.73 jmcneill mutex_enter(sc->lock); 1034 1.73 jmcneill if (sc->dying || !sc->isopen) { 1035 1.73 jmcneill mutex_exit(sc->lock); 1036 1.44 chap return; 1037 1.73 jmcneill } 1038 1.73 jmcneill if (sc->rcv_quiescent) { 1039 1.44 chap sc->rcv_eof = 1; 1040 1.44 chap sc->rcv_quiescent = 0; 1041 1.44 chap sc->rcv_expect_asense = 0; 1042 1.73 jmcneill cv_broadcast(&sc->rchan); 1043 1.73 jmcneill selnotify(&sc->rsel, 0, NOTE_SUBMIT); 1044 1.73 jmcneill if (sc->async) 1045 1.73 jmcneill softint_schedule(sc->sih); 1046 1.73 jmcneill mutex_exit(sc->lock); 1047 1.44 chap return; 1048 1.85 msaitoh } 1049 1.44 chap sc->rcv_quiescent = 1; 1050 1.44 chap callout_schedule(&sc->rcv_asense_co, MIDI_RCV_ASENSE_PERIOD); 1051 1.73 jmcneill mutex_exit(sc->lock); 1052 1.1 augustss } 1053 1.1 augustss 1054 1.73 jmcneill static void 1055 1.44 chap midi_xmt_asense(void *arg) 1056 1.44 chap { 1057 1.73 jmcneill struct midi_softc *sc; 1058 1.73 jmcneill int error, armed; 1059 1.73 jmcneill 1060 1.73 jmcneill sc = arg; 1061 1.85 msaitoh 1062 1.73 jmcneill mutex_enter(sc->lock); 1063 1.73 jmcneill if (sc->pbus || sc->dying || !sc->isopen) { 1064 1.73 jmcneill mutex_exit(sc->lock); 1065 1.44 chap return; 1066 1.44 chap } 1067 1.44 chap sc->pbus = 1; 1068 1.73 jmcneill if (sc->props & MIDI_PROP_OUT_INTR) { 1069 1.44 chap error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK); 1070 1.44 chap armed = (error == 0); 1071 1.73 jmcneill } else { 1072 1.44 chap error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK); 1073 1.44 chap armed = 0; 1074 1.44 chap } 1075 1.73 jmcneill if (!armed) { 1076 1.44 chap sc->pbus = 0; 1077 1.44 chap callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD); 1078 1.44 chap } 1079 1.73 jmcneill mutex_exit(sc->lock); 1080 1.44 chap } 1081 1.44 chap 1082 1.44 chap /* 1083 1.44 chap * The way this function was hacked up to plug into poll_out and intr_out 1084 1.44 chap * after they were written won't win it any beauty contests, but it'll work 1085 1.73 jmcneill * (code in haste, refactor at leisure). 1086 1.44 chap */ 1087 1.73 jmcneill static int 1088 1.73 jmcneill midi_msg_out(struct midi_softc *sc, u_char **idx, u_char **idxl, u_char **buf, 1089 1.73 jmcneill u_char **bufl) 1090 1.73 jmcneill { 1091 1.44 chap MIDI_BUF_DECLARE(idx); 1092 1.44 chap MIDI_BUF_DECLARE(buf); 1093 1.44 chap MIDI_BUF_EXTENT_INIT(&sc->outbuf,idx); 1094 1.44 chap MIDI_BUF_EXTENT_INIT(&sc->outbuf,buf); 1095 1.44 chap int length; 1096 1.44 chap int error; 1097 1.44 chap u_char contig[3]; 1098 1.44 chap u_char *cp; 1099 1.44 chap u_char *ep; 1100 1.73 jmcneill 1101 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 1102 1.73 jmcneill 1103 1.44 chap idx_cur = *idx; 1104 1.44 chap idx_lim = *idxl; 1105 1.44 chap buf_cur = *buf; 1106 1.44 chap buf_lim = *bufl; 1107 1.85 msaitoh 1108 1.44 chap length = MB_IDX_LEN(*idx_cur); 1109 1.85 msaitoh 1110 1.73 jmcneill for ( cp = contig, ep = cp + length; cp < ep;) { 1111 1.44 chap *cp++ = *buf_cur++; 1112 1.44 chap MIDI_BUF_WRAP(buf); 1113 1.44 chap } 1114 1.44 chap cp = contig; 1115 1.44 chap 1116 1.73 jmcneill switch ( MB_IDX_CAT(*idx_cur)) { 1117 1.44 chap case FST_CHV: /* chnmsg to be compressed (for device that wants it) */ 1118 1.44 chap ++ cp; 1119 1.44 chap -- length; 1120 1.44 chap /* FALLTHROUGH */ 1121 1.44 chap case FST_CHN: 1122 1.44 chap error = sc->hw_if_ext->channel(sc->hw_hdl, 1123 1.73 jmcneill MIDI_GET_STATUS(contig[0]), MIDI_GET_CHAN(contig[0]), 1124 1.73 jmcneill cp, length); 1125 1.44 chap break; 1126 1.44 chap case FST_COM: 1127 1.44 chap error = sc->hw_if_ext->common(sc->hw_hdl, 1128 1.73 jmcneill MIDI_GET_STATUS(contig[0]), cp, length); 1129 1.44 chap break; 1130 1.44 chap case FST_SYX: 1131 1.44 chap case FST_SXP: 1132 1.73 jmcneill error = sc->hw_if_ext->sysex(sc->hw_hdl, cp, length); 1133 1.44 chap break; 1134 1.44 chap case FST_RT: 1135 1.44 chap error = sc->hw_if->output(sc->hw_hdl, *cp); 1136 1.44 chap break; 1137 1.44 chap default: 1138 1.44 chap error = EIO; 1139 1.44 chap } 1140 1.85 msaitoh 1141 1.73 jmcneill if (!error) { 1142 1.44 chap ++ idx_cur; 1143 1.44 chap MIDI_BUF_WRAP(idx); 1144 1.44 chap *idx = idx_cur; 1145 1.44 chap *idxl = idx_lim; 1146 1.44 chap *buf = buf_cur; 1147 1.44 chap *bufl = buf_lim; 1148 1.44 chap } 1149 1.85 msaitoh 1150 1.44 chap return error; 1151 1.44 chap } 1152 1.44 chap 1153 1.44 chap /* 1154 1.44 chap * midi_poll_out is intended for the midi hw (the vast majority of MIDI UARTs 1155 1.44 chap * on sound cards, apparently) that _do not have transmit-ready interrupts_. 1156 1.44 chap * Every call to hw_if->output for one of these may busy-wait to output the 1157 1.44 chap * byte; at the standard midi data rate that'll be 320us per byte. The 1158 1.44 chap * technique of writing only MIDI_MAX_WRITE bytes in a row and then waiting 1159 1.44 chap * for MIDI_WAIT does not reduce the total time spent busy-waiting, and it 1160 1.44 chap * adds arbitrary delays in transmission (and, since MIDI_WAIT is roughly the 1161 1.44 chap * same as the time to send MIDI_MAX_WRITE bytes, it effectively halves the 1162 1.44 chap * data rate). Here, a somewhat bolder approach is taken. Since midi traffic 1163 1.44 chap * is bursty but time-sensitive--most of the time there will be none at all, 1164 1.44 chap * but when there is it should go out ASAP--the strategy is to just get it 1165 1.44 chap * over with, and empty the buffer in one go. The effect this can have on 1166 1.44 chap * the rest of the system will be limited by the size of the buffer and the 1167 1.44 chap * sparseness of the traffic. But some precautions are in order. Interrupts 1168 1.44 chap * should all be unmasked when this is called, and midiwrite should not fill 1169 1.44 chap * the buffer more than once (when MIDI_PROP_CAN_INTR is false) without a 1170 1.44 chap * yield() so some other process can get scheduled. If the write is nonblocking, 1171 1.44 chap * midiwrite should return a short count rather than yield. 1172 1.44 chap * 1173 1.44 chap * Someday when there is fine-grained MP support, this should be reworked to 1174 1.44 chap * run in a callout so the writing process really could proceed concurrently. 1175 1.44 chap * But obviously where performance is a concern, interrupt-driven hardware 1176 1.44 chap * such as USB midi or (apparently) clcs will always be preferable. And it 1177 1.44 chap * seems (kern/32651) that many of the devices currently working in poll mode 1178 1.44 chap * may really have tx interrupt capability and want only implementation; that 1179 1.44 chap * ought to happen. 1180 1.44 chap */ 1181 1.73 jmcneill static int 1182 1.44 chap midi_poll_out(struct midi_softc *sc) 1183 1.1 augustss { 1184 1.1 augustss struct midi_buffer *mb = &sc->outbuf; 1185 1.1 augustss int error; 1186 1.44 chap int msglen; 1187 1.44 chap MIDI_BUF_DECLARE(idx); 1188 1.44 chap MIDI_BUF_DECLARE(buf); 1189 1.1 augustss 1190 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 1191 1.73 jmcneill 1192 1.1 augustss error = 0; 1193 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,idx); 1194 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,buf); 1195 1.44 chap 1196 1.73 jmcneill for (;;) { 1197 1.73 jmcneill while (idx_cur != idx_lim) { 1198 1.73 jmcneill if (sc->hw_if_ext) { 1199 1.44 chap error = midi_msg_out(sc, &idx_cur, &idx_lim, 1200 1.73 jmcneill &buf_cur, &buf_lim); 1201 1.73 jmcneill if (error != 0) { 1202 1.73 jmcneill break; 1203 1.73 jmcneill } 1204 1.44 chap continue; 1205 1.44 chap } 1206 1.44 chap /* or, lacking hw_if_ext ... */ 1207 1.44 chap msglen = MB_IDX_LEN(*idx_cur); 1208 1.44 chap DPRINTFN(7,("midi_poll_out: %p <- %#02x\n", 1209 1.73 jmcneill sc->hw_hdl, *buf_cur)); 1210 1.44 chap error = sc->hw_if->output(sc->hw_hdl, *buf_cur); 1211 1.73 jmcneill if (error) { 1212 1.73 jmcneill break; 1213 1.73 jmcneill } 1214 1.73 jmcneill buf_cur++; 1215 1.44 chap MIDI_BUF_WRAP(buf); 1216 1.73 jmcneill msglen--; 1217 1.73 jmcneill if (msglen) { 1218 1.44 chap *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur), 1219 1.73 jmcneill msglen); 1220 1.73 jmcneill } else { 1221 1.73 jmcneill idx_cur++; 1222 1.44 chap MIDI_BUF_WRAP(idx); 1223 1.44 chap } 1224 1.44 chap } 1225 1.73 jmcneill if (error != 0) { 1226 1.73 jmcneill break; 1227 1.73 jmcneill } 1228 1.44 chap KASSERT(buf_cur == buf_lim); 1229 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,idx); 1230 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,buf); 1231 1.44 chap MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* any more to transmit? */ 1232 1.44 chap MIDI_BUF_CONSUMER_REFRESH(mb,buf); 1233 1.73 jmcneill if (idx_lim == idx_cur) 1234 1.73 jmcneill break; 1235 1.44 chap } 1236 1.18 tshiozak 1237 1.73 jmcneill if (error != 0) { 1238 1.73 jmcneill DPRINTF(("midi_poll_output error %d\n", error)); 1239 1.73 jmcneill MIDI_BUF_CONSUMER_WBACK(mb,idx); 1240 1.73 jmcneill MIDI_BUF_CONSUMER_WBACK(mb,buf); 1241 1.73 jmcneill } 1242 1.44 chap sc->pbus = 0; 1243 1.44 chap callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD); 1244 1.44 chap return error; 1245 1.44 chap } 1246 1.44 chap 1247 1.44 chap /* 1248 1.44 chap * The interrupt flavor acquires spl and lock once and releases at the end, 1249 1.44 chap * as it expects to write only one byte or message. The interface convention 1250 1.44 chap * is that if hw_if->output returns 0, it has initiated transmission and the 1251 1.44 chap * completion interrupt WILL be forthcoming; if it has not returned 0, NO 1252 1.44 chap * interrupt will be forthcoming, and if it returns EINPROGRESS it wants 1253 1.44 chap * another byte right away. 1254 1.44 chap */ 1255 1.73 jmcneill static int 1256 1.44 chap midi_intr_out(struct midi_softc *sc) 1257 1.44 chap { 1258 1.73 jmcneill struct midi_buffer *mb; 1259 1.73 jmcneill int error, msglen; 1260 1.44 chap MIDI_BUF_DECLARE(idx); 1261 1.44 chap MIDI_BUF_DECLARE(buf); 1262 1.44 chap int armed = 0; 1263 1.44 chap 1264 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 1265 1.73 jmcneill 1266 1.44 chap error = 0; 1267 1.73 jmcneill mb = &sc->outbuf; 1268 1.44 chap 1269 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,idx); 1270 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,buf); 1271 1.85 msaitoh 1272 1.73 jmcneill while (idx_cur != idx_lim) { 1273 1.73 jmcneill if (sc->hw_if_ext) { 1274 1.44 chap error = midi_msg_out(sc, &idx_cur, &idx_lim, 1275 1.73 jmcneill &buf_cur, &buf_lim); 1276 1.73 jmcneill if (!error ) /* no EINPROGRESS from extended hw_if */ 1277 1.44 chap armed = 1; 1278 1.20 tshiozak break; 1279 1.44 chap } 1280 1.44 chap /* or, lacking hw_if_ext ... */ 1281 1.44 chap msglen = MB_IDX_LEN(*idx_cur); 1282 1.44 chap error = sc->hw_if->output(sc->hw_hdl, *buf_cur); 1283 1.73 jmcneill if (error && error != EINPROGRESS) 1284 1.44 chap break; 1285 1.83 mrg ++buf_cur; 1286 1.44 chap MIDI_BUF_WRAP(buf); 1287 1.83 mrg --msglen; 1288 1.73 jmcneill if (msglen) 1289 1.44 chap *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),msglen); 1290 1.44 chap else { 1291 1.83 mrg ++idx_cur; 1292 1.44 chap MIDI_BUF_WRAP(idx); 1293 1.44 chap } 1294 1.73 jmcneill if (!error) { 1295 1.44 chap armed = 1; 1296 1.44 chap break; 1297 1.44 chap } 1298 1.44 chap } 1299 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,idx); 1300 1.44 chap MIDI_BUF_CONSUMER_WBACK(mb,buf); 1301 1.73 jmcneill if (!armed) { 1302 1.44 chap sc->pbus = 0; 1303 1.44 chap callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD); 1304 1.1 augustss } 1305 1.73 jmcneill cv_broadcast(&sc->wchan); 1306 1.73 jmcneill selnotify(&sc->wsel, 0, NOTE_SUBMIT); 1307 1.73 jmcneill if (sc->async) { 1308 1.73 jmcneill softint_schedule(sc->sih); 1309 1.73 jmcneill } 1310 1.73 jmcneill if (error) { 1311 1.73 jmcneill DPRINTF(("midi_intr_output error %d\n", error)); 1312 1.73 jmcneill } 1313 1.1 augustss return error; 1314 1.1 augustss } 1315 1.1 augustss 1316 1.73 jmcneill static int 1317 1.44 chap midi_start_output(struct midi_softc *sc) 1318 1.44 chap { 1319 1.73 jmcneill 1320 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 1321 1.73 jmcneill 1322 1.44 chap if (sc->dying) 1323 1.44 chap return EIO; 1324 1.73 jmcneill if (sc->props & MIDI_PROP_OUT_INTR) 1325 1.44 chap return midi_intr_out(sc); 1326 1.44 chap return midi_poll_out(sc); 1327 1.44 chap } 1328 1.44 chap 1329 1.44 chap static int 1330 1.44 chap real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc) 1331 1.44 chap { 1332 1.73 jmcneill u_char *iend; 1333 1.73 jmcneill struct midi_buffer *mb; 1334 1.73 jmcneill int arming, count, got; 1335 1.44 chap enum fst_form form; 1336 1.44 chap MIDI_BUF_DECLARE(idx); 1337 1.44 chap MIDI_BUF_DECLARE(buf); 1338 1.82 mrg int error; 1339 1.73 jmcneill 1340 1.73 jmcneill KASSERT(mutex_owned(sc->lock)); 1341 1.73 jmcneill 1342 1.82 mrg if (sc->dying || !sc->isopen) 1343 1.82 mrg return EIO; 1344 1.82 mrg 1345 1.82 mrg sc->refcnt++; 1346 1.82 mrg 1347 1.73 jmcneill iend = ibuf + cc; 1348 1.73 jmcneill mb = &sc->outbuf; 1349 1.73 jmcneill arming = 0; 1350 1.85 msaitoh 1351 1.44 chap /* 1352 1.44 chap * If the hardware uses the extended hw_if, pass it canonicalized 1353 1.44 chap * messages (or compressed ones if it specifically requests, using 1354 1.44 chap * VCOMP form so the bottom half can still pass the op and chan along); 1355 1.44 chap * if it does not, send it compressed messages (using COMPR form as 1356 1.44 chap * there is no need to preserve the status for the bottom half). 1357 1.44 chap */ 1358 1.73 jmcneill if (NULL == sc->hw_if_ext) 1359 1.44 chap form = FST_COMPR; 1360 1.73 jmcneill else if (sc->hw_if_ext->compress) 1361 1.44 chap form = FST_VCOMP; 1362 1.44 chap else 1363 1.44 chap form = FST_CANON; 1364 1.44 chap 1365 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,idx); 1366 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,buf); 1367 1.85 msaitoh 1368 1.73 jmcneill while (ibuf < iend) { 1369 1.44 chap got = midi_fst(&sc->xmt, *ibuf, form); 1370 1.83 mrg ++ibuf; 1371 1.73 jmcneill switch ( got) { 1372 1.44 chap case FST_MORE: 1373 1.44 chap continue; 1374 1.44 chap case FST_ERR: 1375 1.44 chap case FST_HUH: 1376 1.82 mrg error = EPROTO; 1377 1.82 mrg goto out; 1378 1.44 chap case FST_CHN: 1379 1.44 chap case FST_CHV: /* only occurs in VCOMP form */ 1380 1.44 chap case FST_COM: 1381 1.44 chap case FST_RT: 1382 1.44 chap case FST_SYX: 1383 1.44 chap case FST_SXP: 1384 1.44 chap break; /* go add to buffer */ 1385 1.44 chap #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC) 1386 1.44 chap default: 1387 1.44 chap printf("midi_wr: midi_fst returned %d?!\n", got); 1388 1.44 chap #endif 1389 1.44 chap } 1390 1.44 chap count = sc->xmt.end - sc->xmt.pos; 1391 1.73 jmcneill if (0 == count ) /* can happen with stray 0xf7; see midi_fst */ 1392 1.44 chap continue; 1393 1.44 chap /* 1394 1.44 chap * return EWOULDBLOCK if the data passed will not fit in 1395 1.44 chap * the buffer; the caller should have taken steps to avoid that. 1396 1.44 chap * If got==FST_SXP we lose the new status byte, but we're losing 1397 1.44 chap * anyway, so c'est la vie. 1398 1.44 chap */ 1399 1.73 jmcneill if (idx_cur == idx_lim || count > buf_lim - buf_cur) { 1400 1.44 chap MIDI_BUF_PRODUCER_REFRESH(mb,idx); /* get the most */ 1401 1.44 chap MIDI_BUF_PRODUCER_REFRESH(mb,buf); /* current facts */ 1402 1.82 mrg if (idx_cur == idx_lim || count > buf_lim - buf_cur) { 1403 1.82 mrg error = EWOULDBLOCK; /* caller's problem */ 1404 1.82 mrg goto out; 1405 1.82 mrg } 1406 1.44 chap } 1407 1.44 chap *idx_cur++ = PACK_MB_IDX(got,count); 1408 1.44 chap MIDI_BUF_WRAP(idx); 1409 1.73 jmcneill while (count) { 1410 1.44 chap *buf_cur++ = *(sc->xmt.pos)++; 1411 1.44 chap MIDI_BUF_WRAP(buf); 1412 1.44 chap -- count; 1413 1.44 chap } 1414 1.73 jmcneill if (FST_SXP == got) 1415 1.44 chap -- ibuf; /* again with same status byte */ 1416 1.44 chap } 1417 1.44 chap MIDI_BUF_PRODUCER_WBACK(mb,buf); 1418 1.44 chap MIDI_BUF_PRODUCER_WBACK(mb,idx); 1419 1.44 chap /* 1420 1.44 chap * If the output transfer is not already busy, and there is a message 1421 1.44 chap * buffered, mark it busy, stop the Active Sense callout (what if we're 1422 1.44 chap * too late and it's expired already? No big deal, an extra Active Sense 1423 1.44 chap * never hurt anybody) and start the output transfer once we're out of 1424 1.44 chap * the critical section (pbus==1 will stop anyone else doing the same). 1425 1.44 chap */ 1426 1.44 chap MIDI_BUF_CONSUMER_INIT(mb,idx); /* check what consumer's got to read */ 1427 1.73 jmcneill if (!sc->pbus && idx_cur < idx_lim) { 1428 1.44 chap sc->pbus = 1; 1429 1.44 chap callout_stop(&sc->xmt_asense_co); 1430 1.44 chap arming = 1; 1431 1.44 chap } 1432 1.82 mrg 1433 1.82 mrg error = arming ? midi_start_output(sc) : 0; 1434 1.82 mrg 1435 1.82 mrg out: 1436 1.82 mrg if (--sc->refcnt < 0) 1437 1.82 mrg cv_broadcast(&sc->detach_cv); 1438 1.82 mrg 1439 1.82 mrg return error; 1440 1.44 chap } 1441 1.44 chap 1442 1.73 jmcneill static int 1443 1.22 augustss midiwrite(dev_t dev, struct uio *uio, int ioflag) 1444 1.1 augustss { 1445 1.73 jmcneill struct midi_softc *sc; 1446 1.73 jmcneill struct midi_buffer *mb; 1447 1.1 augustss int error; 1448 1.44 chap u_char inp[256]; 1449 1.44 chap MIDI_BUF_DECLARE(idx); 1450 1.44 chap MIDI_BUF_DECLARE(buf); 1451 1.44 chap size_t idxspace; 1452 1.44 chap size_t bufspace; 1453 1.44 chap size_t xfrcount; 1454 1.44 chap int pollout = 0; 1455 1.1 augustss 1456 1.79 martin (void)buf_end; (void)idx_end; 1457 1.73 jmcneill sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 1458 1.73 jmcneill 1459 1.73 jmcneill DPRINTFN(6,("midiwrite: %p, unit=%d, count=%lu\n", sc, (int)minor(dev), 1460 1.73 jmcneill (unsigned long)uio->uio_resid)); 1461 1.1 augustss 1462 1.73 jmcneill mutex_enter(sc->lock); 1463 1.73 jmcneill if (sc->dying) { 1464 1.73 jmcneill mutex_exit(sc->lock); 1465 1.18 tshiozak return EIO; 1466 1.73 jmcneill } 1467 1.82 mrg 1468 1.82 mrg sc->refcnt++; 1469 1.82 mrg 1470 1.73 jmcneill mb = &sc->outbuf; 1471 1.1 augustss error = 0; 1472 1.1 augustss while (uio->uio_resid > 0 && !error) { 1473 1.44 chap /* 1474 1.44 chap * block if necessary for the minimum buffer space to guarantee 1475 1.44 chap * we can write something. 1476 1.44 chap */ 1477 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,idx); /* init can't go above loop; */ 1478 1.44 chap MIDI_BUF_PRODUCER_INIT(mb,buf); /* real_writebytes moves cur */ 1479 1.73 jmcneill for (;;) { 1480 1.44 chap idxspace = MIDI_BUF_PRODUCER_REFRESH(mb,idx) - idx_cur; 1481 1.44 chap bufspace = MIDI_BUF_PRODUCER_REFRESH(mb,buf) - buf_cur; 1482 1.73 jmcneill if (idxspace >= 1 && bufspace >= 3 && !pollout) 1483 1.44 chap break; 1484 1.85 msaitoh DPRINTFN(8,("midi_write: sleep idx=%zd buf=%zd\n", 1485 1.44 chap idxspace, bufspace)); 1486 1.1 augustss if (ioflag & IO_NDELAY) { 1487 1.44 chap /* 1488 1.44 chap * If some amount has already been transferred, 1489 1.44 chap * the common syscall code will automagically 1490 1.44 chap * convert this to success with a short count. 1491 1.44 chap */ 1492 1.82 mrg error = EWOULDBLOCK; 1493 1.82 mrg goto out; 1494 1.1 augustss } 1495 1.73 jmcneill if (pollout) { 1496 1.73 jmcneill mutex_exit(sc->lock); 1497 1.73 jmcneill yield(); /* see midi_poll_output */ 1498 1.73 jmcneill mutex_enter(sc->lock); 1499 1.44 chap pollout = 0; 1500 1.44 chap } else 1501 1.73 jmcneill error = cv_wait_sig(&sc->wchan, sc->lock); 1502 1.83 mrg if (sc->dying) 1503 1.83 mrg error = EIO; 1504 1.73 jmcneill if (error) { 1505 1.44 chap /* 1506 1.44 chap * Similarly, the common code will handle 1507 1.44 chap * EINTR and ERESTART properly here, changing to 1508 1.44 chap * a short count if something transferred. 1509 1.44 chap */ 1510 1.82 mrg goto out; 1511 1.73 jmcneill } 1512 1.39 perry } 1513 1.44 chap 1514 1.44 chap /* 1515 1.44 chap * The number of bytes we can safely extract from the uio 1516 1.44 chap * depends on the available idx and buf space. Worst case, 1517 1.44 chap * every byte is a message so 1 idx is required per byte. 1518 1.44 chap * Worst case, the first byte completes a 3-byte msg in prior 1519 1.44 chap * state, and every subsequent byte is a Program Change or 1520 1.44 chap * Channel Pressure msg with running status and expands to 2 1521 1.44 chap * bytes, so the buf space reqd is 3+2(n-1) or 2n+1. So limit 1522 1.44 chap * the transfer to the min of idxspace and (bufspace-1)>>1. 1523 1.44 chap */ 1524 1.44 chap xfrcount = (bufspace - 1) >> 1; 1525 1.73 jmcneill if (xfrcount > idxspace) 1526 1.44 chap xfrcount = idxspace; 1527 1.73 jmcneill if (xfrcount > sizeof inp) 1528 1.44 chap xfrcount = sizeof inp; 1529 1.73 jmcneill if (xfrcount > uio->uio_resid) 1530 1.44 chap xfrcount = uio->uio_resid; 1531 1.44 chap 1532 1.73 jmcneill mutex_exit(sc->lock); 1533 1.44 chap error = uiomove(inp, xfrcount, uio); 1534 1.73 jmcneill mutex_enter(sc->lock); 1535 1.1 augustss #ifdef MIDI_DEBUG 1536 1.1 augustss if (error) 1537 1.9 augustss printf("midi_write:(1) uiomove failed %d; " 1538 1.72 jakllsch "xfrcount=%zu inp=%p\n", 1539 1.44 chap error, xfrcount, inp); 1540 1.1 augustss #endif 1541 1.83 mrg if (error) 1542 1.44 chap break; 1543 1.85 msaitoh 1544 1.44 chap /* 1545 1.44 chap * The number of bytes we extracted being calculated to 1546 1.44 chap * definitely fit in the buffer even with canonicalization, 1547 1.44 chap * there is no excuse for real_writebytes to return EWOULDBLOCK. 1548 1.44 chap */ 1549 1.44 chap error = real_writebytes(sc, inp, xfrcount); 1550 1.44 chap KASSERT(error != EWOULDBLOCK); 1551 1.73 jmcneill if (error) 1552 1.1 augustss break; 1553 1.73 jmcneill 1554 1.44 chap /* 1555 1.44 chap * If this is a polling device and we just sent a buffer, let's 1556 1.44 chap * not send another without giving some other process a chance. 1557 1.44 chap */ 1558 1.73 jmcneill if ((sc->props & MIDI_PROP_OUT_INTR) == 0) 1559 1.44 chap pollout = 1; 1560 1.54 pavel DPRINTFN(8,("midiwrite: uio_resid now %zu, props=%d\n", 1561 1.73 jmcneill uio->uio_resid, sc->props)); 1562 1.1 augustss } 1563 1.82 mrg 1564 1.82 mrg out: 1565 1.82 mrg if (--sc->refcnt < 0) 1566 1.82 mrg cv_broadcast(&sc->detach_cv); 1567 1.82 mrg 1568 1.73 jmcneill mutex_exit(sc->lock); 1569 1.44 chap return error; 1570 1.5 augustss } 1571 1.5 augustss 1572 1.5 augustss /* 1573 1.9 augustss * This write routine is only called from sequencer code and expects 1574 1.5 augustss * a write that is smaller than the MIDI buffer. 1575 1.5 augustss */ 1576 1.5 augustss int 1577 1.40 christos midi_writebytes(int unit, u_char *bf, int cc) 1578 1.5 augustss { 1579 1.61 cube struct midi_softc *sc = 1580 1.67 cegger device_lookup_private(&midi_cd, unit); 1581 1.73 jmcneill int error; 1582 1.18 tshiozak 1583 1.82 mrg if (!sc) 1584 1.82 mrg return EIO; 1585 1.82 mrg 1586 1.44 chap DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n", 1587 1.44 chap sc, unit, cc, bf[0], bf[1], bf[2])); 1588 1.73 jmcneill 1589 1.73 jmcneill mutex_enter(sc->lock); 1590 1.83 mrg if (sc->dying) 1591 1.83 mrg error = EIO; 1592 1.83 mrg else 1593 1.83 mrg error = real_writebytes(sc, bf, cc); 1594 1.73 jmcneill mutex_exit(sc->lock); 1595 1.73 jmcneill 1596 1.73 jmcneill return error; 1597 1.1 augustss } 1598 1.1 augustss 1599 1.73 jmcneill static int 1600 1.53 christos midiioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1601 1.1 augustss { 1602 1.73 jmcneill struct midi_softc *sc; 1603 1.73 jmcneill const struct midi_hw_if *hw; 1604 1.1 augustss int error; 1605 1.44 chap MIDI_BUF_DECLARE(buf); 1606 1.1 augustss 1607 1.79 martin (void)buf_end; 1608 1.83 mrg sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 1609 1.83 mrg 1610 1.83 mrg mutex_enter(sc->lock); 1611 1.83 mrg if (sc->dying) { 1612 1.83 mrg mutex_exit(sc->lock); 1613 1.18 tshiozak return EIO; 1614 1.83 mrg } 1615 1.73 jmcneill hw = sc->hw_if; 1616 1.73 jmcneill error = 0; 1617 1.73 jmcneill 1618 1.82 mrg sc->refcnt++; 1619 1.82 mrg 1620 1.73 jmcneill DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd)); 1621 1.18 tshiozak 1622 1.1 augustss switch (cmd) { 1623 1.1 augustss case FIONBIO: 1624 1.73 jmcneill /* All handled in the upper layer. */ 1625 1.1 augustss break; 1626 1.85 msaitoh 1627 1.44 chap case FIONREAD: 1628 1.44 chap /* 1629 1.44 chap * This code relies on the current implementation of midi_in 1630 1.44 chap * always updating buf and idx together in a critical section, 1631 1.44 chap * so buf always ends at a message boundary. Document this 1632 1.44 chap * ioctl as always returning a value such that the last message 1633 1.44 chap * included is complete (SysEx the only exception), and then 1634 1.44 chap * make sure the implementation doesn't regress. NB that 1635 1.44 chap * means if this ioctl returns n and the proc then issues a 1636 1.44 chap * read of n, n bytes will be read, but if the proc issues a 1637 1.44 chap * read of m < n, fewer than m bytes may be read to ensure the 1638 1.44 chap * read ends at a message boundary. 1639 1.44 chap */ 1640 1.44 chap MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf); 1641 1.44 chap *(int *)addr = buf_lim - buf_cur; 1642 1.44 chap break; 1643 1.1 augustss 1644 1.1 augustss case FIOASYNC: 1645 1.82 mrg mutex_exit(sc->lock); 1646 1.90 ad mutex_enter(&proc_lock); 1647 1.1 augustss if (*(int *)addr) { 1648 1.73 jmcneill if (sc->async) { 1649 1.73 jmcneill error = EBUSY; 1650 1.73 jmcneill } else { 1651 1.73 jmcneill sc->async = curproc->p_pid; 1652 1.73 jmcneill } 1653 1.73 jmcneill DPRINTFN(5,("midi_ioctl: FIOASYNC %d\n", 1654 1.73 jmcneill curproc->p_pid)); 1655 1.73 jmcneill } else { 1656 1.1 augustss sc->async = 0; 1657 1.73 jmcneill } 1658 1.90 ad mutex_exit(&proc_lock); 1659 1.82 mrg mutex_enter(sc->lock); 1660 1.1 augustss break; 1661 1.1 augustss 1662 1.1 augustss #if 0 1663 1.1 augustss case MIDI_PRETIME: 1664 1.1 augustss /* XXX OSS 1665 1.1 augustss * This should set up a read timeout, but that's 1666 1.1 augustss * why we have poll(), so there's nothing yet. */ 1667 1.1 augustss error = EINVAL; 1668 1.1 augustss break; 1669 1.1 augustss #endif 1670 1.1 augustss 1671 1.4 augustss #ifdef MIDI_SAVE 1672 1.4 augustss case MIDI_GETSAVE: 1673 1.82 mrg mutex_exit(sc->lock); 1674 1.4 augustss error = copyout(&midisave, *(void **)addr, sizeof midisave); 1675 1.82 mrg mutex_enter(sc->lock); 1676 1.4 augustss break; 1677 1.4 augustss #endif 1678 1.4 augustss 1679 1.1 augustss default: 1680 1.73 jmcneill if (hw->ioctl != NULL) { 1681 1.42 christos error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, l); 1682 1.73 jmcneill } else { 1683 1.1 augustss error = EINVAL; 1684 1.73 jmcneill } 1685 1.1 augustss break; 1686 1.1 augustss } 1687 1.82 mrg 1688 1.82 mrg if (--sc->refcnt < 0) 1689 1.82 mrg cv_broadcast(&sc->detach_cv); 1690 1.82 mrg mutex_exit(sc->lock); 1691 1.1 augustss return error; 1692 1.1 augustss } 1693 1.1 augustss 1694 1.73 jmcneill static int 1695 1.42 christos midipoll(dev_t dev, int events, struct lwp *l) 1696 1.1 augustss { 1697 1.73 jmcneill struct midi_softc *sc; 1698 1.73 jmcneill int revents; 1699 1.44 chap MIDI_BUF_DECLARE(idx); 1700 1.44 chap MIDI_BUF_DECLARE(buf); 1701 1.1 augustss 1702 1.79 martin (void)buf_end; (void)idx_end; 1703 1.73 jmcneill sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 1704 1.73 jmcneill revents = 0; 1705 1.73 jmcneill 1706 1.44 chap DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events)); 1707 1.1 augustss 1708 1.73 jmcneill mutex_enter(sc->lock); 1709 1.73 jmcneill if (sc->dying) { 1710 1.73 jmcneill mutex_exit(sc->lock); 1711 1.41 ws return POLLHUP; 1712 1.73 jmcneill } 1713 1.82 mrg 1714 1.82 mrg sc->refcnt++; 1715 1.82 mrg 1716 1.73 jmcneill if ((events & (POLLIN | POLLRDNORM)) != 0) { 1717 1.73 jmcneill MIDI_BUF_CONSUMER_INIT(&sc->inbuf, idx); 1718 1.44 chap if (idx_cur < idx_lim) 1719 1.1 augustss revents |= events & (POLLIN | POLLRDNORM); 1720 1.44 chap else 1721 1.44 chap selrecord(l, &sc->rsel); 1722 1.44 chap } 1723 1.73 jmcneill if ((events & (POLLOUT | POLLWRNORM)) != 0) { 1724 1.73 jmcneill MIDI_BUF_PRODUCER_INIT(&sc->outbuf, idx); 1725 1.73 jmcneill MIDI_BUF_PRODUCER_INIT(&sc->outbuf, buf); 1726 1.73 jmcneill if (idx_lim - idx_cur >= 1 && buf_lim - buf_cur >= 3) 1727 1.1 augustss revents |= events & (POLLOUT | POLLWRNORM); 1728 1.44 chap else 1729 1.42 christos selrecord(l, &sc->wsel); 1730 1.1 augustss } 1731 1.82 mrg 1732 1.82 mrg if (--sc->refcnt < 0) 1733 1.82 mrg cv_broadcast(&sc->detach_cv); 1734 1.82 mrg 1735 1.73 jmcneill mutex_exit(sc->lock); 1736 1.1 augustss 1737 1.1 augustss return revents; 1738 1.30 jdolecek } 1739 1.30 jdolecek 1740 1.30 jdolecek static void 1741 1.30 jdolecek filt_midirdetach(struct knote *kn) 1742 1.30 jdolecek { 1743 1.30 jdolecek struct midi_softc *sc = kn->kn_hook; 1744 1.30 jdolecek 1745 1.73 jmcneill mutex_enter(sc->lock); 1746 1.91 thorpej selremove_knote(&sc->rsel, kn); 1747 1.73 jmcneill mutex_exit(sc->lock); 1748 1.30 jdolecek } 1749 1.30 jdolecek 1750 1.30 jdolecek static int 1751 1.50 christos filt_midiread(struct knote *kn, long hint) 1752 1.30 jdolecek { 1753 1.30 jdolecek struct midi_softc *sc = kn->kn_hook; 1754 1.44 chap MIDI_BUF_DECLARE(buf); 1755 1.30 jdolecek 1756 1.79 martin (void)buf_end; 1757 1.73 jmcneill if (hint != NOTE_SUBMIT) 1758 1.73 jmcneill mutex_enter(sc->lock); 1759 1.44 chap MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf); 1760 1.44 chap kn->kn_data = buf_lim - buf_cur; 1761 1.73 jmcneill if (hint != NOTE_SUBMIT) 1762 1.73 jmcneill mutex_exit(sc->lock); 1763 1.30 jdolecek return (kn->kn_data > 0); 1764 1.30 jdolecek } 1765 1.30 jdolecek 1766 1.87 maya static const struct filterops midiread_filtops = { 1767 1.95 thorpej .f_flags = FILTEROP_ISFD, 1768 1.87 maya .f_attach = NULL, 1769 1.87 maya .f_detach = filt_midirdetach, 1770 1.87 maya .f_event = filt_midiread, 1771 1.87 maya }; 1772 1.30 jdolecek 1773 1.30 jdolecek static void 1774 1.30 jdolecek filt_midiwdetach(struct knote *kn) 1775 1.30 jdolecek { 1776 1.30 jdolecek struct midi_softc *sc = kn->kn_hook; 1777 1.30 jdolecek 1778 1.73 jmcneill mutex_enter(sc->lock); 1779 1.91 thorpej selremove_knote(&sc->wsel, kn); 1780 1.73 jmcneill mutex_exit(sc->lock); 1781 1.30 jdolecek } 1782 1.30 jdolecek 1783 1.30 jdolecek static int 1784 1.50 christos filt_midiwrite(struct knote *kn, long hint) 1785 1.30 jdolecek { 1786 1.30 jdolecek struct midi_softc *sc = kn->kn_hook; 1787 1.44 chap MIDI_BUF_DECLARE(idx); 1788 1.44 chap MIDI_BUF_DECLARE(buf); 1789 1.30 jdolecek 1790 1.82 mrg mutex_exit(sc->lock); 1791 1.82 mrg sc->refcnt++; 1792 1.82 mrg mutex_enter(sc->lock); 1793 1.82 mrg 1794 1.79 martin (void)idx_end; (void)buf_end; 1795 1.73 jmcneill if (hint != NOTE_SUBMIT) 1796 1.73 jmcneill mutex_enter(sc->lock); 1797 1.44 chap MIDI_BUF_PRODUCER_INIT(&sc->outbuf,idx); 1798 1.44 chap MIDI_BUF_PRODUCER_INIT(&sc->outbuf,buf); 1799 1.44 chap kn->kn_data = ((buf_lim - buf_cur)-1)>>1; 1800 1.73 jmcneill if (kn->kn_data > idx_lim - idx_cur) 1801 1.44 chap kn->kn_data = idx_lim - idx_cur; 1802 1.73 jmcneill if (hint != NOTE_SUBMIT) 1803 1.73 jmcneill mutex_exit(sc->lock); 1804 1.82 mrg 1805 1.82 mrg // XXXMRG -- move this up, avoid the relock? 1806 1.82 mrg mutex_enter(sc->lock); 1807 1.82 mrg if (--sc->refcnt < 0) 1808 1.82 mrg cv_broadcast(&sc->detach_cv); 1809 1.82 mrg mutex_exit(sc->lock); 1810 1.82 mrg 1811 1.30 jdolecek return (kn->kn_data > 0); 1812 1.30 jdolecek } 1813 1.30 jdolecek 1814 1.87 maya static const struct filterops midiwrite_filtops = { 1815 1.95 thorpej .f_flags = FILTEROP_ISFD, 1816 1.87 maya .f_attach = NULL, 1817 1.87 maya .f_detach = filt_midiwdetach, 1818 1.87 maya .f_event = filt_midiwrite, 1819 1.87 maya }; 1820 1.30 jdolecek 1821 1.30 jdolecek int 1822 1.30 jdolecek midikqfilter(dev_t dev, struct knote *kn) 1823 1.30 jdolecek { 1824 1.61 cube struct midi_softc *sc = 1825 1.67 cegger device_lookup_private(&midi_cd, MIDIUNIT(dev)); 1826 1.91 thorpej struct selinfo *sip; 1827 1.91 thorpej int error = 0; 1828 1.30 jdolecek 1829 1.91 thorpej mutex_enter(sc->lock); 1830 1.82 mrg sc->refcnt++; 1831 1.82 mrg 1832 1.30 jdolecek switch (kn->kn_filter) { 1833 1.30 jdolecek case EVFILT_READ: 1834 1.91 thorpej sip = &sc->rsel; 1835 1.30 jdolecek kn->kn_fop = &midiread_filtops; 1836 1.30 jdolecek break; 1837 1.30 jdolecek 1838 1.30 jdolecek case EVFILT_WRITE: 1839 1.91 thorpej sip = &sc->wsel; 1840 1.30 jdolecek kn->kn_fop = &midiwrite_filtops; 1841 1.30 jdolecek break; 1842 1.30 jdolecek 1843 1.30 jdolecek default: 1844 1.91 thorpej error = EINVAL; 1845 1.91 thorpej goto out; 1846 1.30 jdolecek } 1847 1.30 jdolecek 1848 1.30 jdolecek kn->kn_hook = sc; 1849 1.30 jdolecek 1850 1.91 thorpej selrecord_knote(sip, kn); 1851 1.91 thorpej out: 1852 1.82 mrg if (--sc->refcnt < 0) 1853 1.82 mrg cv_broadcast(&sc->detach_cv); 1854 1.73 jmcneill mutex_exit(sc->lock); 1855 1.30 jdolecek 1856 1.91 thorpej return (error); 1857 1.1 augustss } 1858 1.1 augustss 1859 1.1 augustss void 1860 1.22 augustss midi_getinfo(dev_t dev, struct midi_info *mi) 1861 1.1 augustss { 1862 1.1 augustss struct midi_softc *sc; 1863 1.1 augustss 1864 1.67 cegger sc = device_lookup_private(&midi_cd, MIDIUNIT(dev)); 1865 1.17 thorpej if (sc == NULL) 1866 1.18 tshiozak return; 1867 1.73 jmcneill mutex_enter(sc->lock); 1868 1.1 augustss sc->hw_if->getinfo(sc->hw_hdl, mi); 1869 1.73 jmcneill mutex_exit(sc->lock); 1870 1.4 augustss } 1871 1.4 augustss 1872 1.45 chap #elif NMIDIBUS > 0 /* but NMIDI == 0 */ 1873 1.45 chap 1874 1.73 jmcneill void 1875 1.73 jmcneill midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) 1876 1.73 jmcneill { 1877 1.73 jmcneill 1878 1.73 jmcneill /* nothing */ 1879 1.45 chap } 1880 1.45 chap 1881 1.10 drochner #endif /* NMIDI > 0 */ 1882 1.10 drochner 1883 1.10 drochner #if NMIDI > 0 || NMIDIBUS > 0 1884 1.10 drochner 1885 1.61 cube device_t 1886 1.61 cube midi_attach_mi(const struct midi_hw_if *mhwp, void *hdlp, device_t dev) 1887 1.4 augustss { 1888 1.4 augustss struct audio_attach_args arg; 1889 1.4 augustss 1890 1.4 augustss if (mhwp == NULL) { 1891 1.73 jmcneill panic("midi_attach_mi: NULL\n"); 1892 1.12 augustss return (0); 1893 1.4 augustss } 1894 1.73 jmcneill 1895 1.4 augustss arg.type = AUDIODEV_TYPE_MIDI; 1896 1.4 augustss arg.hwif = mhwp; 1897 1.4 augustss arg.hdl = hdlp; 1898 1.93 thorpej return (config_found(dev, &arg, audioprint, 1899 1.94 thorpej CFARGS(.iattr = "midibus"))); 1900 1.1 augustss } 1901 1.1 augustss 1902 1.10 drochner #endif /* NMIDI > 0 || NMIDIBUS > 0 */ 1903