Annotation of sys/dev/isa/ym.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ym.c,v 1.13 2006/04/07 22:41:33 jsg 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: 0, /* flush */
125: ym_mpu401_getinfo,
126: 0, /* ioctl */
127: };
128: #endif
129:
130: int
131: ym_intr(v)
132: void *v;
133: {
134: #if NMIDI > 0
135: struct ym_softc *sc = v;
136:
137: if ( /* XXX && */ sc->sc_hasmpu)
138: mpu_intr(&sc->sc_mpu_sc);
139: #endif
140: return ad1848_intr(v);
141: }
142:
143: void
144: ym_attach(sc)
145: struct ym_softc *sc;
146:
147: {
148: struct ad1848_volume vol_mid = {220, 220};
149: #if NMIDI > 0
150: struct midi_hw_if *mhw = &ym_mpu401_hw_if;
151: #endif
152:
153: sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq, IST_EDGE,
154: IPL_AUDIO, ym_intr, &sc->sc_ad1848, sc->sc_dev.dv_xname);
155:
156: ad1848_attach(&sc->sc_ad1848);
157: printf("\n");
158: sc->sc_ad1848.parent = sc;
159:
160: /* Establish chip in well known mode */
161: ym_set_master_gain(sc, &vol_mid);
162: ym_set_mic_gain(sc, 0);
163: sc->master_mute = 0;
164: ym_mute(sc, SA3_VOL_L, sc->master_mute);
165: ym_mute(sc, SA3_VOL_R, sc->master_mute);
166:
167: sc->mic_mute = 1;
168: ym_mute(sc, SA3_MIC_VOL, sc->mic_mute);
169:
170: #if NMIDI > 0
171: sc->sc_hasmpu = 0;
172: if (sc->sc_mpu_sc.iobase) {
173: sc->sc_mpu_sc.iot = sc->sc_iot;
174: if (mpu_find(&sc->sc_mpu_sc)) {
175: sc->sc_hasmpu = 1;
176: mhw = &ym_mpu401_hw_if;
177: }
178: }
179: midi_attach_mi(mhw, sc, &sc->sc_dev);
180: #endif
181:
182: audio_attach_mi(&ym_hw_if, &sc->sc_ad1848, &sc->sc_dev);
183: }
184:
185: static __inline int
186: ym_read(sc, reg)
187: struct ym_softc *sc;
188: int reg;
189: {
190: bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX,
191: (reg & 0xff));
192: return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_DATA));
193: }
194:
195: static __inline void
196: ym_write(sc, reg, data)
197: struct ym_softc *sc;
198: int reg;
199: int data;
200: {
201: bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX,
202: (reg & 0xff));
203: bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_DATA,
204: (data & 0xff));
205: }
206:
207:
208:
209: int
210: ym_getdev(addr, retp)
211: void *addr;
212: struct audio_device *retp;
213: {
214: *retp = ym_device;
215: return 0;
216: }
217:
218:
219: static ad1848_devmap_t mappings[] = {
220: { YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
221: { YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
222: { YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
223: { YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
224: { YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
225: { YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
226: { YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
227: { YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
228: { YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
229: { YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
230: { YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
231: { YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
232: { YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
233: { YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 }
234: };
235:
236: #define NUMMAP (sizeof(mappings) / sizeof(mappings[0]))
237:
238:
239: static void
240: ym_mute(sc, left_reg, mute)
241: struct ym_softc *sc;
242: int left_reg;
243: int mute;
244: {
245: u_int8_t reg;
246:
247: reg = ym_read(sc, left_reg);
248: if (mute)
249: ym_write(sc, left_reg, reg | 0x80);
250: else
251: ym_write(sc, left_reg, reg & ~0x80);
252: }
253:
254: static void
255: ym_set_master_gain(sc, vol)
256: struct ym_softc *sc;
257: struct ad1848_volume *vol;
258: {
259: u_int atten;
260:
261: sc->master_gain = *vol;
262:
263: atten = ((AUDIO_MAX_GAIN - vol->left) * (SA3_VOL_MV + 1)) /
264: (AUDIO_MAX_GAIN + 1);
265:
266: ym_write(sc, SA3_VOL_L, (ym_read(sc, SA3_VOL_L) & ~SA3_VOL_MV) | atten);
267:
268: atten = ((AUDIO_MAX_GAIN - vol->right) * (SA3_VOL_MV + 1)) /
269: (AUDIO_MAX_GAIN + 1);
270:
271: ym_write(sc, SA3_VOL_R, (ym_read(sc, SA3_VOL_R) & ~SA3_VOL_MV) | atten);
272: }
273:
274: static void
275: ym_set_mic_gain(sc, vol)
276: struct ym_softc *sc;
277: int vol;
278: {
279: u_int atten;
280:
281: sc->mic_gain = vol;
282:
283: atten = ((AUDIO_MAX_GAIN - vol) * (SA3_MIC_MCV + 1)) /
284: (AUDIO_MAX_GAIN + 1);
285:
286: ym_write(sc, SA3_MIC_VOL,
287: (ym_read(sc, SA3_MIC_VOL) & ~SA3_MIC_MCV) | atten);
288: }
289:
290: static void
291: ym_set_3d(sc, cp, val, reg)
292: struct ym_softc *sc;
293: mixer_ctrl_t *cp;
294: struct ad1848_volume *val;
295: int reg;
296: {
297: u_int8_t e;
298:
299: ad1848_to_vol(cp, val);
300:
301: e = (val->left * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) /
302: (AUDIO_MAX_GAIN + 1) << SA3_3D_LSHIFT |
303: (val->right * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) /
304: (AUDIO_MAX_GAIN + 1) << SA3_3D_RSHIFT;
305:
306: ym_write(sc, reg, e);
307: }
308:
309: int
310: ym_mixer_set_port(addr, cp)
311: void *addr;
312: mixer_ctrl_t *cp;
313: {
314: struct ad1848_softc *ac = addr;
315: struct ym_softc *sc = ac->parent;
316: struct ad1848_volume vol;
317: int error = ad1848_mixer_set_port(ac, mappings, NUMMAP, cp);
318:
319: if (error != ENXIO)
320: return (error);
321:
322: error = 0;
323:
324: switch (cp->dev) {
325: case YM_OUTPUT_LVL:
326: ad1848_to_vol(cp, &vol);
327: ym_set_master_gain(sc, &vol);
328: break;
329:
330: case YM_OUTPUT_MUTE:
331: sc->master_mute = (cp->un.ord != 0);
332: ym_mute(sc, SA3_VOL_L, sc->master_mute);
333: ym_mute(sc, SA3_VOL_R, sc->master_mute);
334: break;
335:
336: case YM_MIC_LVL:
337: if (cp->un.value.num_channels != 1)
338: error = EINVAL;
339: else
340: ym_set_mic_gain(sc,
341: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
342: break;
343:
344: case YM_MASTER_EQMODE:
345: sc->sc_eqmode = cp->un.ord & SA3_SYS_CTL_YMODE;
346: ym_write(sc, SA3_SYS_CTL, (ym_read(sc, SA3_SYS_CTL) &
347: ~SA3_SYS_CTL_YMODE) | sc->sc_eqmode);
348: break;
349:
350: case YM_MASTER_TREBLE:
351: ym_set_3d(sc, cp, &sc->sc_treble, SA3_3D_TREBLE);
352: break;
353:
354: case YM_MASTER_BASS:
355: ym_set_3d(sc, cp, &sc->sc_bass, SA3_3D_BASS);
356: break;
357:
358: case YM_MASTER_WIDE:
359: ym_set_3d(sc, cp, &sc->sc_wide, SA3_3D_WIDE);
360: break;
361:
362: case YM_MIC_MUTE:
363: sc->mic_mute = (cp->un.ord != 0);
364: ym_mute(sc, SA3_MIC_VOL, sc->mic_mute);
365: break;
366:
367: default:
368: return ENXIO;
369: /* NOTREACHED */
370: }
371:
372: return (error);
373: }
374:
375: int
376: ym_mixer_get_port(addr, cp)
377: void *addr;
378: mixer_ctrl_t *cp;
379: {
380: struct ad1848_softc *ac = addr;
381: struct ym_softc *sc = ac->parent;
382:
383: int error = ad1848_mixer_get_port(ac, mappings, NUMMAP, cp);
384:
385: if (error != ENXIO)
386: return (error);
387:
388: error = 0;
389:
390: switch (cp->dev) {
391: case YM_OUTPUT_LVL:
392: ad1848_from_vol(cp, &sc->master_gain);
393: break;
394:
395: case YM_OUTPUT_MUTE:
396: cp->un.ord = sc->master_mute;
397: break;
398:
399: case YM_MIC_LVL:
400: if (cp->un.value.num_channels != 1)
401: error = EINVAL;
402: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->mic_gain;
403: break;
404:
405: case YM_MASTER_EQMODE:
406: cp->un.ord = sc->sc_eqmode;
407: break;
408:
409: case YM_MASTER_TREBLE:
410: ad1848_from_vol(cp, &sc->sc_treble);
411: break;
412:
413: case YM_MASTER_BASS:
414: ad1848_from_vol(cp, &sc->sc_bass);
415: break;
416:
417: case YM_MASTER_WIDE:
418: ad1848_from_vol(cp, &sc->sc_wide);
419: break;
420:
421: case YM_MIC_MUTE:
422: cp->un.ord = sc->mic_mute;
423: break;
424:
425: default:
426: error = ENXIO;
427: break;
428: }
429:
430: return (error);
431: }
432:
433: static char *mixer_classes[] = {
434: AudioCinputs, AudioCrecord, AudioCoutputs, AudioCmonitor,
435: AudioCequalization
436: };
437:
438: int
439: ym_query_devinfo(addr, dip)
440: void *addr;
441: mixer_devinfo_t *dip;
442: {
443: static char *mixer_port_names[] = { AudioNmidi, AudioNcd, AudioNdac,
444: AudioNline, AudioNspeaker, AudioNmicrophone, AudioNmonitor
445: };
446:
447: dip->next = dip->prev = AUDIO_MIXER_LAST;
448:
449: switch (dip->index) {
450: case YM_INPUT_CLASS: /* input class descriptor */
451: case YM_OUTPUT_CLASS:
452: case YM_MONITOR_CLASS:
453: case YM_RECORD_CLASS:
454: case YM_EQ_CLASS:
455: dip->type = AUDIO_MIXER_CLASS;
456: dip->mixer_class = dip->index;
457: strlcpy(dip->label.name,
458: mixer_classes[dip->index - YM_INPUT_CLASS],
459: sizeof dip->label.name);
460: break;
461:
462: case YM_MIDI_LVL:
463: case YM_CD_LVL:
464: case YM_DAC_LVL:
465: case YM_LINE_LVL:
466: case YM_SPEAKER_LVL:
467: case YM_MIC_LVL:
468: case YM_MONITOR_LVL:
469: dip->type = AUDIO_MIXER_VALUE;
470: if (dip->index == YM_MONITOR_LVL)
471: dip->mixer_class = YM_MONITOR_CLASS;
472: else
473: dip->mixer_class = YM_INPUT_CLASS;
474:
475: dip->next = dip->index + 7;
476:
477: strlcpy(dip->label.name,
478: mixer_port_names[dip->index - YM_MIDI_LVL],
479: sizeof dip->label.name);
480:
481: if (dip->index == YM_SPEAKER_LVL ||
482: dip->index == YM_MIC_LVL)
483: dip->un.v.num_channels = 1;
484: else
485: dip->un.v.num_channels = 2;
486:
487: strlcpy(dip->un.v.units.name, AudioNvolume,
488: sizeof dip->un.v.units.name);
489: break;
490:
491: case YM_MIDI_MUTE:
492: case YM_CD_MUTE:
493: case YM_DAC_MUTE:
494: case YM_LINE_MUTE:
495: case YM_SPEAKER_MUTE:
496: case YM_MIC_MUTE:
497: case YM_MONITOR_MUTE:
498: if (dip->index == YM_MONITOR_MUTE)
499: dip->mixer_class = YM_MONITOR_CLASS;
500: else
501: dip->mixer_class = YM_INPUT_CLASS;
502: dip->type = AUDIO_MIXER_ENUM;
503: dip->prev = dip->index - 7;
504: mute:
505: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
506: dip->un.e.num_mem = 2;
507: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
508: sizeof dip->un.e.member[0].label.name);
509: dip->un.e.member[0].ord = 0;
510: strlcpy(dip->un.e.member[1].label.name, AudioNon,
511: sizeof dip->un.e.member[1].label.name);
512: dip->un.e.member[1].ord = 1;
513: break;
514:
515:
516: case YM_OUTPUT_LVL:
517: dip->type = AUDIO_MIXER_VALUE;
518: dip->mixer_class = YM_OUTPUT_CLASS;
519: dip->next = YM_OUTPUT_MUTE;
520: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
521: dip->un.v.num_channels = 2;
522: strlcpy(dip->un.v.units.name, AudioNvolume,
523: sizeof dip->un.v.units.name);
524: break;
525:
526: case YM_OUTPUT_MUTE:
527: dip->mixer_class = YM_OUTPUT_CLASS;
528: dip->type = AUDIO_MIXER_ENUM;
529: dip->prev = YM_OUTPUT_LVL;
530: goto mute;
531:
532: case YM_REC_LVL: /* record level */
533: dip->type = AUDIO_MIXER_VALUE;
534: dip->mixer_class = YM_RECORD_CLASS;
535: dip->next = YM_RECORD_SOURCE;
536: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
537: dip->un.v.num_channels = 2;
538: strlcpy(dip->un.v.units.name, AudioNvolume,
539: sizeof dip->un.v.units.name);
540: break;
541:
542:
543: case YM_RECORD_SOURCE:
544: dip->mixer_class = YM_RECORD_CLASS;
545: dip->type = AUDIO_MIXER_ENUM;
546: dip->prev = YM_REC_LVL;
547: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
548: dip->un.e.num_mem = 4;
549: strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
550: sizeof dip->un.e.member[0].label.name);
551: dip->un.e.member[0].ord = MIC_IN_PORT;
552: strlcpy(dip->un.e.member[1].label.name, AudioNline,
553: sizeof dip->un.e.member[1].label.name);
554: dip->un.e.member[1].ord = LINE_IN_PORT;
555: strlcpy(dip->un.e.member[2].label.name, AudioNdac,
556: sizeof dip->un.e.member[2].label.name);
557: dip->un.e.member[2].ord = DAC_IN_PORT;
558: strlcpy(dip->un.e.member[3].label.name, AudioNcd,
559: sizeof dip->un.e.member[3].label.name);
560: dip->un.e.member[3].ord = AUX1_IN_PORT;
561: break;
562:
563: case YM_MASTER_EQMODE:
564: dip->type = AUDIO_MIXER_ENUM;
565: dip->mixer_class = YM_EQ_CLASS;
566: strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
567: strlcpy(dip->un.v.units.name, AudioNmode,
568: sizeof dip->un.v.units.name);
569: dip->un.e.num_mem = 4;
570: strlcpy(dip->un.e.member[0].label.name, AudioNdesktop,
571: sizeof dip->un.e.member[0].label.name);
572: dip->un.e.member[0].ord = SA3_SYS_CTL_YMODE0;
573: strlcpy(dip->un.e.member[1].label.name, AudioNlaptop,
574: sizeof dip->un.e.member[1].label.name);
575: dip->un.e.member[1].ord = SA3_SYS_CTL_YMODE1;
576: strlcpy(dip->un.e.member[2].label.name, AudioNsubnote,
577: sizeof dip->un.e.member[2].label.name);
578: dip->un.e.member[2].ord = SA3_SYS_CTL_YMODE2;
579: strlcpy(dip->un.e.member[3].label.name, AudioNhifi,
580: sizeof dip->un.e.member[3].label.name);
581: dip->un.e.member[3].ord = SA3_SYS_CTL_YMODE3;
582: break;
583:
584: case YM_MASTER_TREBLE:
585: dip->type = AUDIO_MIXER_VALUE;
586: dip->mixer_class = YM_EQ_CLASS;
587: strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name);
588: dip->un.v.num_channels = 2;
589: strlcpy(dip->un.v.units.name, AudioNtreble,
590: sizeof dip->un.v.units.name);
591: break;
592:
593: case YM_MASTER_BASS:
594: dip->type = AUDIO_MIXER_VALUE;
595: dip->mixer_class = YM_EQ_CLASS;
596: strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name);
597: dip->un.v.num_channels = 2;
598: strlcpy(dip->un.v.units.name, AudioNbass,
599: sizeof dip->un.v.units.name);
600: break;
601:
602: case YM_MASTER_WIDE:
603: dip->type = AUDIO_MIXER_VALUE;
604: dip->mixer_class = YM_EQ_CLASS;
605: strlcpy(dip->label.name, AudioNsurround,
606: sizeof dip->label.name);
607: dip->un.v.num_channels = 2;
608: strlcpy(dip->un.v.units.name, AudioNsurround,
609: sizeof dip->un.v.units.name);
610: break;
611:
612: default:
613: return ENXIO;
614: /* NOTREACHED */
615: }
616:
617: return 0;
618: }
619: #if NMIDI > 0
620:
621: #define YMMPU(a) (&((struct ym_softc *)addr)->sc_mpu_sc)
622:
623: int
624: ym_mpu401_open(addr, flags, iintr, ointr, arg)
625: void *addr;
626: int flags;
627: void (*iintr)(void *, int);
628: void (*ointr)(void *);
629: void *arg;
630: {
631: return mpu_open(YMMPU(addr), flags, iintr, ointr, arg);
632: }
633:
634: int
635: ym_mpu401_output(addr, d)
636: void *addr;
637: int d;
638: {
639: return mpu_output(YMMPU(addr), d);
640: }
641:
642: void
643: ym_mpu401_close(addr)
644: void *addr;
645: {
646: mpu_close(YMMPU(addr));
647: }
648:
649: void
650: ym_mpu401_getinfo(addr, mi)
651: void *addr;
652: struct midi_info *mi;
653: {
654: mi->name = "YM MPU-401 UART";
655: mi->props = 0;
656: }
657: #endif
CVSweb