[BACK]Return to gus.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

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