midi.c revision 1.43.2.6 1 /* $NetBSD: midi.c,v 1.43.2.6 2006/05/20 03:16:48 chap Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss (at) NetBSD.org) and (MIDI DFA and Active
9 * Sense handling) Chapman Flack (nblists (at) anastigmatix.net).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.43.2.6 2006/05/20 03:16:48 chap Exp $");
42
43 #include "midi.h"
44 #include "sequencer.h"
45
46 #include <sys/param.h>
47 #include <sys/ioctl.h>
48 #include <sys/fcntl.h>
49 #include <sys/vnode.h>
50 #include <sys/select.h>
51 #include <sys/poll.h>
52 #include <sys/malloc.h>
53 #include <sys/proc.h>
54 #include <sys/systm.h>
55 #include <sys/callout.h>
56 #include <sys/syslog.h>
57 #include <sys/kernel.h>
58 #include <sys/signalvar.h>
59 #include <sys/conf.h>
60 #include <sys/audioio.h>
61 #include <sys/midiio.h>
62
63 #include <dev/audio_if.h>
64 #include <dev/midi_if.h>
65 #include <dev/midivar.h>
66
67 #if NMIDI > 0
68
69
70 #ifdef AUDIO_DEBUG
71 #define DPRINTF(x) if (mididebug) printf x
72 #define DPRINTFN(n,x) if (mididebug >= (n)) printf x
73 int mididebug = 0;
74 /*
75 * 1: detected protocol errors and buffer overflows
76 * 2: probe, attach, detach
77 * 3: open, close
78 * 4: data received except realtime
79 * 5: ioctl
80 * 6: read, write, poll
81 * 7: data transmitted
82 * 8: uiomoves, synchronization
83 * 9: realtime data received
84 */
85 #else
86 #define DPRINTF(x)
87 #define DPRINTFN(n,x)
88 #endif
89
90 int midi_wait;
91
92 void midi_in(void *, int);
93 void midi_out(void *);
94 int midi_start_output(struct midi_softc *, int, int);
95 int midi_sleep_timo(int *, char *, int);
96 int midi_sleep(int *, char *);
97 void midi_wakeup(int *);
98 void midi_initbuf(struct midi_buffer *);
99 void midi_timeout(void *);
100
101 int midiprobe(struct device *, struct cfdata *, void *);
102 void midiattach(struct device *, struct device *, void *);
103 int mididetach(struct device *, int);
104 int midiactivate(struct device *, enum devact);
105
106 dev_type_open(midiopen);
107 dev_type_close(midiclose);
108 dev_type_read(midiread);
109 dev_type_write(midiwrite);
110 dev_type_ioctl(midiioctl);
111 dev_type_poll(midipoll);
112 dev_type_kqfilter(midikqfilter);
113
114 const struct cdevsw midi_cdevsw = {
115 midiopen, midiclose, midiread, midiwrite, midiioctl,
116 nostop, notty, midipoll, nommap, midikqfilter,
117 };
118
119 CFATTACH_DECL(midi, sizeof(struct midi_softc),
120 midiprobe, midiattach, mididetach, midiactivate);
121
122 #ifdef MIDI_SAVE
123 #define MIDI_SAVE_SIZE 100000
124 int midicnt;
125 struct {
126 int cnt;
127 u_char buf[MIDI_SAVE_SIZE];
128 } midisave;
129 #define MIDI_GETSAVE _IOWR('m', 100, int)
130
131 #endif
132
133 extern struct cfdriver midi_cd;
134
135 int
136 midiprobe(struct device *parent, struct cfdata *match, void *aux)
137 {
138 struct audio_attach_args *sa = aux;
139
140 DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n",
141 sa->type, sa, sa->hwif));
142 return (sa->type == AUDIODEV_TYPE_MIDI);
143 }
144
145 void
146 midiattach(struct device *parent, struct device *self, void *aux)
147 {
148 struct midi_softc *sc = (void *)self;
149 struct audio_attach_args *sa = aux;
150 struct midi_hw_if *hwp = sa->hwif;
151 void *hdlp = sa->hdl;
152
153 DPRINTFN(2, ("MIDI attach\n"));
154
155 #ifdef DIAGNOSTIC
156 if (hwp == 0 ||
157 hwp->open == 0 ||
158 hwp->close == 0 ||
159 hwp->output == 0 ||
160 hwp->getinfo == 0) {
161 printf("midi: missing method\n");
162 return;
163 }
164 #endif
165
166 sc->hw_if = hwp;
167 sc->hw_hdl = hdlp;
168 midi_attach(sc, parent);
169 }
170
171 int
172 midiactivate(struct device *self, enum devact act)
173 {
174 struct midi_softc *sc = (struct midi_softc *)self;
175
176 switch (act) {
177 case DVACT_ACTIVATE:
178 return (EOPNOTSUPP);
179
180 case DVACT_DEACTIVATE:
181 sc->dying = 1;
182 break;
183 }
184 return (0);
185 }
186
187 int
188 mididetach(struct device *self, int flags)
189 {
190 struct midi_softc *sc = (struct midi_softc *)self;
191 int maj, mn;
192
193 DPRINTFN(2,("midi_detach: sc=%p flags=%d\n", sc, flags));
194
195 sc->dying = 1;
196
197 wakeup(&sc->wchan);
198 wakeup(&sc->rchan);
199
200 /* locate the major number */
201 maj = cdevsw_lookup_major(&midi_cdevsw);
202
203 /* Nuke the vnodes for any open instances (calls close). */
204 mn = self->dv_unit;
205 vdevgone(maj, mn, mn, VCHR);
206
207 evcnt_detach(&sc->xmt.bytesDiscarded);
208 evcnt_detach(&sc->xmt.incompleteMessages);
209 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
210 evcnt_detach(&sc->rcv.bytesDiscarded);
211 evcnt_detach(&sc->rcv.incompleteMessages);
212 }
213
214 return (0);
215 }
216
217 void
218 midi_attach(struct midi_softc *sc, struct device *parent)
219 {
220 struct midi_info mi;
221
222
223 callout_init(&sc->sc_callout);
224 callout_setfunc(&sc->sc_callout, midi_timeout, sc);
225 simple_lock_init(&sc->out_lock);
226 sc->dying = 0;
227 sc->isopen = 0;
228
229 midi_wait = MIDI_WAIT * hz / 1000000;
230 if (midi_wait == 0)
231 midi_wait = 1;
232
233 sc->sc_dev = parent;
234 sc->hw_if->getinfo(sc->hw_hdl, &mi);
235 sc->props = mi.props;
236
237 evcnt_attach_dynamic(&sc->xmt.bytesDiscarded,
238 EVCNT_TYPE_MISC, NULL,
239 sc->dev.dv_xname, "xmt bytes discarded");
240 evcnt_attach_dynamic(&sc->xmt.incompleteMessages,
241 EVCNT_TYPE_MISC, NULL,
242 sc->dev.dv_xname, "xmt incomplete msgs");
243 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
244 evcnt_attach_dynamic(&sc->rcv.bytesDiscarded,
245 EVCNT_TYPE_MISC, NULL,
246 sc->dev.dv_xname, "rcv bytes discarded");
247 evcnt_attach_dynamic(&sc->rcv.incompleteMessages,
248 EVCNT_TYPE_MISC, NULL,
249 sc->dev.dv_xname, "rcv incomplete msgs");
250 }
251
252 printf(": %s\n", mi.name);
253 }
254
255 int
256 midi_unit_count(void)
257 {
258 int i;
259 for ( i = 0; i < midi_cd.cd_ndevs; ++i )
260 if ( NULL == midi_cd.cd_devs[i] )
261 break;
262 return i;
263 }
264
265 void
266 midi_initbuf(struct midi_buffer *mb)
267 {
268 mb->used = 0;
269 mb->usedhigh = MIDI_BUFSIZE;
270 mb->end = mb->start + mb->usedhigh;
271 mb->inp = mb->outp = mb->start;
272 }
273
274 int
275 midi_sleep_timo(int *chan, char *label, int timo)
276 {
277 int st;
278
279 if (!label)
280 label = "midi";
281
282 DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
283 *chan = 1;
284 st = tsleep(chan, PWAIT | PCATCH, label, timo);
285 *chan = 0;
286 #ifdef MIDI_DEBUG
287 if (st != 0)
288 printf("midi_sleep: %d\n", st);
289 #endif
290 return st;
291 }
292
293 int
294 midi_sleep(int *chan, char *label)
295 {
296 return midi_sleep_timo(chan, label, 0);
297 }
298
299 void
300 midi_wakeup(int *chan)
301 {
302 if (*chan) {
303 DPRINTFN(8, ("midi_wakeup: %p\n", chan));
304 wakeup(chan);
305 *chan = 0;
306 }
307 }
308
309 /* in midivar.h:
310 #define MIDI_CAT_DATA 0
311 #define MIDI_CAT_STATUS1 1
312 #define MIDI_CAT_STATUS2 2
313 #define MIDI_CAT_COMMON 3
314 */
315 static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
316 #define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
317 #define DFA_RETURN(offp,endp,ret) \
318 return (s->pos=s->msg+(offp)), (s->end=s->msg+(endp)), (ret)
319
320 enum dfa_ret { DFA_MORE, DFA_CHN, DFA_COM, DFA_SYX, DFA_RT, DFA_ERR, DFA_HUH };
321
322 /*
323 * A MIDI state machine suitable for receiving or transmitting. It will
324 * accept correct MIDI input that uses, doesn't use, or sometimes uses the
325 * 'running status' compression technique, and transduce it to fully expanded
326 * (compress==0) or fully compressed (compress==1) form.
327 *
328 * Returns DFA_MORE if a complete message has not been parsed yet (SysEx
329 * messages are the exception), DFA_ERR or DFA_HUH if the input does not
330 * conform to the protocol, or DFA_CHN (channel messages), DFA_COM (System
331 * Common messages), DFA_RT (System Real-Time messages), or DFA_SYX (System
332 * Exclusive) to broadly categorize the message parsed. s->pos and s->end
333 * locate the parsed message; while (s->pos<s->end) putchar(*(s->pos++));
334 * would output it.
335 *
336 * DFA_HUH means the character c wasn't valid in the original state, but the
337 * state has now been reset to START and the caller should try again passing
338 * the same c. DFA_ERR means c isn't valid in the start state; the caller
339 * should kiss it goodbye and continue to try successive characters from the
340 * input until something other than DFA_ERR or DFA_HUH is returned, at which
341 * point things are resynchronized.
342 *
343 * A DFA_SYX return means that between pos and end are from 1 to 3
344 * bytes of a system exclusive message. A SysEx message will be delivered in
345 * one or more chunks of that form, where the first begins with 0xf0 and the
346 * last (which is the only one that might have length < 3) ends with 0xf7.
347 *
348 * Messages corrupted by a protocol error are discarded and won't be seen at
349 * all; again SysEx is the exception, as one or more chunks of it may already
350 * have been parsed.
351 *
352 * For DFA_CHN messages, s->msg[0] always contains the status byte even if
353 * compression was requested (pos then points to msg[1]). That way, the
354 * caller can always identify the exact message if there is a need to do so.
355 * For all other message types except DFA_SYX, the status byte is at *pos
356 * (which may not necessarily be msg[0]!). There is only one SysEx status
357 * byte, so the return value DFA_SYX is sufficient to identify it.
358 */
359 static enum dfa_ret
360 midi_dfa(struct midi_state *s, u_char c, int compress)
361 {
362 int syxpos = 0;
363 compress = compress ? 1 : 0;
364
365 if ( c >= 0xf8 ) { /* All realtime messages bypass state machine */
366 if ( c == 0xf9 || c == 0xfd ) {
367 DPRINTF( ("midi_dfa: s=%p c=0x%02x undefined\n",
368 s, c));
369 s->bytesDiscarded.ev_count++;
370 return DFA_ERR;
371 }
372 DPRINTFN(9, ("midi_dfa: s=%p System Real-Time data=0x%02x\n",
373 s, c));
374 s->msg[2] = c;
375 DFA_RETURN(2,3,DFA_RT);
376 }
377
378 DPRINTFN(4, ("midi_dfa: s=%p data=0x%02x state=%d\n",
379 s, c, s->state));
380
381 switch ( s->state | MIDI_CAT(c) ) { /* break ==> return DFA_MORE */
382
383 case MIDI_IN_START | MIDI_CAT_COMMON:
384 case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
385 case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
386 s->msg[0] = c;
387 switch ( c ) {
388 case 0xf0: s->state = MIDI_IN_SYX1_3; break;
389 case 0xf1: s->state = MIDI_IN_COM0_1; break;
390 case 0xf2: s->state = MIDI_IN_COM0_2; break;
391 case 0xf3: s->state = MIDI_IN_COM0_1; break;
392 case 0xf6: s->state = MIDI_IN_START; DFA_RETURN(0,1,DFA_COM);
393 default: goto protocol_violation;
394 }
395 break;
396
397 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
398 if ( c == s->msg[0] ) {
399 s->state = MIDI_IN_RNX0_1;
400 break;
401 }
402 /* FALLTHROUGH */
403 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1:
404 case MIDI_IN_START | MIDI_CAT_STATUS1:
405 s->state = MIDI_IN_RUN0_1;
406 s->msg[0] = c;
407 break;
408
409 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
410 if ( c == s->msg[0] ) {
411 s->state = MIDI_IN_RNX0_2;
412 break;
413 }
414 /* FALLTHROUGH */
415 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2:
416 case MIDI_IN_START | MIDI_CAT_STATUS2:
417 s->state = MIDI_IN_RUN0_2;
418 s->msg[0] = c;
419 break;
420
421 case MIDI_IN_COM0_1 | MIDI_CAT_DATA:
422 s->state = MIDI_IN_START;
423 s->msg[1] = c;
424 DFA_RETURN(0,2,DFA_COM);
425
426 case MIDI_IN_COM0_2 | MIDI_CAT_DATA:
427 s->state = MIDI_IN_COM1_2;
428 s->msg[1] = c;
429 break;
430
431 case MIDI_IN_COM1_2 | MIDI_CAT_DATA:
432 s->state = MIDI_IN_START;
433 s->msg[2] = c;
434 DFA_RETURN(0,3,DFA_COM);
435
436 case MIDI_IN_RUN0_1 | MIDI_CAT_DATA:
437 s->state = MIDI_IN_RUN1_1;
438 s->msg[1] = c;
439 DFA_RETURN(0,2,DFA_CHN);
440
441 case MIDI_IN_RUN1_1 | MIDI_CAT_DATA:
442 case MIDI_IN_RNX0_1 | MIDI_CAT_DATA:
443 s->state = MIDI_IN_RUN1_1;
444 s->msg[1] = c;
445 DFA_RETURN(compress,2,DFA_CHN);
446
447 case MIDI_IN_RUN0_2 | MIDI_CAT_DATA:
448 s->state = MIDI_IN_RUN1_2;
449 s->msg[1] = c;
450 break;
451
452 case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
453 s->state = MIDI_IN_RUN2_2;
454 s->msg[2] = c;
455 DFA_RETURN(0,3,DFA_CHN);
456
457 case MIDI_IN_RUN2_2 | MIDI_CAT_DATA:
458 s->state = MIDI_IN_RNX1_2;
459 s->msg[1] = c;
460 break;
461
462 case MIDI_IN_RNX0_2 | MIDI_CAT_DATA:
463 s->state = MIDI_IN_RNY1_2;
464 s->msg[1] = c;
465 break;
466
467 case MIDI_IN_RNX1_2 | MIDI_CAT_DATA:
468 case MIDI_IN_RNY1_2 | MIDI_CAT_DATA:
469 s->state = MIDI_IN_RUN2_2;
470 s->msg[2] = c;
471 DFA_RETURN(compress,3,DFA_CHN);
472
473 case MIDI_IN_SYX1_3 | MIDI_CAT_DATA:
474 s->state = MIDI_IN_SYX2_3;
475 s->msg[1] = c;
476 break;
477
478 case MIDI_IN_SYX2_3 | MIDI_CAT_DATA:
479 s->state = MIDI_IN_SYX0_3;
480 s->msg[2] = c;
481 DFA_RETURN(0,3,DFA_SYX);
482
483 case MIDI_IN_SYX0_3 | MIDI_CAT_DATA:
484 s->state = MIDI_IN_SYX1_3;
485 s->msg[0] = c;
486 break;
487
488 case MIDI_IN_SYX2_3 | MIDI_CAT_COMMON:
489 ++ syxpos;
490 /* FALLTHROUGH */
491 case MIDI_IN_SYX1_3 | MIDI_CAT_COMMON:
492 ++ syxpos;
493 /* FALLTHROUGH */
494 case MIDI_IN_SYX0_3 | MIDI_CAT_COMMON:
495 if ( c == 0xf7 ) {
496 s->state = MIDI_IN_START;
497 s->msg[syxpos] = c;
498 DFA_RETURN(0,1+syxpos,DFA_SYX);
499 }
500 /* FALLTHROUGH */
501
502 default:
503 protocol_violation:
504 DPRINTF(("midi_dfa: unexpected %#02x in state %u\n",
505 c, s->state));
506 switch ( s->state ) {
507 case MIDI_IN_RUN1_1: /* can only get here by seeing an */
508 case MIDI_IN_RUN2_2: /* INVALID System Common message */
509 s->state = MIDI_IN_START;
510 /* FALLTHROUGH */
511 case MIDI_IN_START:
512 s->bytesDiscarded.ev_count++;
513 return DFA_ERR;
514 case MIDI_IN_COM1_2:
515 case MIDI_IN_RUN1_2:
516 case MIDI_IN_SYX2_3:
517 case MIDI_IN_RNY1_2:
518 s->bytesDiscarded.ev_count++;
519 /* FALLTHROUGH */
520 case MIDI_IN_COM0_1:
521 case MIDI_IN_RUN0_1:
522 case MIDI_IN_RNX0_1:
523 case MIDI_IN_COM0_2:
524 case MIDI_IN_RUN0_2:
525 case MIDI_IN_RNX0_2:
526 case MIDI_IN_RNX1_2:
527 case MIDI_IN_SYX1_3:
528 s->bytesDiscarded.ev_count++;
529 /* FALLTHROUGH */
530 case MIDI_IN_SYX0_3:
531 s->incompleteMessages.ev_count++;
532 break;
533 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
534 default:
535 printf("midi_dfa: mishandled %#02x(%u) in state %u?!\n",
536 c, MIDI_CAT(c), s->state);
537 #endif
538 }
539 s->state = MIDI_IN_START;
540 return DFA_HUH;
541 }
542 return DFA_MORE;
543 }
544
545 void
546 midi_in(void *addr, int data)
547 {
548 struct midi_softc *sc = addr;
549 struct midi_buffer *mb = &sc->inbuf;
550 int i;
551 int count;
552 enum dfa_ret got;
553
554 if (!sc->isopen)
555 return;
556
557 if (!(sc->flags & FREAD))
558 return; /* discard data if not reading */
559
560 do
561 got = midi_dfa(&sc->rcv, data, 0);
562 while ( got == DFA_HUH );
563
564 switch ( got ) {
565 case DFA_MORE:
566 case DFA_ERR:
567 return;
568 case DFA_CHN:
569 case DFA_COM:
570 case DFA_RT:
571 #if NSEQUENCER > 0
572 if (sc->seqopen) {
573 extern void midiseq_in(struct midi_dev *,u_char *,int);
574 count = sc->rcv.end - sc->rcv.pos;
575 midiseq_in(sc->seq_md, sc->rcv.pos, count);
576 return;
577 }
578 #endif
579 /*
580 * Pass Active Sense to the sequencer if it's open, but not to
581 * a raw reader. (Really should do something intelligent with
582 * it then, though....)
583 */
584 if ( got == DFA_RT && MIDI_ACK == sc->rcv.pos[0] )
585 return;
586 /* FALLTHROUGH */
587 /*
588 * Ultimately SysEx msgs should be offered to the sequencer also; the
589 * sequencer API addresses them - but maybe our sequencer can't handle
590 * them yet, so offer only to raw reader. (Which means, ultimately,
591 * discard them if the sequencer's open, as it's not doing reads!)
592 */
593 case DFA_SYX:
594 count = sc->rcv.end - sc->rcv.pos;
595 if (mb->used + count > mb->usedhigh) {
596 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
597 sc->rcv.pos[0]));
598 sc->rcv.bytesDiscarded.ev_count += count;
599 return;
600 }
601 for (i = 0; i < count; i++) {
602 *mb->inp++ = sc->rcv.pos[i];
603 if (mb->inp >= mb->end)
604 mb->inp = mb->start;
605 mb->used++;
606 }
607 midi_wakeup(&sc->rchan);
608 selnotify(&sc->rsel, 0);
609 if (sc->async)
610 psignal(sc->async, SIGIO);
611 break;
612 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
613 default:
614 printf("midi_in: midi_dfa returned %d?!\n", got);
615 #endif
616 }
617 }
618
619 void
620 midi_out(void *addr)
621 {
622 struct midi_softc *sc = addr;
623
624 if (!sc->isopen)
625 return;
626 DPRINTFN(8, ("midi_out: %p\n", sc));
627 midi_start_output(sc, 0, 1);
628 }
629
630 int
631 midiopen(dev_t dev, int flags, int ifmt, struct proc *p)
632 {
633 struct midi_softc *sc;
634 struct midi_hw_if *hw;
635 int error;
636
637 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
638 if (sc == NULL)
639 return (ENXIO);
640 if (sc->dying)
641 return (EIO);
642
643 DPRINTFN(3,("midiopen %p\n", sc));
644
645 hw = sc->hw_if;
646 if (!hw)
647 return ENXIO;
648 if (sc->isopen)
649 return EBUSY;
650 sc->rcv.state = MIDI_IN_START;
651 sc->xmt.state = MIDI_IN_START;
652 sc->xmt.pos = sc->xmt.msg;
653 sc->xmt.end = sc->xmt.msg;
654 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
655 if (error)
656 return error;
657 sc->isopen++;
658 midi_initbuf(&sc->outbuf);
659 midi_initbuf(&sc->inbuf);
660 sc->flags = flags;
661 sc->rchan = 0;
662 sc->wchan = 0;
663 sc->pbus = 0;
664 sc->async = 0;
665
666 #ifdef MIDI_SAVE
667 if (midicnt != 0) {
668 midisave.cnt = midicnt;
669 midicnt = 0;
670 }
671 #endif
672
673 return 0;
674 }
675
676 int
677 midiclose(dev_t dev, int flags, int ifmt, struct proc *p)
678 {
679 int unit = MIDIUNIT(dev);
680 struct midi_softc *sc = midi_cd.cd_devs[unit];
681 struct midi_hw_if *hw = sc->hw_if;
682 int s, error;
683
684 DPRINTFN(3,("midiclose %p\n", sc));
685
686 midi_start_output(sc, 1, 0);
687 error = 0;
688 s = splaudio();
689 while (sc->outbuf.used > 0 && !error) {
690 DPRINTFN(8,("midiclose sleep used=%d\n", sc->outbuf.used));
691 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
692 }
693 splx(s);
694 callout_stop(&sc->sc_callout);
695 sc->isopen = 0;
696 hw->close(sc->hw_hdl);
697 #if NSEQUENCER > 0
698 sc->seqopen = 0;
699 sc->seq_md = 0;
700 #endif
701 return 0;
702 }
703
704 int
705 midiread(dev_t dev, struct uio *uio, int ioflag)
706 {
707 int unit = MIDIUNIT(dev);
708 struct midi_softc *sc = midi_cd.cd_devs[unit];
709 struct midi_buffer *mb = &sc->inbuf;
710 int error;
711 u_char *outp;
712 int used, cc, n, resid;
713 int s;
714
715 DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
716 (unsigned long)uio->uio_resid));
717
718 if (sc->dying)
719 return EIO;
720 if ( !(sc->flags & FREAD) )
721 return EBADF;
722 if ( !(sc->props & MIDI_PROP_CAN_INPUT) )
723 return ENXIO;
724
725 error = 0;
726 resid = uio->uio_resid;
727 while (uio->uio_resid == resid && !error) {
728 s = splaudio();
729 while (mb->used <= 0) {
730 if (ioflag & IO_NDELAY) {
731 splx(s);
732 return EWOULDBLOCK;
733 }
734 error = midi_sleep(&sc->rchan, "mid rd");
735 if (error) {
736 splx(s);
737 return error;
738 }
739 }
740 used = mb->used;
741 outp = mb->outp;
742 splx(s);
743 if (sc->dying)
744 return EIO;
745 cc = used; /* maximum to read */
746 n = mb->end - outp;
747 if (n < cc)
748 cc = n; /* don't read beyond end of buffer */
749 if (uio->uio_resid < cc)
750 cc = uio->uio_resid; /* and no more than we want */
751 DPRINTFN(8, ("midiread: uiomove cc=%d\n", cc));
752 error = uiomove(outp, cc, uio);
753 if (error)
754 break;
755 used -= cc;
756 outp += cc;
757 if (outp >= mb->end)
758 outp = mb->start;
759 s = splaudio();
760 mb->outp = outp;
761 mb->used = used;
762 splx(s);
763 }
764 return error;
765 }
766
767 void
768 midi_timeout(void *arg)
769 {
770 struct midi_softc *sc = arg;
771
772 DPRINTFN(8,("midi_timeout: %p\n", sc));
773 midi_start_output(sc, 0, 0);
774 }
775
776 /*
777 * Control can reach midi_start_output three ways:
778 * 1. as a result of user writing (user == 1)
779 * 2. by a ready interrupt from output hw (hw == 1)
780 * 3. by a callout scheduled at the end of midi_start_output.
781 *
782 * The callout is not scheduled unless we are sure the hw will not
783 * interrupt again (either because it just did and we supplied it
784 * no data, or because it lacks interrupt capability). So we do not
785 * expect a hw interrupt to occur with a callout pending.
786 *
787 * A user write may occur while the callout is pending, however, or before
788 * an interrupt-capable device has interrupted. There are two cases:
789 *
790 * 1. A device interrupt is expected, or the pending callout is a MIDI_WAIT
791 * (the brief delay we put in if MIDI_MAX_WRITE characters have been
792 * written without yielding; interrupt-capable hardware can avoid this
793 * penalty by making sure not to use EINPROGRESS to consume MIDI_MAX_WRITE
794 * or more characters at once). In these cases, the user invocation of
795 * start_output returns without action, leaving the output to be resumed
796 * by the device interrupt or by the callout after the proper delay. This
797 * case is identified by sc->pbus == 1.
798 *
799 * 2. The pending callout was scheduled to ensure an Active Sense gets
800 * written if there is no user write in time. In this case the user
801 * invocation (if there is something to write) cancels the pending
802 * callout. However, it may be possible the callout timer expired before
803 * we could cancel it, but the callout hasn't run yet. In this case
804 * (INVOKING status on the callout) the user invocation returns without
805 * further action so the callout can do the work.
806 *
807 * Is it possible that fast interrupt-driven hardware could interrupt while
808 * the start_output that triggered it still holds the lock? In this case we'll
809 * see on unlock that sc->hw_interrupted == 1 and loop around again if there
810 * is more to write.
811 */
812 int
813 midi_start_output(struct midi_softc *sc, int user, int hw)
814 {
815 struct midi_buffer *mb = &sc->outbuf;
816 u_char out;
817 int error;
818 int s;
819 int written;
820 int to_write;
821 u_char *from;
822 u_char *to;
823
824 again:
825 if ( mididebug > 9 ) return EIO;
826 error = 0;
827
828 if (sc->dying)
829 return EIO;
830
831 s = splaudio();
832
833 if ( ! simple_lock_try(&sc->out_lock) ) {
834 if ( hw )
835 sc->hw_interrupted = 1;
836 splx(s);
837 DPRINTFN(8,("midi_start_output: locked out user=%d hw=%d\n",
838 user, hw));
839 return 0;
840 }
841
842 to_write = mb->used;
843
844 if ( user ) {
845 if ( sc->pbus ) {
846 simple_unlock(&sc->out_lock);
847 splx(s);
848 DPRINTFN(8, ("midi_start_output: delaying\n"));
849 return 0;
850 }
851 if ( to_write > 0 ) {
852 callout_stop(&sc->sc_callout);
853 if (callout_invoking(&sc->sc_callout)) {
854 simple_unlock(&sc->out_lock);
855 splx(s);
856 DPRINTFN(8,("midi_start_output: "
857 "callout got away\n"));
858 return 0;
859 }
860 }
861 } else if ( hw )
862 sc->hw_interrupted = 0;
863 else
864 callout_ack(&sc->sc_callout);
865
866 splx(s);
867 /*
868 * As long as we hold the lock, we can rely on mb->outp not changing
869 * and mb->used not decreasing. We only need splaudio to update them.
870 */
871
872 from = mb->outp;
873
874 DPRINTFN(8,("midi_start_output: user=%d hw=%d to_write %u from %p\n",
875 user, hw, to_write, from));
876 sc->pbus = 0;
877
878 written = 0;
879 if ( to_write == 0 && ! user && ! hw ) {
880 error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK);
881 written = 1;
882 }
883
884 do {
885 if ( to_write > MIDI_MAX_WRITE - written )
886 to_write = MIDI_MAX_WRITE - written;
887 if ( to_write == 0 )
888 break;
889 to = from + to_write;
890 if ( to > mb->end )
891 to = mb->end;
892 while ( from < to ) {
893 out = *from++;
894 #ifdef MIDI_SAVE
895 midisave.buf[midicnt] = out;
896 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
897 #endif
898 DPRINTFN(8, ("midi_start_output: %p data=0x%02x\n",
899 sc, out));
900 error = sc->hw_if->output(sc->hw_hdl, out);
901 if ( error == 0 ) {
902 if ( sc->props & MIDI_PROP_OUT_INTR )
903 break;
904 } else if ( ( sc->props & MIDI_PROP_OUT_INTR )
905 && error == EINPROGRESS )
906 continue;
907 else { /* really an error */
908 -- from;
909 break;
910 }
911 }
912 written += from - mb->outp;
913 s = splaudio();
914 mb->used -= from - mb->outp;
915 if ( from == mb->end )
916 from = mb->start;
917 mb->outp = from;
918 splx(s);
919 to_write = mb->used;
920 } while ( error == ( sc->props&MIDI_PROP_OUT_INTR ) ? EINPROGRESS : 0 );
921
922 if ( written > 0 ) {
923 midi_wakeup(&sc->wchan);
924 selnotify(&sc->wsel, 0);
925 if (sc->async)
926 psignal(sc->async, SIGIO);
927 }
928
929 if ( sc->props & MIDI_PROP_OUT_INTR ) {
930 if ( written > 0 && error == 0 ) {
931 sc->pbus = 1;
932 goto unlock_exit;
933 }
934 if ( error == EINPROGRESS )
935 error = 0;
936 }
937
938 if ( error != 0 )
939 goto handle_error;
940
941 if ( to_write == 0 )
942 callout_schedule(&sc->sc_callout, mstohz(285));
943 else {
944 sc->pbus = 1;
945 callout_schedule(&sc->sc_callout, midi_wait);
946 }
947 goto unlock_exit;
948
949 handle_error:
950 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
951 printf("%s: midi_start_output error %d\n",
952 sc->dev.dv_xname, error);
953 #endif
954
955 unlock_exit:
956 simple_unlock(&sc->out_lock);
957 if ( sc->hw_interrupted ) {
958 user = 0;
959 hw = 1;
960 goto again;
961 }
962
963 return error;
964 }
965
966 int
967 midiwrite(dev_t dev, struct uio *uio, int ioflag)
968 {
969 int unit = MIDIUNIT(dev);
970 struct midi_softc *sc = midi_cd.cd_devs[unit];
971 struct midi_buffer *mb = &sc->outbuf;
972 int error;
973 u_char *inp;
974 int used, cc, n;
975 int s;
976
977 DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit,
978 (unsigned long)uio->uio_resid));
979
980 if (sc->dying)
981 return EIO;
982 if ( !(sc->flags & FWRITE) )
983 return EBADF;
984
985 error = 0;
986 while (uio->uio_resid > 0 && !error) {
987 s = splaudio();
988 if (mb->used >= mb->usedhigh) {
989 DPRINTFN(8,("midi_write: sleep used=%d hiwat=%d\n",
990 mb->used, mb->usedhigh));
991 if (ioflag & IO_NDELAY) {
992 splx(s);
993 return EWOULDBLOCK;
994 }
995 error = midi_sleep(&sc->wchan, "mid wr");
996 if (error) {
997 splx(s);
998 return error;
999 }
1000 }
1001 used = mb->used;
1002 inp = mb->inp;
1003 splx(s);
1004 if (sc->dying)
1005 return EIO;
1006 cc = mb->usedhigh - used; /* maximum to write */
1007 n = mb->end - inp;
1008 if (n < cc)
1009 cc = n; /* don't write beyond end of buffer */
1010 if (uio->uio_resid < cc)
1011 cc = uio->uio_resid; /* and no more than we have */
1012 error = uiomove(inp, cc, uio);
1013 #ifdef MIDI_DEBUG
1014 if (error)
1015 printf("midi_write:(1) uiomove failed %d; "
1016 "cc=%d inp=%p\n",
1017 error, cc, inp);
1018 #endif
1019 if (error)
1020 break;
1021 inp = mb->inp + cc;
1022 if (inp >= mb->end)
1023 inp = mb->start;
1024 s = splaudio();
1025 mb->inp = inp;
1026 mb->used += cc;
1027 splx(s);
1028 error = midi_start_output(sc, 1, 0);
1029 }
1030 return error;
1031 }
1032
1033 /*
1034 * This write routine is only called from sequencer code and expects
1035 * a write that is smaller than the MIDI buffer.
1036 */
1037 int
1038 midi_writebytes(int unit, u_char *buf, int cc)
1039 {
1040 struct midi_softc *sc = midi_cd.cd_devs[unit];
1041 struct midi_buffer *mb = &sc->outbuf;
1042 int n, s;
1043
1044 DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
1045 sc, unit, cc, buf[0], buf[1], buf[2]));
1046
1047 if (sc->dying)
1048 return EIO;
1049
1050 s = splaudio();
1051 if (mb->used + cc >= mb->usedhigh) {
1052 splx(s);
1053 return (EWOULDBLOCK);
1054 }
1055 n = mb->end - mb->inp;
1056 if (cc < n)
1057 n = cc;
1058 mb->used += cc;
1059 memcpy(mb->inp, buf, n);
1060 mb->inp += n;
1061 if (mb->inp >= mb->end) {
1062 mb->inp = mb->start;
1063 cc -= n;
1064 if (cc > 0) {
1065 memcpy(mb->inp, buf + n, cc);
1066 mb->inp += cc;
1067 }
1068 }
1069 splx(s);
1070 return (midi_start_output(sc, 1, 0));
1071 }
1072
1073 int
1074 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1075 {
1076 int unit = MIDIUNIT(dev);
1077 struct midi_softc *sc = midi_cd.cd_devs[unit];
1078 struct midi_hw_if *hw = sc->hw_if;
1079 int error;
1080
1081 DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
1082
1083 if (sc->dying)
1084 return EIO;
1085
1086 error = 0;
1087 switch (cmd) {
1088 case FIONBIO:
1089 /* All handled in the upper FS layer. */
1090 break;
1091
1092 case FIOASYNC:
1093 if (*(int *)addr) {
1094 if (sc->async)
1095 return EBUSY;
1096 sc->async = p;
1097 DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", p));
1098 } else
1099 sc->async = 0;
1100 break;
1101
1102 #if 0
1103 case MIDI_PRETIME:
1104 /* XXX OSS
1105 * This should set up a read timeout, but that's
1106 * why we have poll(), so there's nothing yet. */
1107 error = EINVAL;
1108 break;
1109 #endif
1110
1111 #ifdef MIDI_SAVE
1112 case MIDI_GETSAVE:
1113 error = copyout(&midisave, *(void **)addr, sizeof midisave);
1114 break;
1115 #endif
1116
1117 default:
1118 if (hw->ioctl)
1119 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
1120 else
1121 error = EINVAL;
1122 break;
1123 }
1124 return error;
1125 }
1126
1127 int
1128 midipoll(dev_t dev, int events, struct proc *p)
1129 {
1130 int unit = MIDIUNIT(dev);
1131 struct midi_softc *sc = midi_cd.cd_devs[unit];
1132 int revents = 0;
1133 int s;
1134
1135 DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
1136
1137 if (sc->dying)
1138 return EIO;
1139
1140 s = splaudio();
1141
1142 if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM)))
1143 if (sc->inbuf.used > 0)
1144 revents |= events & (POLLIN | POLLRDNORM);
1145
1146 if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM)))
1147 if (sc->outbuf.used < sc->outbuf.usedhigh)
1148 revents |= events & (POLLOUT | POLLWRNORM);
1149
1150 if (revents == 0) {
1151 if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM)))
1152 selrecord(p, &sc->rsel);
1153
1154 if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM)))
1155 selrecord(p, &sc->wsel);
1156 }
1157
1158 splx(s);
1159 return revents;
1160 }
1161
1162 static void
1163 filt_midirdetach(struct knote *kn)
1164 {
1165 struct midi_softc *sc = kn->kn_hook;
1166 int s;
1167
1168 s = splaudio();
1169 SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
1170 splx(s);
1171 }
1172
1173 static int
1174 filt_midiread(struct knote *kn, long hint)
1175 {
1176 struct midi_softc *sc = kn->kn_hook;
1177
1178 /* XXXLUKEM (thorpej): please make sure this is correct. */
1179
1180 kn->kn_data = sc->inbuf.used;
1181 return (kn->kn_data > 0);
1182 }
1183
1184 static const struct filterops midiread_filtops =
1185 { 1, NULL, filt_midirdetach, filt_midiread };
1186
1187 static void
1188 filt_midiwdetach(struct knote *kn)
1189 {
1190 struct midi_softc *sc = kn->kn_hook;
1191 int s;
1192
1193 s = splaudio();
1194 SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
1195 splx(s);
1196 }
1197
1198 static int
1199 filt_midiwrite(struct knote *kn, long hint)
1200 {
1201 struct midi_softc *sc = kn->kn_hook;
1202
1203 /* XXXLUKEM (thorpej): please make sure this is correct. */
1204
1205 kn->kn_data = sc->outbuf.usedhigh - sc->outbuf.used;
1206 return (kn->kn_data > 0);
1207 }
1208
1209 static const struct filterops midiwrite_filtops =
1210 { 1, NULL, filt_midiwdetach, filt_midiwrite };
1211
1212 int
1213 midikqfilter(dev_t dev, struct knote *kn)
1214 {
1215 int unit = MIDIUNIT(dev);
1216 struct midi_softc *sc = midi_cd.cd_devs[unit];
1217 struct klist *klist;
1218 int s;
1219
1220 switch (kn->kn_filter) {
1221 case EVFILT_READ:
1222 klist = &sc->rsel.sel_klist;
1223 kn->kn_fop = &midiread_filtops;
1224 break;
1225
1226 case EVFILT_WRITE:
1227 klist = &sc->wsel.sel_klist;
1228 kn->kn_fop = &midiwrite_filtops;
1229 break;
1230
1231 default:
1232 return (1);
1233 }
1234
1235 kn->kn_hook = sc;
1236
1237 s = splaudio();
1238 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1239 splx(s);
1240
1241 return (0);
1242 }
1243
1244 void
1245 midi_getinfo(dev_t dev, struct midi_info *mi)
1246 {
1247 struct midi_softc *sc;
1248
1249 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
1250 if (sc == NULL)
1251 return;
1252 if (sc->dying)
1253 return;
1254
1255 sc->hw_if->getinfo(sc->hw_hdl, mi);
1256 }
1257
1258 #endif /* NMIDI > 0 */
1259
1260 #if NMIDI > 0 || NMIDIBUS > 0
1261
1262 int audioprint(void *, const char *);
1263
1264 struct device *
1265 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev)
1266 {
1267 struct audio_attach_args arg;
1268
1269 #ifdef DIAGNOSTIC
1270 if (mhwp == NULL) {
1271 aprint_error("midi_attach_mi: NULL\n");
1272 return (0);
1273 }
1274 #endif
1275 arg.type = AUDIODEV_TYPE_MIDI;
1276 arg.hwif = mhwp;
1277 arg.hdl = hdlp;
1278 return (config_found(dev, &arg, audioprint));
1279 }
1280
1281 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
1282