Annotation of sys/dev/isa/gus.c, Revision 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