midi.c revision 1.43.2.3 1 /* $NetBSD: midi.c,v 1.43.2.3 2006/05/20 03:13:11 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).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.43.2.3 2006/05/20 03:13:11 chap Exp $");
41
42 #include "midi.h"
43 #include "sequencer.h"
44
45 #include <sys/param.h>
46 #include <sys/ioctl.h>
47 #include <sys/fcntl.h>
48 #include <sys/vnode.h>
49 #include <sys/select.h>
50 #include <sys/poll.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/systm.h>
54 #include <sys/callout.h>
55 #include <sys/syslog.h>
56 #include <sys/kernel.h>
57 #include <sys/signalvar.h>
58 #include <sys/conf.h>
59 #include <sys/audioio.h>
60 #include <sys/midiio.h>
61 #include <sys/device.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 #ifdef AUDIO_DEBUG
70 #define DPRINTF(x) if (mididebug) printf x
71 #define DPRINTFN(n,x) if (mididebug >= (n)) printf x
72 int mididebug = 0;
73 /*
74 * 1: detected protocol errors and buffer overflows
75 * 2: probe, attach, detach
76 * 3: open, close
77 * 4: data received except realtime
78 * 5: ioctl
79 * 6: read, write, poll
80 * 7: data transmitted
81 * 8: uiomoves, synchronization
82 * 9: realtime data received
83 */
84 #else
85 #define DPRINTF(x)
86 #define DPRINTFN(n,x)
87 #endif
88
89 int midi_wait;
90
91 void midi_in(void *, int);
92 void midi_out(void *);
93 int midi_start_output(struct midi_softc *, int);
94 int midi_sleep_timo(int *, char *, int);
95 int midi_sleep(int *, char *);
96 void midi_wakeup(int *);
97 void midi_initbuf(struct midi_buffer *);
98 void midi_timeout(void *);
99
100 int midiprobe(struct device *, struct cfdata *, void *);
101 void midiattach(struct device *, struct device *, void *);
102 int mididetach(struct device *, int);
103 int midiactivate(struct device *, enum devact);
104
105 dev_type_open(midiopen);
106 dev_type_close(midiclose);
107 dev_type_read(midiread);
108 dev_type_write(midiwrite);
109 dev_type_ioctl(midiioctl);
110 dev_type_poll(midipoll);
111 dev_type_kqfilter(midikqfilter);
112
113 const struct cdevsw midi_cdevsw = {
114 midiopen, midiclose, midiread, midiwrite, midiioctl,
115 nostop, notty, midipoll, nommap, midikqfilter,
116 };
117
118 CFATTACH_DECL(midi, sizeof(struct midi_softc),
119 midiprobe, midiattach, mididetach, midiactivate);
120
121 #ifdef MIDI_SAVE
122 #define MIDI_SAVE_SIZE 100000
123 int midicnt;
124 struct {
125 int cnt;
126 u_char buf[MIDI_SAVE_SIZE];
127 } midisave;
128 #define MIDI_GETSAVE _IOWR('m', 100, int)
129
130 #endif
131
132 extern struct cfdriver midi_cd;
133
134 int
135 midiprobe(struct device *parent, struct cfdata *match, void *aux)
136 {
137 struct audio_attach_args *sa = aux;
138
139 DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n",
140 sa->type, sa, sa->hwif));
141 return (sa->type == AUDIODEV_TYPE_MIDI);
142 }
143
144 void
145 midiattach(struct device *parent, struct device *self, void *aux)
146 {
147 struct midi_softc *sc = (void *)self;
148 struct audio_attach_args *sa = aux;
149 struct midi_hw_if *hwp = sa->hwif;
150 void *hdlp = sa->hdl;
151
152 DPRINTFN(2, ("MIDI attach\n"));
153
154 #ifdef DIAGNOSTIC
155 if (hwp == 0 ||
156 hwp->open == 0 ||
157 hwp->close == 0 ||
158 hwp->output == 0 ||
159 hwp->getinfo == 0) {
160 printf("midi: missing method\n");
161 return;
162 }
163 #endif
164
165 callout_init(&sc->sc_callout);
166
167 sc->hw_if = hwp;
168 sc->hw_hdl = hdlp;
169 sc->dying = 0;
170 midi_attach(sc, parent);
171 }
172
173 int
174 midiactivate(struct device *self, enum devact act)
175 {
176 struct midi_softc *sc = (struct midi_softc *)self;
177
178 switch (act) {
179 case DVACT_ACTIVATE:
180 return (EOPNOTSUPP);
181
182 case DVACT_DEACTIVATE:
183 sc->dying = 1;
184 break;
185 }
186 return (0);
187 }
188
189 int
190 mididetach(struct device *self, int flags)
191 {
192 struct midi_softc *sc = (struct midi_softc *)self;
193 int maj, mn;
194
195 DPRINTFN(2,("midi_detach: sc=%p flags=%d\n", sc, flags));
196
197 sc->dying = 1;
198
199 wakeup(&sc->wchan);
200 wakeup(&sc->rchan);
201
202 /* locate the major number */
203 maj = cdevsw_lookup_major(&midi_cdevsw);
204
205 /* Nuke the vnodes for any open instances (calls close). */
206 mn = self->dv_unit;
207 vdevgone(maj, mn, mn, VCHR);
208
209 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
210 evcnt_detach(&sc->rcvBytesDiscarded);
211 evcnt_detach(&sc->rcvIncompleteMessages);
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 sc->isopen = 0;
223
224 midi_wait = MIDI_WAIT * hz / 1000000;
225 if (midi_wait == 0)
226 midi_wait = 1;
227
228 sc->sc_dev = parent;
229 sc->hw_if->getinfo(sc->hw_hdl, &mi);
230 sc->props = mi.props;
231
232 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
233 evcnt_attach_dynamic(&sc->rcvBytesDiscarded,
234 EVCNT_TYPE_MISC, NULL,
235 sc->dev.dv_xname, "rcv bytes discarded");
236 evcnt_attach_dynamic(&sc->rcvIncompleteMessages,
237 EVCNT_TYPE_MISC, NULL,
238 sc->dev.dv_xname, "rcv incomplete msgs");
239 }
240
241 printf(": %s\n", mi.name);
242 }
243
244 int
245 midi_unit_count(void)
246 {
247 int i;
248 for ( i = 0; i < midi_cd.cd_ndevs; ++i )
249 if ( NULL == midi_cd.cd_devs[i] )
250 break;
251 return i;
252 }
253
254 void
255 midi_initbuf(struct midi_buffer *mb)
256 {
257 mb->used = 0;
258 mb->usedhigh = MIDI_BUFSIZE;
259 mb->end = mb->start + mb->usedhigh;
260 mb->inp = mb->outp = mb->start;
261 }
262
263 int
264 midi_sleep_timo(int *chan, char *label, int timo)
265 {
266 int st;
267
268 if (!label)
269 label = "midi";
270
271 DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
272 *chan = 1;
273 st = tsleep(chan, PWAIT | PCATCH, label, timo);
274 *chan = 0;
275 #ifdef MIDI_DEBUG
276 if (st != 0)
277 printf("midi_sleep: %d\n", st);
278 #endif
279 return st;
280 }
281
282 int
283 midi_sleep(int *chan, char *label)
284 {
285 return midi_sleep_timo(chan, label, 0);
286 }
287
288 void
289 midi_wakeup(int *chan)
290 {
291 if (*chan) {
292 DPRINTFN(8, ("midi_wakeup: %p\n", chan));
293 wakeup(chan);
294 *chan = 0;
295 }
296 }
297
298 /* in midivar.h:
299 #define MIDI_CAT_DATA 0
300 #define MIDI_CAT_STATUS1 1
301 #define MIDI_CAT_STATUS2 2
302 #define MIDI_CAT_COMMON 3
303 */
304 static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
305 #define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
306
307 void
308 midi_in(void *addr, int data)
309 {
310 struct midi_softc *sc = addr;
311 struct midi_buffer *mb = &sc->inbuf;
312 int i;
313 u_char *what = sc->in_msg;
314 u_char rtbuf;
315 int count;
316
317 if (!sc->isopen)
318 return;
319
320 if (!(sc->flags & FREAD))
321 return; /* discard data if not reading */
322
323 if ( data >= 0xf8 ) { /* All realtime messages bypass state machine */
324 if ( data == 0xf9 || data == 0xfd ) {
325 DPRINTF( ("midi_in: sc=%p data=0x%02x undefined\n",
326 sc, data));
327 sc->rcvBytesDiscarded.ev_count++;
328 return;
329 }
330 DPRINTFN(9, ("midi_in: sc=%p System Real-Time data=0x%02x\n",
331 sc, data));
332 rtbuf = data;
333 count = sizeof rtbuf;
334 what = &rtbuf;
335 goto deliver;
336 }
337
338 DPRINTFN(4, ("midi_in: sc=%p data=0x%02x state=%d\n",
339 sc, data, sc->in_state));
340
341 retry:
342 switch ( sc->in_state | MIDI_CAT(data) ) {
343
344 case MIDI_IN_START | MIDI_CAT_COMMON:
345 case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
346 case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
347 sc->in_msg[0] = data;
348 count = 1;
349 switch ( data ) {
350 case 0xf0: sc->in_state = MIDI_IN_SYSEX; goto deliver_raw;
351 case 0xf1: sc->in_state = MIDI_IN_COM0_1; return;
352 case 0xf2: sc->in_state = MIDI_IN_COM0_2; return;
353 case 0xf3: sc->in_state = MIDI_IN_COM0_1; return;
354 case 0xf6: sc->in_state = MIDI_IN_START; break;
355 default: goto protocol_violation;
356 }
357 break;
358
359 case MIDI_IN_START | MIDI_CAT_STATUS1:
360 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
361 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1:
362 sc->in_state = MIDI_IN_RUN0_1;
363 sc->in_msg[0] = data;
364 return;
365
366 case MIDI_IN_START | MIDI_CAT_STATUS2:
367 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2:
368 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
369 sc->in_state = MIDI_IN_RUN0_2;
370 sc->in_msg[0] = data;
371 return;
372
373 case MIDI_IN_COM0_1 | MIDI_CAT_DATA:
374 sc->in_state = MIDI_IN_START;
375 sc->in_msg[1] = data;
376 count = 2;
377 break;
378
379 case MIDI_IN_COM0_2 | MIDI_CAT_DATA:
380 sc->in_state = MIDI_IN_COM1_2;
381 sc->in_msg[1] = data;
382 return;
383
384 case MIDI_IN_COM1_2 | MIDI_CAT_DATA:
385 sc->in_state = MIDI_IN_START;
386 sc->in_msg[2] = data;
387 count = 3;
388 break;
389
390 case MIDI_IN_RUN0_1 | MIDI_CAT_DATA:
391 case MIDI_IN_RUN1_1 | MIDI_CAT_DATA:
392 sc->in_state = MIDI_IN_RUN1_1;
393 sc->in_msg[1] = data;
394 count = 2;
395 break;
396
397 case MIDI_IN_RUN0_2 | MIDI_CAT_DATA:
398 case MIDI_IN_RUN2_2 | MIDI_CAT_DATA:
399 sc->in_state = MIDI_IN_RUN1_2;
400 sc->in_msg[1] = data;
401 return;
402
403 case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
404 sc->in_state = MIDI_IN_RUN2_2;
405 sc->in_msg[2] = data;
406 count = 3;
407 break;
408
409 case MIDI_IN_SYSEX | MIDI_CAT_DATA:
410 sc->in_msg[0] = data;
411 count = 1;
412 goto deliver_raw;
413
414 case MIDI_IN_SYSEX | MIDI_CAT_COMMON:
415 if ( data == 0xf7 ) {
416 sc->in_state = MIDI_IN_START;
417 sc->in_msg[0] = data;
418 count = 1;
419 goto deliver_raw;
420 }
421 /* FALLTHROUGH */
422
423 default:
424 protocol_violation:
425 DPRINTF(("midi_in: unexpected %#02x in state %u\n",
426 data, sc->in_state));
427 switch ( sc->in_state ) {
428 case MIDI_IN_RUN1_1: /* can only get here by seeing an */
429 case MIDI_IN_RUN2_2: /* INVALID System Common message */
430 sc->in_state = MIDI_IN_START;
431 /* FALLTHROUGH */
432 case MIDI_IN_START:
433 sc->rcvBytesDiscarded.ev_count++;
434 return;
435 case MIDI_IN_COM1_2:
436 case MIDI_IN_RUN1_2:
437 sc->rcvBytesDiscarded.ev_count++;
438 /* FALLTHROUGH */
439 case MIDI_IN_COM0_1:
440 case MIDI_IN_RUN0_1:
441 case MIDI_IN_COM0_2:
442 case MIDI_IN_RUN0_2:
443 sc->rcvBytesDiscarded.ev_count++;
444 /* FALLTHROUGH */
445 case MIDI_IN_SYSEX:
446 sc->rcvIncompleteMessages.ev_count++;
447 break;
448 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
449 default:
450 printf("midi_in: mishandled %#02x(%u) in state %u?!\n",
451 data, MIDI_CAT(data), sc->in_state);
452 #endif
453 }
454 sc->in_state = MIDI_IN_START;
455 goto retry;
456 }
457
458 deliver:
459 #if NSEQUENCER > 0
460 if (sc->seqopen) {
461 extern void midiseq_in(struct midi_dev *,u_char *,int);
462 midiseq_in(sc->seq_md, what, count);
463 return;
464 }
465 #endif
466 if ( data == MIDI_ACK ) /* sequencer should see these to support API */
467 return; /* otherwise discard (could track time last seen) */
468 deliver_raw:
469 if (mb->used + count > mb->usedhigh) {
470 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
471 what[0]));
472 sc->rcvBytesDiscarded.ev_count += count;
473 return;
474 }
475 for (i = 0; i < count; i++) {
476 *mb->inp++ = what[i];
477 if (mb->inp >= mb->end)
478 mb->inp = mb->start;
479 mb->used++;
480 }
481 midi_wakeup(&sc->rchan);
482 selnotify(&sc->rsel, 0);
483 if (sc->async)
484 psignal(sc->async, SIGIO);
485 }
486
487 void
488 midi_out(void *addr)
489 {
490 struct midi_softc *sc = addr;
491
492 if (!sc->isopen)
493 return;
494 DPRINTFN(8, ("midi_out: %p\n", sc));
495 midi_start_output(sc, 1);
496 }
497
498 int
499 midiopen(dev_t dev, int flags, int ifmt, struct proc *p)
500 {
501 struct midi_softc *sc;
502 struct midi_hw_if *hw;
503 int error;
504
505 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
506 if (sc == NULL)
507 return (ENXIO);
508 if (sc->dying)
509 return (EIO);
510
511 DPRINTFN(3,("midiopen %p\n", sc));
512
513 hw = sc->hw_if;
514 if (!hw)
515 return ENXIO;
516 if (sc->isopen)
517 return EBUSY;
518 sc->in_state = MIDI_IN_START;
519 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
520 if (error)
521 return error;
522 sc->isopen++;
523 midi_initbuf(&sc->outbuf);
524 midi_initbuf(&sc->inbuf);
525 sc->flags = flags;
526 sc->rchan = 0;
527 sc->wchan = 0;
528 sc->pbus = 0;
529 sc->async = 0;
530
531 #ifdef MIDI_SAVE
532 if (midicnt != 0) {
533 midisave.cnt = midicnt;
534 midicnt = 0;
535 }
536 #endif
537
538 return 0;
539 }
540
541 int
542 midiclose(dev_t dev, int flags, int ifmt, struct proc *p)
543 {
544 int unit = MIDIUNIT(dev);
545 struct midi_softc *sc = midi_cd.cd_devs[unit];
546 struct midi_hw_if *hw = sc->hw_if;
547 int s, error;
548
549 DPRINTFN(3,("midiclose %p\n", sc));
550
551 midi_start_output(sc, 0);
552 error = 0;
553 s = splaudio();
554 while (sc->outbuf.used > 0 && !error) {
555 DPRINTFN(8,("midiclose sleep used=%d\n", sc->outbuf.used));
556 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
557 }
558 splx(s);
559 sc->isopen = 0;
560 hw->close(sc->hw_hdl);
561 #if NSEQUENCER > 0
562 sc->seqopen = 0;
563 sc->seq_md = 0;
564 #endif
565 return 0;
566 }
567
568 int
569 midiread(dev_t dev, struct uio *uio, int ioflag)
570 {
571 int unit = MIDIUNIT(dev);
572 struct midi_softc *sc = midi_cd.cd_devs[unit];
573 struct midi_buffer *mb = &sc->inbuf;
574 int error;
575 u_char *outp;
576 int used, cc, n, resid;
577 int s;
578
579 DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
580 (unsigned long)uio->uio_resid));
581
582 if (sc->dying)
583 return EIO;
584
585 error = 0;
586 resid = uio->uio_resid;
587 while (uio->uio_resid == resid && !error) {
588 s = splaudio();
589 while (mb->used <= 0) {
590 if (ioflag & IO_NDELAY) {
591 splx(s);
592 return EWOULDBLOCK;
593 }
594 error = midi_sleep(&sc->rchan, "mid rd");
595 if (error) {
596 splx(s);
597 return error;
598 }
599 }
600 used = mb->used;
601 outp = mb->outp;
602 splx(s);
603 if (sc->dying)
604 return EIO;
605 cc = used; /* maximum to read */
606 n = mb->end - outp;
607 if (n < cc)
608 cc = n; /* don't read beyond end of buffer */
609 if (uio->uio_resid < cc)
610 cc = uio->uio_resid; /* and no more than we want */
611 DPRINTFN(8, ("midiread: uiomove cc=%d\n", cc));
612 error = uiomove(outp, cc, uio);
613 if (error)
614 break;
615 used -= cc;
616 outp += cc;
617 if (outp >= mb->end)
618 outp = mb->start;
619 s = splaudio();
620 mb->outp = outp;
621 mb->used = used;
622 splx(s);
623 }
624 return error;
625 }
626
627 void
628 midi_timeout(void *arg)
629 {
630 struct midi_softc *sc = arg;
631
632 DPRINTFN(8,("midi_timeout: %p\n", sc));
633 midi_start_output(sc, 1);
634 }
635
636 int
637 midi_start_output(struct midi_softc *sc, int intr)
638 {
639 struct midi_buffer *mb = &sc->outbuf;
640 u_char out;
641 int error;
642 int s;
643 int i;
644
645 error = 0;
646
647 if (sc->dying)
648 return EIO;
649
650 if (sc->pbus && !intr) {
651 DPRINTFN(8, ("midi_start_output: busy\n"));
652 return 0;
653 }
654 sc->pbus = (mb->used > 0)?1:0;
655 for (i = 0; i < MIDI_MAX_WRITE && mb->used > 0 &&
656 (!error || error==EINPROGRESS); i++) {
657 s = splaudio();
658 out = *mb->outp;
659 mb->outp++;
660 if (mb->outp >= mb->end)
661 mb->outp = mb->start;
662 mb->used--;
663 splx(s);
664 #ifdef MIDI_SAVE
665 midisave.buf[midicnt] = out;
666 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
667 #endif
668 DPRINTFN(8, ("midi_start_output: %p i=%d, data=0x%02x\n",
669 sc, i, out));
670 error = sc->hw_if->output(sc->hw_hdl, out);
671 if ((sc->props & MIDI_PROP_OUT_INTR) && error!=EINPROGRESS)
672 /* If ointr is enabled, midi_start_output()
673 * normally writes only one byte,
674 * except hw_if->output() returns EINPROGRESS.
675 */
676 break;
677 }
678 midi_wakeup(&sc->wchan);
679 selnotify(&sc->wsel, 0);
680 if (sc->async)
681 psignal(sc->async, SIGIO);
682 if (!(sc->props & MIDI_PROP_OUT_INTR) || error==EINPROGRESS) {
683 if (mb->used > 0)
684 callout_reset(&sc->sc_callout, midi_wait,
685 midi_timeout, sc);
686 else
687 sc->pbus = 0;
688 }
689 if ((sc->props & MIDI_PROP_OUT_INTR) && error==EINPROGRESS)
690 error = 0;
691
692 return error;
693 }
694
695 int
696 midiwrite(dev_t dev, struct uio *uio, int ioflag)
697 {
698 int unit = MIDIUNIT(dev);
699 struct midi_softc *sc = midi_cd.cd_devs[unit];
700 struct midi_buffer *mb = &sc->outbuf;
701 int error;
702 u_char *inp;
703 int used, cc, n;
704 int s;
705
706 DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit,
707 (unsigned long)uio->uio_resid));
708
709 if (sc->dying)
710 return EIO;
711
712 error = 0;
713 while (uio->uio_resid > 0 && !error) {
714 s = splaudio();
715 if (mb->used >= mb->usedhigh) {
716 DPRINTFN(8,("midi_write: sleep used=%d hiwat=%d\n",
717 mb->used, mb->usedhigh));
718 if (ioflag & IO_NDELAY) {
719 splx(s);
720 return EWOULDBLOCK;
721 }
722 error = midi_sleep(&sc->wchan, "mid wr");
723 if (error) {
724 splx(s);
725 return error;
726 }
727 }
728 used = mb->used;
729 inp = mb->inp;
730 splx(s);
731 if (sc->dying)
732 return EIO;
733 cc = mb->usedhigh - used; /* maximum to write */
734 n = mb->end - inp;
735 if (n < cc)
736 cc = n; /* don't write beyond end of buffer */
737 if (uio->uio_resid < cc)
738 cc = uio->uio_resid; /* and no more than we have */
739 error = uiomove(inp, cc, uio);
740 #ifdef MIDI_DEBUG
741 if (error)
742 printf("midi_write:(1) uiomove failed %d; "
743 "cc=%d inp=%p\n",
744 error, cc, inp);
745 #endif
746 if (error)
747 break;
748 inp = mb->inp + cc;
749 if (inp >= mb->end)
750 inp = mb->start;
751 s = splaudio();
752 mb->inp = inp;
753 mb->used += cc;
754 splx(s);
755 error = midi_start_output(sc, 0);
756 }
757 return error;
758 }
759
760 /*
761 * This write routine is only called from sequencer code and expects
762 * a write that is smaller than the MIDI buffer.
763 */
764 int
765 midi_writebytes(int unit, u_char *buf, int cc)
766 {
767 struct midi_softc *sc = midi_cd.cd_devs[unit];
768 struct midi_buffer *mb = &sc->outbuf;
769 int n, s;
770
771 DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
772 sc, unit, cc, buf[0], buf[1], buf[2]));
773
774 if (sc->dying)
775 return EIO;
776
777 s = splaudio();
778 if (mb->used + cc >= mb->usedhigh) {
779 splx(s);
780 return (EWOULDBLOCK);
781 }
782 n = mb->end - mb->inp;
783 if (cc < n)
784 n = cc;
785 mb->used += cc;
786 memcpy(mb->inp, buf, n);
787 mb->inp += n;
788 if (mb->inp >= mb->end) {
789 mb->inp = mb->start;
790 cc -= n;
791 if (cc > 0) {
792 memcpy(mb->inp, buf + n, cc);
793 mb->inp += cc;
794 }
795 }
796 splx(s);
797 return (midi_start_output(sc, 0));
798 }
799
800 int
801 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
802 {
803 int unit = MIDIUNIT(dev);
804 struct midi_softc *sc = midi_cd.cd_devs[unit];
805 struct midi_hw_if *hw = sc->hw_if;
806 int error;
807
808 DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
809
810 if (sc->dying)
811 return EIO;
812
813 error = 0;
814 switch (cmd) {
815 case FIONBIO:
816 /* All handled in the upper FS layer. */
817 break;
818
819 case FIOASYNC:
820 if (*(int *)addr) {
821 if (sc->async)
822 return EBUSY;
823 sc->async = p;
824 DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", p));
825 } else
826 sc->async = 0;
827 break;
828
829 #if 0
830 case MIDI_PRETIME:
831 /* XXX OSS
832 * This should set up a read timeout, but that's
833 * why we have poll(), so there's nothing yet. */
834 error = EINVAL;
835 break;
836 #endif
837
838 #ifdef MIDI_SAVE
839 case MIDI_GETSAVE:
840 error = copyout(&midisave, *(void **)addr, sizeof midisave);
841 break;
842 #endif
843
844 default:
845 if (hw->ioctl)
846 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
847 else
848 error = EINVAL;
849 break;
850 }
851 return error;
852 }
853
854 int
855 midipoll(dev_t dev, int events, struct proc *p)
856 {
857 int unit = MIDIUNIT(dev);
858 struct midi_softc *sc = midi_cd.cd_devs[unit];
859 int revents = 0;
860 int s;
861
862 DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
863
864 if (sc->dying)
865 return EIO;
866
867 s = splaudio();
868
869 if (events & (POLLIN | POLLRDNORM))
870 if (sc->inbuf.used > 0)
871 revents |= events & (POLLIN | POLLRDNORM);
872
873 if (events & (POLLOUT | POLLWRNORM))
874 if (sc->outbuf.used < sc->outbuf.usedhigh)
875 revents |= events & (POLLOUT | POLLWRNORM);
876
877 if (revents == 0) {
878 if (events & (POLLIN | POLLRDNORM))
879 selrecord(p, &sc->rsel);
880
881 if (events & (POLLOUT | POLLWRNORM))
882 selrecord(p, &sc->wsel);
883 }
884
885 splx(s);
886 return revents;
887 }
888
889 static void
890 filt_midirdetach(struct knote *kn)
891 {
892 struct midi_softc *sc = kn->kn_hook;
893 int s;
894
895 s = splaudio();
896 SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
897 splx(s);
898 }
899
900 static int
901 filt_midiread(struct knote *kn, long hint)
902 {
903 struct midi_softc *sc = kn->kn_hook;
904
905 /* XXXLUKEM (thorpej): please make sure this is correct. */
906
907 kn->kn_data = sc->inbuf.used;
908 return (kn->kn_data > 0);
909 }
910
911 static const struct filterops midiread_filtops =
912 { 1, NULL, filt_midirdetach, filt_midiread };
913
914 static void
915 filt_midiwdetach(struct knote *kn)
916 {
917 struct midi_softc *sc = kn->kn_hook;
918 int s;
919
920 s = splaudio();
921 SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
922 splx(s);
923 }
924
925 static int
926 filt_midiwrite(struct knote *kn, long hint)
927 {
928 struct midi_softc *sc = kn->kn_hook;
929
930 /* XXXLUKEM (thorpej): please make sure this is correct. */
931
932 kn->kn_data = sc->outbuf.usedhigh - sc->outbuf.used;
933 return (kn->kn_data > 0);
934 }
935
936 static const struct filterops midiwrite_filtops =
937 { 1, NULL, filt_midiwdetach, filt_midiwrite };
938
939 int
940 midikqfilter(dev_t dev, struct knote *kn)
941 {
942 int unit = MIDIUNIT(dev);
943 struct midi_softc *sc = midi_cd.cd_devs[unit];
944 struct klist *klist;
945 int s;
946
947 switch (kn->kn_filter) {
948 case EVFILT_READ:
949 klist = &sc->rsel.sel_klist;
950 kn->kn_fop = &midiread_filtops;
951 break;
952
953 case EVFILT_WRITE:
954 klist = &sc->wsel.sel_klist;
955 kn->kn_fop = &midiwrite_filtops;
956 break;
957
958 default:
959 return (1);
960 }
961
962 kn->kn_hook = sc;
963
964 s = splaudio();
965 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
966 splx(s);
967
968 return (0);
969 }
970
971 void
972 midi_getinfo(dev_t dev, struct midi_info *mi)
973 {
974 struct midi_softc *sc;
975
976 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
977 if (sc == NULL)
978 return;
979 if (sc->dying)
980 return;
981
982 sc->hw_if->getinfo(sc->hw_hdl, mi);
983 }
984
985 #endif /* NMIDI > 0 */
986
987 #if NMIDI > 0 || NMIDIBUS > 0
988
989 int audioprint(void *, const char *);
990
991 struct device *
992 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev)
993 {
994 struct audio_attach_args arg;
995
996 #ifdef DIAGNOSTIC
997 if (mhwp == NULL) {
998 aprint_error("midi_attach_mi: NULL\n");
999 return (0);
1000 }
1001 #endif
1002 arg.type = AUDIODEV_TYPE_MIDI;
1003 arg.hwif = mhwp;
1004 arg.hdl = hdlp;
1005 return (config_found(dev, &arg, audioprint));
1006 }
1007
1008 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
1009