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