1 /* $OpenBSD: ym.c,v 1.12 2003/04/27 11:22:53 ho Exp $ */
2
3
4 /*
5 * Copyright (c) 1998 Constantine Sapuntzakis. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "midi.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/syslog.h>
37 #include <sys/device.h>
38 #include <sys/proc.h>
39 #include <sys/buf.h>
40
41 #include <machine/cpu.h>
42 #include <machine/intr.h>
43 #include <machine/bus.h>
44
45 #include <sys/audioio.h>
46 #include <dev/audio_if.h>
47 #include <dev/midi_if.h>
48
49 #include <dev/isa/isavar.h>
50 #include <dev/isa/isadmavar.h>
51
52 #include <dev/ic/ad1848reg.h>
53 #include <dev/isa/ad1848var.h>
54 #include <dev/ic/opl3sa3reg.h>
55 #include <dev/ic/mpuvar.h>
56 #include <dev/isa/ymvar.h>
57
58 int ym_getdev(void *, struct audio_device *);
59 int ym_mixer_set_port(void *, mixer_ctrl_t *);
60 int ym_mixer_get_port(void *, mixer_ctrl_t *);
61 int ym_query_devinfo(void *, mixer_devinfo_t *);
62 int ym_intr(void *);
63
64 static void ym_mute(struct ym_softc *, int, int);
65 static void ym_set_master_gain(struct ym_softc *, struct ad1848_volume *);
66 static void ym_set_mic_gain(struct ym_softc *, int);
67 static void ym_set_3d(struct ym_softc *, mixer_ctrl_t *,
68 struct ad1848_volume *, int);
69
70 struct audio_hw_if ym_hw_if = {
71 ad1848_open,
72 ad1848_close,
73 NULL,
74 ad1848_query_encoding,
75 ad1848_set_params,
76 ad1848_round_blocksize,
77 ad1848_commit_settings,
78 ad1848_dma_init_output,
79 ad1848_dma_init_input,
80 ad1848_dma_output,
81 ad1848_dma_input,
82 ad1848_halt_out_dma,
83 ad1848_halt_in_dma,
84 NULL,
85 ym_getdev,
86 NULL,
87 ym_mixer_set_port,
88 ym_mixer_get_port,
89 ym_query_devinfo,
90 ad1848_malloc,
91 ad1848_free,
92 ad1848_round,
93 ad1848_mappage,
94 ad1848_get_props,
95 NULL,
96 NULL
97 };
98
99
100 struct cfdriver ym_cd = {
101 NULL, "ym", DV_DULL
102 };
103
104 struct audio_device ym_device = {
105 "ym,ad1848",
106 "",
107 "ym"
108 };
109
110 static __inline int ym_read(struct ym_softc *, int);
111 static __inline void ym_write(struct ym_softc *, int, int);
112
113 #if NMIDI > 0
114 int ym_mpu401_open(void *, int, void (*iintr)(void *, int),
115 void (*ointr)(void *), void *arg);
116 void ym_mpu401_close(void *);
117 int ym_mpu401_output(void *, int);
118 void ym_mpu401_getinfo(void *, struct midi_info *);
119
120 struct midi_hw_if ym_mpu401_hw_if = {
121 ym_mpu401_open,
122 ym_mpu401_close,
123 ym_mpu401_output,
124 ym_mpu401_getinfo,
125 0, /* ioctl */
126 };
127 #endif
128
129 int
ym_intr(v)130 ym_intr(v)
131 void *v;
132 {
133 #if NMIDI > 0
134 struct ym_softc *sc = v;
135
136 if ( /* XXX && */ sc->sc_hasmpu)
137 mpu_intr(&sc->sc_mpu_sc);
138 #endif
139 return ad1848_intr(v);
140 }
141
142 void
ym_attach(sc)143 ym_attach(sc)
144 struct ym_softc *sc;
145
146 {
147 struct ad1848_volume vol_mid = {220, 220};
148 #if NMIDI > 0
149 struct midi_hw_if *mhw = &ym_mpu401_hw_if;
150 #endif
151
152 sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq, IST_EDGE,
153 IPL_AUDIO, ym_intr, &sc->sc_ad1848, sc->sc_dev.dv_xname);
154
155 ad1848_attach(&sc->sc_ad1848);
156 printf("\n");
157 sc->sc_ad1848.parent = sc;
158
159 /* Establish chip in well known mode */
160 ym_set_master_gain(sc, &vol_mid);
161 ym_set_mic_gain(sc, 0);
162 sc->master_mute = 0;
163 ym_mute(sc, SA3_VOL_L, sc->master_mute);
164 ym_mute(sc, SA3_VOL_R, sc->master_mute);
165
166 sc->mic_mute = 1;
167 ym_mute(sc, SA3_MIC_VOL, sc->mic_mute);
168
169 #if NMIDI > 0
170 sc->sc_hasmpu = 0;
171 if (sc->sc_mpu_sc.iobase) {
172 sc->sc_mpu_sc.iot = sc->sc_iot;
173 if (mpu_find(&sc->sc_mpu_sc)) {
174 sc->sc_hasmpu = 1;
175 mhw = &ym_mpu401_hw_if;
176 }
177 }
178 midi_attach_mi(mhw, sc, &sc->sc_dev);
179 #endif
180
181 audio_attach_mi(&ym_hw_if, &sc->sc_ad1848, &sc->sc_dev);
182 }
183
184 static __inline int
ym_read(sc,reg)185 ym_read(sc, reg)
186 struct ym_softc *sc;
187 int reg;
188 {
189 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX,
190 (reg & 0xff));
191 return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_DATA));
192 }
193
194 static __inline void
ym_write(sc,reg,data)195 ym_write(sc, reg, data)
196 struct ym_softc *sc;
197 int reg;
198 int data;
199 {
200 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX,
201 (reg & 0xff));
202 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_DATA,
203 (data & 0xff));
204 }
205
206
207
208 int
ym_getdev(addr,retp)209 ym_getdev(addr, retp)
210 void *addr;
211 struct audio_device *retp;
212 {
213 *retp = ym_device;
214 return 0;
215 }
216
217
218 static ad1848_devmap_t mappings[] = {
219 { YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
220 { YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
221 { YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
222 { YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
223 { YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
224 { YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
225 { YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
226 { YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
227 { YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
228 { YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
229 { YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
230 { YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
231 { YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
232 { YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 }
233 };
234
235 #define NUMMAP (sizeof(mappings) / sizeof(mappings[0]))
236
237
238 static void
ym_mute(sc,left_reg,mute)239 ym_mute(sc, left_reg, mute)
240 struct ym_softc *sc;
241 int left_reg;
242 int mute;
243 {
244 u_int8_t reg;
245
246 reg = ym_read(sc, left_reg);
247 if (mute)
248 ym_write(sc, left_reg, reg | 0x80);
249 else
250 ym_write(sc, left_reg, reg & ~0x80);
251 }
252
253 static void
ym_set_master_gain(sc,vol)254 ym_set_master_gain(sc, vol)
255 struct ym_softc *sc;
256 struct ad1848_volume *vol;
257 {
258 u_int atten;
259
260 sc->master_gain = *vol;
261
262 atten = ((AUDIO_MAX_GAIN - vol->left) * (SA3_VOL_MV + 1)) /
263 (AUDIO_MAX_GAIN + 1);
264
265 ym_write(sc, SA3_VOL_L, (ym_read(sc, SA3_VOL_L) & ~SA3_VOL_MV) | atten);
266
267 atten = ((AUDIO_MAX_GAIN - vol->right) * (SA3_VOL_MV + 1)) /
268 (AUDIO_MAX_GAIN + 1);
269
270 ym_write(sc, SA3_VOL_R, (ym_read(sc, SA3_VOL_R) & ~SA3_VOL_MV) | atten);
271 }
272
273 static void
ym_set_mic_gain(sc,vol)274 ym_set_mic_gain(sc, vol)
275 struct ym_softc *sc;
276 int vol;
277 {
278 u_int atten;
279
280 sc->mic_gain = vol;
281
282 atten = ((AUDIO_MAX_GAIN - vol) * (SA3_MIC_MCV + 1)) /
283 (AUDIO_MAX_GAIN + 1);
284
285 ym_write(sc, SA3_MIC_VOL,
286 (ym_read(sc, SA3_MIC_VOL) & ~SA3_MIC_MCV) | atten);
287 }
288
289 static void
ym_set_3d(sc,cp,val,reg)290 ym_set_3d(sc, cp, val, reg)
291 struct ym_softc *sc;
292 mixer_ctrl_t *cp;
293 struct ad1848_volume *val;
294 int reg;
295 {
296 u_int8_t e;
297
298 ad1848_to_vol(cp, val);
299
300 e = (val->left * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) /
301 (AUDIO_MAX_GAIN + 1) << SA3_3D_LSHIFT |
302 (val->right * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) /
303 (AUDIO_MAX_GAIN + 1) << SA3_3D_RSHIFT;
304
305 ym_write(sc, reg, e);
306 }
307
308 int
ym_mixer_set_port(addr,cp)309 ym_mixer_set_port(addr, cp)
310 void *addr;
311 mixer_ctrl_t *cp;
312 {
313 struct ad1848_softc *ac = addr;
314 struct ym_softc *sc = ac->parent;
315 struct ad1848_volume vol;
316 int error = ad1848_mixer_set_port(ac, mappings, NUMMAP, cp);
317
318 if (error != ENXIO)
319 return (error);
320
321 error = 0;
322
323 switch (cp->dev) {
324 case YM_OUTPUT_LVL:
325 ad1848_to_vol(cp, &vol);
326 ym_set_master_gain(sc, &vol);
327 break;
328
329 case YM_OUTPUT_MUTE:
330 sc->master_mute = (cp->un.ord != 0);
331 ym_mute(sc, SA3_VOL_L, sc->master_mute);
332 ym_mute(sc, SA3_VOL_R, sc->master_mute);
333 break;
334
335 case YM_MIC_LVL:
336 if (cp->un.value.num_channels != 1)
337 error = EINVAL;
338 else
339 ym_set_mic_gain(sc,
340 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
341 break;
342
343 case YM_MASTER_EQMODE:
344 sc->sc_eqmode = cp->un.ord & SA3_SYS_CTL_YMODE;
345 ym_write(sc, SA3_SYS_CTL, (ym_read(sc, SA3_SYS_CTL) &
346 ~SA3_SYS_CTL_YMODE) | sc->sc_eqmode);
347 break;
348
349 case YM_MASTER_TREBLE:
350 ym_set_3d(sc, cp, &sc->sc_treble, SA3_3D_TREBLE);
351 break;
352
353 case YM_MASTER_BASS:
354 ym_set_3d(sc, cp, &sc->sc_bass, SA3_3D_BASS);
355 break;
356
357 case YM_MASTER_WIDE:
358 ym_set_3d(sc, cp, &sc->sc_wide, SA3_3D_WIDE);
359 break;
360
361 case YM_MIC_MUTE:
362 sc->mic_mute = (cp->un.ord != 0);
363 ym_mute(sc, SA3_MIC_VOL, sc->mic_mute);
364 break;
365
366 default:
367 return ENXIO;
368 /* NOTREACHED */
369 }
370
371 return (error);
372 }
373
374 int
ym_mixer_get_port(addr,cp)375 ym_mixer_get_port(addr, cp)
376 void *addr;
377 mixer_ctrl_t *cp;
378 {
379 struct ad1848_softc *ac = addr;
380 struct ym_softc *sc = ac->parent;
381
382 int error = ad1848_mixer_get_port(ac, mappings, NUMMAP, cp);
383
384 if (error != ENXIO)
385 return (error);
386
387 error = 0;
388
389 switch (cp->dev) {
390 case YM_OUTPUT_LVL:
391 ad1848_from_vol(cp, &sc->master_gain);
392 break;
393
394 case YM_OUTPUT_MUTE:
395 cp->un.ord = sc->master_mute;
396 break;
397
398 case YM_MIC_LVL:
399 if (cp->un.value.num_channels != 1)
400 error = EINVAL;
401 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->mic_gain;
402 break;
403
404 case YM_MASTER_EQMODE:
405 cp->un.ord = sc->sc_eqmode;
406 break;
407
408 case YM_MASTER_TREBLE:
409 ad1848_from_vol(cp, &sc->sc_treble);
410 break;
411
412 case YM_MASTER_BASS:
413 ad1848_from_vol(cp, &sc->sc_bass);
414 break;
415
416 case YM_MASTER_WIDE:
417 ad1848_from_vol(cp, &sc->sc_wide);
418 break;
419
420 case YM_MIC_MUTE:
421 cp->un.ord = sc->mic_mute;
422 break;
423
424 default:
425 error = ENXIO;
426 break;
427 }
428
429 return (error);
430 }
431
432 static char *mixer_classes[] = {
433 AudioCinputs, AudioCrecord, AudioCoutputs, AudioCmonitor,
434 AudioCequalization
435 };
436
437 int
ym_query_devinfo(addr,dip)438 ym_query_devinfo(addr, dip)
439 void *addr;
440 mixer_devinfo_t *dip;
441 {
442 static char *mixer_port_names[] = { AudioNmidi, AudioNcd, AudioNdac,
443 AudioNline, AudioNspeaker, AudioNmicrophone, AudioNmonitor
444 };
445
446 dip->next = dip->prev = AUDIO_MIXER_LAST;
447
448 switch (dip->index) {
449 case YM_INPUT_CLASS: /* input class descriptor */
450 case YM_OUTPUT_CLASS:
451 case YM_MONITOR_CLASS:
452 case YM_RECORD_CLASS:
453 case YM_EQ_CLASS:
454 dip->type = AUDIO_MIXER_CLASS;
455 dip->mixer_class = dip->index;
456 strlcpy(dip->label.name,
457 mixer_classes[dip->index - YM_INPUT_CLASS],
458 sizeof dip->label.name);
459 break;
460
461 case YM_MIDI_LVL:
462 case YM_CD_LVL:
463 case YM_DAC_LVL:
464 case YM_LINE_LVL:
465 case YM_SPEAKER_LVL:
466 case YM_MIC_LVL:
467 case YM_MONITOR_LVL:
468 dip->type = AUDIO_MIXER_VALUE;
469 if (dip->index == YM_MONITOR_LVL)
470 dip->mixer_class = YM_MONITOR_CLASS;
471 else
472 dip->mixer_class = YM_INPUT_CLASS;
473
474 dip->next = dip->index + 7;
475
476 strlcpy(dip->label.name,
477 mixer_port_names[dip->index - YM_MIDI_LVL],
478 sizeof dip->label.name);
479
480 if (dip->index == YM_SPEAKER_LVL ||
481 dip->index == YM_MIC_LVL)
482 dip->un.v.num_channels = 1;
483 else
484 dip->un.v.num_channels = 2;
485
486 strlcpy(dip->un.v.units.name, AudioNvolume,
487 sizeof dip->un.v.units.name);
488 break;
489
490 case YM_MIDI_MUTE:
491 case YM_CD_MUTE:
492 case YM_DAC_MUTE:
493 case YM_LINE_MUTE:
494 case YM_SPEAKER_MUTE:
495 case YM_MIC_MUTE:
496 case YM_MONITOR_MUTE:
497 if (dip->index == YM_MONITOR_MUTE)
498 dip->mixer_class = YM_MONITOR_CLASS;
499 else
500 dip->mixer_class = YM_INPUT_CLASS;
501 dip->type = AUDIO_MIXER_ENUM;
502 dip->prev = dip->index - 7;
503 mute:
504 strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
505 dip->un.e.num_mem = 2;
506 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
507 sizeof dip->un.e.member[0].label.name);
508 dip->un.e.member[0].ord = 0;
509 strlcpy(dip->un.e.member[1].label.name, AudioNon,
510 sizeof dip->un.e.member[1].label.name);
511 dip->un.e.member[1].ord = 1;
512 break;
513
514
515 case YM_OUTPUT_LVL:
516 dip->type = AUDIO_MIXER_VALUE;
517 dip->mixer_class = YM_OUTPUT_CLASS;
518 dip->next = YM_OUTPUT_MUTE;
519 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
520 dip->un.v.num_channels = 2;
521 strlcpy(dip->un.v.units.name, AudioNvolume,
522 sizeof dip->un.v.units.name);
523 break;
524
525 case YM_OUTPUT_MUTE:
526 dip->mixer_class = YM_OUTPUT_CLASS;
527 dip->type = AUDIO_MIXER_ENUM;
528 dip->prev = YM_OUTPUT_LVL;
529 goto mute;
530
531 case YM_REC_LVL: /* record level */
532 dip->type = AUDIO_MIXER_VALUE;
533 dip->mixer_class = YM_RECORD_CLASS;
534 dip->next = YM_RECORD_SOURCE;
535 strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
536 dip->un.v.num_channels = 2;
537 strlcpy(dip->un.v.units.name, AudioNvolume,
538 sizeof dip->un.v.units.name);
539 break;
540
541
542 case YM_RECORD_SOURCE:
543 dip->mixer_class = YM_RECORD_CLASS;
544 dip->type = AUDIO_MIXER_ENUM;
545 dip->prev = YM_REC_LVL;
546 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
547 dip->un.e.num_mem = 4;
548 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
549 sizeof dip->un.e.member[0].label.name);
550 dip->un.e.member[0].ord = MIC_IN_PORT;
551 strlcpy(dip->un.e.member[1].label.name, AudioNline,
552 sizeof dip->un.e.member[1].label.name);
553 dip->un.e.member[1].ord = LINE_IN_PORT;
554 strlcpy(dip->un.e.member[2].label.name, AudioNdac,
555 sizeof dip->un.e.member[2].label.name);
556 dip->un.e.member[2].ord = DAC_IN_PORT;
557 strlcpy(dip->un.e.member[3].label.name, AudioNcd,
558 sizeof dip->un.e.member[3].label.name);
559 dip->un.e.member[3].ord = AUX1_IN_PORT;
560 break;
561
562 case YM_MASTER_EQMODE:
563 dip->type = AUDIO_MIXER_ENUM;
564 dip->mixer_class = YM_EQ_CLASS;
565 strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
566 strlcpy(dip->un.v.units.name, AudioNmode,
567 sizeof dip->un.v.units.name);
568 dip->un.e.num_mem = 4;
569 strlcpy(dip->un.e.member[0].label.name, AudioNdesktop,
570 sizeof dip->un.e.member[0].label.name);
571 dip->un.e.member[0].ord = SA3_SYS_CTL_YMODE0;
572 strlcpy(dip->un.e.member[1].label.name, AudioNlaptop,
573 sizeof dip->un.e.member[1].label.name);
574 dip->un.e.member[1].ord = SA3_SYS_CTL_YMODE1;
575 strlcpy(dip->un.e.member[2].label.name, AudioNsubnote,
576 sizeof dip->un.e.member[2].label.name);
577 dip->un.e.member[2].ord = SA3_SYS_CTL_YMODE2;
578 strlcpy(dip->un.e.member[3].label.name, AudioNhifi,
579 sizeof dip->un.e.member[3].label.name);
580 dip->un.e.member[3].ord = SA3_SYS_CTL_YMODE3;
581 break;
582
583 case YM_MASTER_TREBLE:
584 dip->type = AUDIO_MIXER_VALUE;
585 dip->mixer_class = YM_EQ_CLASS;
586 strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name);
587 dip->un.v.num_channels = 2;
588 strlcpy(dip->un.v.units.name, AudioNtreble,
589 sizeof dip->un.v.units.name);
590 break;
591
592 case YM_MASTER_BASS:
593 dip->type = AUDIO_MIXER_VALUE;
594 dip->mixer_class = YM_EQ_CLASS;
595 strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name);
596 dip->un.v.num_channels = 2;
597 strlcpy(dip->un.v.units.name, AudioNbass,
598 sizeof dip->un.v.units.name);
599 break;
600
601 case YM_MASTER_WIDE:
602 dip->type = AUDIO_MIXER_VALUE;
603 dip->mixer_class = YM_EQ_CLASS;
604 strlcpy(dip->label.name, AudioNsurround,
605 sizeof dip->label.name);
606 dip->un.v.num_channels = 2;
607 strlcpy(dip->un.v.units.name, AudioNsurround,
608 sizeof dip->un.v.units.name);
609 break;
610
611 default:
612 return ENXIO;
613 /* NOTREACHED */
614 }
615
616 return 0;
617 }
618 #if NMIDI > 0
619
620 #define YMMPU(a) (&((struct ym_softc *)addr)->sc_mpu_sc)
621
622 int
ym_mpu401_open(addr,flags,iintr,ointr,arg)623 ym_mpu401_open(addr, flags, iintr, ointr, arg)
624 void *addr;
625 int flags;
626 void (*iintr)(void *, int);
627 void (*ointr)(void *);
628 void *arg;
629 {
630 return mpu_open(YMMPU(addr), flags, iintr, ointr, arg);
631 }
632
633 int
ym_mpu401_output(addr,d)634 ym_mpu401_output(addr, d)
635 void *addr;
636 int d;
637 {
638 return mpu_output(YMMPU(addr), d);
639 }
640
641 void
ym_mpu401_close(addr)642 ym_mpu401_close(addr)
643 void *addr;
644 {
645 mpu_close(YMMPU(addr));
646 }
647
648 void
ym_mpu401_getinfo(addr,mi)649 ym_mpu401_getinfo(addr, mi)
650 void *addr;
651 struct midi_info *mi;
652 {
653 mi->name = "YM MPU-401 UART";
654 mi->props = 0;
655 }
656 #endif
657