Annotation of sys/dev/isa/ad1848.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ad1848.c,v 1.32 2005/05/22 19:40:51 art Exp $ */
! 2: /* $NetBSD: ad1848.c,v 1.45 1998/01/30 02:02:38 augustss Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1994 John Brezak
! 6: * Copyright (c) 1991-1993 Regents of the University of California.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by the Computer Systems
! 20: * Engineering Group at Lawrence Berkeley Laboratory.
! 21: * 4. Neither the name of the University nor of the Laboratory may be used
! 22: * to endorse or promote products derived from this software without
! 23: * specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: */
! 38:
! 39: /*
! 40: * Copyright by Hannu Savolainen 1994
! 41: *
! 42: * Redistribution and use in source and binary forms, with or without
! 43: * modification, are permitted provided that the following conditions are
! 44: * met: 1. Redistributions of source code must retain the above copyright
! 45: * notice, this list of conditions and the following disclaimer. 2.
! 46: * Redistributions in binary form must reproduce the above copyright notice,
! 47: * this list of conditions and the following disclaimer in the documentation
! 48: * and/or other materials provided with the distribution.
! 49: *
! 50: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
! 51: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 52: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 53: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
! 54: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 56: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! 57: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 60: * SUCH DAMAGE.
! 61: *
! 62: */
! 63: /*
! 64: * Portions of this code are from the VOXware support for the ad1848
! 65: * by Hannu Savolainen <hannu@voxware.pp.fi>
! 66: *
! 67: * Portions also supplied from the SoundBlaster driver for NetBSD.
! 68: */
! 69:
! 70: #include <sys/param.h>
! 71: #include <sys/systm.h>
! 72: #include <sys/errno.h>
! 73: #include <sys/ioctl.h>
! 74: #include <sys/syslog.h>
! 75: #include <sys/device.h>
! 76: #include <sys/proc.h>
! 77: #include <sys/buf.h>
! 78:
! 79: #include <machine/cpu.h>
! 80: #include <machine/bus.h>
! 81:
! 82: #include <sys/audioio.h>
! 83:
! 84: #include <dev/audio_if.h>
! 85: #include <dev/auconv.h>
! 86:
! 87: #include <dev/isa/isavar.h>
! 88: #include <dev/isa/isadmavar.h>
! 89:
! 90: #include <dev/ic/ad1848reg.h>
! 91: #include <dev/ic/cs4231reg.h>
! 92: #include <dev/isa/ad1848var.h>
! 93: #include <dev/isa/cs4231var.h>
! 94:
! 95: #ifdef AUDIO_DEBUG
! 96: #define DPRINTF(x) if (ad1848debug) printf x
! 97: int ad1848debug = 0;
! 98: #else
! 99: #define DPRINTF(x)
! 100: #endif
! 101:
! 102: /*
! 103: * Initial values for the indirect registers of CS4248/AD1848.
! 104: */
! 105: static int ad1848_init_values[] = {
! 106: /* Left Input Control */
! 107: GAIN_12|INPUT_MIC_GAIN_ENABLE,
! 108: /* Right Input Control */
! 109: GAIN_12|INPUT_MIC_GAIN_ENABLE,
! 110: ATTEN_12, /* Left Aux #1 Input Control */
! 111: ATTEN_12, /* Right Aux #1 Input Control */
! 112: ATTEN_12, /* Left Aux #2 Input Control */
! 113: ATTEN_12, /* Right Aux #2 Input Control */
! 114: /* bits 5-0 are attenuation select */
! 115: ATTEN_12, /* Left DAC output Control */
! 116: ATTEN_12, /* Right DAC output Control */
! 117: /* Clock and Data Format */
! 118: CLOCK_XTAL1|FMT_PCM8,
! 119: /* Interface Config */
! 120: SINGLE_DMA|AUTO_CAL_ENABLE,
! 121: INTERRUPT_ENABLE, /* Pin control */
! 122: 0x00, /* Test and Init */
! 123: MODE2, /* Misc control */
! 124: ATTEN_0<<2, /* Digital Mix Control */
! 125: 0, /* Upper base Count */
! 126: 0, /* Lower base Count */
! 127:
! 128: /* These are for CS4231 &c. only (additional registers): */
! 129: 0, /* Alt feature 1 */
! 130: 0, /* Alt feature 2 */
! 131: ATTEN_12, /* Left line in */
! 132: ATTEN_12, /* Right line in */
! 133: 0, /* Timer low */
! 134: 0, /* Timer high */
! 135: 0, /* unused */
! 136: 0, /* unused */
! 137: 0, /* IRQ status */
! 138: 0, /* unused */
! 139: /* Mono input (a.k.a speaker) (mic) Control */
! 140: MONO_INPUT_MUTE|ATTEN_6, /* mute speaker by default */
! 141: 0, /* unused */
! 142: 0, /* record format */
! 143: 0, /* Crystal Clock Select */
! 144: 0, /* upper record count */
! 145: 0 /* lower record count */
! 146: };
! 147:
! 148: void ad1848_reset(struct ad1848_softc *);
! 149: int ad1848_set_speed(struct ad1848_softc *, u_long *);
! 150: void ad1848_mute_monitor(void *, int);
! 151:
! 152: static int ad_read(struct ad1848_softc *, int);
! 153: static void ad_write(struct ad1848_softc *, int, int);
! 154: static void ad_set_MCE(struct ad1848_softc *, int);
! 155: static void wait_for_calibration(struct ad1848_softc *);
! 156:
! 157: #define ADREAD(sc, addr) bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_iooffs+(addr))
! 158: #define ADWRITE(sc, addr, data) bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_iooffs+(addr), (data))
! 159:
! 160: static int
! 161: ad_read(sc, reg)
! 162: struct ad1848_softc *sc;
! 163: int reg;
! 164: {
! 165: int x, s;
! 166:
! 167: s = splaudio();
! 168: ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
! 169: x = ADREAD(sc, AD1848_IDATA);
! 170: splx(s);
! 171: /* printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */
! 172:
! 173: return x;
! 174: }
! 175:
! 176: static void
! 177: ad_write(sc, reg, data)
! 178: struct ad1848_softc *sc;
! 179: int reg;
! 180: int data;
! 181: {
! 182: int s = splaudio();
! 183: ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
! 184: ADWRITE(sc, AD1848_IDATA, data & 0xff);
! 185: splx(s);
! 186: /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */
! 187: }
! 188:
! 189: static void
! 190: ad_set_MCE(sc, state)
! 191: struct ad1848_softc *sc;
! 192: int state;
! 193: {
! 194: if (state)
! 195: sc->MCE_bit = MODE_CHANGE_ENABLE;
! 196: else
! 197: sc->MCE_bit = 0;
! 198:
! 199: ADWRITE(sc, AD1848_IADDR, sc->MCE_bit);
! 200: }
! 201:
! 202: static void
! 203: wait_for_calibration(sc)
! 204: struct ad1848_softc *sc;
! 205: {
! 206: int timeout;
! 207:
! 208: DPRINTF(("ad1848: Auto calibration started.\n"));
! 209: /*
! 210: * Wait until the auto calibration process has finished.
! 211: *
! 212: * 1) Wait until the chip becomes ready (reads don't return 0x80).
! 213: * 2) Wait until the ACI bit of I11 gets on and then off.
! 214: */
! 215: timeout = 100000;
! 216: while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
! 217: timeout--;
! 218:
! 219: if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
! 220: DPRINTF(("ad1848: Auto calibration timed out(1).\n"));
! 221:
! 222: ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
! 223: timeout = 100000;
! 224: while (timeout > 0 && ADREAD(sc, AD1848_IADDR) != SP_TEST_AND_INIT)
! 225: timeout--;
! 226:
! 227: if (ADREAD(sc, AD1848_IADDR) == SP_TEST_AND_INIT)
! 228: DPRINTF(("ad1848: Auto calibration timed out(1.5).\n"));
! 229:
! 230: if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) {
! 231: timeout = 100000;
! 232: while (timeout > 0 && !(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG))
! 233: timeout--;
! 234:
! 235: if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG))
! 236: DPRINTF(("ad1848: Auto calibration timed out(2).\n"));
! 237: }
! 238:
! 239: timeout = 100000;
! 240: while (timeout > 0 && ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)
! 241: timeout--;
! 242: if (ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)
! 243: DPRINTF(("ad1848: Auto calibration timed out(3).\n"));
! 244: }
! 245:
! 246: #ifdef AUDIO_DEBUG
! 247: void ad1848_dump_regs(struct ad1848_softc *);
! 248:
! 249: void
! 250: ad1848_dump_regs(sc)
! 251: struct ad1848_softc *sc;
! 252: {
! 253: int i;
! 254: u_char r;
! 255:
! 256: printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS));
! 257: printf(" regs: ");
! 258: for (i = 0; i < 16; i++) {
! 259: r = ad_read(sc, i);
! 260: printf("%02x ", r);
! 261: }
! 262: if (sc->mode == 2) {
! 263: for (i = 16; i < 32; i++) {
! 264: r = ad_read(sc, i);
! 265: printf("%02x ", r);
! 266: }
! 267: }
! 268: printf("\n");
! 269: }
! 270: #endif
! 271:
! 272: /*
! 273: * Map and probe for the ad1848 chip
! 274: */
! 275: int
! 276: ad1848_mapprobe(sc, iobase)
! 277: struct ad1848_softc *sc;
! 278: int iobase;
! 279: {
! 280: if (!AD1848_BASE_VALID(iobase)) {
! 281: #ifdef AUDIO_DEBUG
! 282: printf("ad1848: configured iobase %04x invalid\n", iobase);
! 283: #endif
! 284: return 0;
! 285: }
! 286:
! 287: sc->sc_iooffs = 0;
! 288: /* Map the AD1848 ports */
! 289: if (bus_space_map(sc->sc_iot, iobase, AD1848_NPORT, 0, &sc->sc_ioh))
! 290: return 0;
! 291:
! 292: if (!ad1848_probe(sc)) {
! 293: bus_space_unmap(sc->sc_iot, sc->sc_ioh, AD1848_NPORT);
! 294: return 0;
! 295: } else
! 296: return 1;
! 297: }
! 298:
! 299: /*
! 300: * Probe for the ad1848 chip
! 301: */
! 302: int
! 303: ad1848_probe(sc)
! 304: struct ad1848_softc *sc;
! 305: {
! 306: u_char tmp, tmp1 = 0xff, tmp2 = 0xff;
! 307: #if 0
! 308: int i;
! 309: #endif
! 310:
! 311: /* Is there an ad1848 chip ? */
! 312: sc->MCE_bit = MODE_CHANGE_ENABLE;
! 313: sc->mode = 1; /* MODE 1 = original ad1848/ad1846/cs4248 */
! 314:
! 315: /*
! 316: * Check that the I/O address is in use.
! 317: *
! 318: * The SP_IN_INIT bit of the base I/O port is known to be 0 after the
! 319: * chip has performed its power-on initialization. Just assume
! 320: * this has happened before the OS is starting.
! 321: *
! 322: * If the I/O address is unused, inb() typically returns 0xff.
! 323: */
! 324: tmp = ADREAD(sc, AD1848_IADDR);
! 325: if (tmp & SP_IN_INIT) { /* Not a AD1848 */
! 326: #if 0
! 327: DPRINTF(("ad_detect_A %x\n", tmp));
! 328: #endif
! 329: goto bad;
! 330: }
! 331:
! 332: /*
! 333: * Test if it's possible to change contents of the indirect registers.
! 334: * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
! 335: * so try to avoid using it.
! 336: */
! 337: ad_write(sc, 0, 0xaa);
! 338: ad_write(sc, 1, 0x45); /* 0x55 with bit 0x10 clear */
! 339:
! 340: if ((tmp1 = ad_read(sc, 0)) != 0xaa ||
! 341: (tmp2 = ad_read(sc, 1)) != 0x45) {
! 342: DPRINTF(("ad_detect_B (%x/%x)\n", tmp1, tmp2));
! 343: goto bad;
! 344: }
! 345:
! 346: ad_write(sc, 0, 0x45);
! 347: ad_write(sc, 1, 0xaa);
! 348:
! 349: if ((tmp1 = ad_read(sc, 0)) != 0x45 ||
! 350: (tmp2 = ad_read(sc, 1)) != 0xaa) {
! 351: DPRINTF(("ad_detect_C (%x/%x)\n", tmp1, tmp2));
! 352: goto bad;
! 353: }
! 354:
! 355: /*
! 356: * The indirect register I12 has some read only bits. Lets
! 357: * try to change them.
! 358: */
! 359: tmp = ad_read(sc, SP_MISC_INFO);
! 360: ad_write(sc, SP_MISC_INFO, (~tmp) & 0x0f);
! 361:
! 362: if ((tmp & 0x0f) != ((tmp1 = ad_read(sc, SP_MISC_INFO)) & 0x0f)) {
! 363: DPRINTF(("ad_detect_D (%x)\n", tmp1));
! 364: goto bad;
! 365: }
! 366:
! 367: /*
! 368: * MSB and 4 LSBs of the reg I12 tell the chip revision.
! 369: *
! 370: * A preliminary version of the AD1846 data sheet stated that it
! 371: * used an ID field of 0x0B. The current version, however,
! 372: * states that the AD1846 uses ID 0x0A, just like the AD1848K.
! 373: *
! 374: * this switch statement will need updating as newer clones arrive....
! 375: */
! 376: switch (tmp1 & 0x8f) {
! 377: case 0x09:
! 378: sc->chip_name = "AD1848J";
! 379: break;
! 380: case 0x0A:
! 381: sc->chip_name = "AD1848K";
! 382: break;
! 383: #if 0 /* See above */
! 384: case 0x0B:
! 385: sc->chip_name = "AD1846";
! 386: break;
! 387: #endif
! 388: case 0x81:
! 389: sc->chip_name = "CS4248revB"; /* or CS4231 rev B; see below */
! 390: break;
! 391: case 0x89:
! 392: sc->chip_name = "CS4248";
! 393: break;
! 394: case 0x8A:
! 395: sc->chip_name = "broken"; /* CS4231/AD1845; see below */
! 396: break;
! 397: default:
! 398: sc->chip_name = "unknown";
! 399: DPRINTF(("ad1848: unknown codec version %#02X\n", (tmp1 & 0x8f)));
! 400: }
! 401:
! 402: #if 0
! 403: /*
! 404: * XXX I don't know why, but this probe fails on an otherwise well-working
! 405: * AW35/pro card, so I'll just take it out for now. [niklas@openbsd.org]
! 406: */
! 407:
! 408: /*
! 409: * The original AD1848/CS4248 has just 16 indirect registers. This means
! 410: * that I0 and I16 should return the same value (etc.).
! 411: * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
! 412: * with CS4231, AD1845, etc.
! 413: */
! 414: ad_write(sc, SP_MISC_INFO, 0); /* Mode2 = disabled */
! 415:
! 416: for (i = 0; i < 16; i++)
! 417: if ((tmp1 = ad_read(sc, i)) != (tmp2 = ad_read(sc, i + 16))) {
! 418: if (i != SP_TEST_AND_INIT) {
! 419: DPRINTF(("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
! 420: goto bad;
! 421: }
! 422: }
! 423: #endif
! 424:
! 425: /*
! 426: * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit
! 427: * The bit 0x80 is always 1 in CS4248, CS4231, and AD1845.
! 428: */
! 429: ad_write(sc, SP_MISC_INFO, MODE2); /* Set mode2, clear 0x80 */
! 430:
! 431: tmp1 = ad_read(sc, SP_MISC_INFO);
! 432: if ((tmp1 & 0xc0) == (0x80 | MODE2)) {
! 433: /*
! 434: * CS4231 or AD1845 detected - is it?
! 435: *
! 436: * Verify that setting I2 doesn't change I18.
! 437: */
! 438: ad_write(sc, 18, 0x88); /* Set I18 to known value */
! 439:
! 440: ad_write(sc, 2, 0x45);
! 441: if ((tmp2 = ad_read(sc, 18)) != 0x45) { /* No change -> CS4231? */
! 442: ad_write(sc, 2, 0xaa);
! 443: if ((tmp2 = ad_read(sc, 18)) == 0xaa) { /* Rotten bits? */
! 444: DPRINTF(("ad_detect_H(%x)\n", tmp2));
! 445: goto bad;
! 446: }
! 447:
! 448: /*
! 449: * It's a CS4231, or another clone with 32 registers.
! 450: * Let's find out which by checking I25.
! 451: */
! 452: if ((tmp1 & 0x8f) == 0x8a) {
! 453: tmp1 = ad_read(sc, CS_VERSION_ID);
! 454: switch (tmp1 & 0xe7) {
! 455: case 0xA0:
! 456: sc->chip_name = "CS4231A";
! 457: break;
! 458: case 0x80:
! 459: /* XXX I25 no good, AD1845 same as CS4231 */
! 460: sc->chip_name = "CS4231 or AD1845";
! 461: break;
! 462: case 0x82:
! 463: case 0xa2:
! 464: sc->chip_name = "CS4232";
! 465: break;
! 466: case 0x03:
! 467: sc->chip_name = "CS4236/CS4236B";
! 468: break;
! 469: }
! 470: }
! 471: sc->mode = 2;
! 472: }
! 473: }
! 474:
! 475: /* Wait for 1848 to init */
! 476: while(ADREAD(sc, AD1848_IADDR) & SP_IN_INIT)
! 477: ;
! 478:
! 479: /* Wait for 1848 to autocal */
! 480: ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
! 481: while(ADREAD(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG)
! 482: ;
! 483:
! 484: return 1;
! 485: bad:
! 486: return 0;
! 487: }
! 488:
! 489: /* Unmap the I/O ports */
! 490: void
! 491: ad1848_unmap(sc)
! 492: struct ad1848_softc *sc;
! 493: {
! 494: bus_space_unmap(sc->sc_iot, sc->sc_ioh, AD1848_NPORT);
! 495: }
! 496:
! 497: /*
! 498: * Attach hardware to driver, attach hardware driver to audio
! 499: * pseudo-device driver .
! 500: */
! 501: void
! 502: ad1848_attach(sc)
! 503: struct ad1848_softc *sc;
! 504: {
! 505: int i;
! 506: struct ad1848_volume vol_mid = {220, 220};
! 507: struct ad1848_volume vol_0 = {0, 0};
! 508: struct audio_params pparams, rparams;
! 509: int timeout;
! 510:
! 511: sc->sc_locked = 0;
! 512: sc->sc_playrun = NOTRUNNING;
! 513: sc->sc_recrun = NOTRUNNING;
! 514:
! 515: if (sc->sc_drq != -1) {
! 516: if (isa_dmamap_create(sc->sc_isa, sc->sc_drq, MAX_ISADMA,
! 517: BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 518: printf("ad1848_attach: can't create map for drq %d\n",
! 519: sc->sc_drq);
! 520: return;
! 521: }
! 522: }
! 523: if (sc->sc_recdrq != -1 && sc->sc_recdrq != sc->sc_drq) {
! 524: if (isa_dmamap_create(sc->sc_isa, sc->sc_recdrq, MAX_ISADMA,
! 525: BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 526: printf("ad1848_attach: can't creape map for drq %d\n",
! 527: sc->sc_recdrq);
! 528: return;
! 529: }
! 530: }
! 531:
! 532: /* Initialize the ad1848... */
! 533: for (i = 0; i < 0x10; i++) {
! 534: ad_write(sc, i, ad1848_init_values[i]);
! 535: timeout = 100000;
! 536: while (timeout > 0 && ad_read(sc, AD1848_IADDR) & SP_IN_INIT)
! 537: timeout--;
! 538: }
! 539: /* ...and additional CS4231 stuff too */
! 540: if (sc->mode == 2) {
! 541: ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */
! 542: for (i = 0x10; i < 0x20; i++)
! 543: if (ad1848_init_values[i] != 0) {
! 544: ad_write(sc, i, ad1848_init_values[i]);
! 545: timeout = 100000;
! 546: while (timeout > 0 &&
! 547: ad_read(sc, AD1848_IADDR) & SP_IN_INIT)
! 548: timeout--;
! 549: }
! 550: }
! 551: ad1848_reset(sc);
! 552:
! 553: pparams = audio_default;
! 554: rparams = audio_default;
! 555: (void) ad1848_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
! 556:
! 557: /* Set default gains */
! 558: (void) ad1848_set_rec_gain(sc, &vol_mid);
! 559: (void) ad1848_set_channel_gain(sc, AD1848_DAC_CHANNEL, &vol_mid);
! 560: (void) ad1848_set_channel_gain(sc, AD1848_MONITOR_CHANNEL, &vol_0);
! 561: (void) ad1848_set_channel_gain(sc, AD1848_AUX1_CHANNEL, &vol_mid); /* CD volume */
! 562: if (sc->mode == 2) {
! 563: (void) ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_mid); /* CD volume */
! 564: (void) ad1848_set_channel_gain(sc, AD1848_LINE_CHANNEL, &vol_mid);
! 565: (void) ad1848_set_channel_gain(sc, AD1848_MONO_CHANNEL, &vol_0);
! 566: sc->mute[AD1848_MONO_CHANNEL] = MUTE_ALL;
! 567: } else
! 568: (void) ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_0);
! 569:
! 570: /* Set default port */
! 571: (void) ad1848_set_rec_port(sc, MIC_IN_PORT);
! 572:
! 573: if (sc->chip_name)
! 574: printf(": %s", sc->chip_name);
! 575: #undef WAITREADY
! 576: }
! 577:
! 578: /*
! 579: * Various routines to interface to higher level audio driver
! 580: */
! 581: struct ad1848_mixerinfo {
! 582: int left_reg;
! 583: int right_reg;
! 584: int atten_bits;
! 585: int atten_mask;
! 586: } mixer_channel_info[] =
! 587: { { SP_LEFT_AUX2_CONTROL, SP_RIGHT_AUX2_CONTROL, AUX_INPUT_ATTEN_BITS,
! 588: AUX_INPUT_ATTEN_MASK },
! 589: { SP_LEFT_AUX1_CONTROL, SP_RIGHT_AUX1_CONTROL, AUX_INPUT_ATTEN_BITS,
! 590: AUX_INPUT_ATTEN_MASK },
! 591: { SP_LEFT_OUTPUT_CONTROL, SP_RIGHT_OUTPUT_CONTROL,
! 592: OUTPUT_ATTEN_BITS, OUTPUT_ATTEN_MASK },
! 593: { CS_LEFT_LINE_CONTROL, CS_RIGHT_LINE_CONTROL, LINE_INPUT_ATTEN_BITS,
! 594: LINE_INPUT_ATTEN_MASK },
! 595: { CS_MONO_IO_CONTROL, 0, MONO_INPUT_ATTEN_BITS, MONO_INPUT_ATTEN_MASK },
! 596: { SP_DIGITAL_MIX, 0, OUTPUT_ATTEN_BITS, MIX_ATTEN_MASK }
! 597: };
! 598:
! 599: /*
! 600: * This function doesn't set the mute flags but does use them.
! 601: * The mute flags reflect the mutes that have been applied by the user.
! 602: * However, the driver occasionally wants to mute devices (e.g. when chaing
! 603: * sampling rate). These operations should not affect the mute flags.
! 604: */
! 605:
! 606: void
! 607: ad1848_mute_channel(sc, device, mute)
! 608: struct ad1848_softc *sc;
! 609: int device;
! 610: int mute;
! 611: {
! 612: u_char reg;
! 613:
! 614: reg = ad_read(sc, mixer_channel_info[device].left_reg);
! 615:
! 616: if (mute & MUTE_LEFT) {
! 617: if (device == AD1848_MONITOR_CHANNEL)
! 618: ad_write(sc, mixer_channel_info[device].left_reg, reg & 0xFE);
! 619: else
! 620: ad_write(sc, mixer_channel_info[device].left_reg, reg | 0x80);
! 621: } else if (!(sc->mute[device] & MUTE_LEFT)) {
! 622: if (device == AD1848_MONITOR_CHANNEL)
! 623: ad_write(sc, mixer_channel_info[device].left_reg, reg | 0x01);
! 624: else
! 625: ad_write(sc, mixer_channel_info[device].left_reg, reg & ~0x80);
! 626: }
! 627:
! 628: if (!mixer_channel_info[device].right_reg) {
! 629: return;
! 630: }
! 631:
! 632: reg = ad_read(sc, mixer_channel_info[device].right_reg);
! 633:
! 634: if (mute & MUTE_RIGHT)
! 635: ad_write(sc, mixer_channel_info[device].right_reg, reg | 0x80);
! 636: else if (!(sc->mute[device] & MUTE_RIGHT)) {
! 637: ad_write(sc, mixer_channel_info[device].right_reg, reg & ~0x80);
! 638: }
! 639: }
! 640:
! 641:
! 642: int
! 643: ad1848_set_channel_gain(sc, device, gp)
! 644: struct ad1848_softc *sc;
! 645: int device;
! 646: struct ad1848_volume *gp;
! 647: {
! 648: struct ad1848_mixerinfo *info = &mixer_channel_info[device];
! 649: u_char reg;
! 650: u_int atten;
! 651:
! 652: sc->gains[device] = *gp;
! 653:
! 654: atten = ((AUDIO_MAX_GAIN - gp->left) * info->atten_bits)/AUDIO_MAX_GAIN;
! 655:
! 656: reg = ad_read(sc, info->left_reg) & (info->atten_mask);
! 657: if (device == AD1848_MONITOR_CHANNEL)
! 658: reg |= ((atten & info->atten_bits) << 2);
! 659: else
! 660: reg |= ((atten & info->atten_bits));
! 661:
! 662: ad_write(sc, info->left_reg, reg);
! 663:
! 664: if (!info->right_reg)
! 665: return (0);
! 666:
! 667: atten = ((AUDIO_MAX_GAIN - gp->right) * info->atten_bits)/AUDIO_MAX_GAIN;
! 668: reg = ad_read(sc, info->right_reg);
! 669: reg &= (info->atten_mask);
! 670: ad_write(sc, info->right_reg, (atten& info->atten_bits)|reg);
! 671:
! 672: return(0);
! 673: }
! 674:
! 675:
! 676: int
! 677: ad1848_get_device_gain(sc, device, gp)
! 678: struct ad1848_softc *sc;
! 679: int device;
! 680: struct ad1848_volume *gp;
! 681: {
! 682: *gp = sc->gains[device];
! 683: return(0);
! 684: }
! 685:
! 686: int
! 687: ad1848_get_rec_gain(sc, gp)
! 688: struct ad1848_softc *sc;
! 689: struct ad1848_volume *gp;
! 690: {
! 691: *gp = sc->rec_gain;
! 692: return(0);
! 693: }
! 694:
! 695: int
! 696: ad1848_set_rec_gain(sc, gp)
! 697: struct ad1848_softc *sc;
! 698: struct ad1848_volume *gp;
! 699: {
! 700: u_char reg, gain;
! 701:
! 702: DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right));
! 703:
! 704: sc->rec_gain = *gp;
! 705:
! 706: gain = (gp->left * GAIN_22_5)/AUDIO_MAX_GAIN;
! 707: reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
! 708: reg &= INPUT_GAIN_MASK;
! 709: ad_write(sc, SP_LEFT_INPUT_CONTROL, (gain&0x0f)|reg);
! 710:
! 711: gain = (gp->right * GAIN_22_5)/AUDIO_MAX_GAIN;
! 712: reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
! 713: reg &= INPUT_GAIN_MASK;
! 714: ad_write(sc, SP_RIGHT_INPUT_CONTROL, (gain&0x0f)|reg);
! 715:
! 716: return(0);
! 717: }
! 718:
! 719:
! 720: void
! 721: ad1848_mute_monitor(addr, mute)
! 722: void *addr;
! 723: int mute;
! 724: {
! 725: struct ad1848_softc *sc = addr;
! 726:
! 727: DPRINTF(("ad1848_mute_monitor: %smuting\n", mute ? "" : "un"));
! 728: if (sc->mode == 2) {
! 729: ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, mute ? MUTE_ALL : 0);
! 730: ad1848_mute_channel(sc, AD1848_MONO_CHANNEL, mute ? MUTE_MONO : 0);
! 731: ad1848_mute_channel(sc, AD1848_LINE_CHANNEL, mute ? MUTE_ALL : 0);
! 732: }
! 733:
! 734: ad1848_mute_channel(sc, AD1848_AUX2_CHANNEL, mute ? MUTE_ALL : 0);
! 735: ad1848_mute_channel(sc, AD1848_AUX1_CHANNEL, mute ? MUTE_ALL : 0);
! 736: }
! 737:
! 738: int
! 739: ad1848_set_mic_gain(sc, gp)
! 740: struct ad1848_softc *sc;
! 741: struct ad1848_volume *gp;
! 742: {
! 743: u_char reg;
! 744:
! 745: DPRINTF(("cs4231_set_mic_gain: %d\n", gp->left));
! 746:
! 747: if (gp->left > AUDIO_MAX_GAIN/2) {
! 748: sc->mic_gain_on = 1;
! 749: reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
! 750: ad_write(sc, SP_LEFT_INPUT_CONTROL, reg | INPUT_MIC_GAIN_ENABLE);
! 751: } else {
! 752: sc->mic_gain_on = 0;
! 753: reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
! 754: ad_write(sc, SP_LEFT_INPUT_CONTROL, reg & ~INPUT_MIC_GAIN_ENABLE);
! 755: }
! 756:
! 757: return(0);
! 758: }
! 759:
! 760: int
! 761: ad1848_get_mic_gain(sc, gp)
! 762: struct ad1848_softc *sc;
! 763: struct ad1848_volume *gp;
! 764: {
! 765: if (sc->mic_gain_on)
! 766: gp->left = gp->right = AUDIO_MAX_GAIN;
! 767: else
! 768: gp->left = gp->right = AUDIO_MIN_GAIN;
! 769: return(0);
! 770: }
! 771:
! 772:
! 773: static ad1848_devmap_t *ad1848_mixer_find_dev(ad1848_devmap_t *, int, mixer_ctrl_t *);
! 774:
! 775: static ad1848_devmap_t *
! 776: ad1848_mixer_find_dev(map, cnt, cp)
! 777: ad1848_devmap_t *map;
! 778: int cnt;
! 779: mixer_ctrl_t *cp;
! 780:
! 781: {
! 782: int idx;
! 783:
! 784: for (idx = 0; idx < cnt; idx++) {
! 785: if (map[idx].id == cp->dev) {
! 786: return (&map[idx]);
! 787: }
! 788: }
! 789: return (NULL);
! 790: }
! 791:
! 792: int
! 793: ad1848_mixer_get_port(ac, map, cnt, cp)
! 794: struct ad1848_softc *ac;
! 795: struct ad1848_devmap *map;
! 796: int cnt;
! 797: mixer_ctrl_t *cp;
! 798: {
! 799: ad1848_devmap_t *entry;
! 800: struct ad1848_volume vol;
! 801: int error = EINVAL;
! 802: int dev;
! 803:
! 804: if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
! 805: return (ENXIO);
! 806:
! 807: dev = entry->dev;
! 808:
! 809: switch (entry->kind) {
! 810: case AD1848_KIND_LVL:
! 811: if (cp->type != AUDIO_MIXER_VALUE)
! 812: break;
! 813:
! 814: if (dev < AD1848_AUX2_CHANNEL ||
! 815: dev > AD1848_MONITOR_CHANNEL)
! 816: break;
! 817:
! 818: if (cp->un.value.num_channels != 1 &&
! 819: mixer_channel_info[dev].right_reg == 0)
! 820: break;
! 821:
! 822: error = ad1848_get_device_gain(ac, dev, &vol);
! 823: if (!error)
! 824: ad1848_from_vol(cp, &vol);
! 825:
! 826: break;
! 827:
! 828: case AD1848_KIND_MUTE:
! 829: if (cp->type != AUDIO_MIXER_ENUM) break;
! 830:
! 831: cp->un.ord = ac->mute[dev] ? 1 : 0;
! 832: error = 0;
! 833: break;
! 834:
! 835: case AD1848_KIND_RECORDGAIN:
! 836: if (cp->type != AUDIO_MIXER_VALUE) break;
! 837:
! 838: error = ad1848_get_rec_gain(ac, &vol);
! 839: if (!error)
! 840: ad1848_from_vol(cp, &vol);
! 841:
! 842: break;
! 843:
! 844: case AD1848_KIND_MICGAIN:
! 845: if (cp->type != AUDIO_MIXER_VALUE) break;
! 846:
! 847: error = ad1848_get_mic_gain(ac, &vol);
! 848: if (!error)
! 849: ad1848_from_vol(cp, &vol);
! 850:
! 851: break;
! 852:
! 853: case AD1848_KIND_RECORDSOURCE:
! 854: if (cp->type != AUDIO_MIXER_ENUM) break;
! 855: cp->un.ord = ad1848_get_rec_port(ac);
! 856: error = 0;
! 857: break;
! 858: default:
! 859: printf ("Invalid kind\n");
! 860: break;
! 861: }
! 862:
! 863: return (error);
! 864: }
! 865:
! 866: int
! 867: ad1848_mixer_set_port(ac, map, cnt, cp)
! 868: struct ad1848_softc *ac;
! 869: struct ad1848_devmap *map;
! 870: int cnt;
! 871: mixer_ctrl_t *cp;
! 872: {
! 873: ad1848_devmap_t *entry;
! 874: struct ad1848_volume vol;
! 875: int error = EINVAL;
! 876: int dev;
! 877:
! 878: if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
! 879: return (ENXIO);
! 880:
! 881: dev = entry->dev;
! 882:
! 883: switch (entry->kind) {
! 884: case AD1848_KIND_LVL:
! 885: if (cp->type != AUDIO_MIXER_VALUE)
! 886: break;
! 887:
! 888: if (dev < AD1848_AUX2_CHANNEL ||
! 889: dev > AD1848_MONITOR_CHANNEL)
! 890: break;
! 891:
! 892: if (cp->un.value.num_channels != 1 &&
! 893: mixer_channel_info[dev].right_reg == 0)
! 894: break;
! 895:
! 896: ad1848_to_vol(cp, &vol);
! 897: error = ad1848_set_channel_gain(ac, dev, &vol);
! 898: break;
! 899:
! 900: case AD1848_KIND_MUTE:
! 901: if (cp->type != AUDIO_MIXER_ENUM) break;
! 902:
! 903: ac->mute[dev] = (cp->un.ord ? MUTE_ALL : 0);
! 904: ad1848_mute_channel(ac, dev, ac->mute[dev]);
! 905: error = 0;
! 906: break;
! 907:
! 908: case AD1848_KIND_RECORDGAIN:
! 909: if (cp->type != AUDIO_MIXER_VALUE) break;
! 910:
! 911: ad1848_to_vol(cp, &vol);
! 912: error = ad1848_set_rec_gain(ac, &vol);
! 913: break;
! 914:
! 915: case AD1848_KIND_MICGAIN:
! 916: if (cp->type != AUDIO_MIXER_VALUE) break;
! 917:
! 918: ad1848_to_vol(cp, &vol);
! 919: error = ad1848_set_mic_gain(ac, &vol);
! 920: break;
! 921:
! 922: case AD1848_KIND_RECORDSOURCE:
! 923: if (cp->type != AUDIO_MIXER_ENUM) break;
! 924:
! 925: error = ad1848_set_rec_port(ac, cp->un.ord);
! 926: break;
! 927: default:
! 928: printf ("Invalid kind\n");
! 929: break;
! 930: }
! 931:
! 932: return (error);
! 933: }
! 934:
! 935:
! 936: int
! 937: ad1848_query_encoding(addr, fp)
! 938: void *addr;
! 939: struct audio_encoding *fp;
! 940: {
! 941: struct ad1848_softc *sc = addr;
! 942:
! 943: switch (fp->index) {
! 944: case 0:
! 945: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 946: fp->encoding = AUDIO_ENCODING_ULAW;
! 947: fp->precision = 8;
! 948: fp->flags = 0;
! 949: break;
! 950: case 1:
! 951: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 952: fp->encoding = AUDIO_ENCODING_ALAW;
! 953: fp->precision = 8;
! 954: fp->flags = 0;
! 955: break;
! 956: case 2:
! 957: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 958: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 959: fp->precision = 16;
! 960: fp->flags = 0;
! 961: break;
! 962: case 3:
! 963: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 964: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 965: fp->precision = 8;
! 966: fp->flags = 0;
! 967: break;
! 968:
! 969: case 4: /* only on CS4231 */
! 970: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 971: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 972: fp->precision = 16;
! 973: fp->flags = sc->mode == 1 ? AUDIO_ENCODINGFLAG_EMULATED : 0;
! 974: break;
! 975:
! 976: /* emulate some modes */
! 977: case 5:
! 978: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 979: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 980: fp->precision = 8;
! 981: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 982: break;
! 983: case 6:
! 984: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 985: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 986: fp->precision = 16;
! 987: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 988: break;
! 989: case 7:
! 990: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 991: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 992: fp->precision = 16;
! 993: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 994: break;
! 995:
! 996: case 8: /* only on CS4231 */
! 997: if (sc->mode == 1)
! 998: return EINVAL;
! 999: strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
! 1000: fp->encoding = AUDIO_ENCODING_ADPCM;
! 1001: fp->precision = 8;
! 1002: fp->flags = 0;
! 1003: break;
! 1004: default:
! 1005: return EINVAL;
! 1006: /*NOTREACHED*/
! 1007: }
! 1008: return (0);
! 1009: }
! 1010:
! 1011: int
! 1012: ad1848_set_params(addr, setmode, usemode, p, r)
! 1013: void *addr;
! 1014: int setmode, usemode;
! 1015: struct audio_params *p, *r;
! 1016: {
! 1017: struct ad1848_softc *sc = addr;
! 1018: int error, bits, enc;
! 1019: void (*pswcode)(void *, u_char *buf, int cnt);
! 1020: void (*rswcode)(void *, u_char *buf, int cnt);
! 1021:
! 1022: DPRINTF(("ad1848_set_params: %d %d %d %ld\n",
! 1023: p->encoding, p->precision, p->channels, p->sample_rate));
! 1024:
! 1025: enc = p->encoding;
! 1026: pswcode = rswcode = 0;
! 1027: switch (enc) {
! 1028: case AUDIO_ENCODING_SLINEAR_LE:
! 1029: if (p->precision == 8) {
! 1030: enc = AUDIO_ENCODING_ULINEAR_LE;
! 1031: pswcode = rswcode = change_sign8;
! 1032: }
! 1033: break;
! 1034: case AUDIO_ENCODING_SLINEAR_BE:
! 1035: if (p->precision == 16 && sc->mode == 1) {
! 1036: enc = AUDIO_ENCODING_SLINEAR_LE;
! 1037: pswcode = rswcode = swap_bytes;
! 1038: }
! 1039: break;
! 1040: case AUDIO_ENCODING_ULINEAR_LE:
! 1041: if (p->precision == 16) {
! 1042: enc = AUDIO_ENCODING_SLINEAR_LE;
! 1043: pswcode = rswcode = change_sign16;
! 1044: }
! 1045: break;
! 1046: case AUDIO_ENCODING_ULINEAR_BE:
! 1047: if (p->precision == 16) {
! 1048: enc = AUDIO_ENCODING_SLINEAR_LE;
! 1049: pswcode = swap_bytes_change_sign16;
! 1050: rswcode = change_sign16_swap_bytes;
! 1051: }
! 1052: break;
! 1053: }
! 1054: switch (enc) {
! 1055: case AUDIO_ENCODING_ULAW:
! 1056: bits = FMT_ULAW >> 5;
! 1057: break;
! 1058: case AUDIO_ENCODING_ALAW:
! 1059: bits = FMT_ALAW >> 5;
! 1060: break;
! 1061: case AUDIO_ENCODING_ADPCM:
! 1062: bits = FMT_ADPCM >> 5;
! 1063: break;
! 1064: case AUDIO_ENCODING_SLINEAR_LE:
! 1065: if (p->precision == 16)
! 1066: bits = FMT_TWOS_COMP >> 5;
! 1067: else
! 1068: return EINVAL;
! 1069: break;
! 1070: case AUDIO_ENCODING_SLINEAR_BE:
! 1071: if (p->precision == 16)
! 1072: bits = FMT_TWOS_COMP_BE >> 5;
! 1073: else
! 1074: return EINVAL;
! 1075: break;
! 1076: case AUDIO_ENCODING_ULINEAR_LE:
! 1077: if (p->precision == 8)
! 1078: bits = FMT_PCM8 >> 5;
! 1079: else
! 1080: return EINVAL;
! 1081: break;
! 1082: default:
! 1083: return EINVAL;
! 1084: }
! 1085:
! 1086: if (p->channels < 1 || p->channels > 2)
! 1087: return EINVAL;
! 1088:
! 1089: error = ad1848_set_speed(sc, &p->sample_rate);
! 1090: if (error)
! 1091: return error;
! 1092:
! 1093: p->sw_code = pswcode;
! 1094: r->sw_code = rswcode;
! 1095:
! 1096: sc->format_bits = bits;
! 1097: sc->channels = p->channels;
! 1098: sc->precision = p->precision;
! 1099: sc->need_commit = 1;
! 1100:
! 1101: DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits));
! 1102: return (0);
! 1103: }
! 1104:
! 1105: int
! 1106: ad1848_set_rec_port(sc, port)
! 1107: struct ad1848_softc *sc;
! 1108: int port;
! 1109: {
! 1110: u_char inp, reg;
! 1111:
! 1112: DPRINTF(("ad1848_set_rec_port: 0x%x\n", port));
! 1113:
! 1114: if (port == MIC_IN_PORT) {
! 1115: inp = MIC_INPUT;
! 1116: }
! 1117: else if (port == LINE_IN_PORT) {
! 1118: inp = LINE_INPUT;
! 1119: }
! 1120: else if (port == DAC_IN_PORT) {
! 1121: inp = MIXED_DAC_INPUT;
! 1122: }
! 1123: else if (sc->mode == 2 && port == AUX1_IN_PORT) {
! 1124: inp = AUX_INPUT;
! 1125: }
! 1126: else
! 1127: return(EINVAL);
! 1128:
! 1129: reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
! 1130: reg &= INPUT_SOURCE_MASK;
! 1131: ad_write(sc, SP_LEFT_INPUT_CONTROL, (inp|reg));
! 1132:
! 1133: reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
! 1134: reg &= INPUT_SOURCE_MASK;
! 1135: ad_write(sc, SP_RIGHT_INPUT_CONTROL, (inp|reg));
! 1136:
! 1137: sc->rec_port = port;
! 1138:
! 1139: return(0);
! 1140: }
! 1141:
! 1142: int
! 1143: ad1848_get_rec_port(sc)
! 1144: struct ad1848_softc *sc;
! 1145: {
! 1146: return(sc->rec_port);
! 1147: }
! 1148:
! 1149: int
! 1150: ad1848_round_blocksize(addr, blk)
! 1151: void *addr;
! 1152: int blk;
! 1153: {
! 1154: struct ad1848_softc *sc = addr;
! 1155:
! 1156: sc->sc_lastcc = -1;
! 1157:
! 1158: /* Round to a multiple of the biggest sample size. */
! 1159: blk = (blk + 3) & -4;
! 1160:
! 1161: return (blk);
! 1162: }
! 1163:
! 1164: int
! 1165: ad1848_open(addr, flags)
! 1166: void *addr;
! 1167: int flags;
! 1168: {
! 1169: struct ad1848_softc *sc = addr;
! 1170:
! 1171: DPRINTF(("ad1848_open: sc=%p\n", sc));
! 1172:
! 1173: sc->sc_intr = 0;
! 1174: sc->sc_lastcc = -1;
! 1175: sc->sc_locked = 0;
! 1176:
! 1177: /* Enable interrupts */
! 1178: DPRINTF(("ad1848_open: enable intrs\n"));
! 1179: ad_write(sc, SP_PIN_CONTROL, INTERRUPT_ENABLE|ad_read(sc, SP_PIN_CONTROL));
! 1180:
! 1181: #ifdef AUDIO_DEBUG
! 1182: if (ad1848debug)
! 1183: ad1848_dump_regs(sc);
! 1184: #endif
! 1185:
! 1186: return 0;
! 1187: }
! 1188:
! 1189: /*
! 1190: * Close function is called at splaudio().
! 1191: */
! 1192: void
! 1193: ad1848_close(addr)
! 1194: void *addr;
! 1195: {
! 1196: struct ad1848_softc *sc = addr;
! 1197: u_char r;
! 1198:
! 1199: sc->sc_intr = 0;
! 1200:
! 1201: DPRINTF(("ad1848_close: stop DMA\n"));
! 1202: if (sc->sc_playrun != NOTRUNNING) {
! 1203: isa_dmaabort(sc->sc_isa, sc->sc_drq);
! 1204: sc->sc_playrun = NOTRUNNING;
! 1205: }
! 1206: if (sc->sc_recrun != NOTRUNNING) {
! 1207: isa_dmaabort(sc->sc_isa, sc->sc_recdrq);
! 1208: sc->sc_recrun = NOTRUNNING;
! 1209: }
! 1210: ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)0);
! 1211: ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)0);
! 1212:
! 1213: /* Disable interrupts */
! 1214: DPRINTF(("ad1848_close: disable intrs\n"));
! 1215: ad_write(sc, SP_PIN_CONTROL,
! 1216: ad_read(sc, SP_PIN_CONTROL) & ~INTERRUPT_ENABLE);
! 1217:
! 1218: DPRINTF(("ad1848_close: disable capture and playback\n"));
! 1219: r = ad_read(sc, SP_INTERFACE_CONFIG);
! 1220: r &= ~(CAPTURE_ENABLE|PLAYBACK_ENABLE);
! 1221: ad_write(sc, SP_INTERFACE_CONFIG, r);
! 1222:
! 1223: #ifdef AUDIO_DEBUG
! 1224: if (ad1848debug)
! 1225: ad1848_dump_regs(sc);
! 1226: #endif
! 1227: }
! 1228:
! 1229: /*
! 1230: * Lower-level routines
! 1231: */
! 1232: int
! 1233: ad1848_commit_settings(addr)
! 1234: void *addr;
! 1235: {
! 1236: struct ad1848_softc *sc = addr;
! 1237: int timeout;
! 1238: u_char fs;
! 1239: int s;
! 1240:
! 1241: if (!sc->need_commit)
! 1242: return 0;
! 1243:
! 1244: s = splaudio();
! 1245:
! 1246: ad1848_mute_monitor(sc, 1);
! 1247:
! 1248: ad_set_MCE(sc, 1); /* Enables changes to the format select reg */
! 1249:
! 1250: fs = sc->speed_bits | (sc->format_bits << 5);
! 1251:
! 1252: if (sc->channels == 2)
! 1253: fs |= FMT_STEREO;
! 1254:
! 1255: ad_write(sc, SP_CLOCK_DATA_FORMAT, fs);
! 1256:
! 1257: /*
! 1258: * If mode == 2 (CS4231), set I28 also. It's the capture format register.
! 1259: */
! 1260: if (sc->mode == 2) {
! 1261: /* Gravis Ultrasound MAX SDK sources says something about errata
! 1262: * sheets, with the implication that these inb()s are necessary.
! 1263: */
! 1264: (void)ADREAD(sc, AD1848_IDATA);
! 1265: (void)ADREAD(sc, AD1848_IDATA);
! 1266: /*
! 1267: * Write to I8 starts resynchronization. Wait until it completes.
! 1268: */
! 1269: timeout = 100000;
! 1270: while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
! 1271: timeout--;
! 1272:
! 1273: ad_write(sc, CS_REC_FORMAT, fs);
! 1274: /* Gravis Ultrasound MAX SDK sources says something about errata
! 1275: * sheets, with the implication that these inb()s are necessary.
! 1276: */
! 1277: (void)ADREAD(sc, AD1848_IDATA);
! 1278: (void)ADREAD(sc, AD1848_IDATA);
! 1279: /* Now wait for resync for capture side of the house */
! 1280: }
! 1281: /*
! 1282: * Write to I8 starts resynchronization. Wait until it completes.
! 1283: */
! 1284: timeout = 100000;
! 1285: while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
! 1286: timeout--;
! 1287:
! 1288: if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
! 1289: printf("ad1848_commit: Auto calibration timed out\n");
! 1290:
! 1291: /*
! 1292: * Starts the calibration process and
! 1293: * enters playback mode after it.
! 1294: */
! 1295: ad_set_MCE(sc, 0);
! 1296: wait_for_calibration(sc);
! 1297:
! 1298: ad1848_mute_monitor(sc, 0);
! 1299:
! 1300: sc->sc_lastcc = -1;
! 1301:
! 1302: splx(s);
! 1303:
! 1304: sc->need_commit = 0;
! 1305: return 0;
! 1306: }
! 1307:
! 1308: void
! 1309: ad1848_reset(sc)
! 1310: struct ad1848_softc *sc;
! 1311: {
! 1312: u_char r;
! 1313:
! 1314: DPRINTF(("ad1848_reset\n"));
! 1315:
! 1316: /* Clear the PEN and CEN bits */
! 1317: r = ad_read(sc, SP_INTERFACE_CONFIG);
! 1318: r &= ~(CAPTURE_ENABLE|PLAYBACK_ENABLE);
! 1319: ad_write(sc, SP_INTERFACE_CONFIG, r);
! 1320:
! 1321: if (sc->mode == 2) {
! 1322: ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS);
! 1323: ADWRITE(sc, AD1848_IDATA, 0);
! 1324: }
! 1325: /* Clear interrupt status */
! 1326: ADWRITE(sc, AD1848_STATUS, 0);
! 1327: #ifdef AUDIO_DEBUG
! 1328: if (ad1848debug)
! 1329: ad1848_dump_regs(sc);
! 1330: #endif
! 1331: }
! 1332:
! 1333: int
! 1334: ad1848_set_speed(sc, argp)
! 1335: struct ad1848_softc *sc;
! 1336: u_long *argp;
! 1337: {
! 1338: /*
! 1339: * The sampling speed is encoded in the least significant nible of I8. The
! 1340: * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other
! 1341: * three bits select the divisor (indirectly):
! 1342: *
! 1343: * The available speeds are in the following table. Keep the speeds in
! 1344: * the increasing order.
! 1345: */
! 1346: typedef struct {
! 1347: int speed;
! 1348: u_char bits;
! 1349: } speed_struct;
! 1350: u_long arg = *argp;
! 1351:
! 1352: static speed_struct speed_table[] = {
! 1353: {5510, (0 << 1) | 1},
! 1354: {5510, (0 << 1) | 1},
! 1355: {6620, (7 << 1) | 1},
! 1356: {8000, (0 << 1) | 0},
! 1357: {9600, (7 << 1) | 0},
! 1358: {11025, (1 << 1) | 1},
! 1359: {16000, (1 << 1) | 0},
! 1360: {18900, (2 << 1) | 1},
! 1361: {22050, (3 << 1) | 1},
! 1362: {27420, (2 << 1) | 0},
! 1363: {32000, (3 << 1) | 0},
! 1364: {33075, (6 << 1) | 1},
! 1365: {37800, (4 << 1) | 1},
! 1366: {44100, (5 << 1) | 1},
! 1367: {48000, (6 << 1) | 0}
! 1368: };
! 1369:
! 1370: int i, n, selected = -1;
! 1371:
! 1372: n = sizeof(speed_table) / sizeof(speed_struct);
! 1373:
! 1374: if (arg < speed_table[0].speed)
! 1375: selected = 0;
! 1376: if (arg > speed_table[n - 1].speed)
! 1377: selected = n - 1;
! 1378:
! 1379: for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
! 1380: if (speed_table[i].speed == arg)
! 1381: selected = i;
! 1382: else if (speed_table[i].speed > arg) {
! 1383: int diff1, diff2;
! 1384:
! 1385: diff1 = arg - speed_table[i - 1].speed;
! 1386: diff2 = speed_table[i].speed - arg;
! 1387:
! 1388: if (diff1 < diff2)
! 1389: selected = i - 1;
! 1390: else
! 1391: selected = i;
! 1392: }
! 1393:
! 1394: if (selected == -1) {
! 1395: printf("ad1848: Can't find speed???\n");
! 1396: selected = 3;
! 1397: }
! 1398:
! 1399: sc->speed_bits = speed_table[selected].bits;
! 1400: sc->need_commit = 1;
! 1401: *argp = speed_table[selected].speed;
! 1402:
! 1403: return (0);
! 1404: }
! 1405:
! 1406: /*
! 1407: * Halt a DMA in progress.
! 1408: */
! 1409: int
! 1410: ad1848_halt_out_dma(addr)
! 1411: void *addr;
! 1412: {
! 1413: struct ad1848_softc *sc = addr;
! 1414: u_char reg;
! 1415:
! 1416: DPRINTF(("ad1848: ad1848_halt_out_dma\n"));
! 1417:
! 1418: reg = ad_read(sc, SP_INTERFACE_CONFIG);
! 1419: ad_write(sc, SP_INTERFACE_CONFIG, (reg & ~PLAYBACK_ENABLE));
! 1420: sc->sc_locked = 0;
! 1421:
! 1422: return(0);
! 1423: }
! 1424:
! 1425: int
! 1426: ad1848_halt_in_dma(addr)
! 1427: void *addr;
! 1428: {
! 1429: struct ad1848_softc *sc = addr;
! 1430: u_char reg;
! 1431:
! 1432: DPRINTF(("ad1848: ad1848_halt_in_dma\n"));
! 1433:
! 1434: reg = ad_read(sc, SP_INTERFACE_CONFIG);
! 1435: ad_write(sc, SP_INTERFACE_CONFIG, (reg & ~CAPTURE_ENABLE));
! 1436: sc->sc_locked = 0;
! 1437:
! 1438: return(0);
! 1439: }
! 1440:
! 1441: int
! 1442: ad1848_dma_init_input(addr, buf, cc)
! 1443: void *addr;
! 1444: void *buf;
! 1445: int cc;
! 1446: {
! 1447: struct ad1848_softc *sc = addr;
! 1448:
! 1449: sc->sc_recrun = DMARUNNING;
! 1450: sc->sc_dma_flags = DMAMODE_READ | DMAMODE_LOOP;
! 1451: sc->sc_dma_bp = buf;
! 1452: sc->sc_dma_cnt = cc;
! 1453: isa_dmastart(sc->sc_isa, sc->sc_recdrq, buf, cc, NULL,
! 1454: sc->sc_dma_flags, BUS_DMA_NOWAIT);
! 1455: DPRINTF(("ad1848_dma_init_input: %p %d\n", buf, cc));
! 1456: return 0;
! 1457: }
! 1458:
! 1459: /*
! 1460: * DMA input/output are called at splaudio().
! 1461: */
! 1462: int
! 1463: ad1848_dma_input(addr, p, cc, intr, arg)
! 1464: void *addr;
! 1465: void *p;
! 1466: int cc;
! 1467: void (*intr)(void *);
! 1468: void *arg;
! 1469: {
! 1470: struct ad1848_softc *sc = addr;
! 1471: u_char reg;
! 1472:
! 1473: if (sc->sc_locked) {
! 1474: DPRINTF(("ad1848_dma_input: locked\n"));
! 1475: return 0;
! 1476: }
! 1477:
! 1478: #ifdef AUDIO_DEBUG
! 1479: if (ad1848debug > 1)
! 1480: printf("ad1848_dma_input: cc=%d %p (%p)\n", cc, intr, arg);
! 1481: #endif
! 1482: sc->sc_locked = 1;
! 1483: sc->sc_intr = intr;
! 1484: sc->sc_arg = arg;
! 1485:
! 1486: switch (sc->sc_recrun) {
! 1487: case NOTRUNNING:
! 1488: sc->sc_dma_flags = DMAMODE_READ;
! 1489: sc->sc_dma_bp = p;
! 1490: sc->sc_dma_cnt = cc;
! 1491: isa_dmastart(sc->sc_isa, sc->sc_recdrq, p, cc, NULL,
! 1492: DMAMODE_READ, BUS_DMA_NOWAIT);
! 1493: goto startpcm;
! 1494: case DMARUNNING:
! 1495: sc->sc_recrun = PCMRUNNING;
! 1496: startpcm:
! 1497: if (sc->precision == 16)
! 1498: cc >>= 1;
! 1499: if (sc->channels == 2)
! 1500: cc >>= 1;
! 1501: cc--;
! 1502:
! 1503: if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_RECORD) {
! 1504: ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff));
! 1505: ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff));
! 1506:
! 1507: if (sc->mode == 2) {
! 1508: ad_write(sc, CS_LOWER_REC_CNT, (u_char)(cc & 0xff));
! 1509: ad_write(sc, CS_UPPER_REC_CNT, (u_char)((cc >> 8) & 0xff));
! 1510: }
! 1511:
! 1512: reg = ad_read(sc, SP_INTERFACE_CONFIG);
! 1513: ad_write(sc, SP_INTERFACE_CONFIG, (CAPTURE_ENABLE|reg));
! 1514:
! 1515: sc->sc_lastcc = cc;
! 1516: sc->sc_mode = AUMODE_RECORD;
! 1517: #ifdef AUDIO_DEBUG
! 1518: if (ad1848debug > 1)
! 1519: printf("ad1848_dma_input: started capture\n");
! 1520: #endif
! 1521: }
! 1522: case PCMRUNNING:
! 1523: break;
! 1524: }
! 1525:
! 1526: return 0;
! 1527: }
! 1528:
! 1529: int
! 1530: ad1848_dma_init_output(addr, buf, cc)
! 1531: void *addr;
! 1532: void *buf;
! 1533: int cc;
! 1534: {
! 1535: struct ad1848_softc *sc = addr;
! 1536:
! 1537: sc->sc_playrun = DMARUNNING;
! 1538: sc->sc_dma_flags = DMAMODE_WRITE | DMAMODE_LOOP;
! 1539: sc->sc_dma_bp = buf;
! 1540: sc->sc_dma_cnt = cc;
! 1541: isa_dmastart(sc->sc_isa, sc->sc_drq, buf, cc, NULL,
! 1542: sc->sc_dma_flags, BUS_DMA_NOWAIT);
! 1543: DPRINTF(("ad1848_dma_init_output: %p %d\n", buf, cc));
! 1544: return 0;
! 1545: }
! 1546:
! 1547: int
! 1548: ad1848_dma_output(addr, p, cc, intr, arg)
! 1549: void *addr;
! 1550: void *p;
! 1551: int cc;
! 1552: void (*intr)(void *);
! 1553: void *arg;
! 1554: {
! 1555: struct ad1848_softc *sc = addr;
! 1556: u_char reg;
! 1557:
! 1558: if (sc->sc_locked) {
! 1559: DPRINTF(("ad1848_dma_output: locked\n"));
! 1560: return 0;
! 1561: }
! 1562:
! 1563: #ifdef AUDIO_DEBUG
! 1564: if (ad1848debug > 0)
! 1565: printf("ad1848_dma_output: cc=%d at %p %p (%p)\n", cc, p, intr, arg);
! 1566: #endif
! 1567: sc->sc_locked = 1;
! 1568: sc->sc_intr = intr;
! 1569: sc->sc_arg = arg;
! 1570:
! 1571: switch (sc->sc_playrun) {
! 1572: case NOTRUNNING:
! 1573: sc->sc_dma_flags = DMAMODE_WRITE;
! 1574: sc->sc_dma_bp = p;
! 1575: sc->sc_dma_cnt = cc;
! 1576: isa_dmastart(sc->sc_isa, sc->sc_drq, p, cc, NULL,
! 1577: DMAMODE_WRITE, BUS_DMA_NOWAIT);
! 1578: goto startpcm;
! 1579: case DMARUNNING:
! 1580: sc->sc_playrun = PCMRUNNING;
! 1581: startpcm:
! 1582: if (sc->precision == 16)
! 1583: cc >>= 1;
! 1584: if (sc->channels == 2)
! 1585: cc >>= 1;
! 1586: cc--;
! 1587:
! 1588: if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_PLAY) {
! 1589: ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff));
! 1590: ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff));
! 1591:
! 1592: reg = ad_read(sc, SP_INTERFACE_CONFIG);
! 1593: ad_write(sc, SP_INTERFACE_CONFIG, (PLAYBACK_ENABLE|reg));
! 1594:
! 1595: sc->sc_lastcc = cc;
! 1596: sc->sc_mode = AUMODE_PLAY;
! 1597: }
! 1598: break;
! 1599: case PCMRUNNING:
! 1600: break;
! 1601: }
! 1602:
! 1603: return 0;
! 1604: }
! 1605:
! 1606: int
! 1607: ad1848_intr(arg)
! 1608: void *arg;
! 1609: {
! 1610: struct ad1848_softc *sc = arg;
! 1611: int retval = 0;
! 1612: u_char status;
! 1613:
! 1614: /* Get intr status */
! 1615: status = ADREAD(sc, AD1848_STATUS);
! 1616:
! 1617: #ifdef AUDIO_DEBUG
! 1618: if (ad1848debug > 1)
! 1619: printf("ad1848_intr: intr=%p status=%x\n", sc->sc_intr, status);
! 1620: #endif
! 1621: sc->sc_locked = 0;
! 1622: sc->sc_interrupts++;
! 1623:
! 1624: /* Handle interrupt */
! 1625: if (sc->sc_intr && (status & INTERRUPT_STATUS)) {
! 1626: /* ACK DMA read because it may be in a bounce buffer */
! 1627: /* XXX Do write to mask DMA ? */
! 1628: if ((sc->sc_dma_flags & DMAMODE_READ) && sc->sc_recrun == NOTRUNNING)
! 1629: isa_dmadone(sc->sc_isa, sc->sc_recdrq);
! 1630: (*sc->sc_intr)(sc->sc_arg);
! 1631: retval = 1;
! 1632: }
! 1633:
! 1634: /* clear interrupt */
! 1635: if (status & INTERRUPT_STATUS)
! 1636: ADWRITE(sc, AD1848_STATUS, 0);
! 1637:
! 1638: return(retval);
! 1639: }
! 1640:
! 1641: void *
! 1642: ad1848_malloc(addr, direction, size, pool, flags)
! 1643: void *addr;
! 1644: int direction;
! 1645: size_t size;
! 1646: int pool;
! 1647: int flags;
! 1648: {
! 1649: struct ad1848_softc *sc = addr;
! 1650: int drq;
! 1651:
! 1652: if (sc->sc_mode == AUMODE_RECORD)
! 1653: drq = sc->sc_recdrq == -1 ? sc->sc_drq : sc->sc_recdrq;
! 1654: else
! 1655: drq = sc->sc_drq;
! 1656:
! 1657: return isa_malloc(sc->sc_isa, drq, size, pool, flags);
! 1658: }
! 1659:
! 1660: void
! 1661: ad1848_free(addr, ptr, pool)
! 1662: void *addr;
! 1663: void *ptr;
! 1664: int pool;
! 1665: {
! 1666: isa_free(ptr, pool);
! 1667: }
! 1668:
! 1669: size_t
! 1670: ad1848_round(addr, direction, size)
! 1671: void *addr;
! 1672: int direction;
! 1673: size_t size;
! 1674: {
! 1675: if (size > MAX_ISADMA)
! 1676: size = MAX_ISADMA;
! 1677: return size;
! 1678: }
! 1679:
! 1680: paddr_t
! 1681: ad1848_mappage(addr, mem, off, prot)
! 1682: void *addr;
! 1683: void *mem;
! 1684: off_t off;
! 1685: int prot;
! 1686: {
! 1687: return isa_mappage(mem, off, prot);
! 1688: }
! 1689:
! 1690: int
! 1691: ad1848_get_props(addr)
! 1692: void *addr;
! 1693: {
! 1694: struct ad1848_softc *sc = addr;
! 1695:
! 1696: return AUDIO_PROP_MMAP |
! 1697: (sc->sc_drq != sc->sc_recdrq ? AUDIO_PROP_FULLDUPLEX : 0);
! 1698: }
CVSweb