midi.c revision 1.4 1 /* $NetBSD: midi.c,v 1.4 1998/08/17 21:16:11 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_initbuf(&sc->outbuf);
154 midi_initbuf(&sc->inbuf);
155
156 midi_wait = MIDI_WAIT * hz / 1000000;
157 if (midi_wait == 0)
158 midi_wait = 1;
159
160 sc->sc_dev = parent;
161 sc->hw_if->getinfo(sc->hw_hdl, &mi);
162 sc->props = mi.props;
163 printf(": <%s>\n", mi.name);
164 }
165
166 int
167 midi_unit_count()
168 {
169 return midi_cd.cd_ndevs;
170 }
171
172 void
173 midi_initbuf(mb)
174 struct midi_buffer *mb;
175 {
176 mb->used = 0;
177 mb->usedhigh = MIDI_BUFSIZE;
178 mb->end = mb->start + mb->usedhigh;
179 mb->inp = mb->outp = mb->start;
180 }
181
182 int
183 midi_sleep_timo(chan, label, timo)
184 int *chan;
185 char *label;
186 int timo;
187 {
188 int st;
189
190 if (!label)
191 label = "midi";
192
193 DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
194 *chan = 1;
195 st = tsleep(chan, PWAIT | PCATCH, label, timo);
196 *chan = 0;
197 #ifdef MIDI_DEBUG
198 if (st != 0)
199 printf("midi_sleep: %d\n", st);
200 #endif
201 return st;
202 }
203
204 int
205 midi_sleep(chan, label)
206 int *chan;
207 char *label;
208 {
209 return midi_sleep_timo(chan, label, 0);
210 }
211
212 void
213 midi_wakeup(chan)
214 int *chan;
215 {
216 if (*chan) {
217 DPRINTFN(5, ("midi_wakeup: %p\n", chan));
218 wakeup(chan);
219 *chan = 0;
220 }
221 }
222
223 static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
224 /* Number of bytes in a MIDI command */
225 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
226
227 void
228 midi_in(addr, data)
229 void *addr;
230 int data;
231 {
232 struct midi_softc *sc = addr;
233 struct midi_buffer *mb = &sc->inbuf;
234 int i;
235
236 if (!sc->isopen)
237 return;
238 if (data == MIDI_ACK)
239 return;
240 DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
241 if (!(sc->flags & FREAD))
242 return; /* discard data if not reading */
243
244 switch(sc->in_state) {
245 case MIDI_IN_START:
246 if (MIDI_IS_STATUS(data)) {
247 switch(data) {
248 case 0xf0: /* Sysex */
249 sc->in_state = MIDI_IN_SYSEX;
250 break;
251 case 0xf1: /* MTC quarter frame */
252 case 0xf3: /* Song select */
253 sc->in_state = MIDI_IN_DATA;
254 sc->in_msg[0] = data;
255 sc->in_pos = 1;
256 sc->in_left = 1;
257 break;
258 case 0xf2: /* Song position pointer */
259 sc->in_state = MIDI_IN_DATA;
260 sc->in_msg[0] = data;
261 sc->in_pos = 1;
262 sc->in_left = 2;
263 break;
264 default:
265 if (MIDI_IS_COMMON(data)) {
266 sc->in_msg[0] = data;
267 sc->in_pos = 1;
268 goto deliver;
269 } else {
270 sc->in_state = MIDI_IN_DATA;
271 sc->in_msg[0] = sc->in_status = data;
272 sc->in_pos = 1;
273 sc->in_left = MIDI_LENGTH(sc->in_status);
274 }
275 break;
276 }
277 } else {
278 if (MIDI_IS_STATUS(sc->in_status)) {
279 sc->in_state = MIDI_IN_DATA;
280 sc->in_msg[0] = sc->in_status;
281 sc->in_msg[1] = data;
282 sc->in_pos = 2;
283 sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
284 }
285 }
286 return;
287 case MIDI_IN_DATA:
288 sc->in_msg[sc->in_pos++] = data;
289 if (--sc->in_left <= 0)
290 break; /* deliver data */
291 return;
292 case MIDI_IN_SYSEX:
293 if (data == MIDI_SYSEX_END)
294 sc->in_state = MIDI_IN_START;
295 return;
296 }
297 deliver:
298 sc->in_state = MIDI_IN_START;
299 #if NSEQUENCER > 0
300 if (sc->seqopen) {
301 extern void midiseq_in __P((struct midi_softc *,u_char *,int));
302 midiseq_in(sc, sc->in_msg, sc->in_pos);
303 return;
304 }
305 #endif
306
307 if (mb->used + sc->in_pos > mb->usedhigh) {
308 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
309 sc->in_msg[0]));
310 return;
311 }
312 for (i = 0; i < sc->in_pos; i++) {
313 *mb->inp++ = sc->in_msg[i];
314 if (mb->inp >= mb->end)
315 mb->inp = mb->start;
316 mb->used++;
317 }
318 midi_wakeup(&sc->rchan);
319 selwakeup(&sc->rsel);
320 if (sc->async)
321 psignal(sc->async, SIGIO);
322 }
323
324 void
325 midi_out(addr)
326 void *addr;
327 {
328 struct midi_softc *sc = addr;
329
330 if (!sc->isopen)
331 return;
332 DPRINTFN(3, ("midi_out: %p\n", sc));
333 midi_start_output(sc, 1);
334 }
335
336 int
337 midiopen(dev, flags, ifmt, p)
338 dev_t dev;
339 int flags, ifmt;
340 struct proc *p;
341 {
342 int unit = MIDIUNIT(dev);
343 struct midi_softc *sc;
344 struct midi_hw_if *hw;
345 int error;
346
347 if (unit >= midi_cd.cd_ndevs ||
348 (sc = midi_cd.cd_devs[unit]) == NULL)
349 return ENXIO;
350 DPRINTF(("midiopen %p\n", sc));
351
352 hw = sc->hw_if;
353 if (!hw)
354 return ENXIO;
355 if (sc->isopen)
356 return EBUSY;
357 sc->in_state = MIDI_IN_START;
358 sc->in_status = 0;
359 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
360 if (error)
361 return error;
362 sc->isopen++;
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 sc->isopen = 0;
400 splx(s);
401 hw->close(sc->hw_hdl);
402 #if NSEQUENCER > 0
403 sc->seqopen = 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 int
586 midiioctl(dev, cmd, addr, flag, p)
587 dev_t dev;
588 u_long cmd;
589 caddr_t addr;
590 int flag;
591 struct proc *p;
592 {
593 int unit = MIDIUNIT(dev);
594 struct midi_softc *sc = midi_cd.cd_devs[unit];
595 struct midi_hw_if *hw = sc->hw_if;
596 int error;
597
598 DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
599 error = 0;
600 switch (cmd) {
601 case FIONBIO:
602 /* All handled in the upper FS layer. */
603 break;
604
605 case FIOASYNC:
606 if (*(int *)addr) {
607 if (sc->async)
608 return EBUSY;
609 sc->async = p;
610 DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
611 } else
612 sc->async = 0;
613 break;
614
615 #if 0
616 case MIDI_PRETIME:
617 /* XXX OSS
618 * This should set up a read timeout, but that's
619 * why we have poll(), so there's nothing yet. */
620 error = EINVAL;
621 break;
622 #endif
623
624 #ifdef MIDI_SAVE
625 case MIDI_GETSAVE:
626 error = copyout(&midisave, *(void **)addr, sizeof midisave);
627 break;
628 #endif
629
630 default:
631 if (hw->ioctl)
632 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
633 else
634 error = EINVAL;
635 break;
636 }
637 return error;
638 }
639
640 int
641 midipoll(dev, events, p)
642 dev_t dev;
643 int events;
644 struct proc *p;
645 {
646 int unit = MIDIUNIT(dev);
647 struct midi_softc *sc = midi_cd.cd_devs[unit];
648 int revents = 0;
649 int s = splaudio();
650
651 DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
652
653 if (events & (POLLIN | POLLRDNORM))
654 if (sc->inbuf.used > 0)
655 revents |= events & (POLLIN | POLLRDNORM);
656
657 if (events & (POLLOUT | POLLWRNORM))
658 if (sc->outbuf.used < sc->outbuf.usedhigh)
659 revents |= events & (POLLOUT | POLLWRNORM);
660
661 if (revents == 0) {
662 if (events & (POLLIN | POLLRDNORM))
663 selrecord(p, &sc->rsel);
664
665 if (events & (POLLOUT | POLLWRNORM))
666 selrecord(p, &sc->wsel);
667 }
668
669 splx(s);
670 return revents;
671 }
672
673 void
674 midi_getinfo(dev, mi)
675 dev_t dev;
676 struct midi_info *mi;
677 {
678 int unit = MIDIUNIT(dev);
679 struct midi_softc *sc;
680
681 if (unit >= midi_cd.cd_ndevs ||
682 (sc = midi_cd.cd_devs[unit]) == NULL)
683 return;
684 sc->hw_if->getinfo(sc->hw_hdl, mi);
685 }
686
687 int audioprint __P((void *, const char *));
688
689 void
690 midi_attach_mi(mhwp, hdlp, dev)
691 struct midi_hw_if *mhwp;
692 void *hdlp;
693 struct device *dev;
694 {
695 struct audio_attach_args arg;
696
697 #ifdef DIAGNOSTIC
698 if (mhwp == NULL) {
699 printf("midi_attach_mi: NULL\n");
700 return;
701 }
702 #endif
703 arg.type = AUDIODEV_TYPE_MIDI;
704 arg.hwif = mhwp;
705 arg.hdl = hdlp;
706 (void)config_found(dev, &arg, audioprint);
707 }
708
709 #endif /* NMIDI > 0 */
710