Annotation of sys/dev/pci/cmpci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cmpci.c,v 1.14 2006/07/27 00:45:59 brad Exp $ */
! 2: /* $NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Takuya SHIOZAKI <tshiozak@NetBSD.org> .
! 10: *
! 11: * This code is derived from software contributed to The NetBSD Foundation
! 12: * by ITOH Yasufumi.
! 13: *
! 14: * Redistribution and use in source and binary forms, with or without
! 15: * modification, are permitted provided that the following conditions
! 16: * are met:
! 17: * 1. Redistributions of source code must retain the above copyright
! 18: * notice, this list of conditions and the following disclaimer.
! 19: * 2. Redistributions in binary form must reproduce the above copyright
! 20: * notice, this list of conditions and the following disclaimer in the
! 21: * documentation and/or other materials provided with the distribution.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: */
! 36:
! 37: /*
! 38: * C-Media CMI8x38 Audio Chip Support.
! 39: *
! 40: * TODO:
! 41: * - 4ch / 6ch support.
! 42: * - Joystick support.
! 43: *
! 44: */
! 45:
! 46: #if 0
! 47: #include <sys/cdefs.h>
! 48: __KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $");
! 49: #endif
! 50:
! 51: #if defined(AUDIO_DEBUG) || defined(DEBUG)
! 52: #define DPRINTF(x) if (cmpcidebug) printf x
! 53: int cmpcidebug = 0;
! 54: #else
! 55: #define DPRINTF(x)
! 56: #endif
! 57:
! 58: #include <sys/param.h>
! 59: #include <sys/systm.h>
! 60: #include <sys/kernel.h>
! 61: #include <sys/malloc.h>
! 62: #include <sys/device.h>
! 63: #include <sys/proc.h>
! 64:
! 65: #include <dev/pci/pcidevs.h>
! 66: #include <dev/pci/pcivar.h>
! 67:
! 68: #include <sys/audioio.h>
! 69: #include <dev/audio_if.h>
! 70: #include <dev/midi_if.h>
! 71:
! 72: #include <dev/mulaw.h>
! 73: #include <dev/auconv.h>
! 74: #include <dev/pci/cmpcireg.h>
! 75: #include <dev/pci/cmpcivar.h>
! 76:
! 77: #include <dev/ic/mpuvar.h>
! 78: #include <machine/bus.h>
! 79: #include <machine/intr.h>
! 80:
! 81: /*
! 82: * Low-level HW interface
! 83: */
! 84: __inline uint8_t cmpci_mixerreg_read(struct cmpci_softc *,
! 85: uint8_t);
! 86: __inline void cmpci_mixerreg_write(struct cmpci_softc *,
! 87: uint8_t, uint8_t);
! 88: __inline void cmpci_reg_partial_write_1(struct cmpci_softc *,
! 89: int, int,
! 90: unsigned, unsigned);
! 91: __inline void cmpci_reg_partial_write_4(struct cmpci_softc *,
! 92: int, int,
! 93: uint32_t, uint32_t);
! 94: __inline void cmpci_reg_set_1(struct cmpci_softc *,
! 95: int, uint8_t);
! 96: __inline void cmpci_reg_clear_1(struct cmpci_softc *,
! 97: int, uint8_t);
! 98: __inline void cmpci_reg_set_4(struct cmpci_softc *,
! 99: int, uint32_t);
! 100: __inline void cmpci_reg_clear_4(struct cmpci_softc *,
! 101: int, uint32_t);
! 102: __inline void cmpci_reg_set_reg_misc(struct cmpci_softc *,
! 103: uint32_t);
! 104: __inline void cmpci_reg_clear_reg_misc(struct cmpci_softc *,
! 105: uint32_t);
! 106: int cmpci_rate_to_index(int);
! 107: __inline int cmpci_index_to_rate(int);
! 108: __inline int cmpci_index_to_divider(int);
! 109:
! 110: int cmpci_adjust(int, int);
! 111: void cmpci_set_mixer_gain(struct cmpci_softc *, int);
! 112: void cmpci_set_out_ports(struct cmpci_softc *);
! 113: int cmpci_set_in_ports(struct cmpci_softc *);
! 114:
! 115: /*
! 116: * autoconf interface
! 117: */
! 118: int cmpci_match(struct device *, void *, void *);
! 119: void cmpci_attach(struct device *, struct device *, void *);
! 120:
! 121: struct cfdriver cmpci_cd = {
! 122: NULL, "cmpci", DV_DULL
! 123: };
! 124:
! 125: struct cfattach cmpci_ca = {
! 126: sizeof (struct cmpci_softc), cmpci_match, cmpci_attach
! 127: };
! 128:
! 129: /* interrupt */
! 130: int cmpci_intr(void *);
! 131:
! 132: /*
! 133: * DMA stuff
! 134: */
! 135: int cmpci_alloc_dmamem(struct cmpci_softc *,
! 136: size_t, int,
! 137: int, caddr_t *);
! 138: int cmpci_free_dmamem(struct cmpci_softc *, caddr_t,
! 139: int);
! 140: struct cmpci_dmanode * cmpci_find_dmamem(struct cmpci_softc *,
! 141: caddr_t);
! 142:
! 143: /*
! 144: * Interface to machine independent layer
! 145: */
! 146: int cmpci_open(void *, int);
! 147: void cmpci_close(void *);
! 148: int cmpci_query_encoding(void *, struct audio_encoding *);
! 149: int cmpci_set_params(void *, int, int,
! 150: struct audio_params *,
! 151: struct audio_params *);
! 152: int cmpci_round_blocksize(void *, int);
! 153: int cmpci_halt_output(void *);
! 154: int cmpci_halt_input(void *);
! 155: int cmpci_getdev(void *, struct audio_device *);
! 156: int cmpci_set_port(void *, mixer_ctrl_t *);
! 157: int cmpci_get_port(void *, mixer_ctrl_t *);
! 158: int cmpci_query_devinfo(void *, mixer_devinfo_t *);
! 159: void *cmpci_malloc(void *, int, size_t, int, int);
! 160: void cmpci_free(void *, void *, int);
! 161: size_t cmpci_round_buffersize(void *, int, size_t);
! 162: paddr_t cmpci_mappage(void *, void *, off_t, int);
! 163: int cmpci_get_props(void *);
! 164: int cmpci_trigger_output(void *, void *, void *, int,
! 165: void (*)(void *), void *,
! 166: struct audio_params *);
! 167: int cmpci_trigger_input(void *, void *, void *, int,
! 168: void (*)(void *), void *,
! 169: struct audio_params *);
! 170:
! 171: struct audio_hw_if cmpci_hw_if = {
! 172: cmpci_open, /* open */
! 173: cmpci_close, /* close */
! 174: NULL, /* drain */
! 175: cmpci_query_encoding, /* query_encoding */
! 176: cmpci_set_params, /* set_params */
! 177: cmpci_round_blocksize, /* round_blocksize */
! 178: NULL, /* commit_settings */
! 179: NULL, /* init_output */
! 180: NULL, /* init_input */
! 181: NULL, /* start_output */
! 182: NULL, /* start_input */
! 183: cmpci_halt_output, /* halt_output */
! 184: cmpci_halt_input, /* halt_input */
! 185: NULL, /* speaker_ctl */
! 186: cmpci_getdev, /* getdev */
! 187: NULL, /* setfd */
! 188: cmpci_set_port, /* set_port */
! 189: cmpci_get_port, /* get_port */
! 190: cmpci_query_devinfo, /* query_devinfo */
! 191: cmpci_malloc, /* malloc */
! 192: cmpci_free, /* free */
! 193: cmpci_round_buffersize,/* round_buffersize */
! 194: cmpci_mappage, /* mappage */
! 195: cmpci_get_props, /* get_props */
! 196: cmpci_trigger_output, /* trigger_output */
! 197: cmpci_trigger_input, /* trigger_input */
! 198: };
! 199:
! 200: /*
! 201: * Low-level HW interface
! 202: */
! 203:
! 204: /* mixer register read/write */
! 205: __inline uint8_t
! 206: cmpci_mixerreg_read(struct cmpci_softc *sc, uint8_t no)
! 207: {
! 208: uint8_t ret;
! 209:
! 210: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no);
! 211: delay(10);
! 212: ret = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBDATA);
! 213: delay(10);
! 214: return ret;
! 215: }
! 216:
! 217: __inline void
! 218: cmpci_mixerreg_write(struct cmpci_softc *sc, uint8_t no, uint8_t val)
! 219: {
! 220: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no);
! 221: delay(10);
! 222: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBDATA, val);
! 223: delay(10);
! 224: }
! 225:
! 226: /* register partial write */
! 227: __inline void
! 228: cmpci_reg_partial_write_1(struct cmpci_softc *sc, int no, int shift,
! 229: unsigned mask, unsigned val)
! 230: {
! 231: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
! 232: (val<<shift) |
! 233: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~(mask<<shift)));
! 234: delay(10);
! 235: }
! 236:
! 237: __inline void
! 238: cmpci_reg_partial_write_4(struct cmpci_softc *sc, int no, int shift,
! 239: uint32_t mask, uint32_t val)
! 240: {
! 241: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
! 242: (val<<shift) |
! 243: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~(mask<<shift)));
! 244: delay(10);
! 245: }
! 246:
! 247: /* register set/clear bit */
! 248: __inline void
! 249: cmpci_reg_set_1(struct cmpci_softc *sc, int no, uint8_t mask)
! 250: {
! 251: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
! 252: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) | mask));
! 253: delay(10);
! 254: }
! 255:
! 256: __inline void
! 257: cmpci_reg_clear_1(struct cmpci_softc *sc, int no, uint8_t mask)
! 258: {
! 259: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
! 260: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~mask));
! 261: delay(10);
! 262: }
! 263:
! 264: __inline void
! 265: cmpci_reg_set_4(struct cmpci_softc *sc, int no, uint32_t mask)
! 266: {
! 267: /* use cmpci_reg_set_reg_misc() for CMPCI_REG_MISC */
! 268: KDASSERT(no != CMPCI_REG_MISC);
! 269:
! 270: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
! 271: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask));
! 272: delay(10);
! 273: }
! 274:
! 275: __inline void
! 276: cmpci_reg_clear_4(struct cmpci_softc *sc, int no, uint32_t mask)
! 277: {
! 278: /* use cmpci_reg_clear_reg_misc() for CMPCI_REG_MISC */
! 279: KDASSERT(no != CMPCI_REG_MISC);
! 280:
! 281: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
! 282: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask));
! 283: delay(10);
! 284: }
! 285:
! 286: /*
! 287: * The CMPCI_REG_MISC register needs special handling, since one of
! 288: * its bits has different read/write values.
! 289: */
! 290: __inline void
! 291: cmpci_reg_set_reg_misc(struct cmpci_softc *sc, uint32_t mask)
! 292: {
! 293: sc->sc_reg_misc |= mask;
! 294: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC,
! 295: sc->sc_reg_misc);
! 296: delay(10);
! 297: }
! 298:
! 299: __inline void
! 300: cmpci_reg_clear_reg_misc(struct cmpci_softc *sc, uint32_t mask)
! 301: {
! 302: sc->sc_reg_misc &= ~mask;
! 303: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC,
! 304: sc->sc_reg_misc);
! 305: delay(10);
! 306: }
! 307:
! 308: /* rate */
! 309: static const struct {
! 310: int rate;
! 311: int divider;
! 312: } cmpci_rate_table[CMPCI_REG_NUMRATE] = {
! 313: #define _RATE(n) { n, CMPCI_REG_RATE_ ## n }
! 314: _RATE(5512),
! 315: _RATE(8000),
! 316: _RATE(11025),
! 317: _RATE(16000),
! 318: _RATE(22050),
! 319: _RATE(32000),
! 320: _RATE(44100),
! 321: _RATE(48000)
! 322: #undef _RATE
! 323: };
! 324:
! 325: int
! 326: cmpci_rate_to_index(int rate)
! 327: {
! 328: int i;
! 329:
! 330: for (i = 0; i < CMPCI_REG_NUMRATE - 1; i++)
! 331: if (rate <=
! 332: (cmpci_rate_table[i].rate + cmpci_rate_table[i+1].rate) / 2)
! 333: return i;
! 334: return i; /* 48000 */
! 335: }
! 336:
! 337: __inline int
! 338: cmpci_index_to_rate(int index)
! 339: {
! 340: return cmpci_rate_table[index].rate;
! 341: }
! 342:
! 343: __inline int
! 344: cmpci_index_to_divider(int index)
! 345: {
! 346: return cmpci_rate_table[index].divider;
! 347: }
! 348:
! 349: const struct pci_matchid cmpci_devices[] = {
! 350: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338A },
! 351: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338B },
! 352: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738 },
! 353: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738B }
! 354: };
! 355:
! 356: /*
! 357: * interface to configure the device.
! 358: */
! 359:
! 360: int
! 361: cmpci_match(struct device *parent, void *match, void *aux)
! 362: {
! 363: return (pci_matchbyid((struct pci_attach_args *)aux, cmpci_devices,
! 364: sizeof(cmpci_devices)/sizeof(cmpci_devices[0])));
! 365: }
! 366:
! 367: void
! 368: cmpci_attach(struct device *parent, struct device *self, void *aux)
! 369: {
! 370: struct cmpci_softc *sc = (struct cmpci_softc *)self;
! 371: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 372: struct audio_attach_args aa;
! 373: pci_intr_handle_t ih;
! 374: char const *intrstr;
! 375: int i, v;
! 376:
! 377: sc->sc_id = pa->pa_id;
! 378: sc->sc_class = pa->pa_class;
! 379: switch (PCI_PRODUCT(sc->sc_id)) {
! 380: case PCI_PRODUCT_CMI_CMI8338A:
! 381: /*FALLTHROUGH*/
! 382: case PCI_PRODUCT_CMI_CMI8338B:
! 383: sc->sc_capable = CMPCI_CAP_CMI8338;
! 384: break;
! 385: case PCI_PRODUCT_CMI_CMI8738:
! 386: /*FALLTHROUGH*/
! 387: case PCI_PRODUCT_CMI_CMI8738B:
! 388: sc->sc_capable = CMPCI_CAP_CMI8738;
! 389: break;
! 390: }
! 391:
! 392: /* map I/O space */
! 393: if (pci_mapreg_map(pa, CMPCI_PCI_IOBASEREG, PCI_MAPREG_TYPE_IO, 0,
! 394: &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0)) {
! 395: printf(": failed to map I/O space\n");
! 396: return;
! 397: }
! 398:
! 399: /* interrupt */
! 400: if (pci_intr_map(pa, &ih)) {
! 401: printf(": failed to map interrupt\n");
! 402: return;
! 403: }
! 404: intrstr = pci_intr_string(pa->pa_pc, ih);
! 405: sc->sc_ih=pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, cmpci_intr, sc,
! 406: sc->sc_dev.dv_xname);
! 407: if (sc->sc_ih == NULL) {
! 408: printf(": failed to establish interrupt");
! 409: if (intrstr != NULL)
! 410: printf(" at %s", intrstr);
! 411: printf("\n");
! 412: return;
! 413: }
! 414: printf(": %s\n", intrstr);
! 415:
! 416: sc->sc_dmat = pa->pa_dmat;
! 417:
! 418: audio_attach_mi(&cmpci_hw_if, sc, &sc->sc_dev);
! 419:
! 420: /* attach OPL device */
! 421: aa.type = AUDIODEV_TYPE_OPL;
! 422: aa.hwif = NULL;
! 423: aa.hdl = NULL;
! 424: (void)config_found(&sc->sc_dev, &aa, audioprint);
! 425:
! 426: /* attach MPU-401 device */
! 427: aa.type = AUDIODEV_TYPE_MPU;
! 428: aa.hwif = NULL;
! 429: aa.hdl = NULL;
! 430: if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
! 431: CMPCI_REG_MPU_BASE, CMPCI_REG_MPU_SIZE, &sc->sc_mpu_ioh) == 0)
! 432: sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint);
! 433:
! 434: /* get initial value (this is 0 and may be omitted but just in case) */
! 435: sc->sc_reg_misc = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
! 436: CMPCI_REG_MISC) & ~CMPCI_REG_SPDIF48K;
! 437:
! 438: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_RESET, 0);
! 439: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0);
! 440: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0);
! 441: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX,
! 442: CMPCI_SB16_SW_CD|CMPCI_SB16_SW_MIC|CMPCI_SB16_SW_LINE);
! 443: for (i = 0; i < CMPCI_NDEVS; i++) {
! 444: switch(i) {
! 445: /*
! 446: * CMI8738 defaults are
! 447: * master: 0xe0 (0x00 - 0xf8)
! 448: * FM, DAC: 0xc0 (0x00 - 0xf8)
! 449: * PC speaker: 0x80 (0x00 - 0xc0)
! 450: * others: 0
! 451: */
! 452: /* volume */
! 453: case CMPCI_MASTER_VOL:
! 454: v = 128; /* 224 */
! 455: break;
! 456: case CMPCI_FM_VOL:
! 457: case CMPCI_DAC_VOL:
! 458: v = 192;
! 459: break;
! 460: case CMPCI_PCSPEAKER:
! 461: v = 128;
! 462: break;
! 463:
! 464: /* booleans, set to true */
! 465: case CMPCI_CD_MUTE:
! 466: case CMPCI_MIC_MUTE:
! 467: case CMPCI_LINE_IN_MUTE:
! 468: case CMPCI_AUX_IN_MUTE:
! 469: v = 1;
! 470: break;
! 471:
! 472: /* volume with inital value 0 */
! 473: case CMPCI_CD_VOL:
! 474: case CMPCI_LINE_IN_VOL:
! 475: case CMPCI_AUX_IN_VOL:
! 476: case CMPCI_MIC_VOL:
! 477: case CMPCI_MIC_RECVOL:
! 478: /* FALLTHROUGH */
! 479:
! 480: /* others are cleared */
! 481: case CMPCI_MIC_PREAMP:
! 482: case CMPCI_RECORD_SOURCE:
! 483: case CMPCI_PLAYBACK_MODE:
! 484: case CMPCI_SPDIF_IN_SELECT:
! 485: case CMPCI_SPDIF_IN_PHASE:
! 486: case CMPCI_SPDIF_LOOP:
! 487: case CMPCI_SPDIF_OUT_PLAYBACK:
! 488: case CMPCI_SPDIF_OUT_VOLTAGE:
! 489: case CMPCI_MONITOR_DAC:
! 490: case CMPCI_REAR:
! 491: case CMPCI_INDIVIDUAL:
! 492: case CMPCI_REVERSE:
! 493: case CMPCI_SURROUND:
! 494: default:
! 495: v = 0;
! 496: break;
! 497: }
! 498: sc->sc_gain[i][CMPCI_LEFT] = sc->sc_gain[i][CMPCI_RIGHT] = v;
! 499: cmpci_set_mixer_gain(sc, i);
! 500: }
! 501: }
! 502:
! 503: int
! 504: cmpci_intr(void *handle)
! 505: {
! 506: struct cmpci_softc *sc = handle;
! 507: uint32_t intrstat;
! 508:
! 509: intrstat = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
! 510: CMPCI_REG_INTR_STATUS);
! 511:
! 512: if (!(intrstat & CMPCI_REG_ANY_INTR))
! 513: return 0;
! 514:
! 515: delay(10);
! 516:
! 517: /* disable and reset intr */
! 518: if (intrstat & CMPCI_REG_CH0_INTR)
! 519: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL,
! 520: CMPCI_REG_CH0_INTR_ENABLE);
! 521: if (intrstat & CMPCI_REG_CH1_INTR)
! 522: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL,
! 523: CMPCI_REG_CH1_INTR_ENABLE);
! 524:
! 525: if (intrstat & CMPCI_REG_CH0_INTR) {
! 526: if (sc->sc_play.intr != NULL)
! 527: (*sc->sc_play.intr)(sc->sc_play.intr_arg);
! 528: }
! 529: if (intrstat & CMPCI_REG_CH1_INTR) {
! 530: if (sc->sc_rec.intr != NULL)
! 531: (*sc->sc_rec.intr)(sc->sc_rec.intr_arg);
! 532: }
! 533:
! 534: /* enable intr */
! 535: if (intrstat & CMPCI_REG_CH0_INTR)
! 536: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL,
! 537: CMPCI_REG_CH0_INTR_ENABLE);
! 538: if (intrstat & CMPCI_REG_CH1_INTR)
! 539: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL,
! 540: CMPCI_REG_CH1_INTR_ENABLE);
! 541:
! 542: #if 0
! 543: if (intrstat & CMPCI_REG_UART_INTR && sc->sc_mpudev != NULL)
! 544: mpu_intr(sc->sc_mpudev);
! 545: #endif
! 546:
! 547: return 1;
! 548: }
! 549:
! 550: /* open/close */
! 551: int
! 552: cmpci_open(void *handle, int flags)
! 553: {
! 554: return 0;
! 555: }
! 556:
! 557: void
! 558: cmpci_close(void *handle)
! 559: {
! 560: }
! 561:
! 562: int
! 563: cmpci_query_encoding(void *handle, struct audio_encoding *fp)
! 564: {
! 565: switch (fp->index) {
! 566: case 0:
! 567: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 568: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 569: fp->precision = 8;
! 570: fp->flags = 0;
! 571: break;
! 572: case 1:
! 573: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 574: fp->encoding = AUDIO_ENCODING_ULAW;
! 575: fp->precision = 8;
! 576: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 577: break;
! 578: case 2:
! 579: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 580: fp->encoding = AUDIO_ENCODING_ALAW;
! 581: fp->precision = 8;
! 582: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 583: break;
! 584: case 3:
! 585: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 586: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 587: fp->precision = 8;
! 588: fp->flags = 0;
! 589: break;
! 590: case 4:
! 591: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 592: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 593: fp->precision = 16;
! 594: fp->flags = 0;
! 595: break;
! 596: case 5:
! 597: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 598: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 599: fp->precision = 16;
! 600: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 601: break;
! 602: case 6:
! 603: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 604: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 605: fp->precision = 16;
! 606: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 607: break;
! 608: case 7:
! 609: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 610: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 611: fp->precision = 16;
! 612: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 613: break;
! 614: default:
! 615: return EINVAL;
! 616: }
! 617: return 0;
! 618: }
! 619:
! 620: int
! 621: cmpci_set_params(void *handle, int setmode, int usemode,
! 622: struct audio_params *play, struct audio_params *rec)
! 623: {
! 624: int i;
! 625: struct cmpci_softc *sc = handle;
! 626:
! 627: for (i = 0; i < 2; i++) {
! 628: int md_format;
! 629: int md_divide;
! 630: int md_index;
! 631: int mode;
! 632: struct audio_params *p;
! 633:
! 634: switch (i) {
! 635: case 0:
! 636: mode = AUMODE_PLAY;
! 637: p = play;
! 638: break;
! 639: case 1:
! 640: mode = AUMODE_RECORD;
! 641: p = rec;
! 642: break;
! 643: default:
! 644: return EINVAL;
! 645: }
! 646:
! 647: if (!(setmode & mode))
! 648: continue;
! 649:
! 650: /* format */
! 651: p->sw_code = NULL;
! 652: switch (p->channels) {
! 653: case 1:
! 654: md_format = CMPCI_REG_FORMAT_MONO;
! 655: break;
! 656: case 2:
! 657: md_format = CMPCI_REG_FORMAT_STEREO;
! 658: break;
! 659: default:
! 660: return (EINVAL);
! 661: }
! 662: switch (p->encoding) {
! 663: case AUDIO_ENCODING_ULAW:
! 664: if (p->precision != 8)
! 665: return (EINVAL);
! 666: if (mode & AUMODE_PLAY) {
! 667: p->factor = 2;
! 668: p->sw_code = mulaw_to_slinear16_le;
! 669: md_format |= CMPCI_REG_FORMAT_16BIT;
! 670: } else {
! 671: p->sw_code = ulinear8_to_mulaw;
! 672: md_format |= CMPCI_REG_FORMAT_8BIT;
! 673: }
! 674: break;
! 675: case AUDIO_ENCODING_ALAW:
! 676: if (p->precision != 8)
! 677: return (EINVAL);
! 678: if (mode & AUMODE_PLAY) {
! 679: p->factor = 2;
! 680: p->sw_code = alaw_to_slinear16_le;
! 681: md_format |= CMPCI_REG_FORMAT_16BIT;
! 682: } else {
! 683: p->sw_code = ulinear8_to_alaw;
! 684: md_format |= CMPCI_REG_FORMAT_8BIT;
! 685: }
! 686: break;
! 687: case AUDIO_ENCODING_SLINEAR_LE:
! 688: switch (p->precision) {
! 689: case 8:
! 690: p->sw_code = change_sign8;
! 691: md_format |= CMPCI_REG_FORMAT_8BIT;
! 692: break;
! 693: case 16:
! 694: md_format |= CMPCI_REG_FORMAT_16BIT;
! 695: break;
! 696: default:
! 697: return (EINVAL);
! 698: }
! 699: break;
! 700: case AUDIO_ENCODING_SLINEAR_BE:
! 701: switch (p->precision) {
! 702: case 8:
! 703: md_format |= CMPCI_REG_FORMAT_8BIT;
! 704: p->sw_code = change_sign8;
! 705: break;
! 706: case 16:
! 707: md_format |= CMPCI_REG_FORMAT_16BIT;
! 708: p->sw_code = swap_bytes;
! 709: break;
! 710: default:
! 711: return (EINVAL);
! 712: }
! 713: break;
! 714: case AUDIO_ENCODING_ULINEAR_LE:
! 715: switch (p->precision) {
! 716: case 8:
! 717: md_format |= CMPCI_REG_FORMAT_8BIT;
! 718: break;
! 719: case 16:
! 720: md_format |= CMPCI_REG_FORMAT_16BIT;
! 721: p->sw_code = change_sign16_le;
! 722: break;
! 723: default:
! 724: return (EINVAL);
! 725: }
! 726: break;
! 727: case AUDIO_ENCODING_ULINEAR_BE:
! 728: switch (p->precision) {
! 729: case 8:
! 730: md_format |= CMPCI_REG_FORMAT_8BIT;
! 731: break;
! 732: case 16:
! 733: md_format |= CMPCI_REG_FORMAT_16BIT;
! 734: if (mode & AUMODE_PLAY)
! 735: p->sw_code =
! 736: swap_bytes_change_sign16_le;
! 737: else
! 738: p->sw_code =
! 739: change_sign16_swap_bytes_le;
! 740: break;
! 741: default:
! 742: return (EINVAL);
! 743: }
! 744: break;
! 745: default:
! 746: return (EINVAL);
! 747: }
! 748: if (mode & AUMODE_PLAY)
! 749: cmpci_reg_partial_write_4(sc,
! 750: CMPCI_REG_CHANNEL_FORMAT,
! 751: CMPCI_REG_CH0_FORMAT_SHIFT,
! 752: CMPCI_REG_CH0_FORMAT_MASK, md_format);
! 753: else
! 754: cmpci_reg_partial_write_4(sc,
! 755: CMPCI_REG_CHANNEL_FORMAT,
! 756: CMPCI_REG_CH1_FORMAT_SHIFT,
! 757: CMPCI_REG_CH1_FORMAT_MASK, md_format);
! 758: /* sample rate */
! 759: md_index = cmpci_rate_to_index(p->sample_rate);
! 760: md_divide = cmpci_index_to_divider(md_index);
! 761: p->sample_rate = cmpci_index_to_rate(md_index);
! 762: DPRINTF(("%s: sample:%d, divider=%d\n",
! 763: sc->sc_dev.dv_xname, (int)p->sample_rate, md_divide));
! 764: if (mode & AUMODE_PLAY) {
! 765: cmpci_reg_partial_write_4(sc,
! 766: CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT,
! 767: CMPCI_REG_DAC_FS_MASK, md_divide);
! 768: sc->sc_play.md_divide = md_divide;
! 769: } else {
! 770: cmpci_reg_partial_write_4(sc,
! 771: CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT,
! 772: CMPCI_REG_ADC_FS_MASK, md_divide);
! 773: sc->sc_rec.md_divide = md_divide;
! 774: }
! 775: cmpci_set_out_ports(sc);
! 776: cmpci_set_in_ports(sc);
! 777: }
! 778: return 0;
! 779: }
! 780:
! 781: /* ARGSUSED */
! 782: int
! 783: cmpci_round_blocksize(void *handle, int block)
! 784: {
! 785: return ((block + 3) & -4);
! 786: }
! 787:
! 788: int
! 789: cmpci_halt_output(void *handle)
! 790: {
! 791: struct cmpci_softc *sc = handle;
! 792: int s;
! 793:
! 794: s = splaudio();
! 795: sc->sc_play.intr = NULL;
! 796: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
! 797: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
! 798: /* wait for reset DMA */
! 799: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
! 800: delay(10);
! 801: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
! 802: splx(s);
! 803:
! 804: return 0;
! 805: }
! 806:
! 807: int
! 808: cmpci_halt_input(void *handle)
! 809: {
! 810: struct cmpci_softc *sc = handle;
! 811: int s;
! 812:
! 813: s = splaudio();
! 814: sc->sc_rec.intr = NULL;
! 815: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
! 816: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE);
! 817: /* wait for reset DMA */
! 818: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
! 819: delay(10);
! 820: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
! 821: splx(s);
! 822:
! 823: return 0;
! 824: }
! 825:
! 826: /* get audio device information */
! 827: int
! 828: cmpci_getdev(void *handle, struct audio_device *ad)
! 829: {
! 830: struct cmpci_softc *sc = handle;
! 831:
! 832: strncpy(ad->name, "CMI PCI Audio", sizeof(ad->name));
! 833: snprintf(ad->version, sizeof(ad->version), "0x%02x",
! 834: PCI_REVISION(sc->sc_class));
! 835: switch (PCI_PRODUCT(sc->sc_id)) {
! 836: case PCI_PRODUCT_CMI_CMI8338A:
! 837: strncpy(ad->config, "CMI8338A", sizeof(ad->config));
! 838: break;
! 839: case PCI_PRODUCT_CMI_CMI8338B:
! 840: strncpy(ad->config, "CMI8338B", sizeof(ad->config));
! 841: break;
! 842: case PCI_PRODUCT_CMI_CMI8738:
! 843: strncpy(ad->config, "CMI8738", sizeof(ad->config));
! 844: break;
! 845: case PCI_PRODUCT_CMI_CMI8738B:
! 846: strncpy(ad->config, "CMI8738B", sizeof(ad->config));
! 847: break;
! 848: default:
! 849: strncpy(ad->config, "unknown", sizeof(ad->config));
! 850: }
! 851:
! 852: return 0;
! 853: }
! 854:
! 855: /* mixer device information */
! 856: int
! 857: cmpci_query_devinfo(void *handle, mixer_devinfo_t *dip)
! 858: {
! 859: static const char *const mixer_port_names[] = {
! 860: AudioNdac, AudioNfmsynth, AudioNcd, AudioNline, AudioNaux,
! 861: AudioNmicrophone
! 862: };
! 863: static const char *const mixer_classes[] = {
! 864: AudioCinputs, AudioCoutputs, AudioCrecord, CmpciCplayback,
! 865: CmpciCspdif
! 866: };
! 867: struct cmpci_softc *sc = handle;
! 868: int i;
! 869:
! 870: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 871:
! 872: switch (dip->index) {
! 873: case CMPCI_INPUT_CLASS:
! 874: case CMPCI_OUTPUT_CLASS:
! 875: case CMPCI_RECORD_CLASS:
! 876: case CMPCI_PLAYBACK_CLASS:
! 877: case CMPCI_SPDIF_CLASS:
! 878: dip->type = AUDIO_MIXER_CLASS;
! 879: dip->mixer_class = dip->index;
! 880: strlcpy(dip->label.name,
! 881: mixer_classes[dip->index - CMPCI_INPUT_CLASS],
! 882: sizeof dip->label.name);
! 883: return 0;
! 884:
! 885: case CMPCI_AUX_IN_VOL:
! 886: dip->un.v.delta = 1 << (8 - CMPCI_REG_AUX_VALBITS);
! 887: goto vol1;
! 888: case CMPCI_DAC_VOL:
! 889: case CMPCI_FM_VOL:
! 890: case CMPCI_CD_VOL:
! 891: case CMPCI_LINE_IN_VOL:
! 892: case CMPCI_MIC_VOL:
! 893: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS);
! 894: vol1: dip->mixer_class = CMPCI_INPUT_CLASS;
! 895: dip->next = dip->index + 6; /* CMPCI_xxx_MUTE */
! 896: strlcpy(dip->label.name, mixer_port_names[dip->index],
! 897: sizeof dip->label.name);
! 898: dip->un.v.num_channels = (dip->index == CMPCI_MIC_VOL ? 1 : 2);
! 899: vol:
! 900: dip->type = AUDIO_MIXER_VALUE;
! 901: strlcpy(dip->un.v.units.name, AudioNvolume,
! 902: sizeof dip->un.v.units.name);
! 903: return 0;
! 904:
! 905: case CMPCI_MIC_MUTE:
! 906: dip->next = CMPCI_MIC_PREAMP;
! 907: /* FALLTHROUGH */
! 908: case CMPCI_DAC_MUTE:
! 909: case CMPCI_FM_MUTE:
! 910: case CMPCI_CD_MUTE:
! 911: case CMPCI_LINE_IN_MUTE:
! 912: case CMPCI_AUX_IN_MUTE:
! 913: dip->prev = dip->index - 6; /* CMPCI_xxx_VOL */
! 914: dip->mixer_class = CMPCI_INPUT_CLASS;
! 915: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
! 916: goto on_off;
! 917: on_off:
! 918: dip->type = AUDIO_MIXER_ENUM;
! 919: dip->un.e.num_mem = 2;
! 920: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 921: sizeof dip->un.e.member[0].label.name);
! 922: dip->un.e.member[0].ord = 0;
! 923: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 924: sizeof dip->un.e.member[1].label.name);
! 925: dip->un.e.member[1].ord = 1;
! 926: return 0;
! 927:
! 928: case CMPCI_MIC_PREAMP:
! 929: dip->mixer_class = CMPCI_INPUT_CLASS;
! 930: dip->prev = CMPCI_MIC_MUTE;
! 931: strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
! 932: goto on_off;
! 933: case CMPCI_PCSPEAKER:
! 934: dip->mixer_class = CMPCI_INPUT_CLASS;
! 935: strlcpy(dip->label.name, AudioNspeaker, sizeof dip->label.name);
! 936: dip->un.v.num_channels = 1;
! 937: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_SPEAKER_VALBITS);
! 938: goto vol;
! 939: case CMPCI_RECORD_SOURCE:
! 940: dip->mixer_class = CMPCI_RECORD_CLASS;
! 941: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
! 942: dip->type = AUDIO_MIXER_SET;
! 943: dip->un.s.num_mem = 7;
! 944: strlcpy(dip->un.s.member[0].label.name, AudioNmicrophone,
! 945: sizeof dip->un.s.member[0].label.name);
! 946: dip->un.s.member[0].mask = CMPCI_RECORD_SOURCE_MIC;
! 947: strlcpy(dip->un.s.member[1].label.name, AudioNcd,
! 948: sizeof dip->un.s.member[1].label.name);
! 949: dip->un.s.member[1].mask = CMPCI_RECORD_SOURCE_CD;
! 950: strlcpy(dip->un.s.member[2].label.name, AudioNline,
! 951: sizeof dip->un.s.member[2].label.name);
! 952: dip->un.s.member[2].mask = CMPCI_RECORD_SOURCE_LINE_IN;
! 953: strlcpy(dip->un.s.member[3].label.name, AudioNaux,
! 954: sizeof dip->un.s.member[3].label.name);
! 955: dip->un.s.member[3].mask = CMPCI_RECORD_SOURCE_AUX_IN;
! 956: strlcpy(dip->un.s.member[4].label.name, AudioNwave,
! 957: sizeof dip->un.s.member[4].label.name);
! 958: dip->un.s.member[4].mask = CMPCI_RECORD_SOURCE_WAVE;
! 959: strlcpy(dip->un.s.member[5].label.name, AudioNfmsynth,
! 960: sizeof dip->un.s.member[5].label.name);
! 961: dip->un.s.member[5].mask = CMPCI_RECORD_SOURCE_FM;
! 962: strlcpy(dip->un.s.member[6].label.name, CmpciNspdif,
! 963: sizeof dip->un.s.member[6].label.name);
! 964: dip->un.s.member[6].mask = CMPCI_RECORD_SOURCE_SPDIF;
! 965: return 0;
! 966: case CMPCI_MIC_RECVOL:
! 967: dip->mixer_class = CMPCI_RECORD_CLASS;
! 968: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
! 969: dip->un.v.num_channels = 1;
! 970: dip->un.v.delta = 1 << (8 - CMPCI_REG_ADMIC_VALBITS);
! 971: goto vol;
! 972:
! 973: case CMPCI_PLAYBACK_MODE:
! 974: dip->mixer_class = CMPCI_PLAYBACK_CLASS;
! 975: dip->type = AUDIO_MIXER_ENUM;
! 976: strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
! 977: dip->un.e.num_mem = 2;
! 978: strlcpy(dip->un.e.member[0].label.name, AudioNdac,
! 979: sizeof dip->un.e.member[0].label.name);
! 980: dip->un.e.member[0].ord = CMPCI_PLAYBACK_MODE_WAVE;
! 981: strlcpy(dip->un.e.member[1].label.name, CmpciNspdif,
! 982: sizeof dip->un.e.member[1].label.name);
! 983: dip->un.e.member[1].ord = CMPCI_PLAYBACK_MODE_SPDIF;
! 984: return 0;
! 985: case CMPCI_SPDIF_IN_SELECT:
! 986: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 987: dip->type = AUDIO_MIXER_ENUM;
! 988: dip->next = CMPCI_SPDIF_IN_PHASE;
! 989: strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
! 990: i = 0;
! 991: strlcpy(dip->un.e.member[i].label.name, CmpciNspdin1,
! 992: sizeof dip->un.e.member[i].label.name);
! 993: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN1;
! 994: if (CMPCI_ISCAP(sc, 2ND_SPDIN)) {
! 995: strlcpy(dip->un.e.member[i].label.name, CmpciNspdin2,
! 996: sizeof dip->un.e.member[i].label.name);
! 997: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN2;
! 998: }
! 999: strlcpy(dip->un.e.member[i].label.name, CmpciNspdout,
! 1000: sizeof dip->un.e.member[i].label.name);
! 1001: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDOUT;
! 1002: dip->un.e.num_mem = i;
! 1003: return 0;
! 1004: case CMPCI_SPDIF_IN_PHASE:
! 1005: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 1006: dip->prev = CMPCI_SPDIF_IN_SELECT;
! 1007: strlcpy(dip->label.name, CmpciNphase, sizeof dip->label.name);
! 1008: dip->type = AUDIO_MIXER_ENUM;
! 1009: dip->un.e.num_mem = 2;
! 1010: strlcpy(dip->un.e.member[0].label.name, CmpciNpositive,
! 1011: sizeof dip->un.e.member[0].label.name);
! 1012: dip->un.e.member[0].ord = CMPCI_SPDIF_IN_PHASE_POSITIVE;
! 1013: strlcpy(dip->un.e.member[1].label.name, CmpciNnegative,
! 1014: sizeof dip->un.e.member[1].label.name);
! 1015: dip->un.e.member[1].ord = CMPCI_SPDIF_IN_PHASE_NEGATIVE;
! 1016: return 0;
! 1017: case CMPCI_SPDIF_LOOP:
! 1018: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 1019: dip->next = CMPCI_SPDIF_OUT_PLAYBACK;
! 1020: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
! 1021: dip->type = AUDIO_MIXER_ENUM;
! 1022: dip->un.e.num_mem = 2;
! 1023: strlcpy(dip->un.e.member[0].label.name, CmpciNplayback,
! 1024: sizeof dip->un.e.member[0].label.name);
! 1025: dip->un.e.member[0].ord = CMPCI_SPDIF_LOOP_OFF;
! 1026: strlcpy(dip->un.e.member[1].label.name, CmpciNspdin,
! 1027: sizeof dip->un.e.member[1].label.name);
! 1028: dip->un.e.member[1].ord = CMPCI_SPDIF_LOOP_ON;
! 1029: return 0;
! 1030: case CMPCI_SPDIF_OUT_PLAYBACK:
! 1031: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 1032: dip->prev = CMPCI_SPDIF_LOOP;
! 1033: dip->next = CMPCI_SPDIF_OUT_VOLTAGE;
! 1034: strlcpy(dip->label.name, CmpciNplayback, sizeof dip->label.name);
! 1035: dip->type = AUDIO_MIXER_ENUM;
! 1036: dip->un.e.num_mem = 2;
! 1037: strlcpy(dip->un.e.member[0].label.name, AudioNwave,
! 1038: sizeof dip->un.e.member[0].label.name);
! 1039: dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_PLAYBACK_WAVE;
! 1040: strlcpy(dip->un.e.member[1].label.name, CmpciNlegacy,
! 1041: sizeof dip->un.e.member[1].label.name);
! 1042: dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_PLAYBACK_LEGACY;
! 1043: return 0;
! 1044: case CMPCI_SPDIF_OUT_VOLTAGE:
! 1045: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 1046: dip->prev = CMPCI_SPDIF_OUT_PLAYBACK;
! 1047: strlcpy(dip->label.name, CmpciNvoltage, sizeof dip->label.name);
! 1048: dip->type = AUDIO_MIXER_ENUM;
! 1049: dip->un.e.num_mem = 2;
! 1050: strlcpy(dip->un.e.member[0].label.name, CmpciNhigh_v,
! 1051: sizeof dip->un.e.member[0].label.name);
! 1052: dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH;
! 1053: strlcpy(dip->un.e.member[1].label.name, CmpciNlow_v,
! 1054: sizeof dip->un.e.member[1].label.name);
! 1055: dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW;
! 1056: return 0;
! 1057: case CMPCI_MONITOR_DAC:
! 1058: dip->mixer_class = CMPCI_SPDIF_CLASS;
! 1059: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
! 1060: dip->type = AUDIO_MIXER_ENUM;
! 1061: dip->un.e.num_mem = 3;
! 1062: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 1063: sizeof dip->un.e.member[0].label.name);
! 1064: dip->un.e.member[0].ord = CMPCI_MONITOR_DAC_OFF;
! 1065: strlcpy(dip->un.e.member[1].label.name, CmpciNspdin,
! 1066: sizeof dip->un.e.member[1].label.name);
! 1067: dip->un.e.member[1].ord = CMPCI_MONITOR_DAC_SPDIN;
! 1068: strlcpy(dip->un.e.member[2].label.name, CmpciNspdout,
! 1069: sizeof dip->un.e.member[2].label.name);
! 1070: dip->un.e.member[2].ord = CMPCI_MONITOR_DAC_SPDOUT;
! 1071: return 0;
! 1072:
! 1073: case CMPCI_MASTER_VOL:
! 1074: dip->mixer_class = CMPCI_OUTPUT_CLASS;
! 1075: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
! 1076: dip->un.v.num_channels = 2;
! 1077: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS);
! 1078: goto vol;
! 1079: case CMPCI_REAR:
! 1080: dip->mixer_class = CMPCI_OUTPUT_CLASS;
! 1081: dip->next = CMPCI_INDIVIDUAL;
! 1082: strlcpy(dip->label.name, CmpciNrear, sizeof dip->label.name);
! 1083: goto on_off;
! 1084: case CMPCI_INDIVIDUAL:
! 1085: dip->mixer_class = CMPCI_OUTPUT_CLASS;
! 1086: dip->prev = CMPCI_REAR;
! 1087: dip->next = CMPCI_REVERSE;
! 1088: strlcpy(dip->label.name, CmpciNindividual, sizeof dip->label.name);
! 1089: goto on_off;
! 1090: case CMPCI_REVERSE:
! 1091: dip->mixer_class = CMPCI_OUTPUT_CLASS;
! 1092: dip->prev = CMPCI_INDIVIDUAL;
! 1093: strlcpy(dip->label.name, CmpciNreverse, sizeof dip->label.name);
! 1094: goto on_off;
! 1095: case CMPCI_SURROUND:
! 1096: dip->mixer_class = CMPCI_OUTPUT_CLASS;
! 1097: strlcpy(dip->label.name, CmpciNsurround, sizeof dip->label.name);
! 1098: goto on_off;
! 1099: }
! 1100:
! 1101: return ENXIO;
! 1102: }
! 1103:
! 1104: int
! 1105: cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, int type, int flags,
! 1106: caddr_t *r_addr)
! 1107: {
! 1108: int error = 0;
! 1109: struct cmpci_dmanode *n;
! 1110: int w;
! 1111:
! 1112: n = malloc(sizeof(struct cmpci_dmanode), type, flags);
! 1113: if (n == NULL) {
! 1114: error = ENOMEM;
! 1115: goto quit;
! 1116: }
! 1117:
! 1118: w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
! 1119: #define CMPCI_DMABUF_ALIGN 0x4
! 1120: #define CMPCI_DMABUF_BOUNDARY 0x0
! 1121: n->cd_tag = sc->sc_dmat;
! 1122: n->cd_size = size;
! 1123: error = bus_dmamem_alloc(n->cd_tag, n->cd_size,
! 1124: CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, n->cd_segs,
! 1125: sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w);
! 1126: if (error)
! 1127: goto mfree;
! 1128: error = bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size,
! 1129: &n->cd_addr, w | BUS_DMA_COHERENT);
! 1130: if (error)
! 1131: goto dmafree;
! 1132: error = bus_dmamap_create(n->cd_tag, n->cd_size, 1, n->cd_size, 0,
! 1133: w, &n->cd_map);
! 1134: if (error)
! 1135: goto unmap;
! 1136: error = bus_dmamap_load(n->cd_tag, n->cd_map, n->cd_addr, n->cd_size,
! 1137: NULL, w);
! 1138: if (error)
! 1139: goto destroy;
! 1140:
! 1141: n->cd_next = sc->sc_dmap;
! 1142: sc->sc_dmap = n;
! 1143: *r_addr = KVADDR(n);
! 1144: return 0;
! 1145:
! 1146: destroy:
! 1147: bus_dmamap_destroy(n->cd_tag, n->cd_map);
! 1148: unmap:
! 1149: bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size);
! 1150: dmafree:
! 1151: bus_dmamem_free(n->cd_tag,
! 1152: n->cd_segs, sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
! 1153: mfree:
! 1154: free(n, type);
! 1155: quit:
! 1156: return error;
! 1157: }
! 1158:
! 1159: int
! 1160: cmpci_free_dmamem(struct cmpci_softc *sc, caddr_t addr, int type)
! 1161: {
! 1162: struct cmpci_dmanode **nnp;
! 1163:
! 1164: for (nnp = &sc->sc_dmap; *nnp; nnp = &(*nnp)->cd_next) {
! 1165: if ((*nnp)->cd_addr == addr) {
! 1166: struct cmpci_dmanode *n = *nnp;
! 1167: bus_dmamap_unload(n->cd_tag, n->cd_map);
! 1168: bus_dmamap_destroy(n->cd_tag, n->cd_map);
! 1169: bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size);
! 1170: bus_dmamem_free(n->cd_tag, n->cd_segs,
! 1171: sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
! 1172: free(n, type);
! 1173: return 0;
! 1174: }
! 1175: }
! 1176: return -1;
! 1177: }
! 1178:
! 1179: struct cmpci_dmanode *
! 1180: cmpci_find_dmamem(struct cmpci_softc *sc, caddr_t addr)
! 1181: {
! 1182: struct cmpci_dmanode *p;
! 1183:
! 1184: for (p = sc->sc_dmap; p; p = p->cd_next) {
! 1185: if (KVADDR(p) == (void *)addr)
! 1186: break;
! 1187: }
! 1188: return p;
! 1189: }
! 1190:
! 1191: #if 0
! 1192: void cmpci_print_dmamem(struct cmpci_dmanode *p);
! 1193:
! 1194: void
! 1195: cmpci_print_dmamem(struct cmpci_dmanode *p)
! 1196: {
! 1197: DPRINTF(("DMA at virt:%p, dmaseg:%p, mapseg:%p, size:%p\n",
! 1198: (void *)p->cd_addr, (void *)p->cd_segs[0].ds_addr,
! 1199: (void *)DMAADDR(p), (void *)p->cd_size));
! 1200: }
! 1201: #endif /* DEBUG */
! 1202:
! 1203: void *
! 1204: cmpci_malloc(void *handle, int direction, size_t size, int type,
! 1205: int flags)
! 1206: {
! 1207: caddr_t addr;
! 1208:
! 1209: if (cmpci_alloc_dmamem(handle, size, type, flags, &addr))
! 1210: return NULL;
! 1211: return addr;
! 1212: }
! 1213:
! 1214: void
! 1215: cmpci_free(void *handle, void *addr, int type)
! 1216: {
! 1217: cmpci_free_dmamem(handle, addr, type);
! 1218: }
! 1219:
! 1220: #define MAXVAL 256
! 1221: int
! 1222: cmpci_adjust(int val, int mask)
! 1223: {
! 1224: val += (MAXVAL - mask) >> 1;
! 1225: if (val >= MAXVAL)
! 1226: val = MAXVAL-1;
! 1227: return val & mask;
! 1228: }
! 1229:
! 1230: void
! 1231: cmpci_set_mixer_gain(struct cmpci_softc *sc, int port)
! 1232: {
! 1233: int src;
! 1234: int bits, mask;
! 1235:
! 1236: switch (port) {
! 1237: case CMPCI_MIC_VOL:
! 1238: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_MIC,
! 1239: CMPCI_ADJUST_MIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
! 1240: return;
! 1241: case CMPCI_MASTER_VOL:
! 1242: src = CMPCI_SB16_MIXER_MASTER_L;
! 1243: break;
! 1244: case CMPCI_LINE_IN_VOL:
! 1245: src = CMPCI_SB16_MIXER_LINE_L;
! 1246: break;
! 1247: case CMPCI_AUX_IN_VOL:
! 1248: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MIXER_AUX,
! 1249: CMPCI_ADJUST_AUX_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT],
! 1250: sc->sc_gain[port][CMPCI_RIGHT]));
! 1251: return;
! 1252: case CMPCI_MIC_RECVOL:
! 1253: cmpci_reg_partial_write_1(sc, CMPCI_REG_MIXER25,
! 1254: CMPCI_REG_ADMIC_SHIFT, CMPCI_REG_ADMIC_MASK,
! 1255: CMPCI_ADJUST_ADMIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
! 1256: return;
! 1257: case CMPCI_DAC_VOL:
! 1258: src = CMPCI_SB16_MIXER_VOICE_L;
! 1259: break;
! 1260: case CMPCI_FM_VOL:
! 1261: src = CMPCI_SB16_MIXER_FM_L;
! 1262: break;
! 1263: case CMPCI_CD_VOL:
! 1264: src = CMPCI_SB16_MIXER_CDDA_L;
! 1265: break;
! 1266: case CMPCI_PCSPEAKER:
! 1267: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_SPEAKER,
! 1268: CMPCI_ADJUST_2_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
! 1269: return;
! 1270: case CMPCI_MIC_PREAMP:
! 1271: if (sc->sc_gain[port][CMPCI_LR])
! 1272: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
! 1273: CMPCI_REG_MICGAINZ);
! 1274: else
! 1275: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
! 1276: CMPCI_REG_MICGAINZ);
! 1277: return;
! 1278:
! 1279: case CMPCI_DAC_MUTE:
! 1280: if (sc->sc_gain[port][CMPCI_LR])
! 1281: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1282: CMPCI_REG_WSMUTE);
! 1283: else
! 1284: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1285: CMPCI_REG_WSMUTE);
! 1286: return;
! 1287: case CMPCI_FM_MUTE:
! 1288: if (sc->sc_gain[port][CMPCI_LR])
! 1289: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1290: CMPCI_REG_FMMUTE);
! 1291: else
! 1292: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1293: CMPCI_REG_FMMUTE);
! 1294: return;
! 1295: case CMPCI_AUX_IN_MUTE:
! 1296: if (sc->sc_gain[port][CMPCI_LR])
! 1297: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
! 1298: CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM);
! 1299: else
! 1300: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
! 1301: CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM);
! 1302: return;
! 1303: case CMPCI_CD_MUTE:
! 1304: mask = CMPCI_SB16_SW_CD;
! 1305: goto sbmute;
! 1306: case CMPCI_MIC_MUTE:
! 1307: mask = CMPCI_SB16_SW_MIC;
! 1308: goto sbmute;
! 1309: case CMPCI_LINE_IN_MUTE:
! 1310: mask = CMPCI_SB16_SW_LINE;
! 1311: sbmute:
! 1312: bits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_OUTMIX);
! 1313: if (sc->sc_gain[port][CMPCI_LR])
! 1314: bits = bits & ~mask;
! 1315: else
! 1316: bits = bits | mask;
! 1317: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX, bits);
! 1318: return;
! 1319:
! 1320: case CMPCI_SPDIF_IN_SELECT:
! 1321: case CMPCI_MONITOR_DAC:
! 1322: case CMPCI_PLAYBACK_MODE:
! 1323: case CMPCI_SPDIF_LOOP:
! 1324: case CMPCI_SPDIF_OUT_PLAYBACK:
! 1325: cmpci_set_out_ports(sc);
! 1326: return;
! 1327: case CMPCI_SPDIF_OUT_VOLTAGE:
! 1328: if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) {
! 1329: if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR]
! 1330: == CMPCI_SPDIF_OUT_VOLTAGE_HIGH)
! 1331: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_5V);
! 1332: else
! 1333: cmpci_reg_set_reg_misc(sc, CMPCI_REG_5V);
! 1334: }
! 1335: return;
! 1336: case CMPCI_SURROUND:
! 1337: if (CMPCI_ISCAP(sc, SURROUND)) {
! 1338: if (sc->sc_gain[CMPCI_SURROUND][CMPCI_LR])
! 1339: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1340: CMPCI_REG_SURROUND);
! 1341: else
! 1342: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1343: CMPCI_REG_SURROUND);
! 1344: }
! 1345: return;
! 1346: case CMPCI_REAR:
! 1347: if (CMPCI_ISCAP(sc, REAR)) {
! 1348: if (sc->sc_gain[CMPCI_REAR][CMPCI_LR])
! 1349: cmpci_reg_set_reg_misc(sc, CMPCI_REG_N4SPK3D);
! 1350: else
! 1351: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_N4SPK3D);
! 1352: }
! 1353: return;
! 1354: case CMPCI_INDIVIDUAL:
! 1355: if (CMPCI_ISCAP(sc, INDIVIDUAL_REAR)) {
! 1356: if (sc->sc_gain[CMPCI_REAR][CMPCI_LR])
! 1357: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1358: CMPCI_REG_INDIVIDUAL);
! 1359: else
! 1360: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1361: CMPCI_REG_INDIVIDUAL);
! 1362: }
! 1363: return;
! 1364: case CMPCI_REVERSE:
! 1365: if (CMPCI_ISCAP(sc, REVERSE_FR)) {
! 1366: if (sc->sc_gain[CMPCI_REVERSE][CMPCI_LR])
! 1367: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1368: CMPCI_REG_REVERSE_FR);
! 1369: else
! 1370: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1371: CMPCI_REG_REVERSE_FR);
! 1372: }
! 1373: return;
! 1374: case CMPCI_SPDIF_IN_PHASE:
! 1375: if (CMPCI_ISCAP(sc, SPDIN_PHASE)) {
! 1376: if (sc->sc_gain[CMPCI_SPDIF_IN_PHASE][CMPCI_LR]
! 1377: == CMPCI_SPDIF_IN_PHASE_POSITIVE)
! 1378: cmpci_reg_clear_1(sc, CMPCI_REG_CHANNEL_FORMAT,
! 1379: CMPCI_REG_SPDIN_PHASE);
! 1380: else
! 1381: cmpci_reg_set_1(sc, CMPCI_REG_CHANNEL_FORMAT,
! 1382: CMPCI_REG_SPDIN_PHASE);
! 1383: }
! 1384: return;
! 1385: default:
! 1386: return;
! 1387: }
! 1388:
! 1389: cmpci_mixerreg_write(sc, src,
! 1390: CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT]));
! 1391: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_L_TO_R(src),
! 1392: CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_RIGHT]));
! 1393: }
! 1394:
! 1395: void
! 1396: cmpci_set_out_ports(struct cmpci_softc *sc)
! 1397: {
! 1398: u_int8_t v;
! 1399: int enspdout = 0;
! 1400:
! 1401: if (!CMPCI_ISCAP(sc, SPDLOOP))
! 1402: return;
! 1403:
! 1404: /* SPDIF/out select */
! 1405: if (sc->sc_gain[CMPCI_SPDIF_LOOP][CMPCI_LR] == CMPCI_SPDIF_LOOP_OFF) {
! 1406: /* playback */
! 1407: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP);
! 1408: } else {
! 1409: /* monitor SPDIF/in */
! 1410: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP);
! 1411: }
! 1412:
! 1413: /* SPDIF in select */
! 1414: v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR];
! 1415: if (v & CMPCI_SPDIFIN_SPDIFIN2)
! 1416: cmpci_reg_set_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN);
! 1417: else
! 1418: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN);
! 1419: if (v & CMPCI_SPDIFIN_SPDIFOUT)
! 1420: cmpci_reg_set_reg_misc(sc, CMPCI_REG_SPDFLOOPI);
! 1421: else
! 1422: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_SPDFLOOPI);
! 1423:
! 1424: /* playback to ... */
! 1425: if (CMPCI_ISCAP(sc, SPDOUT) &&
! 1426: sc->sc_gain[CMPCI_PLAYBACK_MODE][CMPCI_LR]
! 1427: == CMPCI_PLAYBACK_MODE_SPDIF &&
! 1428: (sc->sc_play.md_divide == CMPCI_REG_RATE_44100 ||
! 1429: (CMPCI_ISCAP(sc, SPDOUT_48K) &&
! 1430: sc->sc_play.md_divide==CMPCI_REG_RATE_48000))) {
! 1431: /* playback to SPDIF */
! 1432: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF0_ENABLE);
! 1433: enspdout = 1;
! 1434: if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000)
! 1435: cmpci_reg_set_reg_misc(sc,
! 1436: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
! 1437: else
! 1438: cmpci_reg_clear_reg_misc(sc,
! 1439: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
! 1440: } else {
! 1441: /* playback to DAC */
! 1442: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1,
! 1443: CMPCI_REG_SPDIF0_ENABLE);
! 1444: if (CMPCI_ISCAP(sc, SPDOUT_48K))
! 1445: cmpci_reg_clear_reg_misc(sc,
! 1446: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
! 1447: }
! 1448:
! 1449: /* legacy to SPDIF/out or not */
! 1450: if (CMPCI_ISCAP(sc, SPDLEGACY)) {
! 1451: if (sc->sc_gain[CMPCI_SPDIF_OUT_PLAYBACK][CMPCI_LR]
! 1452: == CMPCI_SPDIF_OUT_PLAYBACK_WAVE)
! 1453: cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL,
! 1454: CMPCI_REG_LEGACY_SPDIF_ENABLE);
! 1455: else {
! 1456: cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL,
! 1457: CMPCI_REG_LEGACY_SPDIF_ENABLE);
! 1458: enspdout = 1;
! 1459: }
! 1460: }
! 1461:
! 1462: /* enable/disable SPDIF/out */
! 1463: if (CMPCI_ISCAP(sc, XSPDOUT) && enspdout)
! 1464: cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL,
! 1465: CMPCI_REG_XSPDIF_ENABLE);
! 1466: else
! 1467: cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL,
! 1468: CMPCI_REG_XSPDIF_ENABLE);
! 1469:
! 1470: /* SPDIF monitor (digital to analog output) */
! 1471: if (CMPCI_ISCAP(sc, SPDIN_MONITOR)) {
! 1472: v = sc->sc_gain[CMPCI_MONITOR_DAC][CMPCI_LR];
! 1473: if (!(v & CMPCI_MONDAC_ENABLE))
! 1474: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1475: CMPCI_REG_SPDIN_MONITOR);
! 1476: if (v & CMPCI_MONDAC_SPDOUT)
! 1477: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1,
! 1478: CMPCI_REG_SPDIFOUT_DAC);
! 1479: else
! 1480: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1,
! 1481: CMPCI_REG_SPDIFOUT_DAC);
! 1482: if (v & CMPCI_MONDAC_ENABLE)
! 1483: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1484: CMPCI_REG_SPDIN_MONITOR);
! 1485: }
! 1486: }
! 1487:
! 1488: int
! 1489: cmpci_set_in_ports(struct cmpci_softc *sc)
! 1490: {
! 1491: int mask;
! 1492: int bitsl, bitsr;
! 1493:
! 1494: mask = sc->sc_in_mask;
! 1495:
! 1496: /*
! 1497: * Note CMPCI_RECORD_SOURCE_CD, CMPCI_RECORD_SOURCE_LINE_IN and
! 1498: * CMPCI_RECORD_SOURCE_FM are defined to the corresponding bit
! 1499: * of the mixer register.
! 1500: */
! 1501: bitsr = mask & (CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN |
! 1502: CMPCI_RECORD_SOURCE_FM);
! 1503:
! 1504: bitsl = CMPCI_SB16_MIXER_SRC_R_TO_L(bitsr);
! 1505: if (mask & CMPCI_RECORD_SOURCE_MIC) {
! 1506: bitsl |= CMPCI_SB16_MIXER_MIC_SRC;
! 1507: bitsr |= CMPCI_SB16_MIXER_MIC_SRC;
! 1508: }
! 1509: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, bitsl);
! 1510: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, bitsr);
! 1511:
! 1512: if (mask & CMPCI_RECORD_SOURCE_AUX_IN)
! 1513: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
! 1514: CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN);
! 1515: else
! 1516: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
! 1517: CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN);
! 1518:
! 1519: if (mask & CMPCI_RECORD_SOURCE_WAVE)
! 1520: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
! 1521: CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR);
! 1522: else
! 1523: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
! 1524: CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR);
! 1525:
! 1526: if (CMPCI_ISCAP(sc, SPDIN) &&
! 1527: (sc->sc_rec.md_divide == CMPCI_REG_RATE_44100 ||
! 1528: (CMPCI_ISCAP(sc, SPDOUT_48K) &&
! 1529: sc->sc_rec.md_divide == CMPCI_REG_RATE_48000/* XXX? */))) {
! 1530: if (mask & CMPCI_RECORD_SOURCE_SPDIF) {
! 1531: /* enable SPDIF/in */
! 1532: cmpci_reg_set_4(sc,
! 1533: CMPCI_REG_FUNC_1,
! 1534: CMPCI_REG_SPDIF1_ENABLE);
! 1535: } else {
! 1536: cmpci_reg_clear_4(sc,
! 1537: CMPCI_REG_FUNC_1,
! 1538: CMPCI_REG_SPDIF1_ENABLE);
! 1539: }
! 1540: }
! 1541:
! 1542: return 0;
! 1543: }
! 1544:
! 1545: int
! 1546: cmpci_set_port(void *handle, mixer_ctrl_t *cp)
! 1547: {
! 1548: struct cmpci_softc *sc = handle;
! 1549: int lgain, rgain;
! 1550:
! 1551: switch (cp->dev) {
! 1552: case CMPCI_MIC_VOL:
! 1553: case CMPCI_PCSPEAKER:
! 1554: case CMPCI_MIC_RECVOL:
! 1555: if (cp->un.value.num_channels != 1)
! 1556: return EINVAL;
! 1557: /* FALLTHROUGH */
! 1558: case CMPCI_DAC_VOL:
! 1559: case CMPCI_FM_VOL:
! 1560: case CMPCI_CD_VOL:
! 1561: case CMPCI_LINE_IN_VOL:
! 1562: case CMPCI_AUX_IN_VOL:
! 1563: case CMPCI_MASTER_VOL:
! 1564: if (cp->type != AUDIO_MIXER_VALUE)
! 1565: return EINVAL;
! 1566: switch (cp->un.value.num_channels) {
! 1567: case 1:
! 1568: lgain = rgain =
! 1569: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
! 1570: break;
! 1571: case 2:
! 1572: lgain = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
! 1573: rgain = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
! 1574: break;
! 1575: default:
! 1576: return EINVAL;
! 1577: }
! 1578: sc->sc_gain[cp->dev][CMPCI_LEFT] = lgain;
! 1579: sc->sc_gain[cp->dev][CMPCI_RIGHT] = rgain;
! 1580:
! 1581: cmpci_set_mixer_gain(sc, cp->dev);
! 1582: break;
! 1583:
! 1584: case CMPCI_RECORD_SOURCE:
! 1585: if (cp->type != AUDIO_MIXER_SET)
! 1586: return EINVAL;
! 1587:
! 1588: if (cp->un.mask & ~(CMPCI_RECORD_SOURCE_MIC |
! 1589: CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN |
! 1590: CMPCI_RECORD_SOURCE_AUX_IN | CMPCI_RECORD_SOURCE_WAVE |
! 1591: CMPCI_RECORD_SOURCE_FM | CMPCI_RECORD_SOURCE_SPDIF))
! 1592: return EINVAL;
! 1593:
! 1594: if (cp->un.mask & CMPCI_RECORD_SOURCE_SPDIF)
! 1595: cp->un.mask = CMPCI_RECORD_SOURCE_SPDIF;
! 1596:
! 1597: sc->sc_in_mask = cp->un.mask;
! 1598: return cmpci_set_in_ports(sc);
! 1599:
! 1600: /* boolean */
! 1601: case CMPCI_DAC_MUTE:
! 1602: case CMPCI_FM_MUTE:
! 1603: case CMPCI_CD_MUTE:
! 1604: case CMPCI_LINE_IN_MUTE:
! 1605: case CMPCI_AUX_IN_MUTE:
! 1606: case CMPCI_MIC_MUTE:
! 1607: case CMPCI_MIC_PREAMP:
! 1608: case CMPCI_PLAYBACK_MODE:
! 1609: case CMPCI_SPDIF_IN_PHASE:
! 1610: case CMPCI_SPDIF_LOOP:
! 1611: case CMPCI_SPDIF_OUT_PLAYBACK:
! 1612: case CMPCI_SPDIF_OUT_VOLTAGE:
! 1613: case CMPCI_REAR:
! 1614: case CMPCI_INDIVIDUAL:
! 1615: case CMPCI_REVERSE:
! 1616: case CMPCI_SURROUND:
! 1617: if (cp->type != AUDIO_MIXER_ENUM)
! 1618: return EINVAL;
! 1619: sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord != 0;
! 1620: cmpci_set_mixer_gain(sc, cp->dev);
! 1621: break;
! 1622:
! 1623: case CMPCI_SPDIF_IN_SELECT:
! 1624: switch (cp->un.ord) {
! 1625: case CMPCI_SPDIF_IN_SPDIN1:
! 1626: case CMPCI_SPDIF_IN_SPDIN2:
! 1627: case CMPCI_SPDIF_IN_SPDOUT:
! 1628: break;
! 1629: default:
! 1630: return EINVAL;
! 1631: }
! 1632: goto xenum;
! 1633: case CMPCI_MONITOR_DAC:
! 1634: switch (cp->un.ord) {
! 1635: case CMPCI_MONITOR_DAC_OFF:
! 1636: case CMPCI_MONITOR_DAC_SPDIN:
! 1637: case CMPCI_MONITOR_DAC_SPDOUT:
! 1638: break;
! 1639: default:
! 1640: return EINVAL;
! 1641: }
! 1642: xenum:
! 1643: if (cp->type != AUDIO_MIXER_ENUM)
! 1644: return EINVAL;
! 1645: sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord;
! 1646: cmpci_set_mixer_gain(sc, cp->dev);
! 1647: break;
! 1648:
! 1649: default:
! 1650: return EINVAL;
! 1651: }
! 1652:
! 1653: return 0;
! 1654: }
! 1655:
! 1656: int
! 1657: cmpci_get_port(void *handle, mixer_ctrl_t *cp)
! 1658: {
! 1659: struct cmpci_softc *sc = handle;
! 1660:
! 1661: switch (cp->dev) {
! 1662: case CMPCI_MIC_VOL:
! 1663: case CMPCI_PCSPEAKER:
! 1664: case CMPCI_MIC_RECVOL:
! 1665: if (cp->un.value.num_channels != 1)
! 1666: return EINVAL;
! 1667: /*FALLTHROUGH*/
! 1668: case CMPCI_DAC_VOL:
! 1669: case CMPCI_FM_VOL:
! 1670: case CMPCI_CD_VOL:
! 1671: case CMPCI_LINE_IN_VOL:
! 1672: case CMPCI_AUX_IN_VOL:
! 1673: case CMPCI_MASTER_VOL:
! 1674: switch (cp->un.value.num_channels) {
! 1675: case 1:
! 1676: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1677: sc->sc_gain[cp->dev][CMPCI_LEFT];
! 1678: break;
! 1679: case 2:
! 1680: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1681: sc->sc_gain[cp->dev][CMPCI_LEFT];
! 1682: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1683: sc->sc_gain[cp->dev][CMPCI_RIGHT];
! 1684: break;
! 1685: default:
! 1686: return EINVAL;
! 1687: }
! 1688: break;
! 1689:
! 1690: case CMPCI_RECORD_SOURCE:
! 1691: cp->un.mask = sc->sc_in_mask;
! 1692: break;
! 1693:
! 1694: case CMPCI_DAC_MUTE:
! 1695: case CMPCI_FM_MUTE:
! 1696: case CMPCI_CD_MUTE:
! 1697: case CMPCI_LINE_IN_MUTE:
! 1698: case CMPCI_AUX_IN_MUTE:
! 1699: case CMPCI_MIC_MUTE:
! 1700: case CMPCI_MIC_PREAMP:
! 1701: case CMPCI_PLAYBACK_MODE:
! 1702: case CMPCI_SPDIF_IN_SELECT:
! 1703: case CMPCI_SPDIF_IN_PHASE:
! 1704: case CMPCI_SPDIF_LOOP:
! 1705: case CMPCI_SPDIF_OUT_PLAYBACK:
! 1706: case CMPCI_SPDIF_OUT_VOLTAGE:
! 1707: case CMPCI_MONITOR_DAC:
! 1708: case CMPCI_REAR:
! 1709: case CMPCI_INDIVIDUAL:
! 1710: case CMPCI_REVERSE:
! 1711: case CMPCI_SURROUND:
! 1712: cp->un.ord = sc->sc_gain[cp->dev][CMPCI_LR];
! 1713: break;
! 1714:
! 1715: default:
! 1716: return EINVAL;
! 1717: }
! 1718:
! 1719: return 0;
! 1720: }
! 1721:
! 1722: /* ARGSUSED */
! 1723: size_t
! 1724: cmpci_round_buffersize(void *handle, int direction, size_t bufsize)
! 1725: {
! 1726: if (bufsize > 0x10000)
! 1727: bufsize = 0x10000;
! 1728:
! 1729: return bufsize;
! 1730: }
! 1731:
! 1732: paddr_t
! 1733: cmpci_mappage(void *handle, void *addr, off_t offset, int prot)
! 1734: {
! 1735: struct cmpci_softc *sc = handle;
! 1736: struct cmpci_dmanode *p;
! 1737:
! 1738: if (offset < 0 || NULL == (p = cmpci_find_dmamem(sc, addr)))
! 1739: return -1;
! 1740:
! 1741: return bus_dmamem_mmap(p->cd_tag, p->cd_segs,
! 1742: sizeof(p->cd_segs)/sizeof(p->cd_segs[0]),
! 1743: offset, prot, BUS_DMA_WAITOK);
! 1744: }
! 1745:
! 1746: /* ARGSUSED */
! 1747: int
! 1748: cmpci_get_props(void *handle)
! 1749: {
! 1750: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
! 1751: }
! 1752:
! 1753: int
! 1754: cmpci_trigger_output(void *handle, void *start, void *end, int blksize,
! 1755: void (*intr)(void *), void *arg, struct audio_params *param)
! 1756: {
! 1757: struct cmpci_softc *sc = handle;
! 1758: struct cmpci_dmanode *p;
! 1759: int bps;
! 1760:
! 1761: sc->sc_play.intr = intr;
! 1762: sc->sc_play.intr_arg = arg;
! 1763: bps = param->channels * param->precision * param->factor / 8;
! 1764: if (!bps)
! 1765: return EINVAL;
! 1766:
! 1767: /* set DMA frame */
! 1768: if (!(p = cmpci_find_dmamem(sc, start)))
! 1769: return EINVAL;
! 1770: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BASE,
! 1771: DMAADDR(p));
! 1772: delay(10);
! 1773: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BYTES,
! 1774: ((caddr_t)end - (caddr_t)start + 1) / bps - 1);
! 1775: delay(10);
! 1776:
! 1777: /* set interrupt count */
! 1778: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_SAMPLES,
! 1779: (blksize + bps - 1) / bps - 1);
! 1780: delay(10);
! 1781:
! 1782: /* start DMA */
! 1783: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); /* PLAY */
! 1784: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
! 1785: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
! 1786:
! 1787: return 0;
! 1788: }
! 1789:
! 1790: int
! 1791: cmpci_trigger_input(void *handle, void *start, void *end, int blksize,
! 1792: void (*intr)(void *), void *arg, struct audio_params *param)
! 1793: {
! 1794: struct cmpci_softc *sc = handle;
! 1795: struct cmpci_dmanode *p;
! 1796: int bps;
! 1797:
! 1798: sc->sc_rec.intr = intr;
! 1799: sc->sc_rec.intr_arg = arg;
! 1800: bps = param->channels*param->precision*param->factor/8;
! 1801: if (!bps)
! 1802: return EINVAL;
! 1803:
! 1804: /* set DMA frame */
! 1805: if (!(p = cmpci_find_dmamem(sc, start)))
! 1806: return EINVAL;
! 1807: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BASE,
! 1808: DMAADDR(p));
! 1809: delay(10);
! 1810: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BYTES,
! 1811: ((caddr_t)end - (caddr_t)start + 1) / bps - 1);
! 1812: delay(10);
! 1813:
! 1814: /* set interrupt count */
! 1815: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_SAMPLES,
! 1816: (blksize + bps - 1) / bps - 1);
! 1817: delay(10);
! 1818:
! 1819: /* start DMA */
! 1820: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); /* REC */
! 1821: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
! 1822: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE);
! 1823:
! 1824: return 0;
! 1825: }
! 1826:
! 1827: /* end of file */
CVSweb