midi.c revision 1.8 1 /* $NetBSD: midi.c,v 1.8 1998/11/25 22:17:07 augustss 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 "midi.h"
40 #if NMIDI > 0
41
42 #include "sequencer.h"
43
44 #include <sys/param.h>
45 #include <sys/ioctl.h>
46 #include <sys/fcntl.h>
47 #include <sys/vnode.h>
48 #include <sys/select.h>
49 #include <sys/poll.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52 #include <sys/systm.h>
53 #include <sys/syslog.h>
54 #include <sys/kernel.h>
55 #include <sys/signalvar.h>
56 #include <sys/conf.h>
57 #include <sys/audioio.h>
58 #include <sys/midiio.h>
59 #include <sys/device.h>
60
61 #include <dev/audio_if.h>
62 #include <dev/midi_if.h>
63 #include <dev/midivar.h>
64
65 #ifdef AUDIO_DEBUG
66 #define DPRINTF(x) if (mididebug) printf x
67 #define DPRINTFN(n,x) if (mididebug >= (n)) printf x
68 int mididebug = 0;
69 #else
70 #define DPRINTF(x)
71 #define DPRINTFN(n,x)
72 #endif
73
74 int midi_wait;
75
76 void midi_in __P((void *, int));
77 void midi_out __P((void *));
78 int midi_start_output __P((struct midi_softc *, int));
79 int midi_sleep_timo __P((int *, char *, int));
80 int midi_sleep __P((int *, char *));
81 void midi_wakeup __P((int *));
82 void midi_initbuf __P((struct midi_buffer *));
83 void midi_timeout __P((void *));
84
85 int midiprobe __P((struct device *, struct cfdata *, void *));
86 void midiattach __P((struct device *, struct device *, void *));
87
88 struct cfattach midi_ca = {
89 sizeof(struct midi_softc), midiprobe, midiattach
90 };
91
92 #ifdef MIDI_SAVE
93 #define MIDI_SAVE_SIZE 100000
94 int midicnt;
95 struct {
96 int cnt;
97 u_char buf[MIDI_SAVE_SIZE];
98 } midisave;
99 #define MIDI_GETSAVE _IOWR('m', 100, int)
100
101 #endif
102
103 extern struct cfdriver midi_cd;
104
105 int
106 midiprobe(parent, match, aux)
107 struct device *parent;
108 struct cfdata *match;
109 void *aux;
110 {
111 struct audio_attach_args *sa = aux;
112
113 DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
114 sa->type, sa, sa->hwif));
115 return (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0;
116 }
117
118 void
119 midiattach(parent, self, aux)
120 struct device *parent, *self;
121 void *aux;
122 {
123 struct midi_softc *sc = (void *)self;
124 struct audio_attach_args *sa = aux;
125 struct midi_hw_if *hwp = sa->hwif;
126 void *hdlp = sa->hdl;
127
128 DPRINTFN(6, ("MIDI attach\n"));
129
130 #ifdef DIAGNOSTIC
131 if (hwp == 0 ||
132 hwp->open == 0 ||
133 hwp->close == 0 ||
134 hwp->output == 0 ||
135 hwp->getinfo == 0) {
136 printf("midi: missing method\n");
137 return;
138 }
139 #endif
140 sc->hw_if = hwp;
141 sc->hw_hdl = hdlp;
142 midi_attach(sc, parent);
143 }
144
145 void
146 midi_attach(sc, parent)
147 struct midi_softc *sc;
148 struct device *parent;
149 {
150 struct midi_info mi;
151
152 sc->isopen = 0;
153
154 midi_wait = MIDI_WAIT * hz / 1000000;
155 if (midi_wait == 0)
156 midi_wait = 1;
157
158 sc->sc_dev = parent;
159 sc->hw_if->getinfo(sc->hw_hdl, &mi);
160 sc->props = mi.props;
161 printf(": <%s>\n", mi.name);
162 }
163
164 int
165 midi_unit_count()
166 {
167 return midi_cd.cd_ndevs;
168 }
169
170 void
171 midi_initbuf(mb)
172 struct midi_buffer *mb;
173 {
174 mb->used = 0;
175 mb->usedhigh = MIDI_BUFSIZE;
176 mb->end = mb->start + mb->usedhigh;
177 mb->inp = mb->outp = mb->start;
178 }
179
180 int
181 midi_sleep_timo(chan, label, timo)
182 int *chan;
183 char *label;
184 int timo;
185 {
186 int st;
187
188 if (!label)
189 label = "midi";
190
191 DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
192 *chan = 1;
193 st = tsleep(chan, PWAIT | PCATCH, label, timo);
194 *chan = 0;
195 #ifdef MIDI_DEBUG
196 if (st != 0)
197 printf("midi_sleep: %d\n", st);
198 #endif
199 return st;
200 }
201
202 int
203 midi_sleep(chan, label)
204 int *chan;
205 char *label;
206 {
207 return midi_sleep_timo(chan, label, 0);
208 }
209
210 void
211 midi_wakeup(chan)
212 int *chan;
213 {
214 if (*chan) {
215 DPRINTFN(5, ("midi_wakeup: %p\n", chan));
216 wakeup(chan);
217 *chan = 0;
218 }
219 }
220
221 static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
222 /* Number of bytes in a MIDI command */
223 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
224
225 void
226 midi_in(addr, data)
227 void *addr;
228 int data;
229 {
230 struct midi_softc *sc = addr;
231 struct midi_buffer *mb = &sc->inbuf;
232 int i;
233
234 if (!sc->isopen)
235 return;
236 if (data == MIDI_ACK)
237 return;
238 DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
239 if (!(sc->flags & FREAD))
240 return; /* discard data if not reading */
241
242 switch(sc->in_state) {
243 case MIDI_IN_START:
244 if (MIDI_IS_STATUS(data)) {
245 switch(data) {
246 case 0xf0: /* Sysex */
247 sc->in_state = MIDI_IN_SYSEX;
248 break;
249 case 0xf1: /* MTC quarter frame */
250 case 0xf3: /* Song select */
251 sc->in_state = MIDI_IN_DATA;
252 sc->in_msg[0] = data;
253 sc->in_pos = 1;
254 sc->in_left = 1;
255 break;
256 case 0xf2: /* Song position pointer */
257 sc->in_state = MIDI_IN_DATA;
258 sc->in_msg[0] = data;
259 sc->in_pos = 1;
260 sc->in_left = 2;
261 break;
262 default:
263 if (MIDI_IS_COMMON(data)) {
264 sc->in_msg[0] = data;
265 sc->in_pos = 1;
266 goto deliver;
267 } else {
268 sc->in_state = MIDI_IN_DATA;
269 sc->in_msg[0] = sc->in_status = data;
270 sc->in_pos = 1;
271 sc->in_left = MIDI_LENGTH(sc->in_status);
272 }
273 break;
274 }
275 } else {
276 if (MIDI_IS_STATUS(sc->in_status)) {
277 sc->in_state = MIDI_IN_DATA;
278 sc->in_msg[0] = sc->in_status;
279 sc->in_msg[1] = data;
280 sc->in_pos = 2;
281 sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
282 }
283 }
284 return;
285 case MIDI_IN_DATA:
286 sc->in_msg[sc->in_pos++] = data;
287 if (--sc->in_left <= 0)
288 break; /* deliver data */
289 return;
290 case MIDI_IN_SYSEX:
291 if (data == MIDI_SYSEX_END)
292 sc->in_state = MIDI_IN_START;
293 return;
294 }
295 deliver:
296 sc->in_state = MIDI_IN_START;
297 #if NSEQUENCER > 0
298 if (sc->seqopen) {
299 extern void midiseq_in __P((struct midi_dev *,u_char *,int));
300 midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos);
301 return;
302 }
303 #endif
304
305 if (mb->used + sc->in_pos > mb->usedhigh) {
306 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
307 sc->in_msg[0]));
308 return;
309 }
310 for (i = 0; i < sc->in_pos; i++) {
311 *mb->inp++ = sc->in_msg[i];
312 if (mb->inp >= mb->end)
313 mb->inp = mb->start;
314 mb->used++;
315 }
316 midi_wakeup(&sc->rchan);
317 selwakeup(&sc->rsel);
318 if (sc->async)
319 psignal(sc->async, SIGIO);
320 }
321
322 void
323 midi_out(addr)
324 void *addr;
325 {
326 struct midi_softc *sc = addr;
327
328 if (!sc->isopen)
329 return;
330 DPRINTFN(3, ("midi_out: %p\n", sc));
331 midi_start_output(sc, 1);
332 }
333
334 int
335 midiopen(dev, flags, ifmt, p)
336 dev_t dev;
337 int flags, ifmt;
338 struct proc *p;
339 {
340 int unit = MIDIUNIT(dev);
341 struct midi_softc *sc;
342 struct midi_hw_if *hw;
343 int error;
344
345 if (unit >= midi_cd.cd_ndevs ||
346 (sc = midi_cd.cd_devs[unit]) == NULL)
347 return ENXIO;
348 DPRINTF(("midiopen %p\n", sc));
349
350 hw = sc->hw_if;
351 if (!hw)
352 return ENXIO;
353 if (sc->isopen)
354 return EBUSY;
355 sc->in_state = MIDI_IN_START;
356 sc->in_status = 0;
357 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
358 if (error)
359 return error;
360 sc->isopen++;
361 midi_initbuf(&sc->outbuf);
362 midi_initbuf(&sc->inbuf);
363 sc->flags = flags;
364 sc->rchan = 0;
365 sc->wchan = 0;
366 sc->pbus = 0;
367 sc->async = 0;
368
369 #ifdef MIDI_SAVE
370 if (midicnt != 0) {
371 midisave.cnt = midicnt;
372 midicnt = 0;
373 }
374 #endif
375
376 return 0;
377 }
378
379 int
380 midiclose(dev, flags, ifmt, p)
381 dev_t dev;
382 int flags, ifmt;
383 struct proc *p;
384 {
385 int unit = MIDIUNIT(dev);
386 struct midi_softc *sc = midi_cd.cd_devs[unit];
387 struct midi_hw_if *hw = sc->hw_if;
388 int s, error;
389
390 DPRINTF(("midiclose %p\n", sc));
391
392 midi_start_output(sc, 0);
393 error = 0;
394 s = splaudio();
395 while (sc->outbuf.used > 0 && !error) {
396 DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
397 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
398 }
399 splx(s);
400 sc->isopen = 0;
401 hw->close(sc->hw_hdl);
402 #if NSEQUENCER > 0
403 sc->seqopen = 0;
404 sc->seq_md = 0;
405 #endif
406 return 0;
407 }
408
409 int
410 midiread(dev, uio, ioflag)
411 dev_t dev;
412 struct uio *uio;
413 int ioflag;
414 {
415 int unit = MIDIUNIT(dev);
416 struct midi_softc *sc = midi_cd.cd_devs[unit];
417 struct midi_buffer *mb = &sc->inbuf;
418 int error;
419 u_char *outp;
420 int used, cc, n, resid;
421 int s;
422
423 DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
424
425 error = 0;
426 resid = uio->uio_resid;
427 while (uio->uio_resid == resid && !error) {
428 s = splaudio();
429 while (mb->used <= 0) {
430 if (ioflag & IO_NDELAY) {
431 splx(s);
432 return EWOULDBLOCK;
433 }
434 error = midi_sleep(&sc->rchan, "mid rd");
435 if (error) {
436 splx(s);
437 return error;
438 }
439 }
440 used = mb->used;
441 outp = mb->outp;
442 splx(s);
443 cc = used; /* maximum to read */
444 n = mb->end - outp;
445 if (n < cc)
446 cc = n; /* don't read beyond end of buffer */
447 if (uio->uio_resid < cc)
448 cc = uio->uio_resid; /* and no more than we want */
449 DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
450 error = uiomove(outp, cc, uio);
451 if (error)
452 break;
453 used -= cc;
454 outp += cc;
455 if (outp >= mb->end)
456 outp = mb->start;
457 s = splaudio();
458 mb->outp = outp;
459 mb->used = used;
460 splx(s);
461 }
462 return error;
463 }
464
465 void
466 midi_timeout(arg)
467 void *arg;
468 {
469 struct midi_softc *sc = arg;
470
471 DPRINTFN(3,("midi_timeout: %p\n", sc));
472 midi_start_output(sc, 1);
473 }
474
475 int
476 midi_start_output(sc, intr)
477 struct midi_softc *sc;
478 int intr;
479 {
480 struct midi_buffer *mb = &sc->outbuf;
481 u_char *outp;
482 int error;
483 int s;
484 int i, mmax;
485
486 error = 0;
487 mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
488 s = splaudio();
489 if (sc->pbus && !intr) {
490 DPRINTFN(4, ("midi_start_output: busy\n"));
491 splx(s);
492 return 0;
493 }
494 sc->pbus = 1;
495 for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
496 outp = mb->outp;
497 splx(s);
498 DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
499 sc, i, *outp));
500 #ifdef MIDI_SAVE
501 midisave.buf[midicnt] = *outp;
502 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
503 #endif
504 error = sc->hw_if->output(sc->hw_hdl, *outp++);
505 if (outp >= mb->end)
506 outp = mb->start;
507 s = splaudio();
508 mb->outp = outp;
509 mb->used--;
510 }
511 midi_wakeup(&sc->wchan);
512 selwakeup(&sc->wsel);
513 if (sc->async)
514 psignal(sc->async, SIGIO);
515 if (mb->used > 0) {
516 if (!(sc->props & MIDI_PROP_OUT_INTR))
517 timeout(midi_timeout, sc, midi_wait);
518 } else
519 sc->pbus = 0;
520 splx(s);
521 return error;
522 }
523
524 int
525 midiwrite(dev, uio, ioflag)
526 dev_t dev;
527 struct uio *uio;
528 int ioflag;
529 {
530 int unit = MIDIUNIT(dev);
531 struct midi_softc *sc = midi_cd.cd_devs[unit];
532 struct midi_buffer *mb = &sc->outbuf;
533 int error;
534 u_char *inp;
535 int used, cc, n;
536 int s;
537
538 DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
539 uio->uio_resid));
540
541 error = 0;
542 while (uio->uio_resid > 0 && !error) {
543 s = splaudio();
544 if (mb->used >= mb->usedhigh) {
545 DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
546 mb->used, mb->usedhigh));
547 if (ioflag & IO_NDELAY) {
548 splx(s);
549 return EWOULDBLOCK;
550 }
551 error = midi_sleep(&sc->wchan, "mid wr");
552 if (error) {
553 splx(s);
554 return error;
555 }
556 }
557 used = mb->used;
558 inp = mb->inp;
559 splx(s);
560 cc = mb->usedhigh - used; /* maximum to write */
561 n = mb->end - inp;
562 if (n < cc)
563 cc = n; /* don't write beyond end of buffer */
564 if (uio->uio_resid < cc)
565 cc = uio->uio_resid; /* and no more than we have */
566 error = uiomove(inp, cc, uio);
567 #ifdef MIDI_DEBUG
568 if (error)
569 printf("midi_write:(1) uiomove failed %d; cc=%d inp=%p\n",
570 error, cc, inp);
571 #endif
572 if (error)
573 break;
574 inp = mb->inp + cc;
575 if (inp >= mb->end)
576 inp = mb->start;
577 s = splaudio();
578 mb->inp = inp;
579 mb->used += cc;
580 splx(s);
581 error = midi_start_output(sc, 0);
582 }
583 return error;
584 }
585
586 /*
587 * This write routine is only called from sequencer code and expect
588 * a write that is smaller than the MIDI buffer.
589 */
590 int
591 midi_writebytes(unit, buf, cc)
592 int unit;
593 u_char *buf;
594 int cc;
595 {
596 struct midi_softc *sc = midi_cd.cd_devs[unit];
597 struct midi_buffer *mb = &sc->outbuf;
598 int n, s;
599
600 DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
601
602 s = splaudio();
603 if (mb->used + cc >= mb->usedhigh) {
604 splx(s);
605 return (EWOULDBLOCK);
606 }
607 n = mb->end - mb->inp;
608 if (cc < n)
609 n = cc;
610 memcpy(mb->inp, buf, cc);
611 mb->inp += n;
612 if (mb->inp >= mb->end) {
613 mb->inp = mb->start;
614 cc -= n;
615 if (cc > 0) {
616 memcpy(mb->inp, buf + n, cc);
617 mb->inp += cc;
618 }
619 }
620 mb->used += cc;
621 splx(s);
622 return (midi_start_output(sc, 0));
623 }
624
625 int
626 midiioctl(dev, cmd, addr, flag, p)
627 dev_t dev;
628 u_long cmd;
629 caddr_t addr;
630 int flag;
631 struct proc *p;
632 {
633 int unit = MIDIUNIT(dev);
634 struct midi_softc *sc = midi_cd.cd_devs[unit];
635 struct midi_hw_if *hw = sc->hw_if;
636 int error;
637
638 DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
639 error = 0;
640 switch (cmd) {
641 case FIONBIO:
642 /* All handled in the upper FS layer. */
643 break;
644
645 case FIOASYNC:
646 if (*(int *)addr) {
647 if (sc->async)
648 return EBUSY;
649 sc->async = p;
650 DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
651 } else
652 sc->async = 0;
653 break;
654
655 #if 0
656 case MIDI_PRETIME:
657 /* XXX OSS
658 * This should set up a read timeout, but that's
659 * why we have poll(), so there's nothing yet. */
660 error = EINVAL;
661 break;
662 #endif
663
664 #ifdef MIDI_SAVE
665 case MIDI_GETSAVE:
666 error = copyout(&midisave, *(void **)addr, sizeof midisave);
667 break;
668 #endif
669
670 default:
671 if (hw->ioctl)
672 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
673 else
674 error = EINVAL;
675 break;
676 }
677 return error;
678 }
679
680 int
681 midipoll(dev, events, p)
682 dev_t dev;
683 int events;
684 struct proc *p;
685 {
686 int unit = MIDIUNIT(dev);
687 struct midi_softc *sc = midi_cd.cd_devs[unit];
688 int revents = 0;
689 int s = splaudio();
690
691 DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
692
693 if (events & (POLLIN | POLLRDNORM))
694 if (sc->inbuf.used > 0)
695 revents |= events & (POLLIN | POLLRDNORM);
696
697 if (events & (POLLOUT | POLLWRNORM))
698 if (sc->outbuf.used < sc->outbuf.usedhigh)
699 revents |= events & (POLLOUT | POLLWRNORM);
700
701 if (revents == 0) {
702 if (events & (POLLIN | POLLRDNORM))
703 selrecord(p, &sc->rsel);
704
705 if (events & (POLLOUT | POLLWRNORM))
706 selrecord(p, &sc->wsel);
707 }
708
709 splx(s);
710 return revents;
711 }
712
713 void
714 midi_getinfo(dev, mi)
715 dev_t dev;
716 struct midi_info *mi;
717 {
718 int unit = MIDIUNIT(dev);
719 struct midi_softc *sc;
720
721 if (unit >= midi_cd.cd_ndevs ||
722 (sc = midi_cd.cd_devs[unit]) == NULL)
723 return;
724 sc->hw_if->getinfo(sc->hw_hdl, mi);
725 }
726
727 int audioprint __P((void *, const char *));
728
729 void
730 midi_attach_mi(mhwp, hdlp, dev)
731 struct midi_hw_if *mhwp;
732 void *hdlp;
733 struct device *dev;
734 {
735 struct audio_attach_args arg;
736
737 #ifdef DIAGNOSTIC
738 if (mhwp == NULL) {
739 printf("midi_attach_mi: NULL\n");
740 return;
741 }
742 #endif
743 arg.type = AUDIODEV_TYPE_MIDI;
744 arg.hwif = mhwp;
745 arg.hdl = hdlp;
746 (void)config_found(dev, &arg, audioprint);
747 }
748
749 #endif /* NMIDI > 0 */
750