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