midi.c revision 1.2 1 /* $NetBSD: midi.c,v 1.2 1998/08/12 18:11:53 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 (data == MIDI_ACK)
225 return;
226 DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
227 if (!(sc->flags & FREAD))
228 return; /* discard data if not reading */
229
230 switch(sc->in_state) {
231 case MIDI_IN_START:
232 if (MIDI_IS_STATUS(data)) {
233 switch(data) {
234 case 0xf0: /* Sysex */
235 sc->in_state = MIDI_IN_SYSEX;
236 break;
237 case 0xf1: /* MTC quarter frame */
238 case 0xf3: /* Song select */
239 sc->in_state = MIDI_IN_DATA;
240 sc->in_msg[0] = data;
241 sc->in_pos = 1;
242 sc->in_left = 1;
243 break;
244 case 0xf2: /* Song position pointer */
245 sc->in_state = MIDI_IN_DATA;
246 sc->in_msg[0] = data;
247 sc->in_pos = 1;
248 sc->in_left = 2;
249 break;
250 default:
251 if (MIDI_IS_COMMON(data)) {
252 sc->in_msg[0] = data;
253 sc->in_pos = 1;
254 goto deliver;
255 } else {
256 sc->in_state = MIDI_IN_DATA;
257 sc->in_msg[0] = sc->in_status = data;
258 sc->in_pos = 1;
259 sc->in_left = MIDI_LENGTH(sc->in_status);
260 }
261 break;
262 }
263 } else {
264 if (MIDI_IS_STATUS(sc->in_status)) {
265 sc->in_state = MIDI_IN_DATA;
266 sc->in_msg[0] = sc->in_status;
267 sc->in_msg[1] = data;
268 sc->in_pos = 2;
269 sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
270 }
271 }
272 return;
273 case MIDI_IN_DATA:
274 sc->in_msg[sc->in_pos++] = data;
275 if (--sc->in_left <= 0)
276 break; /* deliver data */
277 return;
278 case MIDI_IN_SYSEX:
279 if (data == MIDI_SYSEX_END)
280 sc->in_state = MIDI_IN_START;
281 return;
282 }
283 deliver:
284 sc->in_state = MIDI_IN_START;
285 #if NSEQUENCER > 0
286 if (sc->seqopen) {
287 extern void midiseq_in __P((struct midi_softc *,u_char *,int));
288 midiseq_in(sc, sc->in_msg, sc->in_pos);
289 return;
290 }
291 #endif
292
293 if (mb->used + sc->in_pos > mb->usedhigh) {
294 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
295 sc->in_msg[0]));
296 return;
297 }
298 for (i = 0; i < sc->in_pos; i++) {
299 *mb->inp++ = sc->in_msg[i];
300 if (mb->inp >= mb->end)
301 mb->inp = mb->start;
302 mb->used++;
303 }
304 midi_wakeup(&sc->rchan);
305 selwakeup(&sc->rsel);
306 if (sc->async)
307 psignal(sc->async, SIGIO);
308 }
309
310 void
311 midi_out(addr)
312 void *addr;
313 {
314 struct midi_softc *sc = addr;
315 DPRINTFN(3, ("midi_out: %p\n", sc));
316 midi_start_output(sc, 1);
317 }
318
319 int
320 midiopen(dev, flags, ifmt, p)
321 dev_t dev;
322 int flags, ifmt;
323 struct proc *p;
324 {
325 int unit = MIDIUNIT(dev);
326 struct midi_softc *sc;
327 struct midi_hw_if *hw;
328 int error;
329
330 if (unit >= midi_cd.cd_ndevs ||
331 (sc = midi_cd.cd_devs[unit]) == NULL)
332 return ENXIO;
333 DPRINTF(("midiopen %p\n", sc));
334
335 hw = sc->hw_if;
336 if (!hw)
337 return ENXIO;
338 if (sc->isopen)
339 return EBUSY;
340 sc->in_state = MIDI_IN_START;
341 sc->in_status = 0;
342 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
343 if (error)
344 return error;
345 sc->isopen++;
346 sc->flags = flags;
347 sc->rchan = 0;
348 sc->wchan = 0;
349 sc->pbus = 0;
350 sc->async = 0;
351
352 return 0;
353 }
354
355 int
356 midiclose(dev, flags, ifmt, p)
357 dev_t dev;
358 int flags, ifmt;
359 struct proc *p;
360 {
361 int unit = MIDIUNIT(dev);
362 struct midi_softc *sc = midi_cd.cd_devs[unit];
363 struct midi_hw_if *hw = sc->hw_if;
364 int s, error;
365
366 DPRINTF(("midiclose %p\n", sc));
367
368 midi_start_output(sc, 0);
369 error = 0;
370 s = splaudio();
371 while (sc->outbuf.used > 0 && !error) {
372 DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
373 error = midi_sleep_timo(&sc->wchan, "mid dr", 10*hz);
374 }
375 splx(s);
376 hw->close(sc->hw_hdl);
377 sc->isopen = 0;
378 #if NSEQUENCER > 0
379 sc->seqopen = 0;
380 #endif
381 return 0;
382 }
383
384 int
385 midiread(dev, uio, ioflag)
386 dev_t dev;
387 struct uio *uio;
388 int ioflag;
389 {
390 int unit = MIDIUNIT(dev);
391 struct midi_softc *sc = midi_cd.cd_devs[unit];
392 struct midi_buffer *mb = &sc->inbuf;
393 int error;
394 u_char *outp;
395 int used, cc, n, resid;
396 int s;
397
398 DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
399
400 error = 0;
401 resid = uio->uio_resid;
402 while (uio->uio_resid == resid && !error) {
403 s = splaudio();
404 while (mb->used <= 0) {
405 if (ioflag & IO_NDELAY) {
406 splx(s);
407 return EWOULDBLOCK;
408 }
409 error = midi_sleep(&sc->rchan, "mid rd");
410 if (error) {
411 splx(s);
412 return error;
413 }
414 }
415 used = mb->used;
416 outp = mb->outp;
417 splx(s);
418 cc = used; /* maximum to read */
419 n = mb->end - outp;
420 if (n < cc)
421 cc = n; /* don't read beyond end of buffer */
422 if (uio->uio_resid < cc)
423 cc = uio->uio_resid; /* and no more than we want */
424 DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
425 error = uiomove(outp, cc, uio);
426 if (error)
427 break;
428 used -= cc;
429 outp += cc;
430 if (outp >= mb->end)
431 outp = mb->start;
432 s = splaudio();
433 mb->outp = outp;
434 mb->used = used;
435 splx(s);
436 }
437 return error;
438 }
439
440 void
441 midi_timeout(arg)
442 void *arg;
443 {
444 struct midi_softc *sc = arg;
445
446 DPRINTFN(3,("midi_timeout: %p\n", sc));
447 midi_start_output(sc, 1);
448 }
449
450 int
451 midi_start_output(sc, intr)
452 struct midi_softc *sc;
453 int intr;
454 {
455 struct midi_buffer *mb = &sc->outbuf;
456 u_char *outp;
457 int error;
458 int s;
459 int i, mmax;
460
461 error = 0;
462 mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
463 s = splaudio();
464 if (sc->pbus && !intr) {
465 DPRINTFN(4, ("midi_start_output: busy\n"));
466 splx(s);
467 return 0;
468 }
469 sc->pbus = 1;
470 for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
471 outp = mb->outp;
472 splx(s);
473 DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
474 sc, i, *outp));
475 error = sc->hw_if->output(sc->hw_hdl, *outp++);
476 if (outp >= mb->end)
477 outp = mb->start;
478 s = splaudio();
479 mb->outp = outp;
480 mb->used--;
481 }
482 midi_wakeup(&sc->wchan);
483 selwakeup(&sc->wsel);
484 if (sc->async)
485 psignal(sc->async, SIGIO);
486 if (mb->used > 0) {
487 if (!(sc->props & MIDI_PROP_OUT_INTR))
488 timeout(midi_timeout, sc, midi_wait);
489 } else
490 sc->pbus = 0;
491 splx(s);
492 return error;
493 }
494
495 int
496 midiwrite(dev, uio, ioflag)
497 dev_t dev;
498 struct uio *uio;
499 int ioflag;
500 {
501 int unit = MIDIUNIT(dev);
502 struct midi_softc *sc = midi_cd.cd_devs[unit];
503 struct midi_buffer *mb = &sc->outbuf;
504 int error;
505 u_char *inp;
506 int used, cc, n;
507 int s;
508
509 DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
510 uio->uio_resid));
511
512 error = 0;
513 while (uio->uio_resid > 0 && !error) {
514 s = splaudio();
515 if (mb->used >= mb->usedhigh) {
516 DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
517 mb->used, mb->usedhigh));
518 if (ioflag & IO_NDELAY) {
519 splx(s);
520 return EWOULDBLOCK;
521 }
522 error = midi_sleep(&sc->wchan, "mid wr");
523 if (error) {
524 splx(s);
525 return error;
526 }
527 }
528 used = mb->used;
529 inp = mb->inp;
530 splx(s);
531 cc = mb->usedhigh - used; /* maximum to write */
532 n = mb->end - inp;
533 if (n < cc)
534 cc = n; /* don't write beyond end of buffer */
535 if (uio->uio_resid < cc)
536 cc = uio->uio_resid; /* and no more than we have */
537 error = uiomove(inp, cc, uio);
538 #ifdef MIDI_DEBUG
539 if (error)
540 printf("midi_write:(1) uiomove failed %d; cc=%d inp=%p\n",
541 error, cc, inp);
542 #endif
543 if (error)
544 break;
545 inp = mb->inp + cc;
546 if (inp >= mb->end)
547 inp = mb->start;
548 s = splaudio();
549 mb->inp = inp;
550 mb->used += cc;
551 splx(s);
552 error = midi_start_output(sc, 0);
553 }
554 return error;
555 }
556
557 int
558 midiioctl(dev, cmd, addr, flag, p)
559 dev_t dev;
560 u_long cmd;
561 caddr_t addr;
562 int flag;
563 struct proc *p;
564 {
565 int unit = MIDIUNIT(dev);
566 struct midi_softc *sc = midi_cd.cd_devs[unit];
567 struct midi_hw_if *hw = sc->hw_if;
568 int error;
569
570 DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
571 error = 0;
572 switch (cmd) {
573 case FIONBIO:
574 /* All handled in the upper FS layer. */
575 break;
576
577 case FIOASYNC:
578 if (*(int *)addr) {
579 if (sc->async)
580 return EBUSY;
581 sc->async = p;
582 DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
583 } else
584 sc->async = 0;
585 break;
586
587 #if 0
588 case MIDI_PRETIME:
589 /* XXX OSS
590 * This should set up a read timeout, but that's
591 * why we have poll(), so there's nothing yet. */
592 error = EINVAL;
593 break;
594 #endif
595
596 default:
597 if (hw->ioctl)
598 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
599 else
600 error = EINVAL;
601 break;
602 }
603 return error;
604 }
605
606 int
607 midipoll(dev, events, p)
608 dev_t dev;
609 int events;
610 struct proc *p;
611 {
612 int unit = MIDIUNIT(dev);
613 struct midi_softc *sc = midi_cd.cd_devs[unit];
614 int revents = 0;
615 int s = splaudio();
616
617 DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
618
619 if (events & (POLLIN | POLLRDNORM))
620 if (sc->inbuf.used > 0)
621 revents |= events & (POLLIN | POLLRDNORM);
622
623 if (events & (POLLOUT | POLLWRNORM))
624 if (sc->outbuf.used < sc->outbuf.usedhigh)
625 revents |= events & (POLLOUT | POLLWRNORM);
626
627 if (revents == 0) {
628 if (events & (POLLIN | POLLRDNORM))
629 selrecord(p, &sc->rsel);
630
631 if (events & (POLLOUT | POLLWRNORM))
632 selrecord(p, &sc->wsel);
633 }
634
635 splx(s);
636 return revents;
637 }
638
639 void
640 midi_getinfo(dev, mi)
641 dev_t dev;
642 struct midi_info *mi;
643 {
644 int unit = MIDIUNIT(dev);
645 struct midi_softc *sc;
646
647 if (unit >= midi_cd.cd_ndevs ||
648 (sc = midi_cd.cd_devs[unit]) == NULL)
649 return;
650 sc->hw_if->getinfo(sc->hw_hdl, mi);
651 }
652
653 #endif /* NMIDI > 0 */
654