ym.c revision 1.6 1 /* $NetBSD: ym.c,v 1.6 1998/10/11 17:02:36 augustss 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 /*
31 * Original code from OpenBSD.
32 */
33
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/errno.h>
38 #include <sys/device.h>
39
40 #include <machine/cpu.h>
41 #include <machine/intr.h>
42 #include <machine/bus.h>
43
44 #include <sys/audioio.h>
45 #include <dev/audio_if.h>
46
47 #include <dev/isa/isavar.h>
48 #include <dev/isa/isadmavar.h>
49
50 #include <dev/ic/ad1848reg.h>
51 #include <dev/isa/ad1848var.h>
52 #include <dev/ic/opl3sa3.h>
53 #include <dev/isa/ymvar.h>
54
55
56 int ym_getdev __P((void *, struct audio_device *));
57 int ym_mixer_set_port __P((void *, mixer_ctrl_t *));
58 int ym_mixer_get_port __P((void *, mixer_ctrl_t *));
59 int ym_query_devinfo __P((void *, mixer_devinfo_t *));
60
61 static void ym_mute __P((struct ym_softc *, int, int));
62 static void ym_set_master_gain __P((struct ym_softc *, struct ad1848_volume*));
63 static void ym_set_mic_gain __P((struct ym_softc *, struct ad1848_volume *));
64
65
66
67 struct audio_hw_if ym_hw_if = {
68 ad1848_isa_open,
69 ad1848_isa_close,
70 NULL,
71 ad1848_query_encoding,
72 ad1848_set_params,
73 ad1848_round_blocksize,
74 ad1848_commit_settings,
75 ad1848_isa_dma_init_output,
76 ad1848_isa_dma_init_input,
77 ad1848_isa_dma_output,
78 ad1848_isa_dma_input,
79 ad1848_halt_out,
80 ad1848_halt_in,
81 NULL,
82 ym_getdev,
83 NULL,
84 ym_mixer_set_port,
85 ym_mixer_get_port,
86 ym_query_devinfo,
87 ad1848_isa_malloc,
88 ad1848_isa_free,
89 ad1848_isa_round,
90 ad1848_isa_mappage,
91 ad1848_isa_get_props,
92 };
93
94
95 struct audio_device ym_device = {
96 "ym,ad1848",
97 "",
98 "ym"
99 };
100
101 static __inline int ym_read __P((struct ym_softc *, int));
102 static __inline void ym_write __P((struct ym_softc *, int, int));
103
104 void
105 ym_attach(sc)
106 struct ym_softc *sc;
107 {
108 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
109 struct ad1848_volume vol_mid = {220, 220};
110 struct ad1848_volume vol_0 = {0, 0};
111
112 sc->sc_ad1848.sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq,
113 IST_EDGE,
114 IPL_AUDIO, ad1848_isa_intr,
115 &sc->sc_ad1848);
116
117 ad1848_isa_attach(&sc->sc_ad1848);
118 printf("\n");
119 ac->parent = sc;
120
121 /* Establish chip in well known mode */
122 ym_set_master_gain(sc, &vol_mid);
123 ym_set_mic_gain(sc, &vol_0);
124 sc->master_mute = 0;
125 ym_mute(sc, SA3_LCH, sc->master_mute);
126 ym_mute(sc, SA3_RCH, sc->master_mute);
127
128 sc->mic_mute = 1;
129 ym_mute(sc, SA3_MIC, sc->mic_mute);
130
131 audio_attach_mi(&ym_hw_if, ac, &ac->sc_dev);
132 }
133
134 static __inline int
135 ym_read(sc, reg)
136 struct ym_softc *sc;
137 int reg;
138 {
139 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
140 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
141 return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, 1));
142 }
143
144 static __inline void
145 ym_write(sc, reg, data)
146 struct ym_softc *sc;
147 int reg;
148 int data;
149 {
150 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
151 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
152 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 1, (data & 0xff));
153 }
154
155
156
157 int
158 ym_getdev(addr, retp)
159 void *addr;
160 struct audio_device *retp;
161 {
162 *retp = ym_device;
163 return 0;
164 }
165
166
167 static ad1848_devmap_t mappings[] = {
168 { YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
169 { YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
170 { YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
171 { YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
172 { YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
173 { YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
174 { YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
175 { YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
176 { YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
177 { YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
178 { YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
179 { YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
180 { YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
181 { YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
182 };
183
184 static int nummap = sizeof(mappings) / sizeof(mappings[0]);
185
186
187 static void
188 ym_mute(sc, left_reg, mute)
189 struct ym_softc *sc;
190 int left_reg;
191 int mute;
192
193 {
194 u_char reg;
195
196 if (mute) {
197 reg = ym_read(sc, left_reg);
198 ym_write (sc, left_reg, reg | 0x80);
199 } else {
200 reg = ym_read(sc, left_reg);
201 ym_write (sc, left_reg, reg & ~0x80);
202 }
203 }
204
205 #define MIC_ATTEN_BITS 0x1f
206 #define MASTER_ATTEN_BITS 0x0f
207
208
209 static void
210 ym_set_master_gain(sc, vol)
211 struct ym_softc *sc;
212 struct ad1848_volume *vol;
213 {
214 u_char reg;
215 u_int atten;
216
217 sc->master_gain = *vol;
218
219 atten = ((AUDIO_MAX_GAIN - vol->left) * MASTER_ATTEN_BITS) /
220 AUDIO_MAX_GAIN;
221
222 reg = ym_read(sc, SA3_LCH);
223
224 reg &= ~(MASTER_ATTEN_BITS);
225 reg |= atten;
226
227 ym_write (sc, SA3_LCH, reg);
228
229 atten = ((AUDIO_MAX_GAIN - vol->right) * MASTER_ATTEN_BITS) /
230 AUDIO_MAX_GAIN;
231
232 reg = ym_read(sc, SA3_RCH) & ~(MASTER_ATTEN_BITS);
233 reg |= atten;
234
235 ym_write (sc, SA3_RCH, reg);
236 }
237
238 static void
239 ym_set_mic_gain(sc, vol)
240 struct ym_softc *sc;
241 struct ad1848_volume *vol;
242 {
243 u_char reg;
244 u_int atten;
245
246 sc->mic_gain = *vol;
247
248 atten = ((AUDIO_MAX_GAIN - vol->left) * MIC_ATTEN_BITS)/AUDIO_MAX_GAIN;
249
250 reg = ym_read(sc, SA3_MIC) & ~(MIC_ATTEN_BITS);
251 reg |= atten;
252
253 ym_write (sc, SA3_MIC, reg);
254 }
255
256 int
257 ym_mixer_set_port(addr, cp)
258 void *addr;
259 mixer_ctrl_t *cp;
260 {
261 struct ad1848_softc *ac = addr;
262 struct ym_softc *sc = ac->parent;
263 struct ad1848_volume vol;
264 int error = ad1848_mixer_set_port(ac, mappings, nummap, cp);
265
266 if (error != ENXIO)
267 return (error);
268
269 error = 0;
270
271 switch (cp->dev) {
272 case YM_OUTPUT_LVL:
273 ad1848_to_vol(cp, &vol);
274 ym_set_master_gain(sc, &vol);
275 break;
276
277 case YM_OUTPUT_MUTE:
278 sc->master_mute = (cp->un.ord != 0);
279 ym_mute(sc, SA3_LCH, sc->master_mute);
280 ym_mute(sc, SA3_RCH, sc->master_mute);
281 break;
282
283 case YM_MIC_LVL:
284 if (cp->un.value.num_channels != 1)
285 error = EINVAL;
286
287 ad1848_to_vol(cp, &vol);
288 ym_set_mic_gain(sc, &vol);
289 break;
290
291 case YM_MIC_MUTE:
292 sc->mic_mute = (cp->un.ord != 0);
293 ym_mute(sc, SA3_MIC, sc->mic_mute);
294 break;
295
296 default:
297 return ENXIO;
298 /*NOTREACHED*/
299 }
300
301 return (error);
302 }
303
304 int
305 ym_mixer_get_port(addr, cp)
306 void *addr;
307 mixer_ctrl_t *cp;
308 {
309 struct ad1848_softc *ac = addr;
310 struct ym_softc *sc = ac->parent;
311
312 int error = ad1848_mixer_get_port(ac, mappings, nummap, cp);
313
314 if (error != ENXIO)
315 return (error);
316
317 error = 0;
318
319 switch (cp->dev) {
320 case YM_OUTPUT_LVL:
321 ad1848_from_vol(cp, &sc->master_gain);
322 break;
323
324 case YM_OUTPUT_MUTE:
325 cp->un.ord = sc->master_mute;
326 break;
327
328 case YM_MIC_LVL:
329 if (cp->un.value.num_channels != 1)
330 error = EINVAL;
331 ad1848_from_vol(cp, &sc->mic_gain);
332 break;
333
334 case YM_MIC_MUTE:
335 cp->un.ord = sc->mic_mute;
336 break;
337
338 default:
339 error = ENXIO;
340 break;
341 }
342
343 return(error);
344 }
345
346 static char *mixer_classes[] =
347 { AudioCinputs, AudioCrecord, AudioCoutputs, AudioCmonitor };
348
349 int
350 ym_query_devinfo(addr, dip)
351 void *addr;
352 mixer_devinfo_t *dip;
353 {
354 static char *mixer_port_names[] =
355 { AudioNmidi, AudioNcd, AudioNdac, AudioNline, AudioNspeaker,
356 AudioNmicrophone, AudioNmonitor};
357
358 dip->next = dip->prev = AUDIO_MIXER_LAST;
359
360 switch(dip->index) {
361 case YM_INPUT_CLASS: /* input class descriptor */
362 case YM_OUTPUT_CLASS:
363 case YM_MONITOR_CLASS:
364 case YM_RECORD_CLASS:
365 dip->type = AUDIO_MIXER_CLASS;
366 dip->mixer_class = dip->index;
367 strcpy(dip->label.name,
368 mixer_classes[dip->index - YM_INPUT_CLASS]);
369 break;
370
371 case YM_MIDI_LVL:
372 case YM_CD_LVL:
373 case YM_DAC_LVL:
374 case YM_LINE_LVL:
375 case YM_SPEAKER_LVL:
376 case YM_MIC_LVL:
377 case YM_MONITOR_LVL:
378 dip->type = AUDIO_MIXER_VALUE;
379 if (dip->index == YM_MONITOR_LVL)
380 dip->mixer_class = YM_MONITOR_CLASS;
381 else
382 dip->mixer_class = YM_INPUT_CLASS;
383
384 dip->next = dip->index + 7;
385
386 strcpy(dip->label.name,
387 mixer_port_names[dip->index - YM_MIDI_LVL]);
388
389 if (dip->index == YM_SPEAKER_LVL ||
390 dip->index == YM_MIC_LVL)
391 dip->un.v.num_channels = 1;
392 else
393 dip->un.v.num_channels = 2;
394
395 strcpy(dip->un.v.units.name, AudioNvolume);
396 break;
397
398 case YM_MIDI_MUTE:
399 case YM_CD_MUTE:
400 case YM_DAC_MUTE:
401 case YM_LINE_MUTE:
402 case YM_SPEAKER_MUTE:
403 case YM_MIC_MUTE:
404 case YM_MONITOR_MUTE:
405 if (dip->index == YM_MONITOR_MUTE)
406 dip->mixer_class = YM_MONITOR_CLASS;
407 else
408 dip->mixer_class = YM_INPUT_CLASS;
409 dip->type = AUDIO_MIXER_ENUM;
410 dip->prev = dip->index - 7;
411 mute:
412 strcpy(dip->label.name, AudioNmute);
413 dip->un.e.num_mem = 2;
414 strcpy(dip->un.e.member[0].label.name, AudioNoff);
415 dip->un.e.member[0].ord = 0;
416 strcpy(dip->un.e.member[1].label.name, AudioNon);
417 dip->un.e.member[1].ord = 1;
418 break;
419
420
421 case YM_OUTPUT_LVL:
422 dip->type = AUDIO_MIXER_VALUE;
423 dip->mixer_class = YM_OUTPUT_CLASS;
424 dip->next = YM_OUTPUT_MUTE;
425 strcpy(dip->label.name, AudioNmaster);
426 dip->un.v.num_channels = 2;
427 strcpy(dip->un.v.units.name, AudioNvolume);
428 break;
429
430 case YM_OUTPUT_MUTE:
431 dip->mixer_class = YM_OUTPUT_CLASS;
432 dip->type = AUDIO_MIXER_ENUM;
433 dip->prev = YM_OUTPUT_LVL;
434 goto mute;
435
436 case YM_REC_LVL: /* record level */
437 dip->type = AUDIO_MIXER_VALUE;
438 dip->mixer_class = YM_RECORD_CLASS;
439 dip->next = YM_RECORD_SOURCE;
440 strcpy(dip->label.name, AudioNrecord);
441 dip->un.v.num_channels = 2;
442 strcpy(dip->un.v.units.name, AudioNvolume);
443 break;
444
445
446 case YM_RECORD_SOURCE:
447 dip->mixer_class = YM_RECORD_CLASS;
448 dip->type = AUDIO_MIXER_ENUM;
449 dip->prev = YM_REC_LVL;
450 strcpy(dip->label.name, AudioNsource);
451 dip->un.e.num_mem = 4;
452 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
453 dip->un.e.member[0].ord = MIC_IN_PORT;
454 strcpy(dip->un.e.member[1].label.name, AudioNline);
455 dip->un.e.member[1].ord = LINE_IN_PORT;
456 strcpy(dip->un.e.member[2].label.name, AudioNdac);
457 dip->un.e.member[2].ord = DAC_IN_PORT;
458 strcpy(dip->un.e.member[3].label.name, AudioNcd);
459 dip->un.e.member[3].ord = AUX1_IN_PORT;
460 break;
461
462 default:
463 return ENXIO;
464 /*NOTREACHED*/
465 }
466
467 return 0;
468 }
469