midi.c revision 1.43.2.2 1 /* $NetBSD: midi.c,v 1.43.2.2 2006/05/20 03:09:12 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.2 2006/05/20 03:09:12 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 return (0);
210 }
211
212 void
213 midi_attach(struct midi_softc *sc, struct device *parent)
214 {
215 struct midi_info mi;
216
217 sc->isopen = 0;
218
219 midi_wait = MIDI_WAIT * hz / 1000000;
220 if (midi_wait == 0)
221 midi_wait = 1;
222
223 sc->sc_dev = parent;
224 sc->hw_if->getinfo(sc->hw_hdl, &mi);
225 sc->props = mi.props;
226 printf(": %s\n", mi.name);
227 }
228
229 int
230 midi_unit_count(void)
231 {
232 return midi_cd.cd_ndevs;
233 }
234
235 void
236 midi_initbuf(struct midi_buffer *mb)
237 {
238 mb->used = 0;
239 mb->usedhigh = MIDI_BUFSIZE;
240 mb->end = mb->start + mb->usedhigh;
241 mb->inp = mb->outp = mb->start;
242 }
243
244 int
245 midi_sleep_timo(int *chan, char *label, int timo)
246 {
247 int st;
248
249 if (!label)
250 label = "midi";
251
252 DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
253 *chan = 1;
254 st = tsleep(chan, PWAIT | PCATCH, label, timo);
255 *chan = 0;
256 #ifdef MIDI_DEBUG
257 if (st != 0)
258 printf("midi_sleep: %d\n", st);
259 #endif
260 return st;
261 }
262
263 int
264 midi_sleep(int *chan, char *label)
265 {
266 return midi_sleep_timo(chan, label, 0);
267 }
268
269 void
270 midi_wakeup(int *chan)
271 {
272 if (*chan) {
273 DPRINTFN(8, ("midi_wakeup: %p\n", chan));
274 wakeup(chan);
275 *chan = 0;
276 }
277 }
278
279 /* in midivar.h:
280 #define MIDI_CAT_DATA 0
281 #define MIDI_CAT_STATUS1 1
282 #define MIDI_CAT_STATUS2 2
283 #define MIDI_CAT_COMMON 3
284 */
285 static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
286 #define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
287
288 void
289 midi_in(void *addr, int data)
290 {
291 struct midi_softc *sc = addr;
292 struct midi_buffer *mb = &sc->inbuf;
293 int i;
294 u_char *what = sc->in_msg;
295 u_char rtbuf;
296 int count;
297
298 if (!sc->isopen)
299 return;
300
301 if (!(sc->flags & FREAD))
302 return; /* discard data if not reading */
303
304 if ( data >= 0xf8 ) { /* All realtime messages bypass state machine */
305 if ( data == 0xf9 || data == 0xfd ) {
306 DPRINTF( ("midi_in: sc=%p data=0x%02x undefined\n",
307 sc, data));
308 ++ sc->in.bytesDiscarded;
309 return;
310 }
311 DPRINTFN(9, ("midi_in: sc=%p System Real-Time data=0x%02x\n",
312 sc, data));
313 rtbuf = data;
314 count = sizeof rtbuf;
315 what = &rtbuf;
316 goto deliver;
317 }
318
319 DPRINTFN(4, ("midi_in: sc=%p data=0x%02x state=%d\n",
320 sc, data, sc->in_state));
321
322 retry:
323 switch ( sc->in_state | MIDI_CAT(data) ) {
324
325 case MIDI_IN_START | MIDI_CAT_COMMON:
326 case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
327 case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
328 sc->in_msg[0] = data;
329 count = 1;
330 switch ( data ) {
331 case 0xf0: sc->in_state = MIDI_IN_SYSEX; goto deliver_raw;
332 case 0xf1: sc->in_state = MIDI_IN_COM0_1; return;
333 case 0xf2: sc->in_state = MIDI_IN_COM0_2; return;
334 case 0xf3: sc->in_state = MIDI_IN_COM0_1; return;
335 case 0xf6: sc->in_state = MIDI_IN_START; break;
336 default: goto protocol_violation;
337 }
338 break;
339
340 case MIDI_IN_START | MIDI_CAT_STATUS1:
341 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
342 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1:
343 sc->in_state = MIDI_IN_RUN0_1;
344 sc->in_msg[0] = data;
345 return;
346
347 case MIDI_IN_START | MIDI_CAT_STATUS2:
348 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2:
349 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
350 sc->in_state = MIDI_IN_RUN0_2;
351 sc->in_msg[0] = data;
352 return;
353
354 case MIDI_IN_COM0_1 | MIDI_CAT_DATA:
355 sc->in_state = MIDI_IN_START;
356 sc->in_msg[1] = data;
357 count = 2;
358 break;
359
360 case MIDI_IN_COM0_2 | MIDI_CAT_DATA:
361 sc->in_state = MIDI_IN_COM1_2;
362 sc->in_msg[1] = data;
363 return;
364
365 case MIDI_IN_COM1_2 | MIDI_CAT_DATA:
366 sc->in_state = MIDI_IN_START;
367 sc->in_msg[2] = data;
368 count = 3;
369 break;
370
371 case MIDI_IN_RUN0_1 | MIDI_CAT_DATA:
372 case MIDI_IN_RUN1_1 | MIDI_CAT_DATA:
373 sc->in_state = MIDI_IN_RUN1_1;
374 sc->in_msg[1] = data;
375 count = 2;
376 break;
377
378 case MIDI_IN_RUN0_2 | MIDI_CAT_DATA:
379 case MIDI_IN_RUN2_2 | MIDI_CAT_DATA:
380 sc->in_state = MIDI_IN_RUN1_2;
381 sc->in_msg[1] = data;
382 return;
383
384 case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
385 sc->in_state = MIDI_IN_RUN2_2;
386 sc->in_msg[2] = data;
387 count = 3;
388 break;
389
390 case MIDI_IN_SYSEX | MIDI_CAT_DATA:
391 sc->in_msg[0] = data;
392 count = 1;
393 goto deliver_raw;
394
395 case MIDI_IN_SYSEX | MIDI_CAT_COMMON:
396 if ( data == 0xf7 ) {
397 sc->in_state = MIDI_IN_START;
398 sc->in_msg[0] = data;
399 count = 1;
400 goto deliver_raw;
401 }
402 /* FALLTHROUGH */
403
404 default:
405 protocol_violation:
406 DPRINTF(("midi_in: unexpected %#02x in state %u\n",
407 data, sc->in_state));
408 switch ( sc->in_state ) {
409 case MIDI_IN_START:
410 sc->in.bytesDiscarded++;
411 return;
412 case MIDI_IN_COM1_2:
413 case MIDI_IN_RUN1_2:
414 sc->in.bytesDiscarded++;
415 /* FALLTHROUGH */
416 case MIDI_IN_COM0_1:
417 case MIDI_IN_RUN0_1:
418 case MIDI_IN_COM0_2:
419 case MIDI_IN_RUN0_2:
420 sc->in.bytesDiscarded++;
421 /* FALLTHROUGH */
422 case MIDI_IN_SYSEX:
423 sc->in.incompleteMessages++;
424 break;
425 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
426 default:
427 printf("midi_in: mishandled protocol violation?\n");
428 #endif
429 }
430 sc->in_state = MIDI_IN_START;
431 goto retry;
432 }
433
434 deliver:
435 #if NSEQUENCER > 0
436 if (sc->seqopen) {
437 extern void midiseq_in(struct midi_dev *,u_char *,int);
438 midiseq_in(sc->seq_md, what, count);
439 return;
440 }
441 #endif
442 if ( data == MIDI_ACK ) /* sequencer should see these to support API */
443 return; /* otherwise discard (could track time last seen) */
444 deliver_raw:
445 if (mb->used + count > mb->usedhigh) {
446 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
447 what[0]));
448 sc->in.bytesDiscarded += count;
449 return;
450 }
451 for (i = 0; i < count; i++) {
452 *mb->inp++ = what[i];
453 if (mb->inp >= mb->end)
454 mb->inp = mb->start;
455 mb->used++;
456 }
457 midi_wakeup(&sc->rchan);
458 selnotify(&sc->rsel, 0);
459 if (sc->async)
460 psignal(sc->async, SIGIO);
461 }
462
463 void
464 midi_out(void *addr)
465 {
466 struct midi_softc *sc = addr;
467
468 if (!sc->isopen)
469 return;
470 DPRINTFN(8, ("midi_out: %p\n", sc));
471 midi_start_output(sc, 1);
472 }
473
474 int
475 midiopen(dev_t dev, int flags, int ifmt, struct proc *p)
476 {
477 struct midi_softc *sc;
478 struct midi_hw_if *hw;
479 int error;
480
481 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
482 if (sc == NULL)
483 return (ENXIO);
484 if (sc->dying)
485 return (EIO);
486
487 DPRINTFN(3,("midiopen %p\n", sc));
488
489 hw = sc->hw_if;
490 if (!hw)
491 return ENXIO;
492 if (sc->isopen)
493 return EBUSY;
494 sc->in_state = MIDI_IN_START;
495 sc->in.bytesDiscarded = 0;
496 sc->in.incompleteMessages = 0;
497 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
498 if (error)
499 return error;
500 sc->isopen++;
501 midi_initbuf(&sc->outbuf);
502 midi_initbuf(&sc->inbuf);
503 sc->flags = flags;
504 sc->rchan = 0;
505 sc->wchan = 0;
506 sc->pbus = 0;
507 sc->async = 0;
508
509 #ifdef MIDI_SAVE
510 if (midicnt != 0) {
511 midisave.cnt = midicnt;
512 midicnt = 0;
513 }
514 #endif
515
516 return 0;
517 }
518
519 int
520 midiclose(dev_t dev, int flags, int ifmt, struct proc *p)
521 {
522 int unit = MIDIUNIT(dev);
523 struct midi_softc *sc = midi_cd.cd_devs[unit];
524 struct midi_hw_if *hw = sc->hw_if;
525 int s, error;
526
527 DPRINTFN(3,("midiclose %p, bytesDiscarded %u, incompleteMessages %u\n",
528 sc, sc->in.bytesDiscarded, sc->in.incompleteMessages));
529
530 midi_start_output(sc, 0);
531 error = 0;
532 s = splaudio();
533 while (sc->outbuf.used > 0 && !error) {
534 DPRINTFN(8,("midiclose sleep used=%d\n", sc->outbuf.used));
535 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
536 }
537 splx(s);
538 sc->isopen = 0;
539 hw->close(sc->hw_hdl);
540 #if NSEQUENCER > 0
541 sc->seqopen = 0;
542 sc->seq_md = 0;
543 #endif
544 return 0;
545 }
546
547 int
548 midiread(dev_t dev, struct uio *uio, int ioflag)
549 {
550 int unit = MIDIUNIT(dev);
551 struct midi_softc *sc = midi_cd.cd_devs[unit];
552 struct midi_buffer *mb = &sc->inbuf;
553 int error;
554 u_char *outp;
555 int used, cc, n, resid;
556 int s;
557
558 DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
559 (unsigned long)uio->uio_resid));
560
561 if (sc->dying)
562 return EIO;
563
564 error = 0;
565 resid = uio->uio_resid;
566 while (uio->uio_resid == resid && !error) {
567 s = splaudio();
568 while (mb->used <= 0) {
569 if (ioflag & IO_NDELAY) {
570 splx(s);
571 return EWOULDBLOCK;
572 }
573 error = midi_sleep(&sc->rchan, "mid rd");
574 if (error) {
575 splx(s);
576 return error;
577 }
578 }
579 used = mb->used;
580 outp = mb->outp;
581 splx(s);
582 if (sc->dying)
583 return EIO;
584 cc = used; /* maximum to read */
585 n = mb->end - outp;
586 if (n < cc)
587 cc = n; /* don't read beyond end of buffer */
588 if (uio->uio_resid < cc)
589 cc = uio->uio_resid; /* and no more than we want */
590 DPRINTFN(8, ("midiread: uiomove cc=%d\n", cc));
591 error = uiomove(outp, cc, uio);
592 if (error)
593 break;
594 used -= cc;
595 outp += cc;
596 if (outp >= mb->end)
597 outp = mb->start;
598 s = splaudio();
599 mb->outp = outp;
600 mb->used = used;
601 splx(s);
602 }
603 return error;
604 }
605
606 void
607 midi_timeout(void *arg)
608 {
609 struct midi_softc *sc = arg;
610
611 DPRINTFN(8,("midi_timeout: %p\n", sc));
612 midi_start_output(sc, 1);
613 }
614
615 int
616 midi_start_output(struct midi_softc *sc, int intr)
617 {
618 struct midi_buffer *mb = &sc->outbuf;
619 u_char out;
620 int error;
621 int s;
622 int i;
623
624 error = 0;
625
626 if (sc->dying)
627 return EIO;
628
629 if (sc->pbus && !intr) {
630 DPRINTFN(8, ("midi_start_output: busy\n"));
631 return 0;
632 }
633 sc->pbus = (mb->used > 0)?1:0;
634 for (i = 0; i < MIDI_MAX_WRITE && mb->used > 0 &&
635 (!error || error==EINPROGRESS); i++) {
636 s = splaudio();
637 out = *mb->outp;
638 mb->outp++;
639 if (mb->outp >= mb->end)
640 mb->outp = mb->start;
641 mb->used--;
642 splx(s);
643 #ifdef MIDI_SAVE
644 midisave.buf[midicnt] = out;
645 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
646 #endif
647 DPRINTFN(8, ("midi_start_output: %p i=%d, data=0x%02x\n",
648 sc, i, out));
649 error = sc->hw_if->output(sc->hw_hdl, out);
650 if ((sc->props & MIDI_PROP_OUT_INTR) && error!=EINPROGRESS)
651 /* If ointr is enabled, midi_start_output()
652 * normally writes only one byte,
653 * except hw_if->output() returns EINPROGRESS.
654 */
655 break;
656 }
657 midi_wakeup(&sc->wchan);
658 selnotify(&sc->wsel, 0);
659 if (sc->async)
660 psignal(sc->async, SIGIO);
661 if (!(sc->props & MIDI_PROP_OUT_INTR) || error==EINPROGRESS) {
662 if (mb->used > 0)
663 callout_reset(&sc->sc_callout, midi_wait,
664 midi_timeout, sc);
665 else
666 sc->pbus = 0;
667 }
668 if ((sc->props & MIDI_PROP_OUT_INTR) && error==EINPROGRESS)
669 error = 0;
670
671 return error;
672 }
673
674 int
675 midiwrite(dev_t dev, struct uio *uio, int ioflag)
676 {
677 int unit = MIDIUNIT(dev);
678 struct midi_softc *sc = midi_cd.cd_devs[unit];
679 struct midi_buffer *mb = &sc->outbuf;
680 int error;
681 u_char *inp;
682 int used, cc, n;
683 int s;
684
685 DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit,
686 (unsigned long)uio->uio_resid));
687
688 if (sc->dying)
689 return EIO;
690
691 error = 0;
692 while (uio->uio_resid > 0 && !error) {
693 s = splaudio();
694 if (mb->used >= mb->usedhigh) {
695 DPRINTFN(8,("midi_write: sleep used=%d hiwat=%d\n",
696 mb->used, mb->usedhigh));
697 if (ioflag & IO_NDELAY) {
698 splx(s);
699 return EWOULDBLOCK;
700 }
701 error = midi_sleep(&sc->wchan, "mid wr");
702 if (error) {
703 splx(s);
704 return error;
705 }
706 }
707 used = mb->used;
708 inp = mb->inp;
709 splx(s);
710 if (sc->dying)
711 return EIO;
712 cc = mb->usedhigh - used; /* maximum to write */
713 n = mb->end - inp;
714 if (n < cc)
715 cc = n; /* don't write beyond end of buffer */
716 if (uio->uio_resid < cc)
717 cc = uio->uio_resid; /* and no more than we have */
718 error = uiomove(inp, cc, uio);
719 #ifdef MIDI_DEBUG
720 if (error)
721 printf("midi_write:(1) uiomove failed %d; "
722 "cc=%d inp=%p\n",
723 error, cc, inp);
724 #endif
725 if (error)
726 break;
727 inp = mb->inp + cc;
728 if (inp >= mb->end)
729 inp = mb->start;
730 s = splaudio();
731 mb->inp = inp;
732 mb->used += cc;
733 splx(s);
734 error = midi_start_output(sc, 0);
735 }
736 return error;
737 }
738
739 /*
740 * This write routine is only called from sequencer code and expects
741 * a write that is smaller than the MIDI buffer.
742 */
743 int
744 midi_writebytes(int unit, u_char *buf, int cc)
745 {
746 struct midi_softc *sc = midi_cd.cd_devs[unit];
747 struct midi_buffer *mb = &sc->outbuf;
748 int n, s;
749
750 DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
751 sc, unit, cc, buf[0], buf[1], buf[2]));
752
753 if (sc->dying)
754 return EIO;
755
756 s = splaudio();
757 if (mb->used + cc >= mb->usedhigh) {
758 splx(s);
759 return (EWOULDBLOCK);
760 }
761 n = mb->end - mb->inp;
762 if (cc < n)
763 n = cc;
764 mb->used += cc;
765 memcpy(mb->inp, buf, n);
766 mb->inp += n;
767 if (mb->inp >= mb->end) {
768 mb->inp = mb->start;
769 cc -= n;
770 if (cc > 0) {
771 memcpy(mb->inp, buf + n, cc);
772 mb->inp += cc;
773 }
774 }
775 splx(s);
776 return (midi_start_output(sc, 0));
777 }
778
779 int
780 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
781 {
782 int unit = MIDIUNIT(dev);
783 struct midi_softc *sc = midi_cd.cd_devs[unit];
784 struct midi_hw_if *hw = sc->hw_if;
785 int error;
786
787 DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
788
789 if (sc->dying)
790 return EIO;
791
792 error = 0;
793 switch (cmd) {
794 case FIONBIO:
795 /* All handled in the upper FS layer. */
796 break;
797
798 case FIOASYNC:
799 if (*(int *)addr) {
800 if (sc->async)
801 return EBUSY;
802 sc->async = p;
803 DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", p));
804 } else
805 sc->async = 0;
806 break;
807
808 #if 0
809 case MIDI_PRETIME:
810 /* XXX OSS
811 * This should set up a read timeout, but that's
812 * why we have poll(), so there's nothing yet. */
813 error = EINVAL;
814 break;
815 #endif
816
817 #ifdef MIDI_SAVE
818 case MIDI_GETSAVE:
819 error = copyout(&midisave, *(void **)addr, sizeof midisave);
820 break;
821 #endif
822
823 default:
824 if (hw->ioctl)
825 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
826 else
827 error = EINVAL;
828 break;
829 }
830 return error;
831 }
832
833 int
834 midipoll(dev_t dev, int events, struct proc *p)
835 {
836 int unit = MIDIUNIT(dev);
837 struct midi_softc *sc = midi_cd.cd_devs[unit];
838 int revents = 0;
839 int s;
840
841 DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
842
843 if (sc->dying)
844 return EIO;
845
846 s = splaudio();
847
848 if (events & (POLLIN | POLLRDNORM))
849 if (sc->inbuf.used > 0)
850 revents |= events & (POLLIN | POLLRDNORM);
851
852 if (events & (POLLOUT | POLLWRNORM))
853 if (sc->outbuf.used < sc->outbuf.usedhigh)
854 revents |= events & (POLLOUT | POLLWRNORM);
855
856 if (revents == 0) {
857 if (events & (POLLIN | POLLRDNORM))
858 selrecord(p, &sc->rsel);
859
860 if (events & (POLLOUT | POLLWRNORM))
861 selrecord(p, &sc->wsel);
862 }
863
864 splx(s);
865 return revents;
866 }
867
868 static void
869 filt_midirdetach(struct knote *kn)
870 {
871 struct midi_softc *sc = kn->kn_hook;
872 int s;
873
874 s = splaudio();
875 SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
876 splx(s);
877 }
878
879 static int
880 filt_midiread(struct knote *kn, long hint)
881 {
882 struct midi_softc *sc = kn->kn_hook;
883
884 /* XXXLUKEM (thorpej): please make sure this is correct. */
885
886 kn->kn_data = sc->inbuf.used;
887 return (kn->kn_data > 0);
888 }
889
890 static const struct filterops midiread_filtops =
891 { 1, NULL, filt_midirdetach, filt_midiread };
892
893 static void
894 filt_midiwdetach(struct knote *kn)
895 {
896 struct midi_softc *sc = kn->kn_hook;
897 int s;
898
899 s = splaudio();
900 SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
901 splx(s);
902 }
903
904 static int
905 filt_midiwrite(struct knote *kn, long hint)
906 {
907 struct midi_softc *sc = kn->kn_hook;
908
909 /* XXXLUKEM (thorpej): please make sure this is correct. */
910
911 kn->kn_data = sc->outbuf.usedhigh - sc->outbuf.used;
912 return (kn->kn_data > 0);
913 }
914
915 static const struct filterops midiwrite_filtops =
916 { 1, NULL, filt_midiwdetach, filt_midiwrite };
917
918 int
919 midikqfilter(dev_t dev, struct knote *kn)
920 {
921 int unit = MIDIUNIT(dev);
922 struct midi_softc *sc = midi_cd.cd_devs[unit];
923 struct klist *klist;
924 int s;
925
926 switch (kn->kn_filter) {
927 case EVFILT_READ:
928 klist = &sc->rsel.sel_klist;
929 kn->kn_fop = &midiread_filtops;
930 break;
931
932 case EVFILT_WRITE:
933 klist = &sc->wsel.sel_klist;
934 kn->kn_fop = &midiwrite_filtops;
935 break;
936
937 default:
938 return (1);
939 }
940
941 kn->kn_hook = sc;
942
943 s = splaudio();
944 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
945 splx(s);
946
947 return (0);
948 }
949
950 void
951 midi_getinfo(dev_t dev, struct midi_info *mi)
952 {
953 struct midi_softc *sc;
954
955 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
956 if (sc == NULL)
957 return;
958 if (sc->dying)
959 return;
960
961 sc->hw_if->getinfo(sc->hw_hdl, mi);
962 }
963
964 #endif /* NMIDI > 0 */
965
966 #if NMIDI > 0 || NMIDIBUS > 0
967
968 int audioprint(void *, const char *);
969
970 struct device *
971 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev)
972 {
973 struct audio_attach_args arg;
974
975 #ifdef DIAGNOSTIC
976 if (mhwp == NULL) {
977 aprint_error("midi_attach_mi: NULL\n");
978 return (0);
979 }
980 #endif
981 arg.type = AUDIODEV_TYPE_MIDI;
982 arg.hwif = mhwp;
983 arg.hdl = hdlp;
984 return (config_found(dev, &arg, audioprint));
985 }
986
987 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
988