Annotation of sys/dev/isa/gus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: gus.c,v 1.29 2006/03/04 12:42:23 miod Exp $ */
2: /* $NetBSD: gus.c,v 1.51 1998/01/25 23:48:06 mycroft Exp $ */
3:
4: /*-
5: * Copyright (c) 1996 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Ken Hornstein and John Kohl.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: *
42: * TODO:
43: * . figure out why mixer activity while sound is playing causes problems
44: * (phantom interrupts?)
45: * . figure out a better deinterleave strategy that avoids sucking up
46: * CPU, memory and cache bandwidth. (Maybe a special encoding?
47: * Maybe use the double-speed sampling/hardware deinterleave trick
48: * from the GUS SDK?) A 486/33 isn't quite fast enough to keep
49: * up with 44.1kHz 16-bit stereo output without some drop-outs.
50: * . use CS4231 for 16-bit sampling, for a-law and mu-law playback.
51: * . actually test full-duplex sampling(recording) and playback.
52: */
53:
54: /*
55: * Gravis UltraSound driver
56: *
57: * For more detailed information, see the GUS developers' kit
58: * available on the net at:
59: *
60: * http://www.gravis.com/Public/sdk/GUSDK222.ZIP
61: *
62: * See ultrawrd.doc inside--it's MS Word (ick), but it's the bible
63: *
64: */
65:
66: /*
67: * The GUS Max has a slightly strange set of connections between the CS4231
68: * and the GF1 and the DMA interconnects. It's set up so that the CS4231 can
69: * be playing while the GF1 is loading patches from the system.
70: *
71: * Here's a recreation of the DMA interconnect diagram:
72: *
73: * GF1
74: * +---------+ digital
75: * | | record ASIC
76: * | |--------------+
77: * | | | +--------+
78: * | | play (dram) | +----+ | |
79: * | |--------------(------|-\ | | +-+ |
80: * +---------+ | | >-|----|---|C|--|------ dma chan 1
81: * | +---|-/ | | +-+ |
82: * | | +----+ | | |
83: * | | +----+ | | |
84: * +---------+ +-+ +--(---|-\ | | | |
85: * | | play |8| | | >-|----|----+---|------ dma chan 2
86: * | ---C----|--------|/|------(---|-/ | | |
87: * | ^ |record |1| | +----+ | |
88: * | | | /----|6|------+ +--------+
89: * | ---+----|--/ +-+
90: * +---------+
91: * CS4231 8-to-16 bit bus conversion, if needed
92: *
93: *
94: * "C" is an optional combiner.
95: *
96: */
97:
98: #include <sys/param.h>
99: #include <sys/systm.h>
100: #include <sys/errno.h>
101: #include <sys/ioctl.h>
102: #include <sys/syslog.h>
103: #include <sys/device.h>
104: #include <sys/proc.h>
105: #include <sys/buf.h>
106: #include <sys/fcntl.h>
107: #include <sys/malloc.h>
108: #include <sys/kernel.h>
109: #include <sys/timeout.h>
110:
111: #include <machine/cpu.h>
112: #include <machine/intr.h>
113: #include <machine/bus.h>
114: #include <machine/cpufunc.h>
115: #include <sys/audioio.h>
116: #include <dev/audio_if.h>
117: #include <dev/mulaw.h>
118: #include <dev/auconv.h>
119:
120: #include <dev/isa/isavar.h>
121: #include <dev/isa/isadmavar.h>
122:
123: #include <dev/ic/ics2101reg.h>
124: #include <dev/ic/cs4231reg.h>
125: #include <dev/ic/ad1848reg.h>
126: #include <dev/isa/ics2101var.h>
127: #include <dev/isa/ad1848var.h>
128: #include <dev/isa/cs4231var.h>
129: #include "gusreg.h"
130: #include "gusvar.h"
131:
132: #ifdef AUDIO_DEBUG
133: #define GUSPLAYDEBUG /*XXX*/
134: #define DPRINTF(x) if (gusdebug) printf x
135: #define DMAPRINTF(x) if (gusdmadebug) printf x
136: int gusdebug = 0;
137: int gusdmadebug = 0;
138: #else
139: #define DPRINTF(x)
140: #define DMAPRINTF(x)
141: #endif
142: int gus_dostereo = 1;
143:
144: #define NDMARECS 2048
145: #ifdef GUSPLAYDEBUG
146: int gusstats = 0;
147:
148: struct dma_record dmarecords[NDMARECS];
149:
150: int dmarecord_index = 0;
151: #endif
152:
153: struct cfdriver gus_cd = {
154: NULL, "gus", DV_DULL
155: };
156:
157: /*
158: * A mapping from IRQ/DRQ values to the values used in the GUS's internal
159: * registers. A zero means that the referenced IRQ/DRQ is invalid
160: */
161: const int gus_irq_map[] = {
162: IRQUNK, IRQUNK, 1, 3, IRQUNK, 2, IRQUNK, 4, IRQUNK, 1, IRQUNK, 5, 6,
163: IRQUNK, IRQUNK, 7
164: };
165: const int gus_drq_map[] = {
166: DRQUNK, 1, DRQUNK, 2, DRQUNK, 3, 4, 5
167: };
168:
169: /*
170: * A list of valid base addresses for the GUS
171: */
172:
173: const int gus_base_addrs[] = {
174: 0x210, 0x220, 0x230, 0x240, 0x250, 0x260
175: };
176: const int gus_addrs = sizeof(gus_base_addrs) / sizeof(gus_base_addrs[0]);
177:
178: /*
179: * Maximum frequency values of the GUS based on the number of currently active
180: * voices. Since the GUS samples a voice every 1.6 us, the maximum frequency
181: * is dependent on the number of active voices. Yes, it is pretty weird.
182: */
183:
184: static const int gus_max_frequency[] = {
185: 44100, /* 14 voices */
186: 41160, /* 15 voices */
187: 38587, /* 16 voices */
188: 36317, /* 17 voices */
189: 34300, /* 18 voices */
190: 32494, /* 19 voices */
191: 30870, /* 20 voices */
192: 29400, /* 21 voices */
193: 28063, /* 22 voices */
194: 26843, /* 23 voices */
195: 25725, /* 24 voices */
196: 24696, /* 25 voices */
197: 23746, /* 26 voices */
198: 22866, /* 27 voices */
199: 22050, /* 28 voices */
200: 21289, /* 29 voices */
201: 20580, /* 30 voices */
202: 19916, /* 31 voices */
203: 19293 /* 32 voices */
204: };
205: /*
206: * A mapping of linear volume levels to the logarithmic volume values used
207: * by the GF1 chip on the GUS. From GUS SDK vol1.c.
208: */
209:
210: static const unsigned short gus_log_volumes[512] = {
211: 0x0000,
212: 0x0700, 0x07ff, 0x0880, 0x08ff, 0x0940, 0x0980, 0x09c0, 0x09ff, 0x0a20,
213: 0x0a40, 0x0a60, 0x0a80, 0x0aa0, 0x0ac0, 0x0ae0, 0x0aff, 0x0b10, 0x0b20,
214: 0x0b30, 0x0b40, 0x0b50, 0x0b60, 0x0b70, 0x0b80, 0x0b90, 0x0ba0, 0x0bb0,
215: 0x0bc0, 0x0bd0, 0x0be0, 0x0bf0, 0x0bff, 0x0c08, 0x0c10, 0x0c18, 0x0c20,
216: 0x0c28, 0x0c30, 0x0c38, 0x0c40, 0x0c48, 0x0c50, 0x0c58, 0x0c60, 0x0c68,
217: 0x0c70, 0x0c78, 0x0c80, 0x0c88, 0x0c90, 0x0c98, 0x0ca0, 0x0ca8, 0x0cb0,
218: 0x0cb8, 0x0cc0, 0x0cc8, 0x0cd0, 0x0cd8, 0x0ce0, 0x0ce8, 0x0cf0, 0x0cf8,
219: 0x0cff, 0x0d04, 0x0d08, 0x0d0c, 0x0d10, 0x0d14, 0x0d18, 0x0d1c, 0x0d20,
220: 0x0d24, 0x0d28, 0x0d2c, 0x0d30, 0x0d34, 0x0d38, 0x0d3c, 0x0d40, 0x0d44,
221: 0x0d48, 0x0d4c, 0x0d50, 0x0d54, 0x0d58, 0x0d5c, 0x0d60, 0x0d64, 0x0d68,
222: 0x0d6c, 0x0d70, 0x0d74, 0x0d78, 0x0d7c, 0x0d80, 0x0d84, 0x0d88, 0x0d8c,
223: 0x0d90, 0x0d94, 0x0d98, 0x0d9c, 0x0da0, 0x0da4, 0x0da8, 0x0dac, 0x0db0,
224: 0x0db4, 0x0db8, 0x0dbc, 0x0dc0, 0x0dc4, 0x0dc8, 0x0dcc, 0x0dd0, 0x0dd4,
225: 0x0dd8, 0x0ddc, 0x0de0, 0x0de4, 0x0de8, 0x0dec, 0x0df0, 0x0df4, 0x0df8,
226: 0x0dfc, 0x0dff, 0x0e02, 0x0e04, 0x0e06, 0x0e08, 0x0e0a, 0x0e0c, 0x0e0e,
227: 0x0e10, 0x0e12, 0x0e14, 0x0e16, 0x0e18, 0x0e1a, 0x0e1c, 0x0e1e, 0x0e20,
228: 0x0e22, 0x0e24, 0x0e26, 0x0e28, 0x0e2a, 0x0e2c, 0x0e2e, 0x0e30, 0x0e32,
229: 0x0e34, 0x0e36, 0x0e38, 0x0e3a, 0x0e3c, 0x0e3e, 0x0e40, 0x0e42, 0x0e44,
230: 0x0e46, 0x0e48, 0x0e4a, 0x0e4c, 0x0e4e, 0x0e50, 0x0e52, 0x0e54, 0x0e56,
231: 0x0e58, 0x0e5a, 0x0e5c, 0x0e5e, 0x0e60, 0x0e62, 0x0e64, 0x0e66, 0x0e68,
232: 0x0e6a, 0x0e6c, 0x0e6e, 0x0e70, 0x0e72, 0x0e74, 0x0e76, 0x0e78, 0x0e7a,
233: 0x0e7c, 0x0e7e, 0x0e80, 0x0e82, 0x0e84, 0x0e86, 0x0e88, 0x0e8a, 0x0e8c,
234: 0x0e8e, 0x0e90, 0x0e92, 0x0e94, 0x0e96, 0x0e98, 0x0e9a, 0x0e9c, 0x0e9e,
235: 0x0ea0, 0x0ea2, 0x0ea4, 0x0ea6, 0x0ea8, 0x0eaa, 0x0eac, 0x0eae, 0x0eb0,
236: 0x0eb2, 0x0eb4, 0x0eb6, 0x0eb8, 0x0eba, 0x0ebc, 0x0ebe, 0x0ec0, 0x0ec2,
237: 0x0ec4, 0x0ec6, 0x0ec8, 0x0eca, 0x0ecc, 0x0ece, 0x0ed0, 0x0ed2, 0x0ed4,
238: 0x0ed6, 0x0ed8, 0x0eda, 0x0edc, 0x0ede, 0x0ee0, 0x0ee2, 0x0ee4, 0x0ee6,
239: 0x0ee8, 0x0eea, 0x0eec, 0x0eee, 0x0ef0, 0x0ef2, 0x0ef4, 0x0ef6, 0x0ef8,
240: 0x0efa, 0x0efc, 0x0efe, 0x0eff, 0x0f01, 0x0f02, 0x0f03, 0x0f04, 0x0f05,
241: 0x0f06, 0x0f07, 0x0f08, 0x0f09, 0x0f0a, 0x0f0b, 0x0f0c, 0x0f0d, 0x0f0e,
242: 0x0f0f, 0x0f10, 0x0f11, 0x0f12, 0x0f13, 0x0f14, 0x0f15, 0x0f16, 0x0f17,
243: 0x0f18, 0x0f19, 0x0f1a, 0x0f1b, 0x0f1c, 0x0f1d, 0x0f1e, 0x0f1f, 0x0f20,
244: 0x0f21, 0x0f22, 0x0f23, 0x0f24, 0x0f25, 0x0f26, 0x0f27, 0x0f28, 0x0f29,
245: 0x0f2a, 0x0f2b, 0x0f2c, 0x0f2d, 0x0f2e, 0x0f2f, 0x0f30, 0x0f31, 0x0f32,
246: 0x0f33, 0x0f34, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3b,
247: 0x0f3c, 0x0f3d, 0x0f3e, 0x0f3f, 0x0f40, 0x0f41, 0x0f42, 0x0f43, 0x0f44,
248: 0x0f45, 0x0f46, 0x0f47, 0x0f48, 0x0f49, 0x0f4a, 0x0f4b, 0x0f4c, 0x0f4d,
249: 0x0f4e, 0x0f4f, 0x0f50, 0x0f51, 0x0f52, 0x0f53, 0x0f54, 0x0f55, 0x0f56,
250: 0x0f57, 0x0f58, 0x0f59, 0x0f5a, 0x0f5b, 0x0f5c, 0x0f5d, 0x0f5e, 0x0f5f,
251: 0x0f60, 0x0f61, 0x0f62, 0x0f63, 0x0f64, 0x0f65, 0x0f66, 0x0f67, 0x0f68,
252: 0x0f69, 0x0f6a, 0x0f6b, 0x0f6c, 0x0f6d, 0x0f6e, 0x0f6f, 0x0f70, 0x0f71,
253: 0x0f72, 0x0f73, 0x0f74, 0x0f75, 0x0f76, 0x0f77, 0x0f78, 0x0f79, 0x0f7a,
254: 0x0f7b, 0x0f7c, 0x0f7d, 0x0f7e, 0x0f7f, 0x0f80, 0x0f81, 0x0f82, 0x0f83,
255: 0x0f84, 0x0f85, 0x0f86, 0x0f87, 0x0f88, 0x0f89, 0x0f8a, 0x0f8b, 0x0f8c,
256: 0x0f8d, 0x0f8e, 0x0f8f, 0x0f90, 0x0f91, 0x0f92, 0x0f93, 0x0f94, 0x0f95,
257: 0x0f96, 0x0f97, 0x0f98, 0x0f99, 0x0f9a, 0x0f9b, 0x0f9c, 0x0f9d, 0x0f9e,
258: 0x0f9f, 0x0fa0, 0x0fa1, 0x0fa2, 0x0fa3, 0x0fa4, 0x0fa5, 0x0fa6, 0x0fa7,
259: 0x0fa8, 0x0fa9, 0x0faa, 0x0fab, 0x0fac, 0x0fad, 0x0fae, 0x0faf, 0x0fb0,
260: 0x0fb1, 0x0fb2, 0x0fb3, 0x0fb4, 0x0fb5, 0x0fb6, 0x0fb7, 0x0fb8, 0x0fb9,
261: 0x0fba, 0x0fbb, 0x0fbc, 0x0fbd, 0x0fbe, 0x0fbf, 0x0fc0, 0x0fc1, 0x0fc2,
262: 0x0fc3, 0x0fc4, 0x0fc5, 0x0fc6, 0x0fc7, 0x0fc8, 0x0fc9, 0x0fca, 0x0fcb,
263: 0x0fcc, 0x0fcd, 0x0fce, 0x0fcf, 0x0fd0, 0x0fd1, 0x0fd2, 0x0fd3, 0x0fd4,
264: 0x0fd5, 0x0fd6, 0x0fd7, 0x0fd8, 0x0fd9, 0x0fda, 0x0fdb, 0x0fdc, 0x0fdd,
265: 0x0fde, 0x0fdf, 0x0fe0, 0x0fe1, 0x0fe2, 0x0fe3, 0x0fe4, 0x0fe5, 0x0fe6,
266: 0x0fe7, 0x0fe8, 0x0fe9, 0x0fea, 0x0feb, 0x0fec, 0x0fed, 0x0fee, 0x0fef,
267: 0x0ff0, 0x0ff1, 0x0ff2, 0x0ff3, 0x0ff4, 0x0ff5, 0x0ff6, 0x0ff7, 0x0ff8,
268: 0x0ff9, 0x0ffa, 0x0ffb, 0x0ffc, 0x0ffd, 0x0ffe, 0x0fff};
269:
270: /*
271: * Interface to higher level audio driver
272: */
273: struct audio_hw_if gus_hw_if = {
274: gusopen,
275: gusclose,
276: NULL, /* drain */
277:
278: gus_query_encoding,
279:
280: gus_set_params,
281:
282: gus_round_blocksize,
283:
284: gus_commit_settings,
285:
286: NULL,
287: NULL,
288:
289: gus_dma_output,
290: gus_dma_input,
291: gus_halt_out_dma,
292: gus_halt_in_dma,
293: gus_speaker_ctl,
294:
295: gus_getdev,
296: NULL,
297: gus_mixer_set_port,
298: gus_mixer_get_port,
299: gus_mixer_query_devinfo,
300: ad1848_malloc,
301: ad1848_free,
302: ad1848_round,
303: ad1848_mappage,
304: gus_get_props,
305:
306: NULL,
307: NULL
308: };
309:
310: static struct audio_hw_if gusmax_hw_if = {
311: gusmaxopen,
312: gusmax_close,
313: NULL, /* drain */
314:
315: gus_query_encoding, /* query encoding */
316:
317: gusmax_set_params,
318:
319: gusmax_round_blocksize,
320:
321: gusmax_commit_settings,
322:
323: NULL,
324: NULL,
325:
326: gusmax_dma_output,
327: gusmax_dma_input,
328: gusmax_halt_out_dma,
329: gusmax_halt_in_dma,
330:
331: gusmax_speaker_ctl,
332:
333: gus_getdev,
334: NULL,
335: gusmax_mixer_set_port,
336: gusmax_mixer_get_port,
337: gusmax_mixer_query_devinfo,
338: ad1848_malloc,
339: ad1848_free,
340: ad1848_round,
341: ad1848_mappage,
342: gusmax_get_props,
343: };
344:
345: /*
346: * Some info about the current audio device
347: */
348: struct audio_device gus_device = {
349: "UltraSound",
350: "",
351: "gus",
352: };
353:
354:
355: int
356: gusopen(addr, flags)
357: void *addr;
358: int flags;
359: {
360: struct gus_softc *sc = addr;
361:
362: DPRINTF(("gusopen() called\n"));
363:
364: if (sc->sc_flags & GUS_OPEN)
365: return EBUSY;
366:
367: /*
368: * Some initialization
369: */
370:
371: sc->sc_flags |= GUS_OPEN;
372: sc->sc_dmabuf = 0;
373: sc->sc_playbuf = -1;
374: sc->sc_bufcnt = 0;
375: sc->sc_voc[GUS_VOICE_LEFT].start_addr = GUS_MEM_OFFSET - 1;
376: sc->sc_voc[GUS_VOICE_LEFT].current_addr = GUS_MEM_OFFSET;
377:
378: if (HAS_CODEC(sc)) {
379: ad1848_open(&sc->sc_codec, flags);
380: sc->sc_codec.mute[AD1848_AUX1_CHANNEL] = 0;
381: ad1848_mute_channel(&sc->sc_codec, AD1848_AUX1_CHANNEL, 0); /* turn on DAC output */
382: if (flags & FREAD) {
383: sc->sc_codec.mute[AD1848_MONO_CHANNEL] = 0;
384: ad1848_mute_channel(&sc->sc_codec, AD1848_MONO_CHANNEL, 0);
385: }
386: } else if (flags & FREAD) {
387: /* enable/unmute the microphone */
388: if (HAS_MIXER(sc)) {
389: gusics_mic_mute(&sc->sc_mixer, 0);
390: } else
391: gus_mic_ctl(sc, SPKR_ON);
392: }
393: if (sc->sc_nbufs == 0)
394: gus_round_blocksize(sc, GUS_BUFFER_MULTIPLE); /* default blksiz */
395: return 0;
396: }
397:
398: int
399: gusmaxopen(addr, flags)
400: void *addr;
401: int flags;
402: {
403: struct ad1848_softc *ac = addr;
404: return gusopen(ac->parent, flags);
405: }
406:
407: void
408: gus_deinterleave(sc, buf, size)
409: struct gus_softc *sc;
410: void *buf;
411: int size;
412: {
413: /* deinterleave the stereo data. We can use sc->sc_deintr_buf
414: for scratch space. */
415: int i;
416:
417: if (size > sc->sc_blocksize) {
418: printf("gus: deinterleave %d > %d\n", size, sc->sc_blocksize);
419: return;
420: } else if (size < sc->sc_blocksize) {
421: DPRINTF(("gus: deinterleave %d < %d\n", size, sc->sc_blocksize));
422: }
423:
424: /*
425: * size is in bytes.
426: */
427: if (sc->sc_precision == 16) {
428: u_short *dei = sc->sc_deintr_buf;
429: u_short *sbuf = buf;
430: size >>= 1; /* bytecnt to shortcnt */
431: /* copy 2nd of each pair of samples to the staging area, while
432: compacting the 1st of each pair into the original area. */
433: for (i = 0; i < size/2-1; i++) {
434: dei[i] = sbuf[i*2+1];
435: sbuf[i+1] = sbuf[i*2+2];
436: }
437: /*
438: * this has copied one less sample than half of the
439: * buffer. The first sample of the 1st stream was
440: * already in place and didn't need copying.
441: * Therefore, we've moved all of the 1st stream's
442: * samples into place. We have one sample from 2nd
443: * stream in the last slot of original area, not
444: * copied to the staging area (But we don't need to!).
445: * Copy the remainder of the original stream into place.
446: */
447: bcopy(dei, &sbuf[size/2], i * sizeof(short));
448: } else {
449: u_char *dei = sc->sc_deintr_buf;
450: u_char *sbuf = buf;
451: for (i = 0; i < size/2-1; i++) {
452: dei[i] = sbuf[i*2+1];
453: sbuf[i+1] = sbuf[i*2+2];
454: }
455: bcopy(dei, &sbuf[size/2], i);
456: }
457: }
458:
459: /*
460: * Actually output a buffer to the DSP chip
461: */
462:
463: int
464: gusmax_dma_output(addr, buf, size, intr, arg)
465: void * addr;
466: void *buf;
467: int size;
468: void (*intr)(void *);
469: void *arg;
470: {
471: struct ad1848_softc *ac = addr;
472: return gus_dma_output(ac->parent, buf, size, intr, arg);
473: }
474:
475: /*
476: * called at splgus() from interrupt handler.
477: */
478: void
479: stereo_dmaintr(arg)
480: void *arg;
481: {
482: struct gus_softc *sc = arg;
483: struct stereo_dma_intr *sa = &sc->sc_stereo;
484:
485: DMAPRINTF(("stereo_dmaintr"));
486:
487: /*
488: * Put other half in its place, then call the real interrupt routine :)
489: */
490:
491: sc->sc_dmaoutintr = sa->intr;
492: sc->sc_outarg = sa->arg;
493:
494: #ifdef GUSPLAYDEBUG
495: if (gusstats) {
496: microtime(&dmarecords[dmarecord_index].tv);
497: dmarecords[dmarecord_index].gusaddr = sa->dmabuf;
498: dmarecords[dmarecord_index].bsdaddr = sa->buffer;
499: dmarecords[dmarecord_index].count = sa->size;
500: dmarecords[dmarecord_index].channel = 1;
501: dmarecords[dmarecord_index++].direction = 1;
502: dmarecord_index = dmarecord_index % NDMARECS;
503: }
504: #endif
505:
506: gusdmaout(sc, sa->flags, sa->dmabuf, (caddr_t) sa->buffer, sa->size);
507:
508: sa->flags = 0;
509: sa->dmabuf = 0;
510: sa->buffer = 0;
511: sa->size = 0;
512: sa->intr = 0;
513: sa->arg = 0;
514: }
515:
516: /*
517: * Start up DMA output to the card.
518: * Called at splgus/splaudio already, either from intr handler or from
519: * generic audio code.
520: */
521: int
522: gus_dma_output(addr, buf, size, intr, arg)
523: void * addr;
524: void *buf;
525: int size;
526: void (*intr)(void *);
527: void *arg;
528: {
529: struct gus_softc *sc = addr;
530: u_char *buffer = buf;
531: u_long boarddma;
532: int flags;
533:
534: DMAPRINTF(("gus_dma_output %d @ %p\n", size, buf));
535:
536: if (size != sc->sc_blocksize) {
537: DPRINTF(("gus_dma_output reqsize %d not sc_blocksize %d\n",
538: size, sc->sc_blocksize));
539: return EINVAL;
540: }
541:
542: flags = GUSMASK_DMA_WRITE;
543: if (sc->sc_precision == 16)
544: flags |= GUSMASK_DMA_DATA_SIZE;
545: if (sc->sc_encoding == AUDIO_ENCODING_ULAW ||
546: sc->sc_encoding == AUDIO_ENCODING_ALAW ||
547: sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE ||
548: sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE)
549: flags |= GUSMASK_DMA_INVBIT;
550:
551: if (sc->sc_channels == 2) {
552: if (sc->sc_precision == 16) {
553: if (size & 3) {
554: DPRINTF(("gus_dma_output: unpaired 16bit samples"));
555: size &= 3;
556: }
557: } else if (size & 1) {
558: DPRINTF(("gus_dma_output: unpaired samples"));
559: size &= 1;
560: }
561: if (size == 0)
562: return 0;
563:
564: gus_deinterleave(sc, (void *)buffer, size);
565:
566: size >>= 1;
567:
568: boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET;
569:
570: sc->sc_stereo.intr = intr;
571: sc->sc_stereo.arg = arg;
572: sc->sc_stereo.size = size;
573: sc->sc_stereo.dmabuf = boarddma + GUS_LEFT_RIGHT_OFFSET;
574: sc->sc_stereo.buffer = buffer + size;
575: sc->sc_stereo.flags = flags;
576: if (gus_dostereo) {
577: intr = stereo_dmaintr;
578: arg = sc;
579: }
580: } else
581: boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET;
582:
583:
584: sc->sc_flags |= GUS_LOCKED;
585: sc->sc_dmaoutintr = intr;
586: sc->sc_outarg = arg;
587:
588: #ifdef GUSPLAYDEBUG
589: if (gusstats) {
590: microtime(&dmarecords[dmarecord_index].tv);
591: dmarecords[dmarecord_index].gusaddr = boarddma;
592: dmarecords[dmarecord_index].bsdaddr = buffer;
593: dmarecords[dmarecord_index].count = size;
594: dmarecords[dmarecord_index].channel = 0;
595: dmarecords[dmarecord_index++].direction = 1;
596: dmarecord_index = dmarecord_index % NDMARECS;
597: }
598: #endif
599:
600: gusdmaout(sc, flags, boarddma, (caddr_t) buffer, size);
601:
602: return 0;
603: }
604:
605: void
606: gusmax_close(addr)
607: void *addr;
608: {
609: struct ad1848_softc *ac = addr;
610: struct gus_softc *sc = ac->parent;
611: #if 0
612: ac->mute[AD1848_AUX1_CHANNEL] = MUTE_ALL;
613: ad1848_mute_channel(ac, MUTE_ALL); /* turn off DAC output */
614: #endif
615: ad1848_close(ac);
616: gusclose(sc);
617: }
618:
619: /*
620: * Close out device stuff. Called at splgus() from generic audio layer.
621: */
622: void
623: gusclose(addr)
624: void *addr;
625: {
626: struct gus_softc *sc = addr;
627:
628: DPRINTF(("gus_close: sc=%p\n", sc));
629:
630:
631: /* if (sc->sc_flags & GUS_DMAOUT_ACTIVE) */ {
632: gus_halt_out_dma(sc);
633: }
634: /* if (sc->sc_flags & GUS_DMAIN_ACTIVE) */ {
635: gus_halt_in_dma(sc);
636: }
637: sc->sc_flags &= ~(GUS_OPEN|GUS_LOCKED|GUS_DMAOUT_ACTIVE|GUS_DMAIN_ACTIVE);
638:
639: if (sc->sc_deintr_buf) {
640: free(sc->sc_deintr_buf, M_DEVBUF);
641: sc->sc_deintr_buf = NULL;
642: }
643: /* turn off speaker, etc. */
644:
645: /* make sure the voices shut up: */
646: gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
647: gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
648: }
649:
650: /*
651: * Service interrupts. Farm them off to helper routines if we are using the
652: * GUS for simple playback/record
653: */
654:
655: #ifdef AUDIO_DEBUG
656: int gusintrcnt;
657: int gusdmaintrcnt;
658: int gusvocintrcnt;
659: #endif
660:
661: int
662: gusintr(arg)
663: void *arg;
664: {
665: struct gus_softc *sc = arg;
666: bus_space_tag_t iot = sc->sc_iot;
667: bus_space_handle_t ioh1 = sc->sc_ioh1;
668: bus_space_handle_t ioh2 = sc->sc_ioh2;
669: unsigned char intr;
670:
671: int retval = 0;
672:
673: DPRINTF(("gusintr\n"));
674: #ifdef AUDIO_DEBUG
675: gusintrcnt++;
676: #endif
677: if (HAS_CODEC(sc))
678: retval = ad1848_intr(&sc->sc_codec);
679: if ((intr = bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS)) & GUSMASK_IRQ_DMATC) {
680: DMAPRINTF(("gusintr dma flags=%x\n", sc->sc_flags));
681: #ifdef AUDIO_DEBUG
682: gusdmaintrcnt++;
683: #endif
684: retval += gus_dmaout_intr(sc);
685: if (sc->sc_flags & GUS_DMAIN_ACTIVE) {
686: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
687: intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
688: if (intr & GUSMASK_SAMPLE_DMATC) {
689: retval += gus_dmain_intr(sc);
690: }
691: }
692: }
693: if (intr & (GUSMASK_IRQ_VOICE | GUSMASK_IRQ_VOLUME)) {
694: DMAPRINTF(("gusintr voice flags=%x\n", sc->sc_flags));
695: #ifdef AUDIO_DEBUG
696: gusvocintrcnt++;
697: #endif
698: retval += gus_voice_intr(sc);
699: }
700: if (retval)
701: return 1;
702: return retval;
703: }
704:
705: int gus_bufcnt[GUS_MEM_FOR_BUFFERS / GUS_BUFFER_MULTIPLE];
706: int gus_restart; /* how many restarts? */
707: int gus_stops; /* how many times did voice stop? */
708: int gus_falsestops; /* stopped but not done? */
709: int gus_continues;
710:
711: struct playcont {
712: struct timeval tv;
713: u_int playbuf;
714: u_int dmabuf;
715: u_char bufcnt;
716: u_char vaction;
717: u_char voccntl;
718: u_char volcntl;
719: u_long curaddr;
720: u_long endaddr;
721: } playstats[NDMARECS];
722:
723: int playcntr;
724:
725: void
726: gus_dmaout_timeout(arg)
727: void *arg;
728: {
729: struct gus_softc *sc = arg;
730: bus_space_tag_t iot = sc->sc_iot;
731: bus_space_handle_t ioh2 = sc->sc_ioh2;
732: int s;
733:
734: printf("%s: dmaout timeout\n", sc->sc_dev.dv_xname);
735: /*
736: * Stop any DMA.
737: */
738:
739: s = splgus();
740: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
741: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
742:
743: #if 0
744: /* XXX we will dmadone below? */
745: isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq);
746: #endif
747:
748: gus_dmaout_dointr(sc);
749: splx(s);
750: }
751:
752:
753: /*
754: * Service DMA interrupts. This routine will only get called if we're doing
755: * a DMA transfer for playback/record requests from the audio layer.
756: */
757:
758: int
759: gus_dmaout_intr(sc)
760: struct gus_softc *sc;
761: {
762: bus_space_tag_t iot = sc->sc_iot;
763: bus_space_handle_t ioh2 = sc->sc_ioh2;
764:
765: /*
766: * If we got a DMA transfer complete from the GUS DRAM, then deal
767: * with it.
768: */
769:
770: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
771: if (bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & GUSMASK_DMA_IRQPEND) {
772: timeout_del(&sc->sc_dma_tmo);
773: gus_dmaout_dointr(sc);
774: return 1;
775: }
776: return 0;
777: }
778:
779: void
780: gus_dmaout_dointr(sc)
781: struct gus_softc *sc;
782: {
783: bus_space_tag_t iot = sc->sc_iot;
784: bus_space_handle_t ioh2 = sc->sc_ioh2;
785:
786: /* sc->sc_dmaoutcnt - 1 because DMA controller counts from zero?. */
787: isa_dmadone(sc->sc_dev.dv_parent, sc->sc_drq);
788: sc->sc_flags &= ~GUS_DMAOUT_ACTIVE; /* pending DMA is done */
789: DMAPRINTF(("gus_dmaout_dointr %d @ %p\n", sc->sc_dmaoutcnt,
790: sc->sc_dmaoutaddr));
791:
792: /*
793: * to prevent clicking, we need to copy last sample
794: * from last buffer to scratch area just before beginning of
795: * buffer. However, if we're doing formats that are converted by
796: * the card during the DMA process, we need to pick up the converted
797: * byte rather than the one we have in memory.
798: */
799: if (sc->sc_dmabuf == sc->sc_nbufs - 1) {
800: int i;
801: switch (sc->sc_encoding) {
802: case AUDIO_ENCODING_SLINEAR_LE:
803: case AUDIO_ENCODING_SLINEAR_BE:
804: if (sc->sc_precision == 8)
805: goto byte;
806: /* we have the native format */
807: for (i = 1; i <= 2; i++)
808: guspoke(iot, ioh2, sc->sc_gusaddr -
809: (sc->sc_nbufs - 1) * sc->sc_chanblocksize - i,
810: sc->sc_dmaoutaddr[sc->sc_dmaoutcnt-i]);
811: break;
812: case AUDIO_ENCODING_ULINEAR_LE:
813: case AUDIO_ENCODING_ULINEAR_BE:
814: guspoke(iot, ioh2, sc->sc_gusaddr -
815: (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 2,
816: guspeek(iot, ioh2,
817: sc->sc_gusaddr + sc->sc_chanblocksize - 2));
818: case AUDIO_ENCODING_ALAW:
819: case AUDIO_ENCODING_ULAW:
820: byte:
821: /* we need to fetch the translated byte, then stuff it. */
822: guspoke(iot, ioh2, sc->sc_gusaddr -
823: (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 1,
824: guspeek(iot, ioh2,
825: sc->sc_gusaddr + sc->sc_chanblocksize - 1));
826: break;
827: }
828: }
829: /*
830: * If this is the first half of stereo, "ignore" this one
831: * and copy out the second half.
832: */
833: if (sc->sc_dmaoutintr == stereo_dmaintr) {
834: (*sc->sc_dmaoutintr)(sc->sc_outarg);
835: return;
836: }
837: /*
838: * If the voice is stopped, then start it. Reset the loop
839: * and roll bits. Call the audio layer routine, since if
840: * we're starting a stopped voice, that means that the next
841: * buffer can be filled
842: */
843:
844: sc->sc_flags &= ~GUS_LOCKED;
845: if (sc->sc_voc[GUS_VOICE_LEFT].voccntl &
846: GUSMASK_VOICE_STOPPED) {
847: if (sc->sc_flags & GUS_PLAYING) {
848: printf("%s: playing yet stopped?\n", sc->sc_dev.dv_xname);
849: }
850: sc->sc_bufcnt++; /* another yet to be played */
851: gus_start_playing(sc, sc->sc_dmabuf);
852: gus_restart++;
853: } else {
854: /*
855: * set the sound action based on which buffer we
856: * just transferred. If we just transferred buffer 0
857: * we want the sound to loop when it gets to the nth
858: * buffer; if we just transferred
859: * any other buffer, we want the sound to roll over
860: * at least one more time. The voice interrupt
861: * handlers will take care of accounting &
862: * setting control bits if it's not caught up to us
863: * yet.
864: */
865: if (++sc->sc_bufcnt == 2) {
866: /*
867: * XXX
868: * If we're too slow in reaction here,
869: * the voice could be just approaching the
870: * end of its run. It should be set to stop,
871: * so these adjustments might not DTRT.
872: */
873: if (sc->sc_dmabuf == 0 &&
874: sc->sc_playbuf == sc->sc_nbufs - 1) {
875: /* player is just at the last buf, we're at the
876: first. Turn on looping, turn off rolling. */
877: sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE;
878: sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~GUSMASK_VOICE_ROLL;
879: playstats[playcntr].vaction = 3;
880: } else {
881: /* player is at previous buf:
882: turn on rolling, turn off looping */
883: sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE;
884: sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL;
885: playstats[playcntr].vaction = 4;
886: }
887: #ifdef GUSPLAYDEBUG
888: if (gusstats) {
889: microtime(&playstats[playcntr].tv);
890: playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr;
891: playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl;
892: playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl;
893: playstats[playcntr].playbuf = sc->sc_playbuf;
894: playstats[playcntr].dmabuf = sc->sc_dmabuf;
895: playstats[playcntr].bufcnt = sc->sc_bufcnt;
896: playstats[playcntr++].curaddr = gus_get_curaddr(sc, GUS_VOICE_LEFT);
897: playcntr = playcntr % NDMARECS;
898: }
899: #endif
900: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT);
901: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
902: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl);
903: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
904: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl);
905: }
906: }
907: gus_bufcnt[sc->sc_bufcnt-1]++;
908: /*
909: * flip to the next DMA buffer
910: */
911:
912: sc->sc_dmabuf = ++sc->sc_dmabuf % sc->sc_nbufs;
913: /*
914: * See comments below about DMA admission control strategy.
915: * We can call the upper level here if we have an
916: * idle buffer (not currently playing) to DMA into.
917: */
918: if (sc->sc_dmaoutintr && sc->sc_bufcnt < sc->sc_nbufs) {
919: /* clean out to prevent double calls */
920: void (*pfunc)(void *) = sc->sc_dmaoutintr;
921: void *arg = sc->sc_outarg;
922:
923: sc->sc_outarg = 0;
924: sc->sc_dmaoutintr = 0;
925: (*pfunc)(arg);
926: }
927: }
928:
929: /*
930: * Service voice interrupts
931: */
932:
933: int
934: gus_voice_intr(sc)
935: struct gus_softc *sc;
936: {
937: bus_space_tag_t iot = sc->sc_iot;
938: bus_space_handle_t ioh2 = sc->sc_ioh2;
939: int ignore = 0, voice, rval = 0;
940: unsigned char intr, status;
941:
942: /*
943: * The point of this may not be obvious at first. A voice can
944: * interrupt more than once; according to the GUS SDK we are supposed
945: * to ignore multiple interrupts for the same voice.
946: */
947:
948: while(1) {
949: SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
950: intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
951:
952: if ((intr & (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE))
953: == (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE))
954: /*
955: * No more interrupts, time to return
956: */
957: return rval;
958:
959: if ((intr & GUSMASK_WIRQ_VOICE) == 0) {
960:
961: /*
962: * We've got a voice interrupt. Ignore previous
963: * interrupts by the same voice.
964: */
965:
966: rval = 1;
967: voice = intr & GUSMASK_WIRQ_VOICEMASK;
968:
969: if ((1 << voice) & ignore)
970: break;
971:
972: ignore |= 1 << voice;
973:
974: /*
975: * If the voice is stopped, then force it to stop
976: * (this stops it from continuously generating IRQs)
977: */
978:
979: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL+0x80);
980: status = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
981: if (status & GUSMASK_VOICE_STOPPED) {
982: if (voice != GUS_VOICE_LEFT) {
983: DMAPRINTF(("%s: spurious voice %d stop?\n",
984: sc->sc_dev.dv_xname, voice));
985: gus_stop_voice(sc, voice, 0);
986: continue;
987: }
988: gus_stop_voice(sc, voice, 1);
989: /* also kill right voice */
990: gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
991: sc->sc_bufcnt--; /* it finished a buffer */
992: if (sc->sc_bufcnt > 0) {
993: /*
994: * probably a race to get here: the voice
995: * stopped while the DMA code was just trying to
996: * get the next buffer in place.
997: * Start the voice again.
998: */
999: printf("%s: stopped voice not drained? (%x)\n",
1000: sc->sc_dev.dv_xname, sc->sc_bufcnt);
1001: gus_falsestops++;
1002:
1003: sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs;
1004: gus_start_playing(sc, sc->sc_playbuf);
1005: } else if (sc->sc_bufcnt < 0) {
1006: #ifdef DDB
1007: printf("%s: negative bufcnt in stopped voice\n",
1008: sc->sc_dev.dv_xname);
1009: Debugger();
1010: #else
1011: panic("%s: negative bufcnt in stopped voice",
1012: sc->sc_dev.dv_xname);
1013: #endif
1014: } else {
1015: sc->sc_playbuf = -1; /* none are active */
1016: gus_stops++;
1017: }
1018: /* fall through to callback and admit another
1019: buffer.... */
1020: } else if (sc->sc_bufcnt != 0) {
1021: /*
1022: * This should always be taken if the voice
1023: * is not stopped.
1024: */
1025: gus_continues++;
1026: if (gus_continue_playing(sc, voice)) {
1027: /*
1028: * we shouldn't have continued--active DMA
1029: * is in the way in the ring, for
1030: * some as-yet undebugged reason.
1031: */
1032: gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
1033: /* also kill right voice */
1034: gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
1035: sc->sc_playbuf = -1;
1036: gus_stops++;
1037: }
1038: }
1039: /*
1040: * call the upper level to send on down another
1041: * block. We do admission rate control as follows:
1042: *
1043: * When starting up output (in the first N
1044: * blocks), call the upper layer after the DMA is
1045: * complete (see above in gus_dmaout_intr()).
1046: *
1047: * When output is already in progress and we have
1048: * no more GUS buffers to use for DMA, the DMA
1049: * output routines do not call the upper layer.
1050: * Instead, we call the DMA completion routine
1051: * here, after the voice interrupts indicating
1052: * that it's finished with a buffer.
1053: *
1054: * However, don't call anything here if the DMA
1055: * output flag is set, (which shouldn't happen)
1056: * because we'll squish somebody else's DMA if
1057: * that's the case. When DMA is done, it will
1058: * call back if there is a spare buffer.
1059: */
1060: if (sc->sc_dmaoutintr && !(sc->sc_flags & GUS_LOCKED)) {
1061: if (sc->sc_dmaoutintr == stereo_dmaintr)
1062: printf("gusdmaout botch?\n");
1063: else {
1064: /* clean out to avoid double calls */
1065: void (*pfunc)(void *) = sc->sc_dmaoutintr;
1066: void *arg = sc->sc_outarg;
1067:
1068: sc->sc_outarg = 0;
1069: sc->sc_dmaoutintr = 0;
1070: (*pfunc)(arg);
1071: }
1072: }
1073: }
1074:
1075: /*
1076: * Ignore other interrupts for now
1077: */
1078: }
1079: return 0;
1080: }
1081:
1082: void
1083: gus_start_playing(sc, bufno)
1084: struct gus_softc *sc;
1085: int bufno;
1086: {
1087: bus_space_tag_t iot = sc->sc_iot;
1088: bus_space_handle_t ioh2 = sc->sc_ioh2;
1089: /*
1090: * Start the voices playing, with buffer BUFNO.
1091: */
1092:
1093: /*
1094: * Loop or roll if we have buffers ready.
1095: */
1096:
1097: if (sc->sc_bufcnt == 1) {
1098: sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~(GUSMASK_LOOP_ENABLE);
1099: sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL);
1100: } else {
1101: if (bufno == sc->sc_nbufs - 1) {
1102: sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE;
1103: sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL);
1104: } else {
1105: sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE;
1106: sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL;
1107: }
1108: }
1109:
1110: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT);
1111:
1112: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1113: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl);
1114:
1115: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
1116: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl);
1117:
1118: sc->sc_voc[GUS_VOICE_LEFT].current_addr =
1119: GUS_MEM_OFFSET + sc->sc_chanblocksize * bufno;
1120: sc->sc_voc[GUS_VOICE_LEFT].end_addr =
1121: sc->sc_voc[GUS_VOICE_LEFT].current_addr + sc->sc_chanblocksize - 1;
1122: sc->sc_voc[GUS_VOICE_RIGHT].current_addr =
1123: sc->sc_voc[GUS_VOICE_LEFT].current_addr +
1124: (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0);
1125: /*
1126: * set up right channel to just loop forever, no interrupts,
1127: * starting at the buffer we just filled. We'll feed it data
1128: * at the same time as left channel.
1129: */
1130: sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_LOOP_ENABLE;
1131: sc->sc_voc[GUS_VOICE_RIGHT].volcntl &= ~(GUSMASK_VOICE_ROLL);
1132:
1133: #ifdef GUSPLAYDEBUG
1134: if (gusstats) {
1135: microtime(&playstats[playcntr].tv);
1136: playstats[playcntr].curaddr = sc->sc_voc[GUS_VOICE_LEFT].current_addr;
1137:
1138: playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl;
1139: playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl;
1140: playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr;
1141: playstats[playcntr].playbuf = bufno;
1142: playstats[playcntr].dmabuf = sc->sc_dmabuf;
1143: playstats[playcntr].bufcnt = sc->sc_bufcnt;
1144: playstats[playcntr++].vaction = 5;
1145: playcntr = playcntr % NDMARECS;
1146: }
1147: #endif
1148:
1149: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_RIGHT);
1150: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1151: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].voccntl);
1152: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
1153: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].volcntl);
1154:
1155: gus_start_voice(sc, GUS_VOICE_RIGHT, 0);
1156: gus_start_voice(sc, GUS_VOICE_LEFT, 1);
1157: if (sc->sc_playbuf == -1)
1158: /* mark start of playing */
1159: sc->sc_playbuf = bufno;
1160: }
1161:
1162: int
1163: gus_continue_playing(sc, voice)
1164: struct gus_softc *sc;
1165: int voice;
1166: {
1167: bus_space_tag_t iot = sc->sc_iot;
1168: bus_space_handle_t ioh2 = sc->sc_ioh2;
1169:
1170: /*
1171: * stop this voice from interrupting while we work.
1172: */
1173:
1174: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1175: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl & ~(GUSMASK_VOICE_IRQ));
1176:
1177: /*
1178: * update playbuf to point to the buffer the hardware just started
1179: * playing
1180: */
1181: sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs;
1182:
1183: /*
1184: * account for buffer just finished
1185: */
1186: if (--sc->sc_bufcnt == 0) {
1187: DPRINTF(("gus: bufcnt 0 on continuing voice?\n"));
1188: }
1189: if (sc->sc_playbuf == sc->sc_dmabuf && (sc->sc_flags & GUS_LOCKED)) {
1190: printf("%s: continue into active dmabuf?\n", sc->sc_dev.dv_xname);
1191: return 1;
1192: }
1193:
1194: /*
1195: * Select the end of the buffer based on the currently active
1196: * buffer, [plus extra contiguous buffers (if ready)].
1197: */
1198:
1199: /*
1200: * set endpoint at end of buffer we just started playing.
1201: *
1202: * The total gets -1 because end addrs are one less than you might
1203: * think (the end_addr is the address of the last sample to play)
1204: */
1205: gus_set_endaddr(sc, voice, GUS_MEM_OFFSET +
1206: sc->sc_chanblocksize * (sc->sc_playbuf + 1) - 1);
1207:
1208: if (sc->sc_bufcnt < 2) {
1209: /*
1210: * Clear out the loop and roll flags, and rotate the currently
1211: * playing buffer. That way, if we don't manage to get more
1212: * data before this buffer finishes, we'll just stop.
1213: */
1214: sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE;
1215: sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL;
1216: playstats[playcntr].vaction = 0;
1217: } else {
1218: /*
1219: * We have some buffers to play. set LOOP if we're on the
1220: * last buffer in the ring, otherwise set ROLL.
1221: */
1222: if (sc->sc_playbuf == sc->sc_nbufs - 1) {
1223: sc->sc_voc[voice].voccntl |= GUSMASK_LOOP_ENABLE;
1224: sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL;
1225: playstats[playcntr].vaction = 1;
1226: } else {
1227: sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE;
1228: sc->sc_voc[voice].volcntl |= GUSMASK_VOICE_ROLL;
1229: playstats[playcntr].vaction = 2;
1230: }
1231: }
1232: #ifdef GUSPLAYDEBUG
1233: if (gusstats) {
1234: microtime(&playstats[playcntr].tv);
1235: playstats[playcntr].curaddr = gus_get_curaddr(sc, voice);
1236:
1237: playstats[playcntr].voccntl = sc->sc_voc[voice].voccntl;
1238: playstats[playcntr].volcntl = sc->sc_voc[voice].volcntl;
1239: playstats[playcntr].endaddr = sc->sc_voc[voice].end_addr;
1240: playstats[playcntr].playbuf = sc->sc_playbuf;
1241: playstats[playcntr].dmabuf = sc->sc_dmabuf;
1242: playstats[playcntr++].bufcnt = sc->sc_bufcnt;
1243: playcntr = playcntr % NDMARECS;
1244: }
1245: #endif
1246:
1247: /*
1248: * (re-)set voice parameters. This will reenable interrupts from this
1249: * voice.
1250: */
1251:
1252: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1253: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
1254: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
1255: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].volcntl);
1256: return 0;
1257: }
1258:
1259: /*
1260: * Send/receive data into GUS's DRAM using DMA. Called at splgus()
1261: */
1262:
1263: void
1264: gusdmaout(sc, flags, gusaddr, buffaddr, length)
1265: struct gus_softc *sc;
1266: int flags, length;
1267: u_long gusaddr;
1268: caddr_t buffaddr;
1269: {
1270: unsigned char c = (unsigned char) flags;
1271: bus_space_tag_t iot = sc->sc_iot;
1272: bus_space_handle_t ioh2 = sc->sc_ioh2;
1273:
1274: DMAPRINTF(("gusdmaout flags=%x scflags=%x\n", flags, sc->sc_flags));
1275:
1276: sc->sc_gusaddr = gusaddr;
1277:
1278: /*
1279: * If we're using a 16 bit DMA channel, we have to jump through some
1280: * extra hoops; this includes translating the DRAM address a bit
1281: */
1282:
1283: if (sc->sc_drq >= 4) {
1284: c |= GUSMASK_DMA_WIDTH;
1285: gusaddr = convert_to_16bit(gusaddr);
1286: }
1287:
1288: /*
1289: * Add flag bits that we always set - fast DMA, enable IRQ
1290: */
1291:
1292: c |= GUSMASK_DMA_ENABLE | GUSMASK_DMA_R0 | GUSMASK_DMA_IRQ;
1293:
1294: /*
1295: * Make sure the GUS _isn't_ setup for DMA
1296: */
1297:
1298: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
1299: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
1300:
1301: /*
1302: * Tell the PC DMA controller to start doing DMA
1303: */
1304:
1305: sc->sc_dmaoutaddr = (u_char *) buffaddr;
1306: sc->sc_dmaoutcnt = length;
1307: isa_dmastart(sc->sc_dev.dv_parent, sc->sc_drq, buffaddr, length,
1308: NULL, DMAMODE_WRITE, BUS_DMA_NOWAIT);
1309:
1310: /*
1311: * Set up DMA address - use the upper 16 bits ONLY
1312: */
1313:
1314: sc->sc_flags |= GUS_DMAOUT_ACTIVE;
1315:
1316: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_START);
1317: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (int) (gusaddr >> 4));
1318:
1319: /*
1320: * Tell the GUS to start doing DMA
1321: */
1322:
1323: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
1324: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, c);
1325:
1326: /*
1327: * XXX If we don't finish in one second, give up...
1328: */
1329: timeout_add(&sc->sc_dma_tmo, hz);
1330: }
1331:
1332: /*
1333: * Start a voice playing on the GUS. Called from interrupt handler at
1334: * splgus().
1335: */
1336:
1337: void
1338: gus_start_voice(sc, voice, intrs)
1339: struct gus_softc *sc;
1340: int voice;
1341: int intrs;
1342: {
1343: bus_space_tag_t iot = sc->sc_iot;
1344: bus_space_handle_t ioh2 = sc->sc_ioh2;
1345: u_long start;
1346: u_long current;
1347: u_long end;
1348:
1349: /*
1350: * Pick all the values for the voice out of the gus_voice struct
1351: * and use those to program the voice
1352: */
1353:
1354: start = sc->sc_voc[voice].start_addr;
1355: current = sc->sc_voc[voice].current_addr;
1356: end = sc->sc_voc[voice].end_addr;
1357:
1358: /*
1359: * If we're using 16 bit data, mangle the addresses a bit
1360: */
1361:
1362: if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) {
1363: /* -1 on start so that we get onto sample boundary--other
1364: code always sets it for 1-byte rollover protection */
1365: start = convert_to_16bit(start-1);
1366: current = convert_to_16bit(current);
1367: end = convert_to_16bit(end);
1368: }
1369:
1370: /*
1371: * Select the voice we want to use, and program the data addresses
1372: */
1373:
1374: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1375:
1376: SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH);
1377: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(start));
1378: SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW);
1379: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(start));
1380:
1381: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
1382: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(current));
1383: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
1384: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(current));
1385:
1386: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
1387: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(end));
1388: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
1389: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(end));
1390:
1391: /*
1392: * (maybe) enable interrupts, disable voice stopping
1393: */
1394:
1395: if (intrs) {
1396: sc->sc_flags |= GUS_PLAYING; /* playing is about to start */
1397: sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_IRQ;
1398: DMAPRINTF(("gus voice playing=%x\n", sc->sc_flags));
1399: } else
1400: sc->sc_voc[voice].voccntl &= ~GUSMASK_VOICE_IRQ;
1401: sc->sc_voc[voice].voccntl &= ~(GUSMASK_VOICE_STOPPED |
1402: GUSMASK_STOP_VOICE);
1403:
1404: /*
1405: * Tell the GUS about it. Note that we're doing volume ramping here
1406: * from 0 up to the set volume to help reduce clicks.
1407: */
1408:
1409: SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
1410: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
1411: SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
1412: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].current_volume >> 4);
1413: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
1414: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x00);
1415: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE);
1416: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 63);
1417:
1418: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1419: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
1420: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
1421: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
1422: delay(50);
1423: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1424: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
1425: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
1426: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
1427:
1428: }
1429:
1430: /*
1431: * Stop a given voice. called at splgus()
1432: */
1433:
1434: void
1435: gus_stop_voice(sc, voice, intrs_too)
1436: struct gus_softc *sc;
1437: int voice;
1438: int intrs_too;
1439: {
1440: bus_space_tag_t iot = sc->sc_iot;
1441: bus_space_handle_t ioh2 = sc->sc_ioh2;
1442:
1443: sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_STOPPED |
1444: GUSMASK_STOP_VOICE;
1445: if (intrs_too) {
1446: sc->sc_voc[voice].voccntl &= ~(GUSMASK_VOICE_IRQ);
1447: /* no more DMA to do */
1448: sc->sc_flags &= ~GUS_PLAYING;
1449: }
1450: DMAPRINTF(("gusintr voice notplaying=%x\n", sc->sc_flags));
1451:
1452: guspoke(iot, ioh2, 0L, 0);
1453:
1454: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1455:
1456: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
1457: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
1458: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1459: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
1460: delay(100);
1461: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
1462: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
1463: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
1464: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
1465:
1466: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
1467: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
1468: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
1469: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
1470:
1471: }
1472:
1473:
1474: /*
1475: * Set the volume of a given voice. Called at splgus().
1476: */
1477: void
1478: gus_set_volume(sc, voice, volume)
1479: struct gus_softc *sc;
1480: int voice, volume;
1481: {
1482: bus_space_tag_t iot = sc->sc_iot;
1483: bus_space_handle_t ioh2 = sc->sc_ioh2;
1484: unsigned int gusvol;
1485:
1486: gusvol = gus_log_volumes[volume < 512 ? volume : 511];
1487:
1488: sc->sc_voc[voice].current_volume = gusvol;
1489:
1490: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1491:
1492: SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
1493: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4));
1494:
1495: SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
1496: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4));
1497:
1498: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
1499: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4);
1500: delay(500);
1501: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4);
1502:
1503: }
1504:
1505: /*
1506: * Interface to the audio layer.
1507: */
1508:
1509: int
1510: gusmax_set_params(addr, setmode, usemode, p, r)
1511: void *addr;
1512: int setmode, usemode;
1513: struct audio_params *p, *r;
1514: {
1515: struct ad1848_softc *ac = addr;
1516: struct gus_softc *sc = ac->parent;
1517: int error;
1518:
1519: error = ad1848_set_params(ac, setmode, usemode, p, r);
1520: if (error)
1521: return error;
1522: error = gus_set_params(sc, setmode, usemode, p, r);
1523: return error;
1524: }
1525:
1526: int
1527: gus_set_params(addr, setmode, usemode, p, r)
1528: void *addr;
1529: int setmode, usemode;
1530: struct audio_params *p, *r;
1531: {
1532: struct gus_softc *sc = addr;
1533: int s;
1534:
1535: switch (p->encoding) {
1536: case AUDIO_ENCODING_ULAW:
1537: case AUDIO_ENCODING_ALAW:
1538: case AUDIO_ENCODING_SLINEAR_LE:
1539: case AUDIO_ENCODING_ULINEAR_LE:
1540: case AUDIO_ENCODING_SLINEAR_BE:
1541: case AUDIO_ENCODING_ULINEAR_BE:
1542: break;
1543: default:
1544: return (EINVAL);
1545: }
1546:
1547: s = splaudio();
1548:
1549: if (p->precision == 8) {
1550: sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_DATA_SIZE16;
1551: sc->sc_voc[GUS_VOICE_RIGHT].voccntl &= ~GUSMASK_DATA_SIZE16;
1552: } else {
1553: sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_DATA_SIZE16;
1554: sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16;
1555: }
1556:
1557: sc->sc_encoding = p->encoding;
1558: sc->sc_precision = p->precision;
1559: sc->sc_channels = p->channels;
1560:
1561: splx(s);
1562:
1563: if (p->sample_rate > gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES])
1564: p->sample_rate = gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES];
1565: if (setmode & AUMODE_RECORD)
1566: sc->sc_irate = p->sample_rate;
1567: if (setmode & AUMODE_PLAY)
1568: sc->sc_orate = p->sample_rate;
1569:
1570: switch (p->encoding) {
1571: case AUDIO_ENCODING_ULAW:
1572: p->sw_code = mulaw_to_ulinear8;
1573: r->sw_code = ulinear8_to_mulaw;
1574: break;
1575: case AUDIO_ENCODING_ALAW:
1576: p->sw_code = alaw_to_ulinear8;
1577: r->sw_code = ulinear8_to_alaw;
1578: break;
1579: case AUDIO_ENCODING_ULINEAR_BE:
1580: case AUDIO_ENCODING_SLINEAR_BE:
1581: r->sw_code = p->sw_code = swap_bytes;
1582: break;
1583: }
1584:
1585: return 0;
1586: }
1587:
1588: /*
1589: * Interface to the audio layer - set the blocksize to the correct number
1590: * of units
1591: */
1592:
1593: int
1594: gusmax_round_blocksize(addr, blocksize)
1595: void * addr;
1596: int blocksize;
1597: {
1598: struct ad1848_softc *ac = addr;
1599: struct gus_softc *sc = ac->parent;
1600:
1601: /* blocksize = ad1848_round_blocksize(ac, blocksize);*/
1602: return gus_round_blocksize(sc, blocksize);
1603: }
1604:
1605: int
1606: gus_round_blocksize(addr, blocksize)
1607: void * addr;
1608: int blocksize;
1609: {
1610: struct gus_softc *sc = addr;
1611:
1612: DPRINTF(("gus_round_blocksize called\n"));
1613:
1614: if ((sc->sc_encoding == AUDIO_ENCODING_ULAW ||
1615: sc->sc_encoding == AUDIO_ENCODING_ALAW) && blocksize > 32768)
1616: blocksize = 32768;
1617: else if (blocksize > 65536)
1618: blocksize = 65536;
1619:
1620: if ((blocksize % GUS_BUFFER_MULTIPLE) != 0)
1621: blocksize = (blocksize / GUS_BUFFER_MULTIPLE + 1) *
1622: GUS_BUFFER_MULTIPLE;
1623:
1624: /* set up temporary buffer to hold the deinterleave, if necessary
1625: for stereo output */
1626: if (sc->sc_deintr_buf) {
1627: free(sc->sc_deintr_buf, M_DEVBUF);
1628: sc->sc_deintr_buf = NULL;
1629: }
1630: sc->sc_deintr_buf = malloc(blocksize/2, M_DEVBUF, M_WAITOK);
1631:
1632: sc->sc_blocksize = blocksize;
1633: /* multi-buffering not quite working yet. */
1634: sc->sc_nbufs = /*GUS_MEM_FOR_BUFFERS / blocksize*/ 2;
1635:
1636: gus_set_chan_addrs(sc);
1637:
1638: return blocksize;
1639: }
1640:
1641: int
1642: gus_get_out_gain(addr)
1643: caddr_t addr;
1644: {
1645: struct gus_softc *sc = (struct gus_softc *) addr;
1646:
1647: DPRINTF(("gus_get_out_gain called\n"));
1648: return sc->sc_ogain / 2;
1649: }
1650:
1651: inline void gus_set_voices(sc, voices)
1652: struct gus_softc *sc;
1653: int voices;
1654: {
1655: bus_space_tag_t iot = sc->sc_iot;
1656: bus_space_handle_t ioh2 = sc->sc_ioh2;
1657: /*
1658: * Select the active number of voices
1659: */
1660:
1661: SELECT_GUS_REG(iot, ioh2, GUSREG_ACTIVE_VOICES);
1662: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (voices-1) | 0xc0);
1663:
1664: sc->sc_voices = voices;
1665: }
1666:
1667: /*
1668: * Actually set the settings of various values on the card
1669: */
1670:
1671: int
1672: gusmax_commit_settings(addr)
1673: void * addr;
1674: {
1675: struct ad1848_softc *ac = addr;
1676: struct gus_softc *sc = ac->parent;
1677: int error;
1678:
1679: error = ad1848_commit_settings(ac);
1680: if (error)
1681: return error;
1682: return gus_commit_settings(sc);
1683: }
1684:
1685: /*
1686: * Commit the settings. Called at normal IPL.
1687: */
1688: int
1689: gus_commit_settings(addr)
1690: void * addr;
1691: {
1692: struct gus_softc *sc = addr;
1693: int s;
1694:
1695: DPRINTF(("gus_commit_settings called (gain = %d)\n",sc->sc_ogain));
1696:
1697:
1698: s = splgus();
1699:
1700: gus_set_recrate(sc, sc->sc_irate);
1701: gus_set_volume(sc, GUS_VOICE_LEFT, sc->sc_ogain);
1702: gus_set_volume(sc, GUS_VOICE_RIGHT, sc->sc_ogain);
1703: gus_set_samprate(sc, GUS_VOICE_LEFT, sc->sc_orate);
1704: gus_set_samprate(sc, GUS_VOICE_RIGHT, sc->sc_orate);
1705: splx(s);
1706: gus_set_chan_addrs(sc);
1707:
1708: return 0;
1709: }
1710:
1711: void
1712: gus_set_chan_addrs(sc)
1713: struct gus_softc *sc;
1714: {
1715: /*
1716: * We use sc_nbufs * blocksize bytes of storage in the on-board GUS
1717: * ram.
1718: * For mono, each of the sc_nbufs buffers is DMA'd to in one chunk,
1719: * and both left & right channels play the same buffer.
1720: *
1721: * For stereo, each channel gets a contiguous half of the memory,
1722: * and each has sc_nbufs buffers of size blocksize/2.
1723: * Stereo data are deinterleaved in main memory before the DMA out
1724: * routines are called to queue the output.
1725: *
1726: * The blocksize per channel is kept in sc_chanblocksize.
1727: */
1728: if (sc->sc_channels == 2)
1729: sc->sc_chanblocksize = sc->sc_blocksize/2;
1730: else
1731: sc->sc_chanblocksize = sc->sc_blocksize;
1732:
1733: sc->sc_voc[GUS_VOICE_LEFT].start_addr = GUS_MEM_OFFSET - 1;
1734: sc->sc_voc[GUS_VOICE_RIGHT].start_addr =
1735: (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0)
1736: + GUS_MEM_OFFSET - 1;
1737: sc->sc_voc[GUS_VOICE_RIGHT].current_addr =
1738: sc->sc_voc[GUS_VOICE_RIGHT].start_addr + 1;
1739: sc->sc_voc[GUS_VOICE_RIGHT].end_addr =
1740: sc->sc_voc[GUS_VOICE_RIGHT].start_addr +
1741: sc->sc_nbufs * sc->sc_chanblocksize;
1742:
1743: }
1744:
1745: /*
1746: * Set the sample rate of the given voice. Called at splgus().
1747: */
1748:
1749: void
1750: gus_set_samprate(sc, voice, freq)
1751: struct gus_softc *sc;
1752: int voice, freq;
1753: {
1754: bus_space_tag_t iot = sc->sc_iot;
1755: bus_space_handle_t ioh2 = sc->sc_ioh2;
1756: unsigned int fc;
1757: u_long temp, f = (u_long) freq;
1758:
1759: /*
1760: * calculate fc based on the number of active voices;
1761: * we need to use longs to preserve enough bits
1762: */
1763:
1764: temp = (u_long) gus_max_frequency[sc->sc_voices-GUS_MIN_VOICES];
1765:
1766: fc = (unsigned int)(((f << 9L) + (temp >> 1L)) / temp);
1767:
1768: fc <<= 1;
1769:
1770:
1771: /*
1772: * Program the voice frequency, and set it in the voice data record
1773: */
1774:
1775: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1776: SELECT_GUS_REG(iot, ioh2, GUSREG_FREQ_CONTROL);
1777: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, fc);
1778:
1779: sc->sc_voc[voice].rate = freq;
1780:
1781: }
1782:
1783: /*
1784: * Set the sample rate of the recording frequency. Formula is from the GUS
1785: * SDK. Called at splgus().
1786: */
1787:
1788: void
1789: gus_set_recrate(sc, rate)
1790: struct gus_softc *sc;
1791: u_long rate;
1792: {
1793: bus_space_tag_t iot = sc->sc_iot;
1794: bus_space_handle_t ioh2 = sc->sc_ioh2;
1795: u_char realrate;
1796: DPRINTF(("gus_set_recrate %lu\n", rate));
1797:
1798: #if 0
1799: realrate = 9878400/(16*(rate+2)); /* formula from GUS docs */
1800: #endif
1801: realrate = (9878400 >> 4)/rate - 2; /* formula from code, sigh. */
1802:
1803: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_FREQ);
1804: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, realrate);
1805: }
1806:
1807: /*
1808: * Interface to the audio layer - turn the output on or off. Note that some
1809: * of these bits are flipped in the register
1810: */
1811:
1812: int
1813: gusmax_speaker_ctl(addr, newstate)
1814: void * addr;
1815: int newstate;
1816: {
1817: struct ad1848_softc *sc = addr;
1818: return gus_speaker_ctl(sc->parent, newstate);
1819: }
1820:
1821: int
1822: gus_speaker_ctl(addr, newstate)
1823: void * addr;
1824: int newstate;
1825: {
1826: struct gus_softc *sc = (struct gus_softc *) addr;
1827: bus_space_tag_t iot = sc->sc_iot;
1828: bus_space_handle_t ioh1 = sc->sc_ioh1;
1829:
1830: /* Line out bit is flipped: 0 enables, 1 disables */
1831: if ((newstate == SPKR_ON) &&
1832: (sc->sc_mixcontrol & GUSMASK_LINE_OUT)) {
1833: sc->sc_mixcontrol &= ~GUSMASK_LINE_OUT;
1834: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1835: }
1836: if ((newstate == SPKR_OFF) &&
1837: (sc->sc_mixcontrol & GUSMASK_LINE_OUT) == 0) {
1838: sc->sc_mixcontrol |= GUSMASK_LINE_OUT;
1839: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1840: }
1841:
1842: return 0;
1843: }
1844:
1845: int
1846: gus_linein_ctl(addr, newstate)
1847: void * addr;
1848: int newstate;
1849: {
1850: struct gus_softc *sc = (struct gus_softc *) addr;
1851: bus_space_tag_t iot = sc->sc_iot;
1852: bus_space_handle_t ioh1 = sc->sc_ioh1;
1853:
1854: /* Line in bit is flipped: 0 enables, 1 disables */
1855: if ((newstate == SPKR_ON) &&
1856: (sc->sc_mixcontrol & GUSMASK_LINE_IN)) {
1857: sc->sc_mixcontrol &= ~GUSMASK_LINE_IN;
1858: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1859: }
1860: if ((newstate == SPKR_OFF) &&
1861: (sc->sc_mixcontrol & GUSMASK_LINE_IN) == 0) {
1862: sc->sc_mixcontrol |= GUSMASK_LINE_IN;
1863: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1864: }
1865:
1866: return 0;
1867: }
1868:
1869: int
1870: gus_mic_ctl(addr, newstate)
1871: void * addr;
1872: int newstate;
1873: {
1874: struct gus_softc *sc = (struct gus_softc *) addr;
1875: bus_space_tag_t iot = sc->sc_iot;
1876: bus_space_handle_t ioh1 = sc->sc_ioh1;
1877:
1878: /* Mic bit is normal: 1 enables, 0 disables */
1879: if ((newstate == SPKR_ON) &&
1880: (sc->sc_mixcontrol & GUSMASK_MIC_IN) == 0) {
1881: sc->sc_mixcontrol |= GUSMASK_MIC_IN;
1882: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1883: }
1884: if ((newstate == SPKR_OFF) &&
1885: (sc->sc_mixcontrol & GUSMASK_MIC_IN)) {
1886: sc->sc_mixcontrol &= ~GUSMASK_MIC_IN;
1887: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
1888: }
1889:
1890: return 0;
1891: }
1892:
1893: /*
1894: * Set the end address of a give voice. Called at splgus()
1895: */
1896:
1897: void
1898: gus_set_endaddr(sc, voice, addr)
1899: struct gus_softc *sc;
1900: int voice;
1901: u_long addr;
1902: {
1903: bus_space_tag_t iot = sc->sc_iot;
1904: bus_space_handle_t ioh2 = sc->sc_ioh2;
1905:
1906: sc->sc_voc[voice].end_addr = addr;
1907:
1908: if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
1909: addr = convert_to_16bit(addr);
1910:
1911: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
1912: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr));
1913: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
1914: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr));
1915:
1916: }
1917:
1918: #ifdef GUSPLAYDEBUG
1919: /*
1920: * Set current address. called at splgus()
1921: */
1922: void
1923: gus_set_curaddr(sc, voice, addr)
1924: struct gus_softc *sc;
1925: int voice;
1926: u_long addr;
1927: {
1928: bus_space_tag_t iot = sc->sc_iot;
1929: bus_space_handle_t ioh2 = sc->sc_ioh2;
1930:
1931: sc->sc_voc[voice].current_addr = addr;
1932:
1933: if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
1934: addr = convert_to_16bit(addr);
1935:
1936: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1937:
1938: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
1939: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr));
1940: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
1941: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr));
1942:
1943: }
1944:
1945: /*
1946: * Get current GUS playback address. Called at splgus().
1947: */
1948: u_long
1949: gus_get_curaddr(sc, voice)
1950: struct gus_softc *sc;
1951: int voice;
1952: {
1953: bus_space_tag_t iot = sc->sc_iot;
1954: bus_space_handle_t ioh2 = sc->sc_ioh2;
1955: u_long addr;
1956:
1957: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
1958: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH|GUSREG_READ);
1959: addr = (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) & 0x1fff) << 7;
1960: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW|GUSREG_READ);
1961: addr |= (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) >> 9L) & 0x7f;
1962:
1963: if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
1964: addr = (addr & 0xc0000) | ((addr & 0x1ffff) << 1); /* undo 16-bit change */
1965: DPRINTF(("gus voice %d curaddr %ld end_addr %ld\n",
1966: voice, addr, sc->sc_voc[voice].end_addr));
1967: /* XXX sanity check the address? */
1968:
1969: return(addr);
1970: }
1971: #endif
1972:
1973: /*
1974: * Convert an address value to a "16 bit" value - why this is necessary I
1975: * have NO idea
1976: */
1977:
1978: u_long
1979: convert_to_16bit(address)
1980: u_long address;
1981: {
1982: u_long old_address;
1983:
1984: old_address = address;
1985: address >>= 1;
1986: address &= 0x0001ffffL;
1987: address |= (old_address & 0x000c0000L);
1988:
1989: return (address);
1990: }
1991:
1992: /*
1993: * Write a value into the GUS's DRAM
1994: */
1995:
1996: void
1997: guspoke(iot, ioh2, address, value)
1998: bus_space_tag_t iot;
1999: bus_space_handle_t ioh2;
2000: long address;
2001: unsigned char value;
2002: {
2003:
2004: /*
2005: * Select the DRAM address
2006: */
2007:
2008: SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW);
2009: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff));
2010: SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH);
2011: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff));
2012:
2013: /*
2014: * Actually write the data
2015: */
2016:
2017: bus_space_write_1(iot, ioh2, GUS_DRAM_DATA, value);
2018: }
2019:
2020: /*
2021: * Read a value from the GUS's DRAM
2022: */
2023:
2024: unsigned char
2025: guspeek(iot, ioh2, address)
2026: bus_space_tag_t iot;
2027: bus_space_handle_t ioh2;
2028: u_long address;
2029: {
2030:
2031: /*
2032: * Select the DRAM address
2033: */
2034:
2035: SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW);
2036: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff));
2037: SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH);
2038: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff));
2039:
2040: /*
2041: * Read in the data from the board
2042: */
2043:
2044: return (unsigned char) bus_space_read_1(iot, ioh2, GUS_DRAM_DATA);
2045: }
2046:
2047: /*
2048: * Reset the Gravis UltraSound card, completely
2049: */
2050:
2051: void
2052: gusreset(sc, voices)
2053: struct gus_softc *sc;
2054: int voices;
2055: {
2056: bus_space_tag_t iot = sc->sc_iot;
2057: bus_space_handle_t ioh1 = sc->sc_ioh1;
2058: bus_space_handle_t ioh2 = sc->sc_ioh2;
2059: bus_space_handle_t ioh4 = sc->sc_ioh4;
2060: int i,s;
2061:
2062: s = splgus();
2063:
2064: /*
2065: * Reset the GF1 chip
2066: */
2067:
2068: SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
2069: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
2070:
2071: delay(500);
2072:
2073: /*
2074: * Release reset
2075: */
2076:
2077: SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
2078: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET);
2079:
2080: delay(500);
2081:
2082: /*
2083: * Reset MIDI port as well
2084: */
2085:
2086: bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, MIDI_RESET);
2087:
2088: delay(500);
2089:
2090: bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, 0x00);
2091:
2092: /*
2093: * Clear interrupts
2094: */
2095:
2096: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
2097: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
2098: SELECT_GUS_REG(iot, ioh2, GUSREG_TIMER_CONTROL);
2099: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
2100: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
2101: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
2102:
2103: gus_set_voices(sc, voices);
2104:
2105: bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS);
2106: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
2107: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2108: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
2109: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2110: SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
2111: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2112:
2113: /*
2114: * Reset voice specific information
2115: */
2116:
2117: for(i = 0; i < voices; i++) {
2118: bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) i);
2119:
2120: SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
2121:
2122: sc->sc_voc[i].voccntl = GUSMASK_VOICE_STOPPED |
2123: GUSMASK_STOP_VOICE;
2124:
2125: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].voccntl);
2126:
2127: sc->sc_voc[i].volcntl = GUSMASK_VOLUME_STOPPED |
2128: GUSMASK_STOP_VOLUME;
2129:
2130: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
2131: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].volcntl);
2132:
2133: delay(100);
2134:
2135: gus_set_samprate(sc, i, 8000);
2136: SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH);
2137: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2138: SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW);
2139: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2140: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
2141: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2142: SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
2143: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2144: SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE);
2145: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x01);
2146: SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
2147: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x10);
2148: SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
2149: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0xe0);
2150: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
2151: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2152:
2153: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
2154: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2155: SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
2156: bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
2157: SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS);
2158: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x07);
2159: }
2160:
2161: /*
2162: * Clear out any pending IRQs
2163: */
2164:
2165: bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS);
2166: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
2167: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2168: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
2169: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2170: SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
2171: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
2172:
2173: SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
2174: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET | GUSMASK_DAC_ENABLE |
2175: GUSMASK_IRQ_ENABLE);
2176:
2177: splx(s);
2178: }
2179:
2180:
2181: int
2182: gus_init_cs4231(sc)
2183: struct gus_softc *sc;
2184: {
2185: bus_space_tag_t iot = sc->sc_iot;
2186: bus_space_handle_t ioh1 = sc->sc_ioh1;
2187: int port = sc->sc_iobase;
2188: u_char ctrl;
2189:
2190: ctrl = (port & 0xf0) >> 4; /* set port address middle nibble */
2191: /*
2192: * The codec is a bit weird--swapped dma channels.
2193: */
2194: ctrl |= GUS_MAX_CODEC_ENABLE;
2195: if (sc->sc_drq >= 4)
2196: ctrl |= GUS_MAX_RECCHAN16;
2197: if (sc->sc_recdrq >= 4)
2198: ctrl |= GUS_MAX_PLAYCHAN16;
2199:
2200: bus_space_write_1(iot, ioh1, GUS_MAX_CTRL, ctrl);
2201:
2202: sc->sc_codec.sc_iot = sc->sc_iot;
2203: sc->sc_codec.sc_iobase = port+GUS_MAX_CODEC_BASE;
2204:
2205: if (ad1848_mapprobe(&sc->sc_codec, sc->sc_codec.sc_iobase) == 0) {
2206: sc->sc_flags &= ~GUS_CODEC_INSTALLED;
2207: return (0);
2208: } else {
2209: struct ad1848_volume vol = {AUDIO_MAX_GAIN, AUDIO_MAX_GAIN};
2210: sc->sc_flags |= GUS_CODEC_INSTALLED;
2211: sc->sc_codec.parent = sc;
2212: sc->sc_codec.sc_drq = sc->sc_recdrq;
2213: sc->sc_codec.sc_recdrq = sc->sc_drq;
2214: gus_hw_if = gusmax_hw_if;
2215: /* enable line in and mic in the GUS mixer; the codec chip
2216: will do the real mixing for them. */
2217: sc->sc_mixcontrol &= ~GUSMASK_LINE_IN; /* 0 enables. */
2218: sc->sc_mixcontrol |= GUSMASK_MIC_IN; /* 1 enables. */
2219: bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
2220:
2221: ad1848_attach(&sc->sc_codec);
2222: /* turn on pre-MUX microphone gain. */
2223: ad1848_set_mic_gain(&sc->sc_codec, &vol);
2224:
2225: return (1);
2226: }
2227: }
2228:
2229:
2230: /*
2231: * Return info about the audio device, for the AUDIO_GETINFO ioctl
2232: */
2233:
2234: int
2235: gus_getdev(addr, dev)
2236: void * addr;
2237: struct audio_device *dev;
2238: {
2239: *dev = gus_device;
2240: return 0;
2241: }
2242:
2243: /*
2244: * stubs (XXX)
2245: */
2246:
2247: int
2248: gus_set_in_gain(addr, gain, balance)
2249: caddr_t addr;
2250: u_int gain;
2251: u_char balance;
2252: {
2253: DPRINTF(("gus_set_in_gain called\n"));
2254: return 0;
2255: }
2256:
2257: int
2258: gus_get_in_gain(addr)
2259: caddr_t addr;
2260: {
2261: DPRINTF(("gus_get_in_gain called\n"));
2262: return 0;
2263: }
2264:
2265: int
2266: gusmax_dma_input(addr, buf, size, callback, arg)
2267: void * addr;
2268: void *buf;
2269: int size;
2270: void (*callback)(void *);
2271: void *arg;
2272: {
2273: struct ad1848_softc *sc = addr;
2274: return gus_dma_input(sc->parent, buf, size, callback, arg);
2275: }
2276:
2277: /*
2278: * Start sampling the input source into the requested DMA buffer.
2279: * Called at splgus(), either from top-half or from interrupt handler.
2280: */
2281: int
2282: gus_dma_input(addr, buf, size, callback, arg)
2283: void * addr;
2284: void *buf;
2285: int size;
2286: void (*callback)(void *);
2287: void *arg;
2288: {
2289: struct gus_softc *sc = addr;
2290: bus_space_tag_t iot = sc->sc_iot;
2291: bus_space_handle_t ioh2 = sc->sc_ioh2;
2292: u_char dmac;
2293: DMAPRINTF(("gus_dma_input called\n"));
2294:
2295: /*
2296: * Sample SIZE bytes of data from the card, into buffer at BUF.
2297: */
2298:
2299: if (sc->sc_precision == 16)
2300: return EINVAL; /* XXX */
2301:
2302: /* set DMA modes */
2303: dmac = GUSMASK_SAMPLE_IRQ|GUSMASK_SAMPLE_START;
2304: if (sc->sc_recdrq >= 4)
2305: dmac |= GUSMASK_SAMPLE_DATA16;
2306: if (sc->sc_encoding == AUDIO_ENCODING_ULAW ||
2307: sc->sc_encoding == AUDIO_ENCODING_ALAW ||
2308: sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE ||
2309: sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE)
2310: dmac |= GUSMASK_SAMPLE_INVBIT;
2311: if (sc->sc_channels == 2)
2312: dmac |= GUSMASK_SAMPLE_STEREO;
2313: isa_dmastart(sc->sc_dev.dv_parent, sc->sc_recdrq, buf, size,
2314: NULL, DMAMODE_READ, BUS_DMA_NOWAIT);
2315:
2316: DMAPRINTF(("gus_dma_input isadma_started\n"));
2317: sc->sc_flags |= GUS_DMAIN_ACTIVE;
2318: sc->sc_dmainintr = callback;
2319: sc->sc_inarg = arg;
2320: sc->sc_dmaincnt = size;
2321: sc->sc_dmainaddr = buf;
2322:
2323: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
2324: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, dmac); /* Go! */
2325:
2326:
2327: DMAPRINTF(("gus_dma_input returning\n"));
2328:
2329: return 0;
2330: }
2331:
2332: int
2333: gus_dmain_intr(sc)
2334: struct gus_softc *sc;
2335: {
2336: void (*callback)(void *);
2337: void *arg;
2338:
2339: DMAPRINTF(("gus_dmain_intr called\n"));
2340: if (sc->sc_dmainintr) {
2341: isa_dmadone(sc->sc_dev.dv_parent, sc->sc_recdrq);
2342: callback = sc->sc_dmainintr;
2343: arg = sc->sc_inarg;
2344:
2345: sc->sc_dmainaddr = 0;
2346: sc->sc_dmaincnt = 0;
2347: sc->sc_dmainintr = 0;
2348: sc->sc_inarg = 0;
2349:
2350: sc->sc_flags &= ~GUS_DMAIN_ACTIVE;
2351: DMAPRINTF(("calling dmain_intr callback %p(%p)\n", callback, arg));
2352: (*callback)(arg);
2353: return 1;
2354: } else {
2355: DMAPRINTF(("gus_dmain_intr false?\n"));
2356: return 0; /* XXX ??? */
2357: }
2358: }
2359:
2360: int
2361: gusmax_halt_out_dma(addr)
2362: void * addr;
2363: {
2364: struct ad1848_softc *sc = addr;
2365: return gus_halt_out_dma(sc->parent);
2366: }
2367:
2368:
2369: int
2370: gusmax_halt_in_dma(addr)
2371: void * addr;
2372: {
2373: struct ad1848_softc *sc = addr;
2374: return gus_halt_in_dma(sc->parent);
2375: }
2376:
2377: /*
2378: * Stop any DMA output. Called at splgus().
2379: */
2380: int
2381: gus_halt_out_dma(addr)
2382: void * addr;
2383: {
2384: struct gus_softc *sc = addr;
2385: bus_space_tag_t iot = sc->sc_iot;
2386: bus_space_handle_t ioh2 = sc->sc_ioh2;
2387:
2388: DMAPRINTF(("gus_halt_out_dma called\n"));
2389: /*
2390: * Make sure the GUS _isn't_ setup for DMA
2391: */
2392:
2393: SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
2394: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
2395:
2396: timeout_del(&sc->sc_dma_tmo);
2397: isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq);
2398: sc->sc_flags &= ~(GUS_DMAOUT_ACTIVE|GUS_LOCKED);
2399: sc->sc_dmaoutintr = 0;
2400: sc->sc_outarg = 0;
2401: sc->sc_dmaoutaddr = 0;
2402: sc->sc_dmaoutcnt = 0;
2403: sc->sc_dmabuf = 0;
2404: sc->sc_bufcnt = 0;
2405: sc->sc_playbuf = -1;
2406: /* also stop playing */
2407: gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
2408: gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
2409:
2410: return 0;
2411: }
2412:
2413: /*
2414: * Stop any DMA output. Called at splgus().
2415: */
2416: int
2417: gus_halt_in_dma(addr)
2418: void * addr;
2419: {
2420: struct gus_softc *sc = addr;
2421: bus_space_tag_t iot = sc->sc_iot;
2422: bus_space_handle_t ioh2 = sc->sc_ioh2;
2423: DMAPRINTF(("gus_halt_in_dma called\n"));
2424:
2425: /*
2426: * Make sure the GUS _isn't_ setup for DMA
2427: */
2428:
2429: SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
2430: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH,
2431: bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & ~(GUSMASK_SAMPLE_START|GUSMASK_SAMPLE_IRQ));
2432:
2433: isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_recdrq);
2434: sc->sc_flags &= ~GUS_DMAIN_ACTIVE;
2435: sc->sc_dmainintr = 0;
2436: sc->sc_inarg = 0;
2437: sc->sc_dmainaddr = 0;
2438: sc->sc_dmaincnt = 0;
2439:
2440: return 0;
2441: }
2442:
2443:
2444: ad1848_devmap_t gusmapping[] = {
2445: {GUSMAX_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL},
2446: {GUSMAX_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL},
2447: {GUSMAX_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL},
2448: {GUSMAX_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL},
2449: {GUSMAX_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL},
2450: {GUSMAX_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL},
2451: {GUSMAX_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL},
2452: {GUSMAX_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL},
2453: {GUSMAX_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL},
2454: {GUSMAX_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL},
2455: {GUSMAX_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL},
2456: {GUSMAX_REC_LVL, AD1848_KIND_RECORDGAIN, -1},
2457: {GUSMAX_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
2458: };
2459:
2460: int nummap = sizeof(gusmapping) / sizeof(gusmapping[0]);
2461:
2462: int
2463: gusmax_mixer_get_port(addr, cp)
2464: void *addr;
2465: mixer_ctrl_t *cp;
2466: {
2467: struct ad1848_softc *ac = addr;
2468: struct gus_softc *sc = ac->parent;
2469: struct ad1848_volume vol;
2470: int error = ad1848_mixer_get_port(ac, gusmapping, nummap, cp);
2471:
2472: if (error != ENXIO)
2473: return (error);
2474:
2475: error = EINVAL;
2476:
2477: switch (cp->dev) {
2478: case GUSMAX_SPEAKER_LVL: /* fake speaker for mute naming */
2479: if (cp->type == AUDIO_MIXER_VALUE) {
2480: if (sc->sc_mixcontrol & GUSMASK_LINE_OUT)
2481: vol.left = vol.right = AUDIO_MAX_GAIN;
2482: else
2483: vol.left = vol.right = AUDIO_MIN_GAIN;
2484: error = 0;
2485: ad1848_from_vol(cp, &vol);
2486: }
2487: break;
2488:
2489: case GUSMAX_SPEAKER_MUTE:
2490: if (cp->type == AUDIO_MIXER_ENUM) {
2491: cp->un.ord = sc->sc_mixcontrol & GUSMASK_LINE_OUT ? 1 : 0;
2492: error = 0;
2493: }
2494: break;
2495: default:
2496: error = ENXIO;
2497: break;
2498: }
2499:
2500: return(error);
2501: }
2502:
2503: int
2504: gus_mixer_get_port(addr, cp)
2505: void *addr;
2506: mixer_ctrl_t *cp;
2507: {
2508: struct gus_softc *sc = addr;
2509: struct ics2101_softc *ic = &sc->sc_mixer;
2510: struct ad1848_volume vol;
2511: int error = EINVAL;
2512:
2513: DPRINTF(("gus_mixer_get_port: dev=%d type=%d\n", cp->dev, cp->type));
2514:
2515: if (!HAS_MIXER(sc) && cp->dev > GUSICS_MASTER_MUTE)
2516: return ENXIO;
2517:
2518: switch (cp->dev) {
2519:
2520: case GUSICS_MIC_IN_MUTE: /* Microphone */
2521: if (cp->type == AUDIO_MIXER_ENUM) {
2522: if (HAS_MIXER(sc))
2523: cp->un.ord = ic->sc_mute[GUSMIX_CHAN_MIC][ICSMIX_LEFT];
2524: else
2525: cp->un.ord =
2526: sc->sc_mixcontrol & GUSMASK_MIC_IN ? 0 : 1;
2527: error = 0;
2528: }
2529: break;
2530:
2531: case GUSICS_LINE_IN_MUTE:
2532: if (cp->type == AUDIO_MIXER_ENUM) {
2533: if (HAS_MIXER(sc))
2534: cp->un.ord = ic->sc_mute[GUSMIX_CHAN_LINE][ICSMIX_LEFT];
2535: else
2536: cp->un.ord =
2537: sc->sc_mixcontrol & GUSMASK_LINE_IN ? 1 : 0;
2538: error = 0;
2539: }
2540: break;
2541:
2542: case GUSICS_MASTER_MUTE:
2543: if (cp->type == AUDIO_MIXER_ENUM) {
2544: if (HAS_MIXER(sc))
2545: cp->un.ord = ic->sc_mute[GUSMIX_CHAN_MASTER][ICSMIX_LEFT];
2546: else
2547: cp->un.ord =
2548: sc->sc_mixcontrol & GUSMASK_LINE_OUT ? 1 : 0;
2549: error = 0;
2550: }
2551: break;
2552:
2553: case GUSICS_DAC_MUTE:
2554: if (cp->type == AUDIO_MIXER_ENUM) {
2555: cp->un.ord = ic->sc_mute[GUSMIX_CHAN_DAC][ICSMIX_LEFT];
2556: error = 0;
2557: }
2558: break;
2559:
2560: case GUSICS_CD_MUTE:
2561: if (cp->type == AUDIO_MIXER_ENUM) {
2562: cp->un.ord = ic->sc_mute[GUSMIX_CHAN_CD][ICSMIX_LEFT];
2563: error = 0;
2564: }
2565: break;
2566:
2567: case GUSICS_MASTER_LVL:
2568: if (cp->type == AUDIO_MIXER_VALUE) {
2569: vol.left = ic->sc_setting[GUSMIX_CHAN_MASTER][ICSMIX_LEFT];
2570: vol.right = ic->sc_setting[GUSMIX_CHAN_MASTER][ICSMIX_RIGHT];
2571: if (ad1848_from_vol(cp, &vol))
2572: error = 0;
2573: }
2574: break;
2575:
2576: case GUSICS_MIC_IN_LVL: /* Microphone */
2577: if (cp->type == AUDIO_MIXER_VALUE) {
2578: vol.left = ic->sc_setting[GUSMIX_CHAN_MIC][ICSMIX_LEFT];
2579: vol.right = ic->sc_setting[GUSMIX_CHAN_MIC][ICSMIX_RIGHT];
2580: if (ad1848_from_vol(cp, &vol))
2581: error = 0;
2582: }
2583: break;
2584:
2585: case GUSICS_LINE_IN_LVL: /* line in */
2586: if (cp->type == AUDIO_MIXER_VALUE) {
2587: vol.left = ic->sc_setting[GUSMIX_CHAN_LINE][ICSMIX_LEFT];
2588: vol.right = ic->sc_setting[GUSMIX_CHAN_LINE][ICSMIX_RIGHT];
2589: if (ad1848_from_vol(cp, &vol))
2590: error = 0;
2591: }
2592: break;
2593:
2594:
2595: case GUSICS_CD_LVL:
2596: if (cp->type == AUDIO_MIXER_VALUE) {
2597: vol.left = ic->sc_setting[GUSMIX_CHAN_CD][ICSMIX_LEFT];
2598: vol.right = ic->sc_setting[GUSMIX_CHAN_CD][ICSMIX_RIGHT];
2599: if (ad1848_from_vol(cp, &vol))
2600: error = 0;
2601: }
2602: break;
2603:
2604: case GUSICS_DAC_LVL: /* dac out */
2605: if (cp->type == AUDIO_MIXER_VALUE) {
2606: vol.left = ic->sc_setting[GUSMIX_CHAN_DAC][ICSMIX_LEFT];
2607: vol.right = ic->sc_setting[GUSMIX_CHAN_DAC][ICSMIX_RIGHT];
2608: if (ad1848_from_vol(cp, &vol))
2609: error = 0;
2610: }
2611: break;
2612:
2613:
2614: case GUSICS_RECORD_SOURCE:
2615: if (cp->type == AUDIO_MIXER_ENUM) {
2616: /* Can't set anything else useful, sigh. */
2617: cp->un.ord = 0;
2618: }
2619: break;
2620:
2621: default:
2622: return ENXIO;
2623: /*NOTREACHED*/
2624: }
2625: return error;
2626: }
2627:
2628: void
2629: gusics_master_mute(ic, mute)
2630: struct ics2101_softc *ic;
2631: int mute;
2632: {
2633: ics2101_mix_mute(ic, GUSMIX_CHAN_MASTER, ICSMIX_LEFT, mute);
2634: ics2101_mix_mute(ic, GUSMIX_CHAN_MASTER, ICSMIX_RIGHT, mute);
2635: }
2636:
2637: void
2638: gusics_mic_mute(ic, mute)
2639: struct ics2101_softc *ic;
2640: int mute;
2641: {
2642: ics2101_mix_mute(ic, GUSMIX_CHAN_MIC, ICSMIX_LEFT, mute);
2643: ics2101_mix_mute(ic, GUSMIX_CHAN_MIC, ICSMIX_RIGHT, mute);
2644: }
2645:
2646: void
2647: gusics_linein_mute(ic, mute)
2648: struct ics2101_softc *ic;
2649: int mute;
2650: {
2651: ics2101_mix_mute(ic, GUSMIX_CHAN_LINE, ICSMIX_LEFT, mute);
2652: ics2101_mix_mute(ic, GUSMIX_CHAN_LINE, ICSMIX_RIGHT, mute);
2653: }
2654:
2655: void
2656: gusics_cd_mute(ic, mute)
2657: struct ics2101_softc *ic;
2658: int mute;
2659: {
2660: ics2101_mix_mute(ic, GUSMIX_CHAN_CD, ICSMIX_LEFT, mute);
2661: ics2101_mix_mute(ic, GUSMIX_CHAN_CD, ICSMIX_RIGHT, mute);
2662: }
2663:
2664: void
2665: gusics_dac_mute(ic, mute)
2666: struct ics2101_softc *ic;
2667: int mute;
2668: {
2669: ics2101_mix_mute(ic, GUSMIX_CHAN_DAC, ICSMIX_LEFT, mute);
2670: ics2101_mix_mute(ic, GUSMIX_CHAN_DAC, ICSMIX_RIGHT, mute);
2671: }
2672:
2673: int
2674: gusmax_mixer_set_port(addr, cp)
2675: void *addr;
2676: mixer_ctrl_t *cp;
2677: {
2678: struct ad1848_softc *ac = addr;
2679: struct gus_softc *sc = ac->parent;
2680: struct ad1848_volume vol;
2681: int error = ad1848_mixer_set_port(ac, gusmapping, nummap, cp);
2682:
2683: if (error != ENXIO)
2684: return (error);
2685:
2686: DPRINTF(("gusmax_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
2687:
2688: switch (cp->dev) {
2689: case GUSMAX_SPEAKER_LVL:
2690: if (cp->type == AUDIO_MIXER_VALUE &&
2691: cp->un.value.num_channels == 1) {
2692: if (ad1848_to_vol(cp, &vol)) {
2693: gus_speaker_ctl(sc, vol.left > AUDIO_MIN_GAIN ?
2694: SPKR_ON : SPKR_OFF);
2695: error = 0;
2696: }
2697: }
2698: break;
2699:
2700: case GUSMAX_SPEAKER_MUTE:
2701: if (cp->type == AUDIO_MIXER_ENUM) {
2702: gus_speaker_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
2703: error = 0;
2704: }
2705: break;
2706:
2707: default:
2708: return ENXIO;
2709: /*NOTREACHED*/
2710: }
2711: return error;
2712: }
2713:
2714: int
2715: gus_mixer_set_port(addr, cp)
2716: void *addr;
2717: mixer_ctrl_t *cp;
2718: {
2719: struct gus_softc *sc = addr;
2720: struct ics2101_softc *ic = &sc->sc_mixer;
2721: struct ad1848_volume vol;
2722: int error = EINVAL;
2723:
2724: DPRINTF(("gus_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
2725:
2726: if (!HAS_MIXER(sc) && cp->dev > GUSICS_MASTER_MUTE)
2727: return ENXIO;
2728:
2729: switch (cp->dev) {
2730:
2731: case GUSICS_MIC_IN_MUTE: /* Microphone */
2732: if (cp->type == AUDIO_MIXER_ENUM) {
2733: DPRINTF(("mic mute %d\n", cp->un.ord));
2734: if (HAS_MIXER(sc)) {
2735: gusics_mic_mute(ic, cp->un.ord);
2736: }
2737: gus_mic_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
2738: error = 0;
2739: }
2740: break;
2741:
2742: case GUSICS_LINE_IN_MUTE:
2743: if (cp->type == AUDIO_MIXER_ENUM) {
2744: DPRINTF(("linein mute %d\n", cp->un.ord));
2745: if (HAS_MIXER(sc)) {
2746: gusics_linein_mute(ic, cp->un.ord);
2747: }
2748: gus_linein_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
2749: error = 0;
2750: }
2751: break;
2752:
2753: case GUSICS_MASTER_MUTE:
2754: if (cp->type == AUDIO_MIXER_ENUM) {
2755: DPRINTF(("master mute %d\n", cp->un.ord));
2756: if (HAS_MIXER(sc)) {
2757: gusics_master_mute(ic, cp->un.ord);
2758: }
2759: gus_speaker_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
2760: error = 0;
2761: }
2762: break;
2763:
2764: case GUSICS_DAC_MUTE:
2765: if (cp->type == AUDIO_MIXER_ENUM) {
2766: gusics_dac_mute(ic, cp->un.ord);
2767: error = 0;
2768: }
2769: break;
2770:
2771: case GUSICS_CD_MUTE:
2772: if (cp->type == AUDIO_MIXER_ENUM) {
2773: gusics_cd_mute(ic, cp->un.ord);
2774: error = 0;
2775: }
2776: break;
2777:
2778: case GUSICS_MASTER_LVL:
2779: if (cp->type == AUDIO_MIXER_VALUE) {
2780: if (ad1848_to_vol(cp, &vol)) {
2781: ics2101_mix_attenuate(ic,
2782: GUSMIX_CHAN_MASTER,
2783: ICSMIX_LEFT,
2784: vol.left);
2785: ics2101_mix_attenuate(ic,
2786: GUSMIX_CHAN_MASTER,
2787: ICSMIX_RIGHT,
2788: vol.right);
2789: error = 0;
2790: }
2791: }
2792: break;
2793:
2794: case GUSICS_MIC_IN_LVL: /* Microphone */
2795: if (cp->type == AUDIO_MIXER_VALUE) {
2796: if (ad1848_to_vol(cp, &vol)) {
2797: ics2101_mix_attenuate(ic,
2798: GUSMIX_CHAN_MIC,
2799: ICSMIX_LEFT,
2800: vol.left);
2801: ics2101_mix_attenuate(ic,
2802: GUSMIX_CHAN_MIC,
2803: ICSMIX_RIGHT,
2804: vol.right);
2805: error = 0;
2806: }
2807: }
2808: break;
2809:
2810: case GUSICS_LINE_IN_LVL: /* line in */
2811: if (cp->type == AUDIO_MIXER_VALUE) {
2812: if (ad1848_to_vol(cp, &vol)) {
2813: ics2101_mix_attenuate(ic,
2814: GUSMIX_CHAN_LINE,
2815: ICSMIX_LEFT,
2816: vol.left);
2817: ics2101_mix_attenuate(ic,
2818: GUSMIX_CHAN_LINE,
2819: ICSMIX_RIGHT,
2820: vol.right);
2821: error = 0;
2822: }
2823: }
2824: break;
2825:
2826:
2827: case GUSICS_CD_LVL:
2828: if (cp->type == AUDIO_MIXER_VALUE) {
2829: if (ad1848_to_vol(cp, &vol)) {
2830: ics2101_mix_attenuate(ic,
2831: GUSMIX_CHAN_CD,
2832: ICSMIX_LEFT,
2833: vol.left);
2834: ics2101_mix_attenuate(ic,
2835: GUSMIX_CHAN_CD,
2836: ICSMIX_RIGHT,
2837: vol.right);
2838: error = 0;
2839: }
2840: }
2841: break;
2842:
2843: case GUSICS_DAC_LVL: /* dac out */
2844: if (cp->type == AUDIO_MIXER_VALUE) {
2845: if (ad1848_to_vol(cp, &vol)) {
2846: ics2101_mix_attenuate(ic,
2847: GUSMIX_CHAN_DAC,
2848: ICSMIX_LEFT,
2849: vol.left);
2850: ics2101_mix_attenuate(ic,
2851: GUSMIX_CHAN_DAC,
2852: ICSMIX_RIGHT,
2853: vol.right);
2854: error = 0;
2855: }
2856: }
2857: break;
2858:
2859:
2860: case GUSICS_RECORD_SOURCE:
2861: if (cp->type == AUDIO_MIXER_ENUM && cp->un.ord == 0) {
2862: /* Can't set anything else useful, sigh. */
2863: error = 0;
2864: }
2865: break;
2866:
2867: default:
2868: return ENXIO;
2869: /*NOTREACHED*/
2870: }
2871: return error;
2872: }
2873:
2874: int
2875: gus_get_props(addr)
2876: void *addr;
2877: {
2878: struct gus_softc *sc = addr;
2879: return AUDIO_PROP_MMAP |
2880: (sc->sc_recdrq == sc->sc_drq ? 0 : AUDIO_PROP_FULLDUPLEX);
2881: }
2882:
2883: int
2884: gusmax_get_props(addr)
2885: void *addr;
2886: {
2887: struct ad1848_softc *ac = addr;
2888: return gus_get_props(ac->parent);
2889: }
2890:
2891: int
2892: gusmax_mixer_query_devinfo(addr, dip)
2893: void *addr;
2894: mixer_devinfo_t *dip;
2895: {
2896: DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index));
2897:
2898: switch(dip->index) {
2899: #if 0
2900: case GUSMAX_MIC_IN_LVL: /* Microphone */
2901: dip->type = AUDIO_MIXER_VALUE;
2902: dip->mixer_class = GUSMAX_INPUT_CLASS;
2903: dip->prev = AUDIO_MIXER_LAST;
2904: dip->next = GUSMAX_MIC_IN_MUTE;
2905: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
2906: dip->un.v.num_channels = 2;
2907: strlcpy(dip->un.v.units.name, AudioNvolume,
2908: sizeof dip->un.v.units.name);
2909: break;
2910: #endif
2911:
2912: case GUSMAX_MONO_LVL: /* mono/microphone mixer */
2913: dip->type = AUDIO_MIXER_VALUE;
2914: dip->mixer_class = GUSMAX_INPUT_CLASS;
2915: dip->prev = AUDIO_MIXER_LAST;
2916: dip->next = GUSMAX_MONO_MUTE;
2917: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
2918: dip->un.v.num_channels = 1;
2919: strlcpy(dip->un.v.units.name, AudioNvolume,
2920: sizeof dip->un.v.units.name);
2921: break;
2922:
2923: case GUSMAX_DAC_LVL: /* dacout */
2924: dip->type = AUDIO_MIXER_VALUE;
2925: dip->mixer_class = GUSMAX_INPUT_CLASS;
2926: dip->prev = AUDIO_MIXER_LAST;
2927: dip->next = GUSMAX_DAC_MUTE;
2928: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
2929: dip->un.v.num_channels = 2;
2930: strlcpy(dip->un.v.units.name, AudioNvolume,
2931: sizeof dip->un.v.units.name);
2932: break;
2933:
2934: case GUSMAX_LINE_IN_LVL: /* line */
2935: dip->type = AUDIO_MIXER_VALUE;
2936: dip->mixer_class = GUSMAX_INPUT_CLASS;
2937: dip->prev = AUDIO_MIXER_LAST;
2938: dip->next = GUSMAX_LINE_IN_MUTE;
2939: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
2940: dip->un.v.num_channels = 2;
2941: strlcpy(dip->un.v.units.name, AudioNvolume,
2942: sizeof dip->un.v.units.name);
2943: break;
2944:
2945: case GUSMAX_CD_LVL: /* cd */
2946: dip->type = AUDIO_MIXER_VALUE;
2947: dip->mixer_class = GUSMAX_INPUT_CLASS;
2948: dip->prev = AUDIO_MIXER_LAST;
2949: dip->next = GUSMAX_CD_MUTE;
2950: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
2951: dip->un.v.num_channels = 2;
2952: strlcpy(dip->un.v.units.name, AudioNvolume,
2953: sizeof dip->un.v.units.name);
2954: break;
2955:
2956:
2957: case GUSMAX_MONITOR_LVL: /* monitor level */
2958: dip->type = AUDIO_MIXER_VALUE;
2959: dip->mixer_class = GUSMAX_MONITOR_CLASS;
2960: dip->next = GUSMAX_MONITOR_MUTE;
2961: dip->prev = AUDIO_MIXER_LAST;
2962: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
2963: dip->un.v.num_channels = 1;
2964: strlcpy(dip->un.v.units.name, AudioNvolume,
2965: sizeof dip->un.v.units.name);
2966: break;
2967:
2968: case GUSMAX_OUT_LVL: /* cs4231 output volume: not useful? */
2969: dip->type = AUDIO_MIXER_VALUE;
2970: dip->mixer_class = GUSMAX_MONITOR_CLASS;
2971: dip->prev = dip->next = AUDIO_MIXER_LAST;
2972: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
2973: dip->un.v.num_channels = 2;
2974: strlcpy(dip->un.v.units.name, AudioNvolume,
2975: sizeof dip->un.v.units.name);
2976: break;
2977:
2978: case GUSMAX_SPEAKER_LVL: /* fake speaker volume */
2979: dip->type = AUDIO_MIXER_VALUE;
2980: dip->mixer_class = GUSMAX_MONITOR_CLASS;
2981: dip->prev = AUDIO_MIXER_LAST;
2982: dip->next = GUSMAX_SPEAKER_MUTE;
2983: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
2984: dip->un.v.num_channels = 2;
2985: strlcpy(dip->un.v.units.name, AudioNvolume,
2986: sizeof dip->un.v.units.name);
2987: break;
2988:
2989: case GUSMAX_LINE_IN_MUTE:
2990: dip->mixer_class = GUSMAX_INPUT_CLASS;
2991: dip->type = AUDIO_MIXER_ENUM;
2992: dip->prev = GUSMAX_LINE_IN_LVL;
2993: dip->next = AUDIO_MIXER_LAST;
2994: goto mute;
2995:
2996: case GUSMAX_DAC_MUTE:
2997: dip->mixer_class = GUSMAX_INPUT_CLASS;
2998: dip->type = AUDIO_MIXER_ENUM;
2999: dip->prev = GUSMAX_DAC_LVL;
3000: dip->next = AUDIO_MIXER_LAST;
3001: goto mute;
3002:
3003: case GUSMAX_CD_MUTE:
3004: dip->mixer_class = GUSMAX_INPUT_CLASS;
3005: dip->type = AUDIO_MIXER_ENUM;
3006: dip->prev = GUSMAX_CD_LVL;
3007: dip->next = AUDIO_MIXER_LAST;
3008: goto mute;
3009:
3010: case GUSMAX_MONO_MUTE:
3011: dip->mixer_class = GUSMAX_INPUT_CLASS;
3012: dip->type = AUDIO_MIXER_ENUM;
3013: dip->prev = GUSMAX_MONO_LVL;
3014: dip->next = AUDIO_MIXER_LAST;
3015: goto mute;
3016:
3017: case GUSMAX_MONITOR_MUTE:
3018: dip->mixer_class = GUSMAX_OUTPUT_CLASS;
3019: dip->type = AUDIO_MIXER_ENUM;
3020: dip->prev = GUSMAX_MONITOR_LVL;
3021: dip->next = AUDIO_MIXER_LAST;
3022: goto mute;
3023:
3024: case GUSMAX_SPEAKER_MUTE:
3025: dip->mixer_class = GUSMAX_OUTPUT_CLASS;
3026: dip->type = AUDIO_MIXER_ENUM;
3027: dip->prev = GUSMAX_SPEAKER_LVL;
3028: dip->next = AUDIO_MIXER_LAST;
3029: mute:
3030: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
3031: dip->un.e.num_mem = 2;
3032: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
3033: sizeof dip->un.e.member[0].label.name);
3034: dip->un.e.member[0].ord = 0;
3035: strlcpy(dip->un.e.member[1].label.name, AudioNon,
3036: sizeof dip->un.e.member[1].label.name);
3037: dip->un.e.member[1].ord = 1;
3038: break;
3039:
3040: case GUSMAX_REC_LVL: /* record level */
3041: dip->type = AUDIO_MIXER_VALUE;
3042: dip->mixer_class = GUSMAX_RECORD_CLASS;
3043: dip->prev = AUDIO_MIXER_LAST;
3044: dip->next = GUSMAX_RECORD_SOURCE;
3045: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
3046: dip->un.v.num_channels = 2;
3047: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
3048: break;
3049:
3050: case GUSMAX_RECORD_SOURCE:
3051: dip->mixer_class = GUSMAX_RECORD_CLASS;
3052: dip->type = AUDIO_MIXER_ENUM;
3053: dip->prev = GUSMAX_REC_LVL;
3054: dip->next = AUDIO_MIXER_LAST;
3055: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
3056: dip->un.e.num_mem = 4;
3057: strlcpy(dip->un.e.member[0].label.name, AudioNoutput,
3058: sizeof dip->un.e.member[0].label.name);
3059: dip->un.e.member[0].ord = DAC_IN_PORT;
3060: strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone,
3061: sizeof dip->un.e.member[1].label.name);
3062: dip->un.e.member[1].ord = MIC_IN_PORT;
3063: strlcpy(dip->un.e.member[2].label.name, AudioNdac,
3064: sizeof dip->un.e.member[2].label.name);
3065: dip->un.e.member[2].ord = AUX1_IN_PORT;
3066: strlcpy(dip->un.e.member[3].label.name, AudioNline,
3067: sizeof dip->un.e.member[3].label.name);
3068: dip->un.e.member[3].ord = LINE_IN_PORT;
3069: break;
3070:
3071: case GUSMAX_INPUT_CLASS: /* input class descriptor */
3072: dip->type = AUDIO_MIXER_CLASS;
3073: dip->mixer_class = GUSMAX_INPUT_CLASS;
3074: dip->next = dip->prev = AUDIO_MIXER_LAST;
3075: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
3076: break;
3077:
3078: case GUSMAX_OUTPUT_CLASS: /* output class descriptor */
3079: dip->type = AUDIO_MIXER_CLASS;
3080: dip->mixer_class = GUSMAX_OUTPUT_CLASS;
3081: dip->next = dip->prev = AUDIO_MIXER_LAST;
3082: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
3083: break;
3084:
3085: case GUSMAX_MONITOR_CLASS: /* monitor class descriptor */
3086: dip->type = AUDIO_MIXER_CLASS;
3087: dip->mixer_class = GUSMAX_MONITOR_CLASS;
3088: dip->next = dip->prev = AUDIO_MIXER_LAST;
3089: strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
3090: break;
3091:
3092: case GUSMAX_RECORD_CLASS: /* record source class */
3093: dip->type = AUDIO_MIXER_CLASS;
3094: dip->mixer_class = GUSMAX_RECORD_CLASS;
3095: dip->next = dip->prev = AUDIO_MIXER_LAST;
3096: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
3097: break;
3098:
3099: default:
3100: return ENXIO;
3101: /*NOTREACHED*/
3102: }
3103: DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
3104: return 0;
3105: }
3106:
3107: int
3108: gus_mixer_query_devinfo(addr, dip)
3109: void *addr;
3110: mixer_devinfo_t *dip;
3111: {
3112: struct gus_softc *sc = addr;
3113:
3114: DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index));
3115:
3116: if (!HAS_MIXER(sc) && dip->index > GUSICS_MASTER_MUTE)
3117: return ENXIO;
3118:
3119: switch(dip->index) {
3120:
3121: case GUSICS_MIC_IN_LVL: /* Microphone */
3122: dip->type = AUDIO_MIXER_VALUE;
3123: dip->mixer_class = GUSICS_INPUT_CLASS;
3124: dip->prev = AUDIO_MIXER_LAST;
3125: dip->next = GUSICS_MIC_IN_MUTE;
3126: strlcpy(dip->label.name, AudioNmicrophone,
3127: sizeof dip->label.name);
3128: dip->un.v.num_channels = 2;
3129: strlcpy(dip->un.v.units.name, AudioNvolume,
3130: sizeof dip->un.v.units.name);
3131: break;
3132:
3133: case GUSICS_LINE_IN_LVL: /* line */
3134: dip->type = AUDIO_MIXER_VALUE;
3135: dip->mixer_class = GUSICS_INPUT_CLASS;
3136: dip->prev = AUDIO_MIXER_LAST;
3137: dip->next = GUSICS_LINE_IN_MUTE;
3138: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
3139: dip->un.v.num_channels = 2;
3140: strlcpy(dip->un.v.units.name, AudioNvolume,
3141: sizeof dip->un.v.units.name);
3142: break;
3143:
3144: case GUSICS_CD_LVL: /* cd */
3145: dip->type = AUDIO_MIXER_VALUE;
3146: dip->mixer_class = GUSICS_INPUT_CLASS;
3147: dip->prev = AUDIO_MIXER_LAST;
3148: dip->next = GUSICS_CD_MUTE;
3149: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
3150: dip->un.v.num_channels = 2;
3151: strlcpy(dip->un.v.units.name, AudioNvolume,
3152: sizeof dip->un.v.units.name);
3153: break;
3154:
3155: case GUSICS_DAC_LVL: /* dacout */
3156: dip->type = AUDIO_MIXER_VALUE;
3157: dip->mixer_class = GUSICS_INPUT_CLASS;
3158: dip->prev = AUDIO_MIXER_LAST;
3159: dip->next = GUSICS_DAC_MUTE;
3160: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
3161: dip->un.v.num_channels = 2;
3162: strlcpy(dip->un.v.units.name, AudioNvolume,
3163: sizeof dip->un.v.units.name);
3164: break;
3165:
3166: case GUSICS_MASTER_LVL: /* master output */
3167: dip->type = AUDIO_MIXER_VALUE;
3168: dip->mixer_class = GUSICS_OUTPUT_CLASS;
3169: dip->prev = AUDIO_MIXER_LAST;
3170: dip->next = GUSICS_MASTER_MUTE;
3171: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
3172: dip->un.v.num_channels = 2;
3173: strlcpy(dip->un.v.units.name, AudioNvolume,
3174: sizeof dip->un.v.units.name);
3175: break;
3176:
3177:
3178: case GUSICS_LINE_IN_MUTE:
3179: dip->mixer_class = GUSICS_INPUT_CLASS;
3180: dip->type = AUDIO_MIXER_ENUM;
3181: dip->prev = GUSICS_LINE_IN_LVL;
3182: dip->next = AUDIO_MIXER_LAST;
3183: goto mute;
3184:
3185: case GUSICS_DAC_MUTE:
3186: dip->mixer_class = GUSICS_INPUT_CLASS;
3187: dip->type = AUDIO_MIXER_ENUM;
3188: dip->prev = GUSICS_DAC_LVL;
3189: dip->next = AUDIO_MIXER_LAST;
3190: goto mute;
3191:
3192: case GUSICS_CD_MUTE:
3193: dip->mixer_class = GUSICS_INPUT_CLASS;
3194: dip->type = AUDIO_MIXER_ENUM;
3195: dip->prev = GUSICS_CD_LVL;
3196: dip->next = AUDIO_MIXER_LAST;
3197: goto mute;
3198:
3199: case GUSICS_MIC_IN_MUTE:
3200: dip->mixer_class = GUSICS_INPUT_CLASS;
3201: dip->type = AUDIO_MIXER_ENUM;
3202: dip->prev = GUSICS_MIC_IN_LVL;
3203: dip->next = AUDIO_MIXER_LAST;
3204: goto mute;
3205:
3206: case GUSICS_MASTER_MUTE:
3207: dip->mixer_class = GUSICS_OUTPUT_CLASS;
3208: dip->type = AUDIO_MIXER_ENUM;
3209: dip->prev = GUSICS_MASTER_LVL;
3210: dip->next = AUDIO_MIXER_LAST;
3211: mute:
3212: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
3213: dip->un.e.num_mem = 2;
3214: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
3215: sizeof dip->un.e.member[0].label.name);
3216: dip->un.e.member[0].ord = 0;
3217: strlcpy(dip->un.e.member[1].label.name, AudioNon,
3218: sizeof dip->un.e.member[1].label.name);
3219: dip->un.e.member[1].ord = 1;
3220: break;
3221:
3222: case GUSICS_RECORD_SOURCE:
3223: dip->mixer_class = GUSICS_RECORD_CLASS;
3224: dip->type = AUDIO_MIXER_ENUM;
3225: dip->prev = dip->next = AUDIO_MIXER_LAST;
3226: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
3227: dip->un.e.num_mem = 1;
3228: strlcpy(dip->un.e.member[0].label.name, AudioNoutput,
3229: sizeof dip->un.e.member[0].label.name);
3230: dip->un.e.member[0].ord = GUSICS_MASTER_LVL;
3231: break;
3232:
3233: case GUSICS_INPUT_CLASS:
3234: dip->type = AUDIO_MIXER_CLASS;
3235: dip->mixer_class = GUSICS_INPUT_CLASS;
3236: dip->next = dip->prev = AUDIO_MIXER_LAST;
3237: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
3238: break;
3239:
3240: case GUSICS_OUTPUT_CLASS:
3241: dip->type = AUDIO_MIXER_CLASS;
3242: dip->mixer_class = GUSICS_OUTPUT_CLASS;
3243: dip->next = dip->prev = AUDIO_MIXER_LAST;
3244: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
3245: break;
3246:
3247: case GUSICS_RECORD_CLASS:
3248: dip->type = AUDIO_MIXER_CLASS;
3249: dip->mixer_class = GUSICS_RECORD_CLASS;
3250: dip->next = dip->prev = AUDIO_MIXER_LAST;
3251: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
3252: break;
3253:
3254: default:
3255: return ENXIO;
3256: /*NOTREACHED*/
3257: }
3258: DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
3259: return 0;
3260: }
3261:
3262: int
3263: gus_query_encoding(addr, fp)
3264: void *addr;
3265: struct audio_encoding *fp;
3266: {
3267: switch (fp->index) {
3268: case 0:
3269: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
3270: fp->encoding = AUDIO_ENCODING_ULAW;
3271: fp->precision = 8;
3272: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
3273: break;
3274: case 1:
3275: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
3276: fp->encoding = AUDIO_ENCODING_SLINEAR;
3277: fp->precision = 8;
3278: fp->flags = 0;
3279: break;
3280: case 2:
3281: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
3282: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
3283: fp->precision = 16;
3284: fp->flags = 0;
3285: break;
3286: case 3:
3287: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
3288: fp->encoding = AUDIO_ENCODING_ULINEAR;
3289: fp->precision = 8;
3290: fp->flags = 0;
3291: break;
3292: case 4:
3293: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
3294: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
3295: fp->precision = 16;
3296: fp->flags = 0;
3297: break;
3298: case 5:
3299: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
3300: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
3301: fp->precision = 16;
3302: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
3303: break;
3304: case 6:
3305: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
3306: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
3307: fp->precision = 16;
3308: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
3309: break;
3310: case 7:
3311: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
3312: fp->encoding = AUDIO_ENCODING_ALAW;
3313: fp->precision = 8;
3314: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
3315: break;
3316:
3317: default:
3318: return(EINVAL);
3319: /*NOTREACHED*/
3320: }
3321: return (0);
3322: }
3323:
3324: /*
3325: * Setup the ICS mixer in "transparent" mode: reset everything to a sensible
3326: * level. Levels as suggested by GUS SDK code.
3327: */
3328:
3329: void
3330: gus_init_ics2101(sc)
3331: struct gus_softc *sc;
3332: {
3333: struct ics2101_softc *ic = &sc->sc_mixer;
3334: sc->sc_mixer.sc_iot = sc->sc_iot;
3335: sc->sc_mixer.sc_selio = GUS_MIXER_SELECT;
3336: sc->sc_mixer.sc_selio_ioh = sc->sc_ioh3;
3337: sc->sc_mixer.sc_dataio = GUS_MIXER_DATA;
3338: sc->sc_mixer.sc_dataio_ioh = sc->sc_ioh2;
3339: sc->sc_mixer.sc_flags = (sc->sc_revision == 5) ? ICS_FLIP : 0;
3340:
3341: ics2101_mix_attenuate(ic,
3342: GUSMIX_CHAN_MIC,
3343: ICSMIX_LEFT,
3344: ICSMIX_MIN_ATTN);
3345: ics2101_mix_attenuate(ic,
3346: GUSMIX_CHAN_MIC,
3347: ICSMIX_RIGHT,
3348: ICSMIX_MIN_ATTN);
3349: /*
3350: * Start with microphone muted by the mixer...
3351: */
3352: gusics_mic_mute(ic, 1);
3353:
3354: /* ... and enabled by the GUS master mix control */
3355: gus_mic_ctl(sc, SPKR_ON);
3356:
3357: ics2101_mix_attenuate(ic,
3358: GUSMIX_CHAN_LINE,
3359: ICSMIX_LEFT,
3360: ICSMIX_MIN_ATTN);
3361: ics2101_mix_attenuate(ic,
3362: GUSMIX_CHAN_LINE,
3363: ICSMIX_RIGHT,
3364: ICSMIX_MIN_ATTN);
3365:
3366: ics2101_mix_attenuate(ic,
3367: GUSMIX_CHAN_CD,
3368: ICSMIX_LEFT,
3369: ICSMIX_MIN_ATTN);
3370: ics2101_mix_attenuate(ic,
3371: GUSMIX_CHAN_CD,
3372: ICSMIX_RIGHT,
3373: ICSMIX_MIN_ATTN);
3374:
3375: ics2101_mix_attenuate(ic,
3376: GUSMIX_CHAN_DAC,
3377: ICSMIX_LEFT,
3378: ICSMIX_MIN_ATTN);
3379: ics2101_mix_attenuate(ic,
3380: GUSMIX_CHAN_DAC,
3381: ICSMIX_RIGHT,
3382: ICSMIX_MIN_ATTN);
3383:
3384: ics2101_mix_attenuate(ic,
3385: ICSMIX_CHAN_4,
3386: ICSMIX_LEFT,
3387: ICSMIX_MAX_ATTN);
3388: ics2101_mix_attenuate(ic,
3389: ICSMIX_CHAN_4,
3390: ICSMIX_RIGHT,
3391: ICSMIX_MAX_ATTN);
3392:
3393: ics2101_mix_attenuate(ic,
3394: GUSMIX_CHAN_MASTER,
3395: ICSMIX_LEFT,
3396: ICSMIX_MIN_ATTN);
3397: ics2101_mix_attenuate(ic,
3398: GUSMIX_CHAN_MASTER,
3399: ICSMIX_RIGHT,
3400: ICSMIX_MIN_ATTN);
3401: /* unmute other stuff: */
3402: gusics_cd_mute(ic, 0);
3403: gusics_dac_mute(ic, 0);
3404: gusics_linein_mute(ic, 0);
3405: return;
3406: }
3407:
3408:
3409:
3410: void
3411: gus_subattach(sc, ia)
3412: struct gus_softc *sc;
3413: struct isa_attach_args *ia;
3414: {
3415: int i;
3416: bus_space_tag_t iot;
3417: unsigned char c,d,m;
3418:
3419: iot = sc->sc_iot;
3420:
3421: /*
3422: * Figure out our board rev, and see if we need to initialize the
3423: * mixer
3424: */
3425:
3426: c = bus_space_read_1(iot, sc->sc_ioh3, GUS_BOARD_REV);
3427: if (c != 0xff)
3428: sc->sc_revision = c;
3429: else
3430: sc->sc_revision = 0;
3431:
3432: SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_RESET);
3433: bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, 0x00);
3434:
3435: gusreset(sc, GUS_MAX_VOICES); /* initialize all voices */
3436: gusreset(sc, GUS_MIN_VOICES); /* then set to just the ones we use */
3437:
3438: /*
3439: * Setup the IRQ and DRQ lines in software, using values from
3440: * config file
3441: */
3442:
3443: m = GUSMASK_LINE_IN|GUSMASK_LINE_OUT; /* disable all */
3444:
3445: c = ((unsigned char) gus_irq_map[ia->ia_irq]) | GUSMASK_BOTH_RQ;
3446:
3447: if (sc->sc_recdrq == sc->sc_drq)
3448: d = (unsigned char) (gus_drq_map[sc->sc_drq] |
3449: GUSMASK_BOTH_RQ);
3450: else
3451: d = (unsigned char) (gus_drq_map[sc->sc_drq] |
3452: gus_drq_map[sc->sc_recdrq] << 3);
3453:
3454: /*
3455: * Program the IRQ and DMA channels on the GUS. Note that we hardwire
3456: * the GUS to only use one IRQ channel, but we give the user the
3457: * option of using two DMA channels (the other one given by the drq2
3458: * option in the config file). Two DMA channels are needed for full-
3459: * duplex operation.
3460: *
3461: * The order of these operations is very magical.
3462: */
3463:
3464: disable_intr(); /* XXX needed? */
3465:
3466: bus_space_write_1(iot, sc->sc_ioh1, GUS_REG_CONTROL, GUS_REG_IRQCTL);
3467: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
3468: bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQCTL_CONTROL, 0x00);
3469: bus_space_write_1(iot, sc->sc_ioh1, 0x0f, 0x00);
3470:
3471: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
3472:
3473: /* magic reset? */
3474: bus_space_write_1(iot, sc->sc_ioh1, GUS_DMA_CONTROL, d | 0x80);
3475:
3476: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
3477: m | GUSMASK_CONTROL_SEL);
3478: bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQ_CONTROL, c);
3479:
3480: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
3481: bus_space_write_1(iot, sc->sc_ioh1, GUS_DMA_CONTROL, d);
3482:
3483: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
3484: m | GUSMASK_CONTROL_SEL);
3485: bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQ_CONTROL, c);
3486:
3487: bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT, 0x00);
3488:
3489: /* enable line in, line out. leave mic disabled. */
3490: bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
3491: (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN));
3492: bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT, 0x00);
3493:
3494: enable_intr();
3495:
3496: sc->sc_mixcontrol =
3497: (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN);
3498:
3499: sc->sc_codec.sc_isa = sc->sc_isa;
3500:
3501: if (sc->sc_revision >= 5 && sc->sc_revision <= 9) {
3502: sc->sc_flags |= GUS_MIXER_INSTALLED;
3503: gus_init_ics2101(sc);
3504: }
3505: if (sc->sc_revision < 10 || !gus_init_cs4231(sc)) {
3506: /* Not using the CS4231, so create our DMA maps. */
3507: if (sc->sc_drq != -1) {
3508: if (isa_dmamap_create(sc->sc_isa, sc->sc_drq,
3509: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
3510: printf("%s: can't create map for drq %d\n",
3511: sc->sc_dev.dv_xname, sc->sc_drq);
3512: return;
3513: }
3514: }
3515: if (sc->sc_recdrq != -1 && sc->sc_recdrq != sc->sc_drq) {
3516: if (isa_dmamap_create(sc->sc_isa, sc->sc_recdrq,
3517: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
3518: printf("%s: can't create map for drq %d\n",
3519: sc->sc_dev.dv_xname, sc->sc_recdrq);
3520: return;
3521: }
3522: }
3523: }
3524:
3525: timeout_set(&sc->sc_dma_tmo, gus_dmaout_timeout, sc);
3526:
3527: SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_RESET);
3528: /*
3529: * Check to see how much memory we have on this card; see if any
3530: * "mirroring" occurs. We're assuming at least 256K already exists
3531: * on the card; otherwise the initial probe would have failed
3532: */
3533:
3534: guspoke(iot, sc->sc_ioh2, 0L, 0x00);
3535: for(i = 1; i < 1024; i++) {
3536: u_long loc;
3537:
3538: /*
3539: * See if we've run into mirroring yet
3540: */
3541:
3542: if (guspeek(iot, sc->sc_ioh2, 0L) != 0)
3543: break;
3544:
3545: loc = i << 10;
3546:
3547: guspoke(iot, sc->sc_ioh2, loc, 0xaa);
3548: if (guspeek(iot, sc->sc_ioh2, loc) != 0xaa)
3549: break;
3550: }
3551:
3552: sc->sc_dsize = i;
3553: /*
3554: * The "official" (3.x) version number cannot easily be obtained.
3555: * The revision register does not correspond to the minor number
3556: * of the board version. Simply use the revision register as
3557: * identification.
3558: */
3559: snprintf(gus_device.version, sizeof gus_device.version, "%d",
3560: sc->sc_revision);
3561:
3562: printf(": ver %d", sc->sc_revision);
3563: if (sc->sc_revision >= 10)
3564: printf(", MAX");
3565: else {
3566: if (HAS_MIXER(sc))
3567: printf(", ICS2101 mixer");
3568: if (HAS_CODEC(sc))
3569: printf(", %s codec/mixer", sc->sc_codec.chip_name);
3570: }
3571: printf(", %dKB DRAM, ", sc->sc_dsize);
3572: if (sc->sc_recdrq == sc->sc_drq) {
3573: printf("half-duplex");
3574: } else {
3575: printf("full-duplex, record drq %d", sc->sc_recdrq);
3576: }
3577:
3578: printf("\n");
3579:
3580: /*
3581: * Setup a default interrupt handler
3582: */
3583:
3584: /* XXX we shouldn't have to use splgus == splclock, nor should
3585: * we use IPL_CLOCK.
3586: */
3587: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
3588: IPL_AUDIO, gusintr, sc /* sc->sc_gusdsp */, sc->sc_dev.dv_xname);
3589:
3590: /*
3591: * Set some default values
3592: * XXX others start with 8kHz mono mulaw
3593: */
3594:
3595: sc->sc_irate = sc->sc_orate = 44100;
3596: sc->sc_encoding = AUDIO_ENCODING_SLINEAR_LE;
3597: sc->sc_precision = 16;
3598: sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_DATA_SIZE16;
3599: sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16;
3600: sc->sc_channels = 1;
3601: sc->sc_ogain = 340;
3602: gus_commit_settings(sc);
3603:
3604: /*
3605: * We always put the left channel full left & right channel
3606: * full right.
3607: * For mono playback, we set up both voices playing the same buffer.
3608: */
3609: bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT,
3610: (u_char)GUS_VOICE_LEFT);
3611: SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_PAN_POS);
3612: bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_LEFT);
3613:
3614: bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT,
3615: (u_char)GUS_VOICE_RIGHT);
3616: SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_PAN_POS);
3617: bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_RIGHT);
3618:
3619: /*
3620: * Attach to the generic audio layer
3621: */
3622:
3623: audio_attach_mi(&gus_hw_if, HAS_CODEC(sc) ? (void *)&sc->sc_codec :
3624: (void *)sc, &sc->sc_dev);
3625: }
3626:
3627: /*
3628: * Test to see if a particular I/O base is valid for the GUS. Return true
3629: * if it is.
3630: */
3631:
3632: int
3633: gus_test_iobase (iot, iobase)
3634: bus_space_tag_t iot;
3635: int iobase;
3636: {
3637: bus_space_handle_t ioh1, ioh2, ioh3, ioh4;
3638: u_char s1, s2;
3639: int s, rv = 0;
3640:
3641: /* Map i/o space */
3642: if (bus_space_map(iot, iobase, GUS_NPORT1, 0, &ioh1))
3643: return 0;
3644: if (bus_space_map(iot, iobase+GUS_IOH2_OFFSET, GUS_NPORT2, 0, &ioh2))
3645: goto bad1;
3646:
3647: /* XXX Maybe we shouldn't fail on mapping this, but just assume
3648: * the card is of revision 0? */
3649: if (bus_space_map(iot, iobase+GUS_IOH3_OFFSET, GUS_NPORT3, 0, &ioh3))
3650: goto bad2;
3651:
3652: if (bus_space_map(iot, iobase+GUS_IOH4_OFFSET, GUS_NPORT4, 0, &ioh4))
3653: goto bad3;
3654:
3655: /*
3656: * Reset GUS to an initial state before we do anything.
3657: */
3658:
3659: s = splgus();
3660: delay(500);
3661:
3662: SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
3663: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
3664:
3665: delay(500);
3666:
3667: SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
3668: bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET);
3669:
3670: delay(500);
3671:
3672: splx(s);
3673:
3674: /*
3675: * See if we can write to the board's memory
3676: */
3677:
3678: s1 = guspeek(iot, ioh2, 0L);
3679: s2 = guspeek(iot, ioh2, 1L);
3680:
3681: guspoke(iot, ioh2, 0L, 0xaa);
3682: guspoke(iot, ioh2, 1L, 0x55);
3683:
3684: if (guspeek(iot, ioh2, 0L) != 0xaa)
3685: goto bad;
3686:
3687: guspoke(iot, ioh2, 0L, s1);
3688: guspoke(iot, ioh2, 1L, s2);
3689:
3690: rv = 1;
3691:
3692: bad:
3693: bus_space_unmap(iot, ioh4, GUS_NPORT4);
3694: bad3:
3695: bus_space_unmap(iot, ioh3, GUS_NPORT3);
3696: bad2:
3697: bus_space_unmap(iot, ioh2, GUS_NPORT2);
3698: bad1:
3699: bus_space_unmap(iot, ioh1, GUS_NPORT1);
3700: return rv;
3701: }
CVSweb