midi.c revision 1.6 1 /* $NetBSD: midi.c,v 1.6 1998/09/13 06:30:25 mycroft 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_softc *,u_char *,int));
299 midiseq_in(sc, 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 #endif
404 return 0;
405 }
406
407 int
408 midiread(dev, uio, ioflag)
409 dev_t dev;
410 struct uio *uio;
411 int ioflag;
412 {
413 int unit = MIDIUNIT(dev);
414 struct midi_softc *sc = midi_cd.cd_devs[unit];
415 struct midi_buffer *mb = &sc->inbuf;
416 int error;
417 u_char *outp;
418 int used, cc, n, resid;
419 int s;
420
421 DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
422
423 error = 0;
424 resid = uio->uio_resid;
425 while (uio->uio_resid == resid && !error) {
426 s = splaudio();
427 while (mb->used <= 0) {
428 if (ioflag & IO_NDELAY) {
429 splx(s);
430 return EWOULDBLOCK;
431 }
432 error = midi_sleep(&sc->rchan, "mid rd");
433 if (error) {
434 splx(s);
435 return error;
436 }
437 }
438 used = mb->used;
439 outp = mb->outp;
440 splx(s);
441 cc = used; /* maximum to read */
442 n = mb->end - outp;
443 if (n < cc)
444 cc = n; /* don't read beyond end of buffer */
445 if (uio->uio_resid < cc)
446 cc = uio->uio_resid; /* and no more than we want */
447 DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
448 error = uiomove(outp, cc, uio);
449 if (error)
450 break;
451 used -= cc;
452 outp += cc;
453 if (outp >= mb->end)
454 outp = mb->start;
455 s = splaudio();
456 mb->outp = outp;
457 mb->used = used;
458 splx(s);
459 }
460 return error;
461 }
462
463 void
464 midi_timeout(arg)
465 void *arg;
466 {
467 struct midi_softc *sc = arg;
468
469 DPRINTFN(3,("midi_timeout: %p\n", sc));
470 midi_start_output(sc, 1);
471 }
472
473 int
474 midi_start_output(sc, intr)
475 struct midi_softc *sc;
476 int intr;
477 {
478 struct midi_buffer *mb = &sc->outbuf;
479 u_char *outp;
480 int error;
481 int s;
482 int i, mmax;
483
484 error = 0;
485 mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
486 s = splaudio();
487 if (sc->pbus && !intr) {
488 DPRINTFN(4, ("midi_start_output: busy\n"));
489 splx(s);
490 return 0;
491 }
492 sc->pbus = 1;
493 for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
494 outp = mb->outp;
495 splx(s);
496 DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
497 sc, i, *outp));
498 #ifdef MIDI_SAVE
499 midisave.buf[midicnt] = *outp;
500 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
501 #endif
502 error = sc->hw_if->output(sc->hw_hdl, *outp++);
503 if (outp >= mb->end)
504 outp = mb->start;
505 s = splaudio();
506 mb->outp = outp;
507 mb->used--;
508 }
509 midi_wakeup(&sc->wchan);
510 selwakeup(&sc->wsel);
511 if (sc->async)
512 psignal(sc->async, SIGIO);
513 if (mb->used > 0) {
514 if (!(sc->props & MIDI_PROP_OUT_INTR))
515 timeout(midi_timeout, sc, midi_wait);
516 } else
517 sc->pbus = 0;
518 splx(s);
519 return error;
520 }
521
522 int
523 midiwrite(dev, uio, ioflag)
524 dev_t dev;
525 struct uio *uio;
526 int ioflag;
527 {
528 int unit = MIDIUNIT(dev);
529 struct midi_softc *sc = midi_cd.cd_devs[unit];
530 struct midi_buffer *mb = &sc->outbuf;
531 int error;
532 u_char *inp;
533 int used, cc, n;
534 int s;
535
536 DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
537 uio->uio_resid));
538
539 error = 0;
540 while (uio->uio_resid > 0 && !error) {
541 s = splaudio();
542 if (mb->used >= mb->usedhigh) {
543 DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
544 mb->used, mb->usedhigh));
545 if (ioflag & IO_NDELAY) {
546 splx(s);
547 return EWOULDBLOCK;
548 }
549 error = midi_sleep(&sc->wchan, "mid wr");
550 if (error) {
551 splx(s);
552 return error;
553 }
554 }
555 used = mb->used;
556 inp = mb->inp;
557 splx(s);
558 cc = mb->usedhigh - used; /* maximum to write */
559 n = mb->end - inp;
560 if (n < cc)
561 cc = n; /* don't write beyond end of buffer */
562 if (uio->uio_resid < cc)
563 cc = uio->uio_resid; /* and no more than we have */
564 error = uiomove(inp, cc, uio);
565 #ifdef MIDI_DEBUG
566 if (error)
567 printf("midi_write:(1) uiomove failed %d; cc=%d inp=%p\n",
568 error, cc, inp);
569 #endif
570 if (error)
571 break;
572 inp = mb->inp + cc;
573 if (inp >= mb->end)
574 inp = mb->start;
575 s = splaudio();
576 mb->inp = inp;
577 mb->used += cc;
578 splx(s);
579 error = midi_start_output(sc, 0);
580 }
581 return error;
582 }
583
584 /*
585 * This write routine is only called from sequencer code and expect
586 * a write that is smaller than the MIDI buffer.
587 */
588 int
589 midi_writebytes(unit, buf, cc)
590 int unit;
591 u_char *buf;
592 int cc;
593 {
594 struct midi_softc *sc = midi_cd.cd_devs[unit];
595 struct midi_buffer *mb = &sc->outbuf;
596 int n, s;
597
598 DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
599
600 s = splaudio();
601 if (mb->used + cc >= mb->usedhigh) {
602 splx(s);
603 return (EWOULDBLOCK);
604 }
605 n = mb->end - mb->inp;
606 if (cc < n)
607 n = cc;
608 memcpy(mb->inp, buf, cc);
609 mb->inp += n;
610 if (mb->inp >= mb->end) {
611 mb->inp = mb->start;
612 cc -= n;
613 if (cc > 0) {
614 memcpy(mb->inp, buf + n, cc);
615 mb->inp += cc;
616 }
617 }
618 mb->used += cc;
619 splx(s);
620 return (midi_start_output(sc, 0));
621 }
622
623 int
624 midiioctl(dev, cmd, addr, flag, p)
625 dev_t dev;
626 u_long cmd;
627 caddr_t addr;
628 int flag;
629 struct proc *p;
630 {
631 int unit = MIDIUNIT(dev);
632 struct midi_softc *sc = midi_cd.cd_devs[unit];
633 struct midi_hw_if *hw = sc->hw_if;
634 int error;
635
636 DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
637 error = 0;
638 switch (cmd) {
639 case FIONBIO:
640 /* All handled in the upper FS layer. */
641 break;
642
643 case FIOASYNC:
644 if (*(int *)addr) {
645 if (sc->async)
646 return EBUSY;
647 sc->async = p;
648 DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
649 } else
650 sc->async = 0;
651 break;
652
653 #if 0
654 case MIDI_PRETIME:
655 /* XXX OSS
656 * This should set up a read timeout, but that's
657 * why we have poll(), so there's nothing yet. */
658 error = EINVAL;
659 break;
660 #endif
661
662 #ifdef MIDI_SAVE
663 case MIDI_GETSAVE:
664 error = copyout(&midisave, *(void **)addr, sizeof midisave);
665 break;
666 #endif
667
668 default:
669 if (hw->ioctl)
670 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
671 else
672 error = EINVAL;
673 break;
674 }
675 return error;
676 }
677
678 int
679 midipoll(dev, events, p)
680 dev_t dev;
681 int events;
682 struct proc *p;
683 {
684 int unit = MIDIUNIT(dev);
685 struct midi_softc *sc = midi_cd.cd_devs[unit];
686 int revents = 0;
687 int s = splaudio();
688
689 DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
690
691 if (events & (POLLIN | POLLRDNORM))
692 if (sc->inbuf.used > 0)
693 revents |= events & (POLLIN | POLLRDNORM);
694
695 if (events & (POLLOUT | POLLWRNORM))
696 if (sc->outbuf.used < sc->outbuf.usedhigh)
697 revents |= events & (POLLOUT | POLLWRNORM);
698
699 if (revents == 0) {
700 if (events & (POLLIN | POLLRDNORM))
701 selrecord(p, &sc->rsel);
702
703 if (events & (POLLOUT | POLLWRNORM))
704 selrecord(p, &sc->wsel);
705 }
706
707 splx(s);
708 return revents;
709 }
710
711 void
712 midi_getinfo(dev, mi)
713 dev_t dev;
714 struct midi_info *mi;
715 {
716 int unit = MIDIUNIT(dev);
717 struct midi_softc *sc;
718
719 if (unit >= midi_cd.cd_ndevs ||
720 (sc = midi_cd.cd_devs[unit]) == NULL)
721 return;
722 sc->hw_if->getinfo(sc->hw_hdl, mi);
723 }
724
725 int audioprint __P((void *, const char *));
726
727 void
728 midi_attach_mi(mhwp, hdlp, dev)
729 struct midi_hw_if *mhwp;
730 void *hdlp;
731 struct device *dev;
732 {
733 struct audio_attach_args arg;
734
735 #ifdef DIAGNOSTIC
736 if (mhwp == NULL) {
737 printf("midi_attach_mi: NULL\n");
738 return;
739 }
740 #endif
741 arg.type = AUDIODEV_TYPE_MIDI;
742 arg.hwif = mhwp;
743 arg.hdl = hdlp;
744 (void)config_found(dev, &arg, audioprint);
745 }
746
747 #endif /* NMIDI > 0 */
748