1 /*
2 * Main midi driver for FreeBSD. This file provides the main
3 * entry points for probe/attach and all i/o demultiplexing, including
4 * default routines for generic devices.
5 *
6 * (C) 1999 Seigo Tanimura
7 *
8 * Redistribution and use in source and binary forms, with or
9 * without modification, are permitted provided that the following
10 * conditions are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
19 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 *
32 * For each card type a template "mididev_info" structure contains
33 * all the relevant parameters, both for configuration and runtime.
34 *
35 * In this file we build tables of pointers to the descriptors for
36 * the various supported cards. The generic probe routine scans
37 * the table(s) looking for a matching entry, then invokes the
38 * board-specific probe routine. If successful, a pointer to the
39 * correct mididev_info is stored in mididev_last_probed, for subsequent
40 * use in the attach routine. The generic attach routine copies
41 * the template to a permanent descriptor (midi_info and
42 * friends), initializes all generic parameters, and calls the
43 * board-specific attach routine.
44 *
45 * On device calls, the generic routines do the checks on unit and
46 * device parameters, then call the board-specific routines if
47 * available, or try to perform the task using the default code.
48 *
49 * $FreeBSD: releng/5.0/sys/dev/sound/midi/midi.c 93818 2002-04-04 21:03:38Z jhb $
50 *
51 */
52
53 #include <dev/sound/midi/midi.h>
54
55 static devclass_t midi_devclass;
56
57 static d_open_t midiopen;
58 static d_close_t midiclose;
59 static d_ioctl_t midiioctl;
60 static d_read_t midiread;
61 static d_write_t midiwrite;
62 static d_poll_t midipoll;
63
64 /* These functions are local. */
65 static d_open_t midistat_open;
66 static d_close_t midistat_close;
67 static d_read_t midistat_read;
68 static int midi_initstatus(char *buf, int size);
69 static int midi_readstatus(char *buf, int *ptr, struct uio *uio);
70
71 #define CDEV_MAJOR MIDI_CDEV_MAJOR
72 static struct cdevsw midi_cdevsw = {
73 /* open */ midiopen,
74 /* close */ midiclose,
75 /* read */ midiread,
76 /* write */ midiwrite,
77 /* ioctl */ midiioctl,
78 /* poll */ midipoll,
79 /* mmap */ nommap,
80 /* strategy */ nostrategy,
81 /* name */ "midi",
82 /* maj */ CDEV_MAJOR,
83 /* dump */ nodump,
84 /* psize */ nopsize,
85 /* flags */ 0,
86 };
87
88 /*
89 * descriptors for active devices. also used as the public softc
90 * of a device.
91 */
92 static TAILQ_HEAD(,_mididev_info) midi_info;
93 static int nmidi, nsynth;
94 /* Mutex to protect midi_info, nmidi and nsynth. */
95 static struct mtx midiinfo_mtx;
96 static int midiinfo_mtx_init;
97
98 /* These make the buffer for /dev/midistat */
99 static int midistatbusy;
100 static char midistatbuf[4096];
101 static int midistatptr;
102
103 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
104
105 int midi_debug;
106 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
107
108 midi_cmdtab cmdtab_midiioctl[] = {
109 {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"},
110 {SNDCTL_MIDI_MPUMODE, "SNDCTL_MIDI_MPUMODE"},
111 {SNDCTL_MIDI_MPUCMD, "SNDCTL_MIDI_MPUCMD"},
112 {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"},
113 {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"},
114 {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"},
115 {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"},
116 {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"},
117 {MIOSPASSTHRU, "MIOSPASSTHRU"},
118 {MIOGPASSTHRU, "MIOGPASSTHRU"},
119 {AIONWRITE, "AIONWRITE"},
120 {AIOGSIZE, "AIOGSIZE"},
121 {AIOSSIZE, "AIOSSIZE"},
122 {AIOGFMT, "AIOGFMT"},
123 {AIOSFMT, "AIOSFMT"},
124 {AIOGMIX, "AIOGMIX"},
125 {AIOSMIX, "AIOSMIX"},
126 {AIOSTOP, "AIOSTOP"},
127 {AIOSYNC, "AIOSYNC"},
128 {AIOGCAP, "AIOGCAP"},
129 {-1, NULL},
130 };
131
132 /*
133 * This is the generic init routine.
134 * Must be called after device-specific init.
135 */
136 int
137 midiinit(mididev_info *d, device_t dev)
138 {
139 int unit;
140
141 /*
142 * initialize standard parameters for the device. This can be
143 * overridden by device-specific configurations but better do
144 * here the generic things.
145 */
146
147 MIDI_DEBUG(printf("midiinit: unit %d.\n", d->unit));
148
149 unit = d->unit;
150 d->softc = device_get_softc(dev);
151 d->dev = dev;
152 d->magic = MAGIC(d->unit); /* debugging... */
153 d->flags = 0;
154 d->fflags = 0;
155 d->midi_dbuf_in.unit_size = 1;
156 d->midi_dbuf_out.unit_size = 1;
157 d->midi_dbuf_passthru.unit_size = 1;
158
159 mtx_unlock(&d->flagqueue_mtx);
160
161 if (midi_devclass == NULL) {
162 midi_devclass = device_get_devclass(dev);
163 make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS),
164 UID_ROOT, GID_WHEEL, 0444, "midistat");
165 }
166 make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN),
167 UID_ROOT, GID_WHEEL, 0666, "midi%d", unit);
168
169 return 0 ;
170 }
171
172 /*
173 * a small utility function which, given a device number, returns
174 * a pointer to the associated mididev_info struct, and sets the unit
175 * number.
176 */
177 mididev_info *
178 get_mididev_info(dev_t i_dev, int *unit)
179 {
180 int u;
181
182 if (MIDIDEV(i_dev) != MIDI_DEV_MIDIN)
183 return NULL;
184 u = MIDIUNIT(i_dev);
185 if (unit)
186 *unit = u;
187
188 return get_mididev_info_unit(u);
189 }
190
191 /*
192 * a small utility function which, given a unit number, returns
193 * a pointer to the associated mididev_info struct.
194 */
195 mididev_info *
196 get_mididev_info_unit(int unit)
197 {
198 mididev_info *md;
199
200 /* XXX */
201 if (!midiinfo_mtx_init) {
202 midiinfo_mtx_init = 1;
203 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
204 TAILQ_INIT(&midi_info);
205 }
206
207 mtx_lock(&midiinfo_mtx);
208 TAILQ_FOREACH(md, &midi_info, md_link) {
209 if (md->unit == unit)
210 break;
211 }
212 mtx_unlock(&midiinfo_mtx);
213
214 return md;
215 }
216
217 /*
218 * a small utility function which, given a unit number, returns
219 * a pointer to the associated mididev_info struct with MDT_MIDI.
220 */
221 mididev_info *
222 get_mididev_midi_unit(int unit)
223 {
224 mididev_info *md;
225
226 /* XXX */
227 if (!midiinfo_mtx_init) {
228 midiinfo_mtx_init = 1;
229 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
230 TAILQ_INIT(&midi_info);
231 }
232
233 mtx_lock(&midiinfo_mtx);
234 TAILQ_FOREACH(md, &midi_info, md_link) {
235 if (md->midiunit == unit)
236 break;
237 }
238 mtx_unlock(&midiinfo_mtx);
239
240 return md;
241 }
242
243 /*
244 * a small utility function which, given a unit number, returns
245 * a pointer to the associated mididev_info struct with MDT_SYNTH.
246 */
247 mididev_info *
248 get_mididev_synth_unit(int unit)
249 {
250 mididev_info *md;
251
252 /* XXX */
253 if (!midiinfo_mtx_init) {
254 midiinfo_mtx_init = 1;
255 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
256 TAILQ_INIT(&midi_info);
257 }
258
259 mtx_lock(&midiinfo_mtx);
260 TAILQ_FOREACH(md, &midi_info, md_link) {
261 if (md->synthunit == unit)
262 break;
263 }
264 mtx_unlock(&midiinfo_mtx);
265
266 return md;
267 }
268
269 /* Create a new midi device info structure. */
270 /* TODO: lock md, then exit. */
271 mididev_info *
272 create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf)
273 {
274 int unit;
275 mididev_info *md, *mdnew;
276
277 /* XXX */
278 if (!midiinfo_mtx_init) {
279 midiinfo_mtx_init = 1;
280 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
281 TAILQ_INIT(&midi_info);
282 }
283
284 /* As malloc(9) might block, allocate mididev_info now. */
285 mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO);
286 if (mdnew == NULL)
287 return NULL;
288 bcopy(mdinf, mdnew, sizeof(mididev_info));
289 bcopy(syninf, &mdnew->synth, sizeof(synthdev_info));
290 midibuf_init(&mdnew->midi_dbuf_in);
291 midibuf_init(&mdnew->midi_dbuf_out);
292 midibuf_init(&mdnew->midi_dbuf_passthru);
293 mtx_init(&mdnew->flagqueue_mtx, "midflq", NULL, MTX_DEF);
294 mtx_init(&mdnew->synth.vc_mtx, "synsvc", NULL, MTX_DEF);
295 mtx_init(&mdnew->synth.status_mtx, "synsst", NULL, MTX_DEF);
296
297 mtx_lock(&midiinfo_mtx);
298
299 switch (type) {
300 case MDT_MIDI:
301 mdnew->midiunit = nmidi;
302 mdnew->synthunit = nmidi;
303 nmidi++;
304 break;
305 case MDT_SYNTH:
306 mdnew->midiunit = -1;
307 mdnew->synthunit = nsynth;
308 nsynth++;
309 break;
310 default:
311 mtx_unlock(&midiinfo_mtx);
312 midibuf_destroy(&mdnew->midi_dbuf_in);
313 midibuf_destroy(&mdnew->midi_dbuf_out);
314 midibuf_destroy(&mdnew->midi_dbuf_passthru);
315 mtx_destroy(&mdnew->flagqueue_mtx);
316 mtx_destroy(&mdnew->synth.vc_mtx);
317 mtx_destroy(&mdnew->synth.status_mtx);
318 free(mdnew, M_DEVBUF);
319 panic("unsupported device type");
320 return NULL;
321 }
322 mdnew->mdtype = type;
323
324 for (unit = 0 ; ; unit++) {
325 TAILQ_FOREACH(md, &midi_info, md_link) {
326 if (md->unit == unit)
327 break;
328 }
329 if (md == NULL)
330 break;
331 }
332
333 mdnew->unit = unit;
334 mtx_lock(&mdnew->flagqueue_mtx);
335 TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link);
336
337 mtx_unlock(&midiinfo_mtx);
338
339 return mdnew;
340 }
341
342 /* Return the number of configured devices. */
343 int
344 mididev_info_number(void)
345 {
346 return nmidi + nsynth;
347 }
348
349 /* Return the number of configured midi devices. */
350 int
351 mididev_midi_number(void)
352 {
353 return nmidi;
354 }
355
356 /* Return the number of configured synth devices. */
357 int
358 mididev_synth_number(void)
359 {
360 return nsynth;
361 }
362
363 /*
364 * here are the switches for the main functions. The switches do
365 * all necessary checks on the device number to make sure
366 * that the device is configured. They also provide some default
367 * functionalities so that device-specific drivers have to deal
368 * only with special cases.
369 */
370
371 static int
372 midiopen(dev_t i_dev, int flags, int mode, struct thread *td)
373 {
374 int ret;
375
376 switch (MIDIDEV(i_dev)) {
377 case MIDI_DEV_MIDIN:
378 ret = midi_open(i_dev, flags, mode, td);
379 break;
380 case MIDI_DEV_STATUS:
381 ret = midistat_open(i_dev, flags, mode, td);
382 break;
383 default:
384 ret = ENXIO;
385 break;
386 }
387
388 return (ret);
389 }
390
391 static int
392 midiclose(dev_t i_dev, int flags, int mode, struct thread *td)
393 {
394 int ret;
395
396 switch (MIDIDEV(i_dev)) {
397 case MIDI_DEV_MIDIN:
398 ret = midi_close(i_dev, flags, mode, td);
399 break;
400 case MIDI_DEV_STATUS:
401 ret = midistat_close(i_dev, flags, mode, td);
402 break;
403 default:
404 ret = ENXIO;
405 break;
406 }
407
408 return (ret);
409 }
410
411 static int
412 midiread(dev_t i_dev, struct uio * buf, int flag)
413 {
414 int ret;
415
416 switch (MIDIDEV(i_dev)) {
417 case MIDI_DEV_MIDIN:
418 ret = midi_read(i_dev, buf, flag);
419 break;
420 case MIDI_DEV_STATUS:
421 ret = midistat_read(i_dev, buf, flag);
422 break;
423 default:
424 ret = ENXIO;
425 break;
426 }
427
428 return (ret);
429 }
430
431 static int
432 midiwrite(dev_t i_dev, struct uio * buf, int flag)
433 {
434 int ret;
435
436 switch (MIDIDEV(i_dev)) {
437 case MIDI_DEV_MIDIN:
438 ret = midi_write(i_dev, buf, flag);
439 break;
440 default:
441 ret = ENXIO;
442 break;
443 }
444
445 return (ret);
446 }
447
448 static int
449 midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
450 {
451 int ret;
452
453 switch (MIDIDEV(i_dev)) {
454 case MIDI_DEV_MIDIN:
455 ret = midi_ioctl(i_dev, cmd, arg, mode, td);
456 break;
457 default:
458 ret = ENXIO;
459 break;
460 }
461
462 return (ret);
463 }
464
465 static int
466 midipoll(dev_t i_dev, int events, struct thread *td)
467 {
468 int ret;
469
470 switch (MIDIDEV(i_dev)) {
471 case MIDI_DEV_MIDIN:
472 ret = midi_poll(i_dev, events, td);
473 break;
474 default:
475 ret = ENXIO;
476 break;
477 }
478
479 return (ret);
480 }
481
482 /*
483 * Followings are the generic methods in midi drivers.
484 */
485
486 int
487 midi_open(dev_t i_dev, int flags, int mode, struct thread *td)
488 {
489 int dev, unit, ret;
490 mididev_info *d;
491
492 dev = minor(i_dev);
493 d = get_mididev_info(i_dev, &unit);
494
495 MIDI_DEBUG(printf("midi_open: unit %d, flags 0x%x.\n", unit, flags));
496
497 if (d == NULL)
498 return (ENXIO);
499
500 /* Mark this device busy. */
501 mtx_lock(&d->flagqueue_mtx);
502 device_busy(d->dev);
503 if ((d->flags & MIDI_F_BUSY) != 0) {
504 mtx_unlock(&d->flagqueue_mtx);
505 printf("midi_open: unit %d is busy.\n", unit);
506 return (EBUSY);
507 }
508 d->fflags = flags;
509 d->flags |= MIDI_F_BUSY;
510 d->flags &= ~(MIDI_F_READING | MIDI_F_WRITING);
511 if ((d->fflags & O_NONBLOCK) != 0)
512 d->flags |= MIDI_F_NBIO;
513
514 /* Init the queue. */
515 if ((flags & FREAD) != 0)
516 midibuf_clear(&d->midi_dbuf_in);
517 if ((flags & FWRITE) != 0) {
518 midibuf_clear(&d->midi_dbuf_out);
519 midibuf_clear(&d->midi_dbuf_passthru);
520 }
521
522 mtx_unlock(&d->flagqueue_mtx);
523
524 if (d->open == NULL)
525 ret = 0;
526 else
527 ret = d->open(i_dev, flags, mode, td);
528
529 mtx_lock(&d->flagqueue_mtx);
530
531 /* Begin recording if nonblocking. */
532 if ((d->flags & (MIDI_F_READING | MIDI_F_NBIO)) == MIDI_F_NBIO && (d->fflags & FREAD) != 0)
533 d->callback(d, MIDI_CB_START | MIDI_CB_RD);
534
535 mtx_unlock(&d->flagqueue_mtx);
536
537 MIDI_DEBUG(printf("midi_open: opened.\n"));
538
539 return (ret);
540 }
541
542 int
543 midi_close(dev_t i_dev, int flags, int mode, struct thread *td)
544 {
545 int dev, unit, ret;
546 mididev_info *d;
547
548 dev = minor(i_dev);
549 d = get_mididev_info(i_dev, &unit);
550
551 MIDI_DEBUG(printf("midi_close: unit %d.\n", unit));
552
553 if (d == NULL)
554 return (ENXIO);
555
556 mtx_lock(&d->flagqueue_mtx);
557
558 /* Stop recording and playing. */
559 if ((d->flags & MIDI_F_READING) != 0)
560 d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD);
561 if ((d->flags & MIDI_F_WRITING) != 0)
562 d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR);
563
564 /* Clear the queues. */
565 if ((d->fflags & FREAD) != 0)
566 midibuf_clear(&d->midi_dbuf_in);
567 if ((d->fflags & FWRITE) != 0) {
568 midibuf_clear(&d->midi_dbuf_out);
569 midibuf_clear(&d->midi_dbuf_passthru);
570 }
571
572 /* Stop playing and unmark this device busy. */
573 d->flags &= ~MIDI_F_BUSY;
574 d->fflags = 0;
575
576 device_unbusy(d->dev);
577
578 mtx_unlock(&d->flagqueue_mtx);
579
580 if (d->close == NULL)
581 ret = 0;
582 else
583 ret = d->close(i_dev, flags, mode, td);
584
585 MIDI_DEBUG(printf("midi_close: closed.\n"));
586
587 return (ret);
588 }
589
590 int
591 midi_read(dev_t i_dev, struct uio * buf, int flag)
592 {
593 int dev, unit, len, lenr, ret;
594 mididev_info *d ;
595 u_char *uiobuf;
596
597 dev = minor(i_dev);
598
599 d = get_mididev_info(i_dev, &unit);
600 MIDI_DEBUG(printf("midi_read: unit %d, resid %d.\n", unit, buf->uio_resid));
601
602 if (d == NULL)
603 return (ENXIO);
604
605 ret = 0;
606
607 len = buf->uio_resid;
608 lenr = 0;
609
610 uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
611 if (uiobuf == NULL)
612 return (ENOMEM);
613
614 mtx_lock(&d->flagqueue_mtx);
615
616 /* Begin recording. */
617 d->callback(d, MIDI_CB_START | MIDI_CB_RD);
618
619 /* Have we got the data to read? */
620 if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0)
621 ret = EAGAIN;
622 else {
623 if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl)
624 len = d->midi_dbuf_in.rl;
625 ret = midibuf_seqread(&d->midi_dbuf_in, uiobuf, len, &lenr,
626 d->callback, d, MIDI_CB_START | MIDI_CB_RD,
627 &d->flagqueue_mtx);
628 }
629
630 mtx_unlock(&d->flagqueue_mtx);
631
632 if (lenr > 0)
633 ret = uiomove(uiobuf, lenr, buf);
634
635 free(uiobuf, M_DEVBUF);
636
637 MIDI_DEBUG(printf("midi_read: ret %d, resid %d.\n", ret, buf->uio_resid));
638
639 return (ret);
640 }
641
642 int
643 midi_write(dev_t i_dev, struct uio * buf, int flag)
644 {
645 int dev, unit, len, len2, lenw, ret;
646 mididev_info *d;
647 u_char *uiobuf;
648
649 dev = minor(i_dev);
650 d = get_mididev_info(i_dev, &unit);
651
652 MIDI_DEBUG(printf("midi_write: unit %d.\n", unit));
653
654 if (d == NULL)
655 return (ENXIO);
656
657 ret = 0;
658
659 len = buf->uio_resid;
660 lenw = 0;
661
662 uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
663 if (uiobuf == NULL)
664 return (ENOMEM);
665
666 ret = uiomove(uiobuf, len, buf);
667 if (ret != 0) {
668 free(uiobuf, M_DEVBUF);
669 return (ret);
670 }
671
672 mtx_lock(&d->flagqueue_mtx);
673
674 /* Have we got the data to write? */
675 if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) {
676 /* Begin playing. */
677 d->callback(d, MIDI_CB_START | MIDI_CB_WR);
678 ret = EAGAIN;
679 } else {
680 len2 = len;
681 if ((d->flags & MIDI_F_NBIO) != 0 && len2 > d->midi_dbuf_out.fl)
682 len2 = d->midi_dbuf_out.fl;
683 ret = midibuf_seqwrite(&d->midi_dbuf_out, uiobuf, len2, &lenw,
684 d->callback, d, MIDI_CB_START | MIDI_CB_WR,
685 &d->flagqueue_mtx);
686 }
687
688 mtx_unlock(&d->flagqueue_mtx);
689
690 free(uiobuf, M_DEVBUF);
691 buf->uio_resid = len - lenw;
692
693 return (ret);
694 }
695
696 /*
697 * generic midi ioctl. Functions of the default driver can be
698 * overridden by the device-specific ioctl call.
699 * If a device-specific call returns ENOSYS (Function not implemented),
700 * the default driver is called. Otherwise, the returned value
701 * is passed up.
702 *
703 * The default handler, for many parameters, sets the value in the
704 * descriptor, sets MIDI_F_INIT, and calls the callback function with
705 * reason INIT. If successful, the callback returns 1 and the caller
706 * can update the parameter.
707 */
708
709 int
710 midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
711 {
712 int ret = ENOSYS, dev, unit;
713 mididev_info *d;
714 struct snd_size *sndsize;
715 snd_sync_parm *sp;
716
717 dev = minor(i_dev);
718 d = get_mididev_info(i_dev, &unit);
719
720 if (d == NULL)
721 return (ENXIO);
722
723 if (d->ioctl)
724 ret = d->ioctl(i_dev, cmd, arg, mode, td);
725 if (ret != ENOSYS)
726 return ret;
727
728 /*
729 * pass control to the default ioctl handler. Set ret to 0 now.
730 */
731 ret = 0;
732
733 MIDI_DEBUG(printf("midi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl)));
734
735 /*
736 * all routines are called with int. blocked. Make sure that
737 * ints are re-enabled when calling slow or blocking functions!
738 */
739 switch(cmd) {
740
741 /*
742 * we start with the new ioctl interface.
743 */
744 case AIONWRITE: /* how many bytes can write ? */
745 mtx_lock(&d->flagqueue_mtx);
746 *(int *)arg = d->midi_dbuf_out.fl;
747 mtx_unlock(&d->flagqueue_mtx);
748 MIDI_DEBUG(printf("midi_ioctl: fl %d.\n", *(int *)arg));
749 break;
750
751 case AIOSSIZE: /* set the current blocksize */
752 sndsize = (struct snd_size *)arg;
753 MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size));
754 mtx_lock(&d->flagqueue_mtx);
755 if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) {
756 d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size;
757 d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size;
758 sndsize->play_size = d->midi_dbuf_out.blocksize;
759 sndsize->rec_size = d->midi_dbuf_in.blocksize;
760 d->flags &= ~MIDI_F_HAS_SIZE;
761 mtx_unlock(&d->flagqueue_mtx);
762 }
763 else {
764 if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4)
765 sndsize->play_size = d->midi_dbuf_out.bufsize / 4;
766 if (sndsize->rec_size > d->midi_dbuf_in.bufsize / 4)
767 sndsize->rec_size = d->midi_dbuf_in.bufsize / 4;
768 /* Round up the size to the multiple of EV_SZ. */
769 d->midi_dbuf_out.blocksize =
770 ((sndsize->play_size + d->midi_dbuf_out.unit_size - 1)
771 / d->midi_dbuf_out.unit_size) * d->midi_dbuf_out.unit_size;
772 d->midi_dbuf_in.blocksize =
773 ((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1)
774 / d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size;
775 sndsize->play_size = d->midi_dbuf_out.blocksize;
776 sndsize->rec_size = d->midi_dbuf_in.blocksize;
777 d->flags |= MIDI_F_HAS_SIZE;
778 mtx_unlock(&d->flagqueue_mtx);
779 }
780
781 ret = 0;
782 break;
783
784 case AIOGSIZE: /* get the current blocksize */
785 sndsize = (struct snd_size *)arg;
786 mtx_lock(&d->flagqueue_mtx);
787 sndsize->play_size = d->midi_dbuf_out.blocksize;
788 sndsize->rec_size = d->midi_dbuf_in.blocksize;
789 mtx_unlock(&d->flagqueue_mtx);
790 MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size));
791
792 ret = 0;
793 break;
794
795 case AIOSTOP:
796 mtx_lock(&d->flagqueue_mtx);
797 if (*(int *)arg == AIOSYNC_PLAY) /* play */
798 *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
799 else if (*(int *)arg == AIOSYNC_CAPTURE)
800 *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD);
801 else {
802 MIDI_DEBUG(printf("midi_ioctl: bad channel 0x%x.\n", *(int *)arg));
803 *(int *)arg = 0 ;
804 }
805 mtx_unlock(&d->flagqueue_mtx);
806 break ;
807
808 case AIOSYNC:
809 sp = (snd_sync_parm *)arg;
810 MIDI_DEBUG(printf("midi_ioctl: unimplemented, chan 0x%03lx pos %lu.\n",
811 sp->chan,
812 sp->pos));
813 break;
814 /*
815 * here follow the standard ioctls (filio.h etc.)
816 */
817 case FIONREAD: /* get # bytes to read */
818 mtx_lock(&d->flagqueue_mtx);
819 *(int *)arg = d->midi_dbuf_in.rl;
820 mtx_unlock(&d->flagqueue_mtx);
821 MIDI_DEBUG(printf("midi_ioctl: rl %d.\n", *(int *)arg));
822 break;
823
824 case FIOASYNC: /*set/clear async i/o */
825 MIDI_DEBUG(printf("FIOASYNC\n"));
826 break;
827
828 case FIONBIO: /* set/clear non-blocking i/o */
829 mtx_lock(&d->flagqueue_mtx);
830 if (*(int *)arg == 0)
831 d->flags &= ~MIDI_F_NBIO ;
832 else
833 d->flags |= MIDI_F_NBIO ;
834 mtx_unlock(&d->flagqueue_mtx);
835 MIDI_DEBUG(printf("midi_ioctl: arg %d.\n", *(int *)arg));
836 break ;
837
838 case MIOSPASSTHRU: /* set/clear passthru */
839 mtx_lock(&d->flagqueue_mtx);
840 if (*(int *)arg == 0)
841 d->flags &= ~MIDI_F_PASSTHRU ;
842 else
843 d->flags |= MIDI_F_PASSTHRU ;
844
845 /* Init the queue. */
846 midibuf_clear(&d->midi_dbuf_passthru);
847
848 mtx_unlock(&d->flagqueue_mtx);
849 MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg));
850
851 /* FALLTHROUGH */
852 case MIOGPASSTHRU: /* get passthru */
853 mtx_lock(&d->flagqueue_mtx);
854 if ((d->flags & MIDI_F_PASSTHRU) != 0)
855 *(int *)arg = 1;
856 else
857 *(int *)arg = 0;
858 mtx_unlock(&d->flagqueue_mtx);
859 MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg));
860 break;
861
862 default:
863 MIDI_DEBUG(printf("midi_ioctl: default ioctl midi%d subdev %d fn 0x%08lx fail\n",
864 unit, dev & 0xf, cmd));
865 ret = EINVAL;
866 break ;
867 }
868 return ret ;
869 }
870
871 int
872 midi_poll(dev_t i_dev, int events, struct thread *td)
873 {
874 int unit, dev, ret, lim;
875 mididev_info *d;
876
877 dev = minor(i_dev);
878 d = get_mididev_info(i_dev, &unit);
879
880 MIDI_DEBUG(printf("midi_poll: unit %d.\n", unit));
881
882 if (d == NULL)
883 return (ENXIO);
884
885 ret = 0;
886
887 mtx_lock(&d->flagqueue_mtx);
888
889 /* Look up the apropriate queue and select it. */
890 if ((events & (POLLOUT | POLLWRNORM)) != 0) {
891 /* Start playing. */
892 d->callback(d, MIDI_CB_START | MIDI_CB_WR);
893
894 /* Find out the boundary. */
895 if ((d->flags & MIDI_F_HAS_SIZE) != 0)
896 lim = d->midi_dbuf_out.blocksize;
897 else
898 lim = d->midi_dbuf_out.unit_size;
899 if (d->midi_dbuf_out.fl < lim)
900 /* No enough space, record select. */
901 selrecord(td, &d->midi_dbuf_out.sel);
902 else
903 /* We can write now. */
904 ret |= events & (POLLOUT | POLLWRNORM);
905 }
906 if ((events & (POLLIN | POLLRDNORM)) != 0) {
907 /* Start recording. */
908 d->callback(d, MIDI_CB_START | MIDI_CB_RD);
909
910 /* Find out the boundary. */
911 if ((d->flags & MIDI_F_HAS_SIZE) != 0)
912 lim = d->midi_dbuf_in.blocksize;
913 else
914 lim = d->midi_dbuf_in.unit_size;
915 if (d->midi_dbuf_in.rl < lim)
916 /* No data ready, record select. */
917 selrecord(td, &d->midi_dbuf_in.sel);
918 else
919 /* We can write now. */
920 ret |= events & (POLLIN | POLLRDNORM);
921 }
922
923 mtx_unlock(&d->flagqueue_mtx);
924
925 return (ret);
926 }
927
928 void
929 midi_intr(mididev_info *d)
930 {
931 if (d->intr != NULL)
932 d->intr(d->intrarg, d);
933 }
934
935 /* Flush the output queue. */
936 #define MIDI_SYNC_TIMEOUT 1
937 int
938 midi_sync(mididev_info *d)
939 {
940 int i, rl;
941
942 mtx_assert(&d->flagqueue_mtx, MA_OWNED);
943
944 MIDI_DEBUG(printf("midi_sync: unit %d.\n", d->unit));
945
946 while (d->midi_dbuf_out.rl > 0) {
947 if ((d->flags & MIDI_F_WRITING) == 0)
948 d->callback(d, MIDI_CB_START | MIDI_CB_WR);
949 rl = d->midi_dbuf_out.rl;
950 i = cv_timedwait_sig(&d->midi_dbuf_out.cv_out,
951 &d->flagqueue_mtx,
952 (d->midi_dbuf_out.bufsize * 10 * hz / 38400)
953 + MIDI_SYNC_TIMEOUT * hz);
954 if (i == EINTR || i == ERESTART) {
955 if (i == EINTR)
956 d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
957 return (i);
958 }
959 if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) {
960 /* A queue seems to be stuck up. Give up and clear the queue. */
961 d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
962 midibuf_clear(&d->midi_dbuf_out);
963 return (0);
964 }
965 }
966
967 return 0;
968 }
969
970 /*
971 * These handle the status message of the midi drivers.
972 */
973
974 int
975 midistat_open(dev_t i_dev, int flags, int mode, struct thread *td)
976 {
977 if (midistatbusy)
978 return (EBUSY);
979
980 bzero(midistatbuf, sizeof(midistatbuf));
981 midistatptr = 0;
982 if (midi_initstatus(midistatbuf, sizeof(midistatbuf) - 1))
983 return (ENOMEM);
984
985 midistatbusy = 1;
986
987 return (0);
988 }
989
990 int
991 midistat_close(dev_t i_dev, int flags, int mode, struct thread *td)
992 {
993 midistatbusy = 0;
994
995 return (0);
996 }
997
998 int
999 midistat_read(dev_t i_dev, struct uio * buf, int flag)
1000 {
1001 return midi_readstatus(midistatbuf, &midistatptr, buf);
1002 }
1003
1004 /*
1005 * finally, some "libraries"
1006 */
1007
1008 /* Inits the buffer for /dev/midistat. */
1009 static int
1010 midi_initstatus(char *buf, int size)
1011 {
1012 int i, p;
1013 device_t dev;
1014 mididev_info *md;
1015
1016 p = 0;
1017 p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__);
1018 for (i = 0 ; i < mididev_info_number() ; i++) {
1019 md = get_mididev_info_unit(i);
1020 if (!MIDICONFED(md))
1021 continue;
1022 dev = devclass_get_device(midi_devclass, i);
1023 if (p < size)
1024 p += snprintf(&buf[p], size - p, "midi%d: <%s> %s\n", i, device_get_desc(dev), md->midistat);
1025 else
1026 return (1);
1027 }
1028
1029 return (0);
1030 }
1031
1032 /* Reads the status message. */
1033 static int
1034 midi_readstatus(char *buf, int *ptr, struct uio *uio)
1035 {
1036 int len;
1037
1038 len = min(uio->uio_resid, strlen(&buf[*ptr]));
1039 if (len > 0) {
1040 uiomove(&buf[*ptr], len, uio);
1041 *ptr += len;
1042 }
1043
1044 return (0);
1045 }
1046
1047 char
1048 *midi_cmdname(int cmd, midi_cmdtab *tab)
1049 {
1050 while (tab->name != NULL) {
1051 if (cmd == tab->cmd)
1052 return (tab->name);
1053 tab++;
1054 }
1055
1056 return ("unknown");
1057 }
Cache object: de765b0a7e5859fceca71e869e49b5ea
|