midi.c revision 1.43.2.4 1 /* $NetBSD: midi.c,v 1.43.2.4 2006/05/20 03:14:12 chap Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss (at) NetBSD.org).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.43.2.4 2006/05/20 03:14:12 chap Exp $");
41
42 #include "midi.h"
43 #include "sequencer.h"
44
45 #include <sys/param.h>
46 #include <sys/ioctl.h>
47 #include <sys/fcntl.h>
48 #include <sys/vnode.h>
49 #include <sys/select.h>
50 #include <sys/poll.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/systm.h>
54 #include <sys/callout.h>
55 #include <sys/syslog.h>
56 #include <sys/kernel.h>
57 #include <sys/signalvar.h>
58 #include <sys/conf.h>
59 #include <sys/audioio.h>
60 #include <sys/midiio.h>
61 #include <sys/device.h>
62
63 #include <dev/audio_if.h>
64 #include <dev/midi_if.h>
65 #include <dev/midivar.h>
66
67 #if NMIDI > 0
68
69 #ifdef AUDIO_DEBUG
70 #define DPRINTF(x) if (mididebug) printf x
71 #define DPRINTFN(n,x) if (mididebug >= (n)) printf x
72 int mididebug = 0;
73 /*
74 * 1: detected protocol errors and buffer overflows
75 * 2: probe, attach, detach
76 * 3: open, close
77 * 4: data received except realtime
78 * 5: ioctl
79 * 6: read, write, poll
80 * 7: data transmitted
81 * 8: uiomoves, synchronization
82 * 9: realtime data received
83 */
84 #else
85 #define DPRINTF(x)
86 #define DPRINTFN(n,x)
87 #endif
88
89 int midi_wait;
90
91 void midi_in(void *, int);
92 void midi_out(void *);
93 int midi_start_output(struct midi_softc *, int);
94 int midi_sleep_timo(int *, char *, int);
95 int midi_sleep(int *, char *);
96 void midi_wakeup(int *);
97 void midi_initbuf(struct midi_buffer *);
98 void midi_timeout(void *);
99
100 int midiprobe(struct device *, struct cfdata *, void *);
101 void midiattach(struct device *, struct device *, void *);
102 int mididetach(struct device *, int);
103 int midiactivate(struct device *, enum devact);
104
105 dev_type_open(midiopen);
106 dev_type_close(midiclose);
107 dev_type_read(midiread);
108 dev_type_write(midiwrite);
109 dev_type_ioctl(midiioctl);
110 dev_type_poll(midipoll);
111 dev_type_kqfilter(midikqfilter);
112
113 const struct cdevsw midi_cdevsw = {
114 midiopen, midiclose, midiread, midiwrite, midiioctl,
115 nostop, notty, midipoll, nommap, midikqfilter,
116 };
117
118 CFATTACH_DECL(midi, sizeof(struct midi_softc),
119 midiprobe, midiattach, mididetach, midiactivate);
120
121 #ifdef MIDI_SAVE
122 #define MIDI_SAVE_SIZE 100000
123 int midicnt;
124 struct {
125 int cnt;
126 u_char buf[MIDI_SAVE_SIZE];
127 } midisave;
128 #define MIDI_GETSAVE _IOWR('m', 100, int)
129
130 #endif
131
132 extern struct cfdriver midi_cd;
133
134 int
135 midiprobe(struct device *parent, struct cfdata *match, void *aux)
136 {
137 struct audio_attach_args *sa = aux;
138
139 DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n",
140 sa->type, sa, sa->hwif));
141 return (sa->type == AUDIODEV_TYPE_MIDI);
142 }
143
144 void
145 midiattach(struct device *parent, struct device *self, void *aux)
146 {
147 struct midi_softc *sc = (void *)self;
148 struct audio_attach_args *sa = aux;
149 struct midi_hw_if *hwp = sa->hwif;
150 void *hdlp = sa->hdl;
151
152 DPRINTFN(2, ("MIDI attach\n"));
153
154 #ifdef DIAGNOSTIC
155 if (hwp == 0 ||
156 hwp->open == 0 ||
157 hwp->close == 0 ||
158 hwp->output == 0 ||
159 hwp->getinfo == 0) {
160 printf("midi: missing method\n");
161 return;
162 }
163 #endif
164
165 callout_init(&sc->sc_callout);
166
167 sc->hw_if = hwp;
168 sc->hw_hdl = hdlp;
169 sc->dying = 0;
170 midi_attach(sc, parent);
171 }
172
173 int
174 midiactivate(struct device *self, enum devact act)
175 {
176 struct midi_softc *sc = (struct midi_softc *)self;
177
178 switch (act) {
179 case DVACT_ACTIVATE:
180 return (EOPNOTSUPP);
181
182 case DVACT_DEACTIVATE:
183 sc->dying = 1;
184 break;
185 }
186 return (0);
187 }
188
189 int
190 mididetach(struct device *self, int flags)
191 {
192 struct midi_softc *sc = (struct midi_softc *)self;
193 int maj, mn;
194
195 DPRINTFN(2,("midi_detach: sc=%p flags=%d\n", sc, flags));
196
197 sc->dying = 1;
198
199 wakeup(&sc->wchan);
200 wakeup(&sc->rchan);
201
202 /* locate the major number */
203 maj = cdevsw_lookup_major(&midi_cdevsw);
204
205 /* Nuke the vnodes for any open instances (calls close). */
206 mn = self->dv_unit;
207 vdevgone(maj, mn, mn, VCHR);
208
209 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
210 evcnt_detach(&sc->rcvBytesDiscarded);
211 evcnt_detach(&sc->rcvIncompleteMessages);
212 }
213
214 return (0);
215 }
216
217 void
218 midi_attach(struct midi_softc *sc, struct device *parent)
219 {
220 struct midi_info mi;
221
222 sc->isopen = 0;
223
224 midi_wait = MIDI_WAIT * hz / 1000000;
225 if (midi_wait == 0)
226 midi_wait = 1;
227
228 sc->sc_dev = parent;
229 sc->hw_if->getinfo(sc->hw_hdl, &mi);
230 sc->props = mi.props;
231
232 if ( sc->props & MIDI_PROP_CAN_INPUT ) {
233 evcnt_attach_dynamic(&sc->rcvBytesDiscarded,
234 EVCNT_TYPE_MISC, NULL,
235 sc->dev.dv_xname, "rcv bytes discarded");
236 evcnt_attach_dynamic(&sc->rcvIncompleteMessages,
237 EVCNT_TYPE_MISC, NULL,
238 sc->dev.dv_xname, "rcv incomplete msgs");
239 }
240
241 printf(": %s\n", mi.name);
242 }
243
244 int
245 midi_unit_count(void)
246 {
247 int i;
248 for ( i = 0; i < midi_cd.cd_ndevs; ++i )
249 if ( NULL == midi_cd.cd_devs[i] )
250 break;
251 return i;
252 }
253
254 void
255 midi_initbuf(struct midi_buffer *mb)
256 {
257 mb->used = 0;
258 mb->usedhigh = MIDI_BUFSIZE;
259 mb->end = mb->start + mb->usedhigh;
260 mb->inp = mb->outp = mb->start;
261 }
262
263 int
264 midi_sleep_timo(int *chan, char *label, int timo)
265 {
266 int st;
267
268 if (!label)
269 label = "midi";
270
271 DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
272 *chan = 1;
273 st = tsleep(chan, PWAIT | PCATCH, label, timo);
274 *chan = 0;
275 #ifdef MIDI_DEBUG
276 if (st != 0)
277 printf("midi_sleep: %d\n", st);
278 #endif
279 return st;
280 }
281
282 int
283 midi_sleep(int *chan, char *label)
284 {
285 return midi_sleep_timo(chan, label, 0);
286 }
287
288 void
289 midi_wakeup(int *chan)
290 {
291 if (*chan) {
292 DPRINTFN(8, ("midi_wakeup: %p\n", chan));
293 wakeup(chan);
294 *chan = 0;
295 }
296 }
297
298 /* in midivar.h:
299 #define MIDI_CAT_DATA 0
300 #define MIDI_CAT_STATUS1 1
301 #define MIDI_CAT_STATUS2 2
302 #define MIDI_CAT_COMMON 3
303 */
304 static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
305 #define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
306
307 void
308 midi_in(void *addr, int data)
309 {
310 struct midi_softc *sc = addr;
311 struct midi_buffer *mb = &sc->inbuf;
312 int i;
313 u_char *what = sc->in_msg;
314 u_char rtbuf;
315 int count;
316
317 if (!sc->isopen)
318 return;
319
320 if (!(sc->flags & FREAD))
321 return; /* discard data if not reading */
322
323 if ( data >= 0xf8 ) { /* All realtime messages bypass state machine */
324 if ( data == 0xf9 || data == 0xfd ) {
325 DPRINTF( ("midi_in: sc=%p data=0x%02x undefined\n",
326 sc, data));
327 sc->rcvBytesDiscarded.ev_count++;
328 return;
329 }
330 DPRINTFN(9, ("midi_in: sc=%p System Real-Time data=0x%02x\n",
331 sc, data));
332 rtbuf = data;
333 count = sizeof rtbuf;
334 what = &rtbuf;
335 goto deliver;
336 }
337
338 DPRINTFN(4, ("midi_in: sc=%p data=0x%02x state=%d\n",
339 sc, data, sc->in_state));
340
341 retry:
342 switch ( sc->in_state | MIDI_CAT(data) ) {
343
344 case MIDI_IN_START | MIDI_CAT_COMMON:
345 case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
346 case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
347 sc->in_msg[0] = data;
348 count = 1;
349 switch ( data ) {
350 case 0xf0: sc->in_state = MIDI_IN_SYSEX; goto deliver_raw;
351 case 0xf1: sc->in_state = MIDI_IN_COM0_1; return;
352 case 0xf2: sc->in_state = MIDI_IN_COM0_2; return;
353 case 0xf3: sc->in_state = MIDI_IN_COM0_1; return;
354 case 0xf6: sc->in_state = MIDI_IN_START; break;
355 default: goto protocol_violation;
356 }
357 break;
358
359 case MIDI_IN_START | MIDI_CAT_STATUS1:
360 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
361 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1:
362 sc->in_state = MIDI_IN_RUN0_1;
363 sc->in_msg[0] = data;
364 return;
365
366 case MIDI_IN_START | MIDI_CAT_STATUS2:
367 case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2:
368 case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
369 sc->in_state = MIDI_IN_RUN0_2;
370 sc->in_msg[0] = data;
371 return;
372
373 case MIDI_IN_COM0_1 | MIDI_CAT_DATA:
374 sc->in_state = MIDI_IN_START;
375 sc->in_msg[1] = data;
376 count = 2;
377 break;
378
379 case MIDI_IN_COM0_2 | MIDI_CAT_DATA:
380 sc->in_state = MIDI_IN_COM1_2;
381 sc->in_msg[1] = data;
382 return;
383
384 case MIDI_IN_COM1_2 | MIDI_CAT_DATA:
385 sc->in_state = MIDI_IN_START;
386 sc->in_msg[2] = data;
387 count = 3;
388 break;
389
390 case MIDI_IN_RUN0_1 | MIDI_CAT_DATA:
391 case MIDI_IN_RUN1_1 | MIDI_CAT_DATA:
392 sc->in_state = MIDI_IN_RUN1_1;
393 sc->in_msg[1] = data;
394 count = 2;
395 break;
396
397 case MIDI_IN_RUN0_2 | MIDI_CAT_DATA:
398 case MIDI_IN_RUN2_2 | MIDI_CAT_DATA:
399 sc->in_state = MIDI_IN_RUN1_2;
400 sc->in_msg[1] = data;
401 return;
402
403 case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
404 sc->in_state = MIDI_IN_RUN2_2;
405 sc->in_msg[2] = data;
406 count = 3;
407 break;
408
409 case MIDI_IN_SYSEX | MIDI_CAT_DATA:
410 sc->in_msg[0] = data;
411 count = 1;
412 goto deliver_raw;
413
414 case MIDI_IN_SYSEX | MIDI_CAT_COMMON:
415 if ( data == 0xf7 ) {
416 sc->in_state = MIDI_IN_START;
417 sc->in_msg[0] = data;
418 count = 1;
419 goto deliver_raw;
420 }
421 /* FALLTHROUGH */
422
423 default:
424 protocol_violation:
425 DPRINTF(("midi_in: unexpected %#02x in state %u\n",
426 data, sc->in_state));
427 switch ( sc->in_state ) {
428 case MIDI_IN_RUN1_1: /* can only get here by seeing an */
429 case MIDI_IN_RUN2_2: /* INVALID System Common message */
430 sc->in_state = MIDI_IN_START;
431 /* FALLTHROUGH */
432 case MIDI_IN_START:
433 sc->rcvBytesDiscarded.ev_count++;
434 return;
435 case MIDI_IN_COM1_2:
436 case MIDI_IN_RUN1_2:
437 sc->rcvBytesDiscarded.ev_count++;
438 /* FALLTHROUGH */
439 case MIDI_IN_COM0_1:
440 case MIDI_IN_RUN0_1:
441 case MIDI_IN_COM0_2:
442 case MIDI_IN_RUN0_2:
443 sc->rcvBytesDiscarded.ev_count++;
444 /* FALLTHROUGH */
445 case MIDI_IN_SYSEX:
446 sc->rcvIncompleteMessages.ev_count++;
447 break;
448 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
449 default:
450 printf("midi_in: mishandled %#02x(%u) in state %u?!\n",
451 data, MIDI_CAT(data), sc->in_state);
452 #endif
453 }
454 sc->in_state = MIDI_IN_START;
455 goto retry;
456 }
457
458 deliver:
459 #if NSEQUENCER > 0
460 if (sc->seqopen) {
461 extern void midiseq_in(struct midi_dev *,u_char *,int);
462 midiseq_in(sc->seq_md, what, count);
463 return;
464 }
465 #endif
466 if ( data == MIDI_ACK ) /* sequencer should see these to support API */
467 return; /* otherwise discard (could track time last seen) */
468 deliver_raw:
469 if (mb->used + count > mb->usedhigh) {
470 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
471 what[0]));
472 sc->rcvBytesDiscarded.ev_count += count;
473 return;
474 }
475 for (i = 0; i < count; i++) {
476 *mb->inp++ = what[i];
477 if (mb->inp >= mb->end)
478 mb->inp = mb->start;
479 mb->used++;
480 }
481 midi_wakeup(&sc->rchan);
482 selnotify(&sc->rsel, 0);
483 if (sc->async)
484 psignal(sc->async, SIGIO);
485 }
486
487 void
488 midi_out(void *addr)
489 {
490 struct midi_softc *sc = addr;
491
492 if (!sc->isopen)
493 return;
494 DPRINTFN(8, ("midi_out: %p\n", sc));
495 midi_start_output(sc, 1);
496 }
497
498 int
499 midiopen(dev_t dev, int flags, int ifmt, struct proc *p)
500 {
501 struct midi_softc *sc;
502 struct midi_hw_if *hw;
503 int error;
504
505 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
506 if (sc == NULL)
507 return (ENXIO);
508 if (sc->dying)
509 return (EIO);
510
511 DPRINTFN(3,("midiopen %p\n", sc));
512
513 hw = sc->hw_if;
514 if (!hw)
515 return ENXIO;
516 if (sc->isopen)
517 return EBUSY;
518 sc->in_state = MIDI_IN_START;
519 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
520 if (error)
521 return error;
522 sc->isopen++;
523 midi_initbuf(&sc->outbuf);
524 midi_initbuf(&sc->inbuf);
525 sc->flags = flags;
526 sc->rchan = 0;
527 sc->wchan = 0;
528 sc->pbus = 0;
529 sc->async = 0;
530
531 #ifdef MIDI_SAVE
532 if (midicnt != 0) {
533 midisave.cnt = midicnt;
534 midicnt = 0;
535 }
536 #endif
537
538 return 0;
539 }
540
541 int
542 midiclose(dev_t dev, int flags, int ifmt, struct proc *p)
543 {
544 int unit = MIDIUNIT(dev);
545 struct midi_softc *sc = midi_cd.cd_devs[unit];
546 struct midi_hw_if *hw = sc->hw_if;
547 int s, error;
548
549 DPRINTFN(3,("midiclose %p\n", sc));
550
551 midi_start_output(sc, 0);
552 error = 0;
553 s = splaudio();
554 while (sc->outbuf.used > 0 && !error) {
555 DPRINTFN(8,("midiclose sleep used=%d\n", sc->outbuf.used));
556 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
557 }
558 splx(s);
559 sc->isopen = 0;
560 hw->close(sc->hw_hdl);
561 #if NSEQUENCER > 0
562 sc->seqopen = 0;
563 sc->seq_md = 0;
564 #endif
565 return 0;
566 }
567
568 int
569 midiread(dev_t dev, struct uio *uio, int ioflag)
570 {
571 int unit = MIDIUNIT(dev);
572 struct midi_softc *sc = midi_cd.cd_devs[unit];
573 struct midi_buffer *mb = &sc->inbuf;
574 int error;
575 u_char *outp;
576 int used, cc, n, resid;
577 int s;
578
579 DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
580 (unsigned long)uio->uio_resid));
581
582 if (sc->dying)
583 return EIO;
584 if ( !(sc->flags & FREAD) )
585 return EBADF;
586 if ( !(sc->props & MIDI_PROP_CAN_INPUT) )
587 return ENXIO;
588
589 error = 0;
590 resid = uio->uio_resid;
591 while (uio->uio_resid == resid && !error) {
592 s = splaudio();
593 while (mb->used <= 0) {
594 if (ioflag & IO_NDELAY) {
595 splx(s);
596 return EWOULDBLOCK;
597 }
598 error = midi_sleep(&sc->rchan, "mid rd");
599 if (error) {
600 splx(s);
601 return error;
602 }
603 }
604 used = mb->used;
605 outp = mb->outp;
606 splx(s);
607 if (sc->dying)
608 return EIO;
609 cc = used; /* maximum to read */
610 n = mb->end - outp;
611 if (n < cc)
612 cc = n; /* don't read beyond end of buffer */
613 if (uio->uio_resid < cc)
614 cc = uio->uio_resid; /* and no more than we want */
615 DPRINTFN(8, ("midiread: uiomove cc=%d\n", cc));
616 error = uiomove(outp, cc, uio);
617 if (error)
618 break;
619 used -= cc;
620 outp += cc;
621 if (outp >= mb->end)
622 outp = mb->start;
623 s = splaudio();
624 mb->outp = outp;
625 mb->used = used;
626 splx(s);
627 }
628 return error;
629 }
630
631 void
632 midi_timeout(void *arg)
633 {
634 struct midi_softc *sc = arg;
635
636 DPRINTFN(8,("midi_timeout: %p\n", sc));
637 midi_start_output(sc, 1);
638 }
639
640 int
641 midi_start_output(struct midi_softc *sc, int intr)
642 {
643 struct midi_buffer *mb = &sc->outbuf;
644 u_char out;
645 int error;
646 int s;
647 int i;
648
649 error = 0;
650
651 if (sc->dying)
652 return EIO;
653
654 if (sc->pbus && !intr) {
655 DPRINTFN(8, ("midi_start_output: busy\n"));
656 return 0;
657 }
658 sc->pbus = (mb->used > 0)?1:0;
659 for (i = 0; i < MIDI_MAX_WRITE && mb->used > 0 &&
660 (!error || error==EINPROGRESS); i++) {
661 s = splaudio();
662 out = *mb->outp;
663 mb->outp++;
664 if (mb->outp >= mb->end)
665 mb->outp = mb->start;
666 mb->used--;
667 splx(s);
668 #ifdef MIDI_SAVE
669 midisave.buf[midicnt] = out;
670 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
671 #endif
672 DPRINTFN(8, ("midi_start_output: %p i=%d, data=0x%02x\n",
673 sc, i, out));
674 error = sc->hw_if->output(sc->hw_hdl, out);
675 if ((sc->props & MIDI_PROP_OUT_INTR) && error!=EINPROGRESS)
676 /* If ointr is enabled, midi_start_output()
677 * normally writes only one byte,
678 * except hw_if->output() returns EINPROGRESS.
679 */
680 break;
681 }
682 midi_wakeup(&sc->wchan);
683 selnotify(&sc->wsel, 0);
684 if (sc->async)
685 psignal(sc->async, SIGIO);
686 if (!(sc->props & MIDI_PROP_OUT_INTR) || error==EINPROGRESS) {
687 if (mb->used > 0)
688 callout_reset(&sc->sc_callout, midi_wait,
689 midi_timeout, sc);
690 else
691 sc->pbus = 0;
692 }
693 if ((sc->props & MIDI_PROP_OUT_INTR) && error==EINPROGRESS)
694 error = 0;
695
696 return error;
697 }
698
699 int
700 midiwrite(dev_t dev, struct uio *uio, int ioflag)
701 {
702 int unit = MIDIUNIT(dev);
703 struct midi_softc *sc = midi_cd.cd_devs[unit];
704 struct midi_buffer *mb = &sc->outbuf;
705 int error;
706 u_char *inp;
707 int used, cc, n;
708 int s;
709
710 DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit,
711 (unsigned long)uio->uio_resid));
712
713 if (sc->dying)
714 return EIO;
715 if ( !(sc->flags & FWRITE) )
716 return EBADF;
717
718 error = 0;
719 while (uio->uio_resid > 0 && !error) {
720 s = splaudio();
721 if (mb->used >= mb->usedhigh) {
722 DPRINTFN(8,("midi_write: sleep used=%d hiwat=%d\n",
723 mb->used, mb->usedhigh));
724 if (ioflag & IO_NDELAY) {
725 splx(s);
726 return EWOULDBLOCK;
727 }
728 error = midi_sleep(&sc->wchan, "mid wr");
729 if (error) {
730 splx(s);
731 return error;
732 }
733 }
734 used = mb->used;
735 inp = mb->inp;
736 splx(s);
737 if (sc->dying)
738 return EIO;
739 cc = mb->usedhigh - used; /* maximum to write */
740 n = mb->end - inp;
741 if (n < cc)
742 cc = n; /* don't write beyond end of buffer */
743 if (uio->uio_resid < cc)
744 cc = uio->uio_resid; /* and no more than we have */
745 error = uiomove(inp, cc, uio);
746 #ifdef MIDI_DEBUG
747 if (error)
748 printf("midi_write:(1) uiomove failed %d; "
749 "cc=%d inp=%p\n",
750 error, cc, inp);
751 #endif
752 if (error)
753 break;
754 inp = mb->inp + cc;
755 if (inp >= mb->end)
756 inp = mb->start;
757 s = splaudio();
758 mb->inp = inp;
759 mb->used += cc;
760 splx(s);
761 error = midi_start_output(sc, 0);
762 }
763 return error;
764 }
765
766 /*
767 * This write routine is only called from sequencer code and expects
768 * a write that is smaller than the MIDI buffer.
769 */
770 int
771 midi_writebytes(int unit, u_char *buf, int cc)
772 {
773 struct midi_softc *sc = midi_cd.cd_devs[unit];
774 struct midi_buffer *mb = &sc->outbuf;
775 int n, s;
776
777 DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
778 sc, unit, cc, buf[0], buf[1], buf[2]));
779
780 if (sc->dying)
781 return EIO;
782
783 s = splaudio();
784 if (mb->used + cc >= mb->usedhigh) {
785 splx(s);
786 return (EWOULDBLOCK);
787 }
788 n = mb->end - mb->inp;
789 if (cc < n)
790 n = cc;
791 mb->used += cc;
792 memcpy(mb->inp, buf, n);
793 mb->inp += n;
794 if (mb->inp >= mb->end) {
795 mb->inp = mb->start;
796 cc -= n;
797 if (cc > 0) {
798 memcpy(mb->inp, buf + n, cc);
799 mb->inp += cc;
800 }
801 }
802 splx(s);
803 return (midi_start_output(sc, 0));
804 }
805
806 int
807 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
808 {
809 int unit = MIDIUNIT(dev);
810 struct midi_softc *sc = midi_cd.cd_devs[unit];
811 struct midi_hw_if *hw = sc->hw_if;
812 int error;
813
814 DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
815
816 if (sc->dying)
817 return EIO;
818
819 error = 0;
820 switch (cmd) {
821 case FIONBIO:
822 /* All handled in the upper FS layer. */
823 break;
824
825 case FIOASYNC:
826 if (*(int *)addr) {
827 if (sc->async)
828 return EBUSY;
829 sc->async = p;
830 DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", p));
831 } else
832 sc->async = 0;
833 break;
834
835 #if 0
836 case MIDI_PRETIME:
837 /* XXX OSS
838 * This should set up a read timeout, but that's
839 * why we have poll(), so there's nothing yet. */
840 error = EINVAL;
841 break;
842 #endif
843
844 #ifdef MIDI_SAVE
845 case MIDI_GETSAVE:
846 error = copyout(&midisave, *(void **)addr, sizeof midisave);
847 break;
848 #endif
849
850 default:
851 if (hw->ioctl)
852 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
853 else
854 error = EINVAL;
855 break;
856 }
857 return error;
858 }
859
860 int
861 midipoll(dev_t dev, int events, struct proc *p)
862 {
863 int unit = MIDIUNIT(dev);
864 struct midi_softc *sc = midi_cd.cd_devs[unit];
865 int revents = 0;
866 int s;
867
868 DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
869
870 if (sc->dying)
871 return EIO;
872
873 s = splaudio();
874
875 if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM)))
876 if (sc->inbuf.used > 0)
877 revents |= events & (POLLIN | POLLRDNORM);
878
879 if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM)))
880 if (sc->outbuf.used < sc->outbuf.usedhigh)
881 revents |= events & (POLLOUT | POLLWRNORM);
882
883 if (revents == 0) {
884 if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM)))
885 selrecord(p, &sc->rsel);
886
887 if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM)))
888 selrecord(p, &sc->wsel);
889 }
890
891 splx(s);
892 return revents;
893 }
894
895 static void
896 filt_midirdetach(struct knote *kn)
897 {
898 struct midi_softc *sc = kn->kn_hook;
899 int s;
900
901 s = splaudio();
902 SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
903 splx(s);
904 }
905
906 static int
907 filt_midiread(struct knote *kn, long hint)
908 {
909 struct midi_softc *sc = kn->kn_hook;
910
911 /* XXXLUKEM (thorpej): please make sure this is correct. */
912
913 kn->kn_data = sc->inbuf.used;
914 return (kn->kn_data > 0);
915 }
916
917 static const struct filterops midiread_filtops =
918 { 1, NULL, filt_midirdetach, filt_midiread };
919
920 static void
921 filt_midiwdetach(struct knote *kn)
922 {
923 struct midi_softc *sc = kn->kn_hook;
924 int s;
925
926 s = splaudio();
927 SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
928 splx(s);
929 }
930
931 static int
932 filt_midiwrite(struct knote *kn, long hint)
933 {
934 struct midi_softc *sc = kn->kn_hook;
935
936 /* XXXLUKEM (thorpej): please make sure this is correct. */
937
938 kn->kn_data = sc->outbuf.usedhigh - sc->outbuf.used;
939 return (kn->kn_data > 0);
940 }
941
942 static const struct filterops midiwrite_filtops =
943 { 1, NULL, filt_midiwdetach, filt_midiwrite };
944
945 int
946 midikqfilter(dev_t dev, struct knote *kn)
947 {
948 int unit = MIDIUNIT(dev);
949 struct midi_softc *sc = midi_cd.cd_devs[unit];
950 struct klist *klist;
951 int s;
952
953 switch (kn->kn_filter) {
954 case EVFILT_READ:
955 klist = &sc->rsel.sel_klist;
956 kn->kn_fop = &midiread_filtops;
957 break;
958
959 case EVFILT_WRITE:
960 klist = &sc->wsel.sel_klist;
961 kn->kn_fop = &midiwrite_filtops;
962 break;
963
964 default:
965 return (1);
966 }
967
968 kn->kn_hook = sc;
969
970 s = splaudio();
971 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
972 splx(s);
973
974 return (0);
975 }
976
977 void
978 midi_getinfo(dev_t dev, struct midi_info *mi)
979 {
980 struct midi_softc *sc;
981
982 sc = device_lookup(&midi_cd, MIDIUNIT(dev));
983 if (sc == NULL)
984 return;
985 if (sc->dying)
986 return;
987
988 sc->hw_if->getinfo(sc->hw_hdl, mi);
989 }
990
991 #endif /* NMIDI > 0 */
992
993 #if NMIDI > 0 || NMIDIBUS > 0
994
995 int audioprint(void *, const char *);
996
997 struct device *
998 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev)
999 {
1000 struct audio_attach_args arg;
1001
1002 #ifdef DIAGNOSTIC
1003 if (mhwp == NULL) {
1004 aprint_error("midi_attach_mi: NULL\n");
1005 return (0);
1006 }
1007 #endif
1008 arg.type = AUDIODEV_TYPE_MIDI;
1009 arg.hwif = mhwp;
1010 arg.hdl = hdlp;
1011 return (config_found(dev, &arg, audioprint));
1012 }
1013
1014 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
1015