diff options
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/dev/pci/cmpci.c | 1720 | ||||
-rw-r--r-- | sys/dev/pci/cmpcireg.h | 71 | ||||
-rw-r--r-- | sys/dev/pci/cmpcivar.h | 249 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 7 | ||||
-rw-r--r-- | sys/dev/pci/opl_cmpci.c | 103 |
6 files changed, 1320 insertions, 833 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 5f30e440933..9a5c1e07472 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.510 2006/07/25 19:16:51 kettenis Exp $ +# $OpenBSD: GENERIC,v 1.511 2006/07/27 00:45:59 brad Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -581,6 +581,7 @@ opl* at eso? opl* at sb? opl* at ess? opl* at yds? +opl* at cmpci? # MIDI support midi* at pcppi? # MIDI interface to the PC speaker diff --git a/sys/dev/pci/cmpci.c b/sys/dev/pci/cmpci.c index 4be9ca505d2..8d58a70fc2b 100644 --- a/sys/dev/pci/cmpci.c +++ b/sys/dev/pci/cmpci.c @@ -1,9 +1,16 @@ -/* $OpenBSD: cmpci.c,v 1.13 2005/04/14 12:42:16 mickey Exp $ */ +/* $OpenBSD: cmpci.c,v 1.14 2006/07/27 00:45:59 brad Exp $ */ +/* $NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $ */ /* - * Copyright (c) 2000 Takuya SHIOZAKI + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Takuya SHIOZAKI <tshiozak@NetBSD.org> . + * + * This code is derived from software contributed to The NetBSD Foundation + * by ITOH Yasufumi. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,15 +38,19 @@ * C-Media CMI8x38 Audio Chip Support. * * TODO: - * - Legacy MPU, OPL and Joystick support (but, I have no interest...) - * - SPDIF support + * - 4ch / 6ch support. + * - Joystick support. * */ -#undef CMPCI_SPDIF_SUPPORT /* XXX: not working */ +#if 0 +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $"); +#endif #if defined(AUDIO_DEBUG) || defined(DEBUG) -#define DPRINTF(x) printf x +#define DPRINTF(x) if (cmpcidebug) printf x +int cmpcidebug = 0; #else #define DPRINTF(x) #endif @@ -56,37 +67,50 @@ #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/midi_if.h> + #include <dev/mulaw.h> #include <dev/auconv.h> - #include <dev/pci/cmpcireg.h> #include <dev/pci/cmpcivar.h> +#include <dev/ic/mpuvar.h> #include <machine/bus.h> #include <machine/intr.h> /* * Low-level HW interface */ -static __inline uint8_t cmpci_mixerreg_read(struct cmpci_softc *, - uint8_t); -static __inline void cmpci_mixerreg_write(struct cmpci_softc *, - uint8_t, uint8_t); -static __inline void cmpci_reg_partial_write_4(struct cmpci_softc *, - int, int, - uint32_t, uint32_t); -static __inline void cmpci_reg_set_4(struct cmpci_softc *, - int, uint32_t); -static __inline void cmpci_reg_clear_4(struct cmpci_softc *, - int, uint32_t); -static int cmpci_rate_to_index(int); -static __inline int cmpci_index_to_rate(int); -static __inline int cmpci_index_to_divider(int); - -static int cmpci_adjust(int, int); -static void cmpci_set_mixer_gain(struct cmpci_softc *, int); -static int cmpci_set_in_ports(struct cmpci_softc *, int); - +__inline uint8_t cmpci_mixerreg_read(struct cmpci_softc *, + uint8_t); +__inline void cmpci_mixerreg_write(struct cmpci_softc *, + uint8_t, uint8_t); +__inline void cmpci_reg_partial_write_1(struct cmpci_softc *, + int, int, + unsigned, unsigned); +__inline void cmpci_reg_partial_write_4(struct cmpci_softc *, + int, int, + uint32_t, uint32_t); +__inline void cmpci_reg_set_1(struct cmpci_softc *, + int, uint8_t); +__inline void cmpci_reg_clear_1(struct cmpci_softc *, + int, uint8_t); +__inline void cmpci_reg_set_4(struct cmpci_softc *, + int, uint32_t); +__inline void cmpci_reg_clear_4(struct cmpci_softc *, + int, uint32_t); +__inline void cmpci_reg_set_reg_misc(struct cmpci_softc *, + uint32_t); +__inline void cmpci_reg_clear_reg_misc(struct cmpci_softc *, + uint32_t); +int cmpci_rate_to_index(int); +__inline int cmpci_index_to_rate(int); +__inline int cmpci_index_to_divider(int); + +int cmpci_adjust(int, int); +void cmpci_set_mixer_gain(struct cmpci_softc *, int); +void cmpci_set_out_ports(struct cmpci_softc *); +int cmpci_set_in_ports(struct cmpci_softc *); /* * autoconf interface @@ -102,24 +126,19 @@ struct cfattach cmpci_ca = { sizeof (struct cmpci_softc), cmpci_match, cmpci_attach }; -struct audio_device cmpci_device = { - "CMI PCI Audio", - "", - "cmpci" -}; - /* interrupt */ int cmpci_intr(void *); - /* * DMA stuff */ int cmpci_alloc_dmamem(struct cmpci_softc *, - size_t, int, int, caddr_t *); -int cmpci_free_dmamem(struct cmpci_softc *, caddr_t, int); + size_t, int, + int, caddr_t *); +int cmpci_free_dmamem(struct cmpci_softc *, caddr_t, + int); struct cmpci_dmanode * cmpci_find_dmamem(struct cmpci_softc *, - caddr_t); + caddr_t); /* * Interface to machine independent layer @@ -128,8 +147,8 @@ int cmpci_open(void *, int); void cmpci_close(void *); int cmpci_query_encoding(void *, struct audio_encoding *); int cmpci_set_params(void *, int, int, - struct audio_params *, - struct audio_params *); + struct audio_params *, + struct audio_params *); int cmpci_round_blocksize(void *, int); int cmpci_halt_output(void *); int cmpci_halt_input(void *); @@ -143,53 +162,51 @@ size_t cmpci_round_buffersize(void *, int, size_t); paddr_t cmpci_mappage(void *, void *, off_t, int); int cmpci_get_props(void *); int cmpci_trigger_output(void *, void *, void *, int, - void (*)(void *), void *, - struct audio_params *); + void (*)(void *), void *, + struct audio_params *); int cmpci_trigger_input(void *, void *, void *, int, - void (*)(void *), void *, - struct audio_params *); + void (*)(void *), void *, + struct audio_params *); struct audio_hw_if cmpci_hw_if = { - cmpci_open, /* open */ - cmpci_close, /* close */ - NULL, /* drain */ - cmpci_query_encoding, /* query_encoding */ - cmpci_set_params, /* set_params */ - cmpci_round_blocksize, /* round_blocksize */ - NULL, /* commit_settings */ - NULL, /* init_output */ - NULL, /* init_input */ - NULL, /* start_output */ - NULL, /* start_input */ - cmpci_halt_output, /* halt_output */ - cmpci_halt_input, /* halt_input */ - NULL, /* speaker_ctl */ - cmpci_getdev, /* getdev */ - NULL, /* setfd */ - cmpci_set_port, /* set_port */ - cmpci_get_port, /* get_port */ - cmpci_query_devinfo, /* query_devinfo */ - cmpci_malloc, /* malloc */ - cmpci_free, /* free */ - cmpci_round_buffersize, /* round_buffersize */ - cmpci_mappage, /* mappage */ - cmpci_get_props, /* get_props */ - cmpci_trigger_output, /* trigger_output */ - cmpci_trigger_input /* trigger_input */ + cmpci_open, /* open */ + cmpci_close, /* close */ + NULL, /* drain */ + cmpci_query_encoding, /* query_encoding */ + cmpci_set_params, /* set_params */ + cmpci_round_blocksize, /* round_blocksize */ + NULL, /* commit_settings */ + NULL, /* init_output */ + NULL, /* init_input */ + NULL, /* start_output */ + NULL, /* start_input */ + cmpci_halt_output, /* halt_output */ + cmpci_halt_input, /* halt_input */ + NULL, /* speaker_ctl */ + cmpci_getdev, /* getdev */ + NULL, /* setfd */ + cmpci_set_port, /* set_port */ + cmpci_get_port, /* get_port */ + cmpci_query_devinfo, /* query_devinfo */ + cmpci_malloc, /* malloc */ + cmpci_free, /* free */ + cmpci_round_buffersize,/* round_buffersize */ + cmpci_mappage, /* mappage */ + cmpci_get_props, /* get_props */ + cmpci_trigger_output, /* trigger_output */ + cmpci_trigger_input, /* trigger_input */ }; - /* * Low-level HW interface */ /* mixer register read/write */ -static __inline uint8_t -cmpci_mixerreg_read(sc, no) - struct cmpci_softc *sc; - uint8_t no; +__inline uint8_t +cmpci_mixerreg_read(struct cmpci_softc *sc, uint8_t no) { uint8_t ret; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no); delay(10); ret = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBDATA); @@ -197,10 +214,8 @@ cmpci_mixerreg_read(sc, no) return ret; } -static __inline void -cmpci_mixerreg_write(sc, no, val) - struct cmpci_softc *sc; - uint8_t no, val; +__inline void +cmpci_mixerreg_write(struct cmpci_softc *sc, uint8_t no, uint8_t val) { bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no); delay(10); @@ -209,11 +224,19 @@ cmpci_mixerreg_write(sc, no, val) } /* register partial write */ -static __inline void -cmpci_reg_partial_write_4(sc, no, shift, mask, val) - struct cmpci_softc *sc; - int no, shift; - uint32_t mask, val; +__inline void +cmpci_reg_partial_write_1(struct cmpci_softc *sc, int no, int shift, + unsigned mask, unsigned val) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, no, + (val<<shift) | + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~(mask<<shift))); + delay(10); +} + +__inline void +cmpci_reg_partial_write_4(struct cmpci_softc *sc, int no, int shift, + uint32_t mask, uint32_t val) { bus_space_write_4(sc->sc_iot, sc->sc_ioh, no, (val<<shift) | @@ -222,33 +245,70 @@ cmpci_reg_partial_write_4(sc, no, shift, mask, val) } /* register set/clear bit */ -static __inline void -cmpci_reg_set_4(sc, no, mask) - struct cmpci_softc *sc; - int no; - uint32_t mask; +__inline void +cmpci_reg_set_1(struct cmpci_softc *sc, int no, uint8_t mask) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, no, + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) | mask)); + delay(10); +} + +__inline void +cmpci_reg_clear_1(struct cmpci_softc *sc, int no, uint8_t mask) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, no, + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~mask)); + delay(10); +} + +__inline void +cmpci_reg_set_4(struct cmpci_softc *sc, int no, uint32_t mask) +{ + /* use cmpci_reg_set_reg_misc() for CMPCI_REG_MISC */ + KDASSERT(no != CMPCI_REG_MISC); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, no, (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask)); delay(10); } -static __inline void -cmpci_reg_clear_4(sc, no, mask) - struct cmpci_softc *sc; - int no; - uint32_t mask; +__inline void +cmpci_reg_clear_4(struct cmpci_softc *sc, int no, uint32_t mask) { + /* use cmpci_reg_clear_reg_misc() for CMPCI_REG_MISC */ + KDASSERT(no != CMPCI_REG_MISC); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, no, (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask)); delay(10); } +/* + * The CMPCI_REG_MISC register needs special handling, since one of + * its bits has different read/write values. + */ +__inline void +cmpci_reg_set_reg_misc(struct cmpci_softc *sc, uint32_t mask) +{ + sc->sc_reg_misc |= mask; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC, + sc->sc_reg_misc); + delay(10); +} + +__inline void +cmpci_reg_clear_reg_misc(struct cmpci_softc *sc, uint32_t mask) +{ + sc->sc_reg_misc &= ~mask; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC, + sc->sc_reg_misc); + delay(10); +} /* rate */ -struct { - int rate; - int divider; +static const struct { + int rate; + int divider; } cmpci_rate_table[CMPCI_REG_NUMRATE] = { #define _RATE(n) { n, CMPCI_REG_RATE_ ## n } _RATE(5512), @@ -259,32 +319,29 @@ struct { _RATE(32000), _RATE(44100), _RATE(48000) -#undef _RATE +#undef _RATE }; int -cmpci_rate_to_index(rate) - int rate; +cmpci_rate_to_index(int rate) { int i; - for (i=0; i<CMPCI_REG_NUMRATE-2; i++) + + for (i = 0; i < CMPCI_REG_NUMRATE - 1; i++) if (rate <= (cmpci_rate_table[i].rate + cmpci_rate_table[i+1].rate) / 2) return i; return i; /* 48000 */ } -static __inline int -cmpci_index_to_rate(index) - int index; +__inline int +cmpci_index_to_rate(int index) { - return cmpci_rate_table[index].rate; } -static __inline int -cmpci_index_to_divider(index) - int index; +__inline int +cmpci_index_to_divider(int index) { return cmpci_rate_table[index].divider; } @@ -293,52 +350,63 @@ const struct pci_matchid cmpci_devices[] = { { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338A }, { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338B }, { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738 }, + { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738B } }; /* * interface to configure the device. */ + int -cmpci_match(parent, match, aux) - struct device *parent; - void *match; - void *aux; +cmpci_match(struct device *parent, void *match, void *aux) { return (pci_matchbyid((struct pci_attach_args *)aux, cmpci_devices, sizeof(cmpci_devices)/sizeof(cmpci_devices[0]))); } void -cmpci_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +cmpci_attach(struct device *parent, struct device *self, void *aux) { struct cmpci_softc *sc = (struct cmpci_softc *)self; struct pci_attach_args *pa = (struct pci_attach_args *)aux; + struct audio_attach_args aa; pci_intr_handle_t ih; char const *intrstr; int i, v; + sc->sc_id = pa->pa_id; + sc->sc_class = pa->pa_class; + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_CMI_CMI8338A: + /*FALLTHROUGH*/ + case PCI_PRODUCT_CMI_CMI8338B: + sc->sc_capable = CMPCI_CAP_CMI8338; + break; + case PCI_PRODUCT_CMI_CMI8738: + /*FALLTHROUGH*/ + case PCI_PRODUCT_CMI_CMI8738B: + sc->sc_capable = CMPCI_CAP_CMI8738; + break; + } + /* map I/O space */ if (pci_mapreg_map(pa, CMPCI_PCI_IOBASEREG, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0)) { - printf("\n%s: failed to map I/O space\n", sc->sc_dev.dv_xname); + printf(": failed to map I/O space\n"); return; } /* interrupt */ if (pci_intr_map(pa, &ih)) { - printf("\n%s: failed to map interrupt\n", sc->sc_dev.dv_xname); + printf(": failed to map interrupt\n"); return; } intrstr = pci_intr_string(pa->pa_pc, ih); - sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, cmpci_intr, - sc, sc->sc_dev.dv_xname); - + sc->sc_ih=pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, cmpci_intr, sc, + sc->sc_dev.dv_xname); if (sc->sc_ih == NULL) { - printf("\n%s: couldn't establish interrupt", - sc->sc_dev.dv_xname); - if (intrstr) + printf(": failed to establish interrupt"); + if (intrstr != NULL) printf(" at %s", intrstr); printf("\n"); return; @@ -349,120 +417,151 @@ cmpci_attach(parent, self, aux) audio_attach_mi(&cmpci_hw_if, sc, &sc->sc_dev); + /* attach OPL device */ + aa.type = AUDIODEV_TYPE_OPL; + aa.hwif = NULL; + aa.hdl = NULL; + (void)config_found(&sc->sc_dev, &aa, audioprint); + + /* attach MPU-401 device */ + aa.type = AUDIODEV_TYPE_MPU; + aa.hwif = NULL; + aa.hdl = NULL; + if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, + CMPCI_REG_MPU_BASE, CMPCI_REG_MPU_SIZE, &sc->sc_mpu_ioh) == 0) + sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint); + + /* get initial value (this is 0 and may be omitted but just in case) */ + sc->sc_reg_misc = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + CMPCI_REG_MISC) & ~CMPCI_REG_SPDIF48K; + cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_RESET, 0); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX, - CMPCI_SB16_SW_CD|CMPCI_SB16_SW_MIC| - CMPCI_SB16_SW_LINE); + CMPCI_SB16_SW_CD|CMPCI_SB16_SW_MIC|CMPCI_SB16_SW_LINE); for (i = 0; i < CMPCI_NDEVS; i++) { switch(i) { - case CMPCI_MIC_VOL: - case CMPCI_LINE_IN_VOL: - v = 0; + /* + * CMI8738 defaults are + * master: 0xe0 (0x00 - 0xf8) + * FM, DAC: 0xc0 (0x00 - 0xf8) + * PC speaker: 0x80 (0x00 - 0xc0) + * others: 0 + */ + /* volume */ + case CMPCI_MASTER_VOL: + v = 128; /* 224 */ break; - case CMPCI_BASS: - case CMPCI_TREBLE: - v = CMPCI_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); + case CMPCI_FM_VOL: + case CMPCI_DAC_VOL: + v = 192; break; - case CMPCI_CD_IN_MUTE: - case CMPCI_MIC_IN_MUTE: - case CMPCI_LINE_IN_MUTE: - case CMPCI_FM_IN_MUTE: - case CMPCI_CD_SWAP: - case CMPCI_MIC_SWAP: - case CMPCI_LINE_SWAP: - case CMPCI_FM_SWAP: - v = 0; + case CMPCI_PCSPEAKER: + v = 128; break; - case CMPCI_CD_OUT_MUTE: - case CMPCI_MIC_OUT_MUTE: - case CMPCI_LINE_OUT_MUTE: + + /* booleans, set to true */ + case CMPCI_CD_MUTE: + case CMPCI_MIC_MUTE: + case CMPCI_LINE_IN_MUTE: + case CMPCI_AUX_IN_MUTE: v = 1; break; + + /* volume with inital value 0 */ + case CMPCI_CD_VOL: + case CMPCI_LINE_IN_VOL: + case CMPCI_AUX_IN_VOL: + case CMPCI_MIC_VOL: + case CMPCI_MIC_RECVOL: + /* FALLTHROUGH */ + + /* others are cleared */ + case CMPCI_MIC_PREAMP: + case CMPCI_RECORD_SOURCE: + case CMPCI_PLAYBACK_MODE: + case CMPCI_SPDIF_IN_SELECT: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_PLAYBACK: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_MONITOR_DAC: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: default: - v = CMPCI_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); + v = 0; + break; } - sc->gain[i][CMPCI_LEFT] = sc->gain[i][CMPCI_RIGHT] = v; + sc->sc_gain[i][CMPCI_LEFT] = sc->sc_gain[i][CMPCI_RIGHT] = v; cmpci_set_mixer_gain(sc, i); } } int -cmpci_intr(handle) - void *handle; +cmpci_intr(void *handle) { struct cmpci_softc *sc = handle; uint32_t intrstat; - int s; intrstat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_INTR_STATUS); - delay(10); if (!(intrstat & CMPCI_REG_ANY_INTR)) return 0; + delay(10); + /* disable and reset intr */ - s = splaudio(); if (intrstat & CMPCI_REG_CH0_INTR) cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, - CMPCI_REG_CH0_INTR_ENABLE); - if (intrstat&CMPCI_REG_CH1_INTR) + CMPCI_REG_CH0_INTR_ENABLE); + if (intrstat & CMPCI_REG_CH1_INTR) cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); - splx(s); if (intrstat & CMPCI_REG_CH0_INTR) { - if (sc->sc_play.intr) + if (sc->sc_play.intr != NULL) (*sc->sc_play.intr)(sc->sc_play.intr_arg); } if (intrstat & CMPCI_REG_CH1_INTR) { - if (sc->sc_rec.intr) - (*sc->sc_rec.intr)(sc->sc_rec.intr_arg); + if (sc->sc_rec.intr != NULL) + (*sc->sc_rec.intr)(sc->sc_rec.intr_arg); } /* enable intr */ - s = splaudio(); - if ( intrstat & CMPCI_REG_CH0_INTR ) + if (intrstat & CMPCI_REG_CH0_INTR) cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); if (intrstat & CMPCI_REG_CH1_INTR) cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); - splx(s); + +#if 0 + if (intrstat & CMPCI_REG_UART_INTR && sc->sc_mpudev != NULL) + mpu_intr(sc->sc_mpudev); +#endif return 1; } /* open/close */ int -cmpci_open(handle, flags) - void *handle; - int flags; +cmpci_open(void *handle, int flags) { - struct cmpci_softc *sc = handle; - (void)sc; - (void)flags; - return 0; } void -cmpci_close(handle) - void *handle; +cmpci_close(void *handle) { - (void)handle; } int -cmpci_query_encoding(handle, fp) - void *handle; - struct audio_encoding *fp; +cmpci_query_encoding(void *handle, struct audio_encoding *fp) { - struct cmpci_softc *sc = handle; - (void)sc; - switch (fp->index) { case 0: strlcpy(fp->name, AudioEulinear, sizeof fp->name); @@ -518,17 +617,14 @@ cmpci_query_encoding(handle, fp) return 0; } - int -cmpci_set_params(handle, setmode, usemode, play, rec) - void *handle; - int setmode, usemode; - struct audio_params *play, *rec; +cmpci_set_params(void *handle, int setmode, int usemode, + struct audio_params *play, struct audio_params *rec) { int i; struct cmpci_softc *sc = handle; - for (i=0; i<2; i++) { + for (i = 0; i < 2; i++) { int md_format; int md_divide; int md_index; @@ -544,6 +640,8 @@ cmpci_set_params(handle, setmode, usemode, play, rec) mode = AUMODE_RECORD; p = rec; break; + default: + return EINVAL; } if (!(setmode & mode)) @@ -567,22 +665,24 @@ cmpci_set_params(handle, setmode, usemode, play, rec) return (EINVAL); if (mode & AUMODE_PLAY) { p->factor = 2; - p->sw_code = mulaw_to_slinear16; + p->sw_code = mulaw_to_slinear16_le; md_format |= CMPCI_REG_FORMAT_16BIT; - } else + } else { p->sw_code = ulinear8_to_mulaw; - md_format |= CMPCI_REG_FORMAT_8BIT; + md_format |= CMPCI_REG_FORMAT_8BIT; + } break; case AUDIO_ENCODING_ALAW: if (p->precision != 8) return (EINVAL); if (mode & AUMODE_PLAY) { p->factor = 2; - p->sw_code = alaw_to_slinear16; + p->sw_code = alaw_to_slinear16_le; md_format |= CMPCI_REG_FORMAT_16BIT; - } else + } else { p->sw_code = ulinear8_to_alaw; - md_format |= CMPCI_REG_FORMAT_8BIT; + md_format |= CMPCI_REG_FORMAT_8BIT; + } break; case AUDIO_ENCODING_SLINEAR_LE: switch (p->precision) { @@ -612,13 +712,13 @@ cmpci_set_params(handle, setmode, usemode, play, rec) } break; case AUDIO_ENCODING_ULINEAR_LE: - switch ( p->precision ) { + switch (p->precision) { case 8: md_format |= CMPCI_REG_FORMAT_8BIT; break; case 16: md_format |= CMPCI_REG_FORMAT_16BIT; - p->sw_code = change_sign16; + p->sw_code = change_sign16_le; break; default: return (EINVAL); @@ -631,10 +731,12 @@ cmpci_set_params(handle, setmode, usemode, play, rec) break; case 16: md_format |= CMPCI_REG_FORMAT_16BIT; - if ( mode&AUMODE_PLAY ) - p->sw_code = swap_bytes_change_sign16; + if (mode & AUMODE_PLAY) + p->sw_code = + swap_bytes_change_sign16_le; else - p->sw_code = change_sign16_swap_bytes; + p->sw_code = + change_sign16_swap_bytes_le; break; default: return (EINVAL); @@ -645,92 +747,46 @@ cmpci_set_params(handle, setmode, usemode, play, rec) } if (mode & AUMODE_PLAY) cmpci_reg_partial_write_4(sc, - CMPCI_REG_CHANNEL_FORMAT, - CMPCI_REG_CH0_FORMAT_SHIFT, - CMPCI_REG_CH0_FORMAT_MASK, - md_format); + CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_CH0_FORMAT_SHIFT, + CMPCI_REG_CH0_FORMAT_MASK, md_format); else cmpci_reg_partial_write_4(sc, - CMPCI_REG_CHANNEL_FORMAT, - CMPCI_REG_CH1_FORMAT_SHIFT, - CMPCI_REG_CH1_FORMAT_MASK, - md_format); + CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_CH1_FORMAT_SHIFT, + CMPCI_REG_CH1_FORMAT_MASK, md_format); /* sample rate */ md_index = cmpci_rate_to_index(p->sample_rate); md_divide = cmpci_index_to_divider(md_index); p->sample_rate = cmpci_index_to_rate(md_index); -#if 0 DPRINTF(("%s: sample:%d, divider=%d\n", sc->sc_dev.dv_xname, (int)p->sample_rate, md_divide)); -#endif if (mode & AUMODE_PLAY) { cmpci_reg_partial_write_4(sc, - CMPCI_REG_FUNC_1, - CMPCI_REG_DAC_FS_SHIFT, - CMPCI_REG_DAC_FS_MASK, - md_divide); -#ifdef CMPCI_SPDIF_SUPPORT - switch (md_divide) { - case CMPCI_REG_RATE_44100: - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - break; - case CMPCI_REG_RATE_48000: - cmpci_reg_set_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - break; - default: - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - } -#endif + CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT, + CMPCI_REG_DAC_FS_MASK, md_divide); + sc->sc_play.md_divide = md_divide; } else { cmpci_reg_partial_write_4(sc, - CMPCI_REG_FUNC_1, - CMPCI_REG_ADC_FS_SHIFT, - CMPCI_REG_ADC_FS_MASK, - md_divide); -#ifdef CMPCI_SPDIF_SUPPORT - if ( sc->in_mask&CMPCI_SPDIF_IN) { - switch (md_divide) { - case CMPCI_REG_RATE_44100: - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF1_ENABLE); - break; - default: - return EINVAL; - } - } else - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF1_ENABLE); -#endif + CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT, + CMPCI_REG_ADC_FS_MASK, md_divide); + sc->sc_rec.md_divide = md_divide; } + cmpci_set_out_ports(sc); + cmpci_set_in_ports(sc); } return 0; } /* ARGSUSED */ int -cmpci_round_blocksize(handle, block) - void *handle; - int block; +cmpci_round_blocksize(void *handle, int block) { return ((block + 3) & -4); } int -cmpci_halt_output(handle) - void *handle; +cmpci_halt_output(void *handle) { struct cmpci_softc *sc = handle; int s; @@ -749,8 +805,7 @@ cmpci_halt_output(handle) } int -cmpci_halt_input(handle) - void *handle; +cmpci_halt_input(void *handle) { struct cmpci_softc *sc = handle; int s; @@ -764,289 +819,299 @@ cmpci_halt_input(handle) delay(10); cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); splx(s); - + return 0; } +/* get audio device information */ int -cmpci_getdev(handle, retp) - void *handle; - struct audio_device *retp; +cmpci_getdev(void *handle, struct audio_device *ad) { - *retp = cmpci_device; + struct cmpci_softc *sc = handle; + + strncpy(ad->name, "CMI PCI Audio", sizeof(ad->name)); + snprintf(ad->version, sizeof(ad->version), "0x%02x", + PCI_REVISION(sc->sc_class)); + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_CMI_CMI8338A: + strncpy(ad->config, "CMI8338A", sizeof(ad->config)); + break; + case PCI_PRODUCT_CMI_CMI8338B: + strncpy(ad->config, "CMI8338B", sizeof(ad->config)); + break; + case PCI_PRODUCT_CMI_CMI8738: + strncpy(ad->config, "CMI8738", sizeof(ad->config)); + break; + case PCI_PRODUCT_CMI_CMI8738B: + strncpy(ad->config, "CMI8738B", sizeof(ad->config)); + break; + default: + strncpy(ad->config, "unknown", sizeof(ad->config)); + } + return 0; } - /* mixer device information */ int -cmpci_query_devinfo(handle, dip) - void *handle; - mixer_devinfo_t *dip; +cmpci_query_devinfo(void *handle, mixer_devinfo_t *dip) { + static const char *const mixer_port_names[] = { + AudioNdac, AudioNfmsynth, AudioNcd, AudioNline, AudioNaux, + AudioNmicrophone + }; + static const char *const mixer_classes[] = { + AudioCinputs, AudioCoutputs, AudioCrecord, CmpciCplayback, + CmpciCspdif + }; struct cmpci_softc *sc = handle; - (void)sc; + int i; + + dip->prev = dip->next = AUDIO_MIXER_LAST; switch (dip->index) { - case CMPCI_MASTER_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - return 0; - case CMPCI_FM_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = CMPCI_FM_IN_MUTE; - strlcpy(dip->label.name, AudioNfmsynth, - sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - return 0; - case CMPCI_CD_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = CMPCI_CD_IN_MUTE; - strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - return 0; - case CMPCI_VOICE_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - return 0; + case CMPCI_INPUT_CLASS: case CMPCI_OUTPUT_CLASS: + case CMPCI_RECORD_CLASS: + case CMPCI_PLAYBACK_CLASS: + case CMPCI_SPDIF_CLASS: dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCoutputs, + dip->mixer_class = dip->index; + strlcpy(dip->label.name, + mixer_classes[dip->index - CMPCI_INPUT_CLASS], sizeof dip->label.name); return 0; + + case CMPCI_AUX_IN_VOL: + dip->un.v.delta = 1 << (8 - CMPCI_REG_AUX_VALBITS); + goto vol1; + case CMPCI_DAC_VOL: + case CMPCI_FM_VOL: + case CMPCI_CD_VOL: + case CMPCI_LINE_IN_VOL: case CMPCI_MIC_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = CMPCI_MIC_IN_MUTE; - strlcpy(dip->label.name, AudioNmicrophone, + dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS); + vol1: dip->mixer_class = CMPCI_INPUT_CLASS; + dip->next = dip->index + 6; /* CMPCI_xxx_MUTE */ + strlcpy(dip->label.name, mixer_port_names[dip->index], sizeof dip->label.name); - dip->un.v.num_channels = 1; + dip->un.v.num_channels = (dip->index == CMPCI_MIC_VOL ? 1 : 2); + vol: + dip->type = AUDIO_MIXER_VALUE; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); return 0; - case CMPCI_LINE_IN_VOL: - dip->type = AUDIO_MIXER_VALUE; + + case CMPCI_MIC_MUTE: + dip->next = CMPCI_MIC_PREAMP; + /* FALLTHROUGH */ + case CMPCI_DAC_MUTE: + case CMPCI_FM_MUTE: + case CMPCI_CD_MUTE: + case CMPCI_LINE_IN_MUTE: + case CMPCI_AUX_IN_MUTE: + dip->prev = dip->index - 6; /* CMPCI_xxx_VOL */ dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = CMPCI_LINE_IN_MUTE; - strlcpy(dip->label.name, AudioNline, sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); + strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name); + goto on_off; + on_off: + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strlcpy(dip->un.e.member[0].label.name, AudioNoff, + sizeof dip->un.e.member[0].label.name); + dip->un.e.member[0].ord = 0; + strlcpy(dip->un.e.member[1].label.name, AudioNon, + sizeof dip->un.e.member[1].label.name); + dip->un.e.member[1].ord = 1; return 0; + + case CMPCI_MIC_PREAMP: + dip->mixer_class = CMPCI_INPUT_CLASS; + dip->prev = CMPCI_MIC_MUTE; + strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name); + goto on_off; + case CMPCI_PCSPEAKER: + dip->mixer_class = CMPCI_INPUT_CLASS; + strlcpy(dip->label.name, AudioNspeaker, sizeof dip->label.name); + dip->un.v.num_channels = 1; + dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_SPEAKER_VALBITS); + goto vol; case CMPCI_RECORD_SOURCE: dip->mixer_class = CMPCI_RECORD_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); dip->type = AUDIO_MIXER_SET; -#ifdef CMPCI_SPDIF_SUPPORT - dip->un.s.num_mem = 5; -#else - dip->un.s.num_mem = 4; -#endif + dip->un.s.num_mem = 7; strlcpy(dip->un.s.member[0].label.name, AudioNmicrophone, sizeof dip->un.s.member[0].label.name); - dip->un.s.member[0].mask = 1 << CMPCI_MIC_VOL; + dip->un.s.member[0].mask = CMPCI_RECORD_SOURCE_MIC; strlcpy(dip->un.s.member[1].label.name, AudioNcd, sizeof dip->un.s.member[1].label.name); - dip->un.s.member[1].mask = 1 << CMPCI_CD_VOL; + dip->un.s.member[1].mask = CMPCI_RECORD_SOURCE_CD; strlcpy(dip->un.s.member[2].label.name, AudioNline, sizeof dip->un.s.member[2].label.name); - dip->un.s.member[2].mask = 1 << CMPCI_LINE_IN_VOL; - strlcpy(dip->un.s.member[3].label.name, AudioNfmsynth, + dip->un.s.member[2].mask = CMPCI_RECORD_SOURCE_LINE_IN; + strlcpy(dip->un.s.member[3].label.name, AudioNaux, sizeof dip->un.s.member[3].label.name); - dip->un.s.member[3].mask = 1 << CMPCI_FM_VOL; -#ifdef CMPCI_SPDIF_SUPPORT - strlcpy(dip->un.s.member[4].label.name, CmpciNspdif, + dip->un.s.member[3].mask = CMPCI_RECORD_SOURCE_AUX_IN; + strlcpy(dip->un.s.member[4].label.name, AudioNwave, sizeof dip->un.s.member[4].label.name); - dip->un.s.member[4].mask = 1 << CMPCI_SPDIF_IN; -#endif - return 0; - case CMPCI_BASS: - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name); - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_EQUALIZATION_CLASS; - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNbass, - sizeof dip->un.v.units.name); + dip->un.s.member[4].mask = CMPCI_RECORD_SOURCE_WAVE; + strlcpy(dip->un.s.member[5].label.name, AudioNfmsynth, + sizeof dip->un.s.member[5].label.name); + dip->un.s.member[5].mask = CMPCI_RECORD_SOURCE_FM; + strlcpy(dip->un.s.member[6].label.name, CmpciNspdif, + sizeof dip->un.s.member[6].label.name); + dip->un.s.member[6].mask = CMPCI_RECORD_SOURCE_SPDIF; return 0; - case CMPCI_TREBLE: - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name); - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_EQUALIZATION_CLASS; - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNtreble, - sizeof dip->un.v.units.name); - return 0; - case CMPCI_RECORD_CLASS: - dip->type = AUDIO_MIXER_CLASS; + case CMPCI_MIC_RECVOL: dip->mixer_class = CMPCI_RECORD_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCrecord, - sizeof dip->label.name); - return 0; - case CMPCI_INPUT_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCinputs, - sizeof dip->label.name); - return 0; - case CMPCI_PCSPEAKER: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, "pc_speaker", sizeof dip->label.name); + strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name); dip->un.v.num_channels = 1; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); + dip->un.v.delta = 1 << (8 - CMPCI_REG_ADMIC_VALBITS); + goto vol; + + case CMPCI_PLAYBACK_MODE: + dip->mixer_class = CMPCI_PLAYBACK_CLASS; + dip->type = AUDIO_MIXER_ENUM; + strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name); + dip->un.e.num_mem = 2; + strlcpy(dip->un.e.member[0].label.name, AudioNdac, + sizeof dip->un.e.member[0].label.name); + dip->un.e.member[0].ord = CMPCI_PLAYBACK_MODE_WAVE; + strlcpy(dip->un.e.member[1].label.name, CmpciNspdif, + sizeof dip->un.e.member[1].label.name); + dip->un.e.member[1].ord = CMPCI_PLAYBACK_MODE_SPDIF; return 0; - case CMPCI_INPUT_GAIN: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNinput, - sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); + case CMPCI_SPDIF_IN_SELECT: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->type = AUDIO_MIXER_ENUM; + dip->next = CMPCI_SPDIF_IN_PHASE; + strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name); + i = 0; + strlcpy(dip->un.e.member[i].label.name, CmpciNspdin1, + sizeof dip->un.e.member[i].label.name); + dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN1; + if (CMPCI_ISCAP(sc, 2ND_SPDIN)) { + strlcpy(dip->un.e.member[i].label.name, CmpciNspdin2, + sizeof dip->un.e.member[i].label.name); + dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN2; + } + strlcpy(dip->un.e.member[i].label.name, CmpciNspdout, + sizeof dip->un.e.member[i].label.name); + dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDOUT; + dip->un.e.num_mem = i; return 0; - case CMPCI_OUTPUT_GAIN: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); - dip->un.v.num_channels = 2; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); + case CMPCI_SPDIF_IN_PHASE: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = CMPCI_SPDIF_IN_SELECT; + strlcpy(dip->label.name, CmpciNphase, sizeof dip->label.name); + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strlcpy(dip->un.e.member[0].label.name, CmpciNpositive, + sizeof dip->un.e.member[0].label.name); + dip->un.e.member[0].ord = CMPCI_SPDIF_IN_PHASE_POSITIVE; + strlcpy(dip->un.e.member[1].label.name, CmpciNnegative, + sizeof dip->un.e.member[1].label.name); + dip->un.e.member[1].ord = CMPCI_SPDIF_IN_PHASE_NEGATIVE; return 0; - case CMPCI_AGC: + case CMPCI_SPDIF_LOOP: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->next = CMPCI_SPDIF_OUT_PLAYBACK; + strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); dip->type = AUDIO_MIXER_ENUM; - dip->mixer_class = CMPCI_INPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, "agc", sizeof dip->label.name); dip->un.e.num_mem = 2; - strlcpy(dip->un.e.member[0].label.name, AudioNoff, + strlcpy(dip->un.e.member[0].label.name, CmpciNplayback, sizeof dip->un.e.member[0].label.name); - dip->un.e.member[0].ord = 0; - strlcpy(dip->un.e.member[1].label.name, AudioNon, + dip->un.e.member[0].ord = CMPCI_SPDIF_LOOP_OFF; + strlcpy(dip->un.e.member[1].label.name, CmpciNspdin, sizeof dip->un.e.member[1].label.name); - dip->un.e.member[1].ord = 1; + dip->un.e.member[1].ord = CMPCI_SPDIF_LOOP_ON; return 0; - case CMPCI_EQUALIZATION_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = CMPCI_EQUALIZATION_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCequalization, - sizeof dip->label.name); + case CMPCI_SPDIF_OUT_PLAYBACK: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = CMPCI_SPDIF_LOOP; + dip->next = CMPCI_SPDIF_OUT_VOLTAGE; + strlcpy(dip->label.name, CmpciNplayback, sizeof dip->label.name); + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strlcpy(dip->un.e.member[0].label.name, AudioNwave, + sizeof dip->un.e.member[0].label.name); + dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_PLAYBACK_WAVE; + strlcpy(dip->un.e.member[1].label.name, CmpciNlegacy, + sizeof dip->un.e.member[1].label.name); + dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_PLAYBACK_LEGACY; return 0; - case CMPCI_CD_IN_MUTE: - dip->prev = CMPCI_CD_VOL; - dip->next = CMPCI_CD_SWAP; - dip->mixer_class = CMPCI_INPUT_CLASS; - goto mute; - case CMPCI_MIC_IN_MUTE: - dip->prev = CMPCI_MIC_VOL; - dip->next = CMPCI_MIC_SWAP; - dip->mixer_class = CMPCI_INPUT_CLASS; - goto mute; - case CMPCI_LINE_IN_MUTE: - dip->prev = CMPCI_LINE_IN_VOL; - dip->next = CMPCI_LINE_SWAP; - dip->mixer_class = CMPCI_INPUT_CLASS; - goto mute; - case CMPCI_FM_IN_MUTE: - dip->prev = CMPCI_FM_VOL; - dip->next = CMPCI_FM_SWAP; - dip->mixer_class = CMPCI_INPUT_CLASS; - goto mute; - case CMPCI_CD_SWAP: - dip->prev = CMPCI_CD_IN_MUTE; - dip->next = CMPCI_CD_OUT_MUTE; - goto swap; - case CMPCI_MIC_SWAP: - dip->prev = CMPCI_MIC_IN_MUTE; - dip->next = CMPCI_MIC_OUT_MUTE; - goto swap; - case CMPCI_LINE_SWAP: - dip->prev = CMPCI_LINE_IN_MUTE; - dip->next = CMPCI_LINE_OUT_MUTE; - goto swap; - case CMPCI_FM_SWAP: - dip->prev = CMPCI_FM_IN_MUTE; - dip->next = AUDIO_MIXER_LAST; - swap: - dip->mixer_class = CMPCI_INPUT_CLASS; - strlcpy(dip->label.name, AudioNswap, sizeof dip->label.name); - goto mute1; - case CMPCI_CD_OUT_MUTE: - dip->prev = CMPCI_CD_SWAP; - dip->next = AUDIO_MIXER_LAST; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - goto mute; - case CMPCI_MIC_OUT_MUTE: - dip->prev = CMPCI_MIC_SWAP; - dip->next = AUDIO_MIXER_LAST; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - goto mute; - case CMPCI_LINE_OUT_MUTE: - dip->prev = CMPCI_LINE_SWAP; - dip->next = AUDIO_MIXER_LAST; - dip->mixer_class = CMPCI_OUTPUT_CLASS; - mute: - strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name); - mute1: + case CMPCI_SPDIF_OUT_VOLTAGE: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = CMPCI_SPDIF_OUT_PLAYBACK; + strlcpy(dip->label.name, CmpciNvoltage, sizeof dip->label.name); dip->type = AUDIO_MIXER_ENUM; dip->un.e.num_mem = 2; + strlcpy(dip->un.e.member[0].label.name, CmpciNhigh_v, + sizeof dip->un.e.member[0].label.name); + dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH; + strlcpy(dip->un.e.member[1].label.name, CmpciNlow_v, + sizeof dip->un.e.member[1].label.name); + dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW; + return 0; + case CMPCI_MONITOR_DAC: + dip->mixer_class = CMPCI_SPDIF_CLASS; + strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name); + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 3; strlcpy(dip->un.e.member[0].label.name, AudioNoff, sizeof dip->un.e.member[0].label.name); - dip->un.e.member[0].ord = 0; - strlcpy(dip->un.e.member[1].label.name, AudioNon, + dip->un.e.member[0].ord = CMPCI_MONITOR_DAC_OFF; + strlcpy(dip->un.e.member[1].label.name, CmpciNspdin, sizeof dip->un.e.member[1].label.name); - dip->un.e.member[1].ord = 1; + dip->un.e.member[1].ord = CMPCI_MONITOR_DAC_SPDIN; + strlcpy(dip->un.e.member[2].label.name, CmpciNspdout, + sizeof dip->un.e.member[2].label.name); + dip->un.e.member[2].ord = CMPCI_MONITOR_DAC_SPDOUT; return 0; + + case CMPCI_MASTER_VOL: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); + dip->un.v.num_channels = 2; + dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS); + goto vol; + case CMPCI_REAR: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->next = CMPCI_INDIVIDUAL; + strlcpy(dip->label.name, CmpciNrear, sizeof dip->label.name); + goto on_off; + case CMPCI_INDIVIDUAL: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = CMPCI_REAR; + dip->next = CMPCI_REVERSE; + strlcpy(dip->label.name, CmpciNindividual, sizeof dip->label.name); + goto on_off; + case CMPCI_REVERSE: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = CMPCI_INDIVIDUAL; + strlcpy(dip->label.name, CmpciNreverse, sizeof dip->label.name); + goto on_off; + case CMPCI_SURROUND: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + strlcpy(dip->label.name, CmpciNsurround, sizeof dip->label.name); + goto on_off; } return ENXIO; } int -cmpci_alloc_dmamem(sc, size, type, flags, r_addr) - struct cmpci_softc *sc; - size_t size; - int type, flags; - caddr_t *r_addr; +cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, int type, int flags, + caddr_t *r_addr) { - int ret = 0; + int error = 0; struct cmpci_dmanode *n; int w; - - if ( NULL == (n=malloc(sizeof(struct cmpci_dmanode), type, flags)) ) { - ret = ENOMEM; + + n = malloc(sizeof(struct cmpci_dmanode), type, flags); + if (n == NULL) { + error = ENOMEM; goto quit; } @@ -1055,52 +1120,50 @@ cmpci_alloc_dmamem(sc, size, type, flags, r_addr) #define CMPCI_DMABUF_BOUNDARY 0x0 n->cd_tag = sc->sc_dmat; n->cd_size = size; - if ( (ret=bus_dmamem_alloc(n->cd_tag, n->cd_size, - CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, - n->cd_segs, - sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), - &n->cd_nsegs, w)) ) + error = bus_dmamem_alloc(n->cd_tag, n->cd_size, + CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, n->cd_segs, + sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w); + if (error) goto mfree; - if ( (ret=bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size, - &n->cd_addr, w | BUS_DMA_COHERENT)) ) + error = bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size, + &n->cd_addr, w | BUS_DMA_COHERENT); + if (error) goto dmafree; - if ( (ret=bus_dmamap_create(n->cd_tag, n->cd_size, 1, n->cd_size, 0, - w, &n->cd_map)) ) + error = bus_dmamap_create(n->cd_tag, n->cd_size, 1, n->cd_size, 0, + w, &n->cd_map); + if (error) goto unmap; - if ( (ret=bus_dmamap_load(n->cd_tag, n->cd_map, n->cd_addr, n->cd_size, - NULL, w)) ) + error = bus_dmamap_load(n->cd_tag, n->cd_map, n->cd_addr, n->cd_size, + NULL, w); + if (error) goto destroy; n->cd_next = sc->sc_dmap; sc->sc_dmap = n; *r_addr = KVADDR(n); return 0; - -destroy: + + destroy: bus_dmamap_destroy(n->cd_tag, n->cd_map); -unmap: + unmap: bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size); -dmafree: + dmafree: bus_dmamem_free(n->cd_tag, n->cd_segs, sizeof(n->cd_segs)/sizeof(n->cd_segs[0])); -mfree: + mfree: free(n, type); -quit: - return ret; + quit: + return error; } int -cmpci_free_dmamem(sc, addr, type) - struct cmpci_softc *sc; - caddr_t addr; - int type; +cmpci_free_dmamem(struct cmpci_softc *sc, caddr_t addr, int type) { - struct cmpci_dmanode **nnp; + struct cmpci_dmanode **nnp; for (nnp = &sc->sc_dmap; *nnp; nnp = &(*nnp)->cd_next) { if ((*nnp)->cd_addr == addr) { struct cmpci_dmanode *n = *nnp; - bus_dmamap_unload(n->cd_tag, n->cd_map); bus_dmamap_destroy(n->cd_tag, n->cd_map); bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size); @@ -1114,11 +1177,10 @@ cmpci_free_dmamem(sc, addr, type) } struct cmpci_dmanode * -cmpci_find_dmamem(sc, addr) - struct cmpci_softc *sc; - caddr_t addr; +cmpci_find_dmamem(struct cmpci_softc *sc, caddr_t addr) { struct cmpci_dmanode *p; + for (p = sc->sc_dmap; p; p = p->cd_next) { if (KVADDR(p) == (void *)addr) break; @@ -1127,11 +1189,10 @@ cmpci_find_dmamem(sc, addr) } #if 0 +void cmpci_print_dmamem(struct cmpci_dmanode *p); + void -cmpci_print_dmamem(struct cmpci_dmanode *p); -void -cmpci_print_dmamem(p) - struct cmpci_dmanode *p; +cmpci_print_dmamem(struct cmpci_dmanode *p) { DPRINTF(("DMA at virt:%p, dmaseg:%p, mapseg:%p, size:%p\n", (void *)p->cd_addr, (void *)p->cd_segs[0].ds_addr, @@ -1140,35 +1201,25 @@ cmpci_print_dmamem(p) #endif /* DEBUG */ void * -cmpci_malloc(handle, direction, size, type, flags) - void *handle; - int direction; - size_t size; - int type, flags; +cmpci_malloc(void *handle, int direction, size_t size, int type, + int flags) { - struct cmpci_softc *sc = handle; caddr_t addr; - - if ( cmpci_alloc_dmamem(sc, size, type, flags, &addr) ) + + if (cmpci_alloc_dmamem(handle, size, type, flags, &addr)) return NULL; return addr; } void -cmpci_free(handle, addr, type) - void *handle; - void *addr; - int type; +cmpci_free(void *handle, void *addr, int type) { - struct cmpci_softc *sc = handle; - - cmpci_free_dmamem(sc, addr, type); + cmpci_free_dmamem(handle, addr, type); } #define MAXVAL 256 int -cmpci_adjust(val, mask) - int val, mask; +cmpci_adjust(int val, int mask) { val += (MAXVAL - mask) >> 1; if (val >= MAXVAL) @@ -1177,23 +1228,33 @@ cmpci_adjust(val, mask) } void -cmpci_set_mixer_gain(sc, port) - struct cmpci_softc *sc; - int port; +cmpci_set_mixer_gain(struct cmpci_softc *sc, int port) { int src; + int bits, mask; switch (port) { case CMPCI_MIC_VOL: - src = CMPCI_SB16_MIXER_MIC; - break; + cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_MIC, + CMPCI_ADJUST_MIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR])); + return; case CMPCI_MASTER_VOL: src = CMPCI_SB16_MIXER_MASTER_L; break; case CMPCI_LINE_IN_VOL: src = CMPCI_SB16_MIXER_LINE_L; break; - case CMPCI_VOICE_VOL: + case CMPCI_AUX_IN_VOL: + bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MIXER_AUX, + CMPCI_ADJUST_AUX_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT], + sc->sc_gain[port][CMPCI_RIGHT])); + return; + case CMPCI_MIC_RECVOL: + cmpci_reg_partial_write_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_ADMIC_SHIFT, CMPCI_REG_ADMIC_MASK, + CMPCI_ADJUST_ADMIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR])); + return; + case CMPCI_DAC_VOL: src = CMPCI_SB16_MIXER_VOICE_L; break; case CMPCI_FM_VOL: @@ -1202,125 +1263,320 @@ cmpci_set_mixer_gain(sc, port) case CMPCI_CD_VOL: src = CMPCI_SB16_MIXER_CDDA_L; break; - case CMPCI_INPUT_GAIN: - src = CMPCI_SB16_MIXER_INGAIN_L; - break; - case CMPCI_OUTPUT_GAIN: - src = CMPCI_SB16_MIXER_OUTGAIN_L; - break; - case CMPCI_TREBLE: - src = CMPCI_SB16_MIXER_TREBLE_L; - break; - case CMPCI_BASS: - src = CMPCI_SB16_MIXER_BASS_L; - break; case CMPCI_PCSPEAKER: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_SPEAKER, - sc->gain[port][CMPCI_LEFT]); + CMPCI_ADJUST_2_GAIN(sc, sc->sc_gain[port][CMPCI_LR])); + return; + case CMPCI_MIC_PREAMP: + if (sc->sc_gain[port][CMPCI_LR]) + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_MICGAINZ); + else + cmpci_reg_set_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_MICGAINZ); + return; + + case CMPCI_DAC_MUTE: + if (sc->sc_gain[port][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_WSMUTE); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_WSMUTE); + return; + case CMPCI_FM_MUTE: + if (sc->sc_gain[port][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_FMMUTE); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_FMMUTE); + return; + case CMPCI_AUX_IN_MUTE: + if (sc->sc_gain[port][CMPCI_LR]) + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM); + else + cmpci_reg_set_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM); + return; + case CMPCI_CD_MUTE: + mask = CMPCI_SB16_SW_CD; + goto sbmute; + case CMPCI_MIC_MUTE: + mask = CMPCI_SB16_SW_MIC; + goto sbmute; + case CMPCI_LINE_IN_MUTE: + mask = CMPCI_SB16_SW_LINE; + sbmute: + bits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_OUTMIX); + if (sc->sc_gain[port][CMPCI_LR]) + bits = bits & ~mask; + else + bits = bits | mask; + cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX, bits); + return; + + case CMPCI_SPDIF_IN_SELECT: + case CMPCI_MONITOR_DAC: + case CMPCI_PLAYBACK_MODE: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_PLAYBACK: + cmpci_set_out_ports(sc); + return; + case CMPCI_SPDIF_OUT_VOLTAGE: + if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) { + if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR] + == CMPCI_SPDIF_OUT_VOLTAGE_HIGH) + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_5V); + else + cmpci_reg_set_reg_misc(sc, CMPCI_REG_5V); + } + return; + case CMPCI_SURROUND: + if (CMPCI_ISCAP(sc, SURROUND)) { + if (sc->sc_gain[CMPCI_SURROUND][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SURROUND); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SURROUND); + } + return; + case CMPCI_REAR: + if (CMPCI_ISCAP(sc, REAR)) { + if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) + cmpci_reg_set_reg_misc(sc, CMPCI_REG_N4SPK3D); + else + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_N4SPK3D); + } + return; + case CMPCI_INDIVIDUAL: + if (CMPCI_ISCAP(sc, INDIVIDUAL_REAR)) { + if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_INDIVIDUAL); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_INDIVIDUAL); + } + return; + case CMPCI_REVERSE: + if (CMPCI_ISCAP(sc, REVERSE_FR)) { + if (sc->sc_gain[CMPCI_REVERSE][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_REVERSE_FR); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_REVERSE_FR); + } + return; + case CMPCI_SPDIF_IN_PHASE: + if (CMPCI_ISCAP(sc, SPDIN_PHASE)) { + if (sc->sc_gain[CMPCI_SPDIF_IN_PHASE][CMPCI_LR] + == CMPCI_SPDIF_IN_PHASE_POSITIVE) + cmpci_reg_clear_1(sc, CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_SPDIN_PHASE); + else + cmpci_reg_set_1(sc, CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_SPDIN_PHASE); + } return; default: return; } - cmpci_mixerreg_write(sc, src, sc->gain[port][CMPCI_LEFT]); + + cmpci_mixerreg_write(sc, src, + CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT])); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_L_TO_R(src), - sc->gain[port][CMPCI_RIGHT]); + CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_RIGHT])); +} + +void +cmpci_set_out_ports(struct cmpci_softc *sc) +{ + u_int8_t v; + int enspdout = 0; + + if (!CMPCI_ISCAP(sc, SPDLOOP)) + return; + + /* SPDIF/out select */ + if (sc->sc_gain[CMPCI_SPDIF_LOOP][CMPCI_LR] == CMPCI_SPDIF_LOOP_OFF) { + /* playback */ + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); + } else { + /* monitor SPDIF/in */ + cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); + } + + /* SPDIF in select */ + v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR]; + if (v & CMPCI_SPDIFIN_SPDIFIN2) + cmpci_reg_set_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN); + else + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN); + if (v & CMPCI_SPDIFIN_SPDIFOUT) + cmpci_reg_set_reg_misc(sc, CMPCI_REG_SPDFLOOPI); + else + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_SPDFLOOPI); + + /* playback to ... */ + if (CMPCI_ISCAP(sc, SPDOUT) && + sc->sc_gain[CMPCI_PLAYBACK_MODE][CMPCI_LR] + == CMPCI_PLAYBACK_MODE_SPDIF && + (sc->sc_play.md_divide == CMPCI_REG_RATE_44100 || + (CMPCI_ISCAP(sc, SPDOUT_48K) && + sc->sc_play.md_divide==CMPCI_REG_RATE_48000))) { + /* playback to SPDIF */ + cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF0_ENABLE); + enspdout = 1; + if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000) + cmpci_reg_set_reg_misc(sc, + CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K); + else + cmpci_reg_clear_reg_misc(sc, + CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K); + } else { + /* playback to DAC */ + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF0_ENABLE); + if (CMPCI_ISCAP(sc, SPDOUT_48K)) + cmpci_reg_clear_reg_misc(sc, + CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K); + } + + /* legacy to SPDIF/out or not */ + if (CMPCI_ISCAP(sc, SPDLEGACY)) { + if (sc->sc_gain[CMPCI_SPDIF_OUT_PLAYBACK][CMPCI_LR] + == CMPCI_SPDIF_OUT_PLAYBACK_WAVE) + cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_LEGACY_SPDIF_ENABLE); + else { + cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_LEGACY_SPDIF_ENABLE); + enspdout = 1; + } + } + + /* enable/disable SPDIF/out */ + if (CMPCI_ISCAP(sc, XSPDOUT) && enspdout) + cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_XSPDIF_ENABLE); + else + cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_XSPDIF_ENABLE); + + /* SPDIF monitor (digital to analog output) */ + if (CMPCI_ISCAP(sc, SPDIN_MONITOR)) { + v = sc->sc_gain[CMPCI_MONITOR_DAC][CMPCI_LR]; + if (!(v & CMPCI_MONDAC_ENABLE)) + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SPDIN_MONITOR); + if (v & CMPCI_MONDAC_SPDOUT) + cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIFOUT_DAC); + else + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIFOUT_DAC); + if (v & CMPCI_MONDAC_ENABLE) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SPDIN_MONITOR); + } } int -cmpci_set_in_ports(sc, mask) - struct cmpci_softc *sc; - int mask; +cmpci_set_in_ports(struct cmpci_softc *sc) { + int mask; int bitsl, bitsr; - if (mask & ~((1<<CMPCI_FM_VOL) | (1<<CMPCI_LINE_IN_VOL) | - (1<<CMPCI_CD_VOL) | (1<<CMPCI_MIC_VOL) -#ifdef CMPCI_SPDIF_SUPPORT - | (1<<CMPCI_SPDIF_IN) -#endif - )) - return EINVAL; - bitsr = 0; - if (mask & (1<<CMPCI_FM_VOL)) - bitsr |= CMPCI_SB16_MIXER_FM_SRC_R; - if (mask & (1<<CMPCI_LINE_IN_VOL)) - bitsr |= CMPCI_SB16_MIXER_LINE_SRC_R; - if (mask & (1<<CMPCI_CD_VOL)) - bitsr |= CMPCI_SB16_MIXER_CD_SRC_R; + mask = sc->sc_in_mask; + + /* + * Note CMPCI_RECORD_SOURCE_CD, CMPCI_RECORD_SOURCE_LINE_IN and + * CMPCI_RECORD_SOURCE_FM are defined to the corresponding bit + * of the mixer register. + */ + bitsr = mask & (CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN | + CMPCI_RECORD_SOURCE_FM); + bitsl = CMPCI_SB16_MIXER_SRC_R_TO_L(bitsr); - if (mask & (1<<CMPCI_MIC_VOL)) { + if (mask & CMPCI_RECORD_SOURCE_MIC) { bitsl |= CMPCI_SB16_MIXER_MIC_SRC; bitsr |= CMPCI_SB16_MIXER_MIC_SRC; } cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, bitsl); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, bitsr); - sc->in_mask = mask; + if (mask & CMPCI_RECORD_SOURCE_AUX_IN) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25, + CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN); + + if (mask & CMPCI_RECORD_SOURCE_WAVE) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR); + + if (CMPCI_ISCAP(sc, SPDIN) && + (sc->sc_rec.md_divide == CMPCI_REG_RATE_44100 || + (CMPCI_ISCAP(sc, SPDOUT_48K) && + sc->sc_rec.md_divide == CMPCI_REG_RATE_48000/* XXX? */))) { + if (mask & CMPCI_RECORD_SOURCE_SPDIF) { + /* enable SPDIF/in */ + cmpci_reg_set_4(sc, + CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF1_ENABLE); + } else { + cmpci_reg_clear_4(sc, + CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF1_ENABLE); + } + } return 0; } int -cmpci_set_port(handle, cp) - void *handle; - mixer_ctrl_t *cp; +cmpci_set_port(void *handle, mixer_ctrl_t *cp) { struct cmpci_softc *sc = handle; int lgain, rgain; - int mask, bits; - int lmask, rmask, lbits, rbits; - int mute, swap; - + switch (cp->dev) { - case CMPCI_TREBLE: - case CMPCI_BASS: - case CMPCI_PCSPEAKER: - case CMPCI_INPUT_GAIN: - case CMPCI_OUTPUT_GAIN: case CMPCI_MIC_VOL: - case CMPCI_LINE_IN_VOL: - case CMPCI_VOICE_VOL: + case CMPCI_PCSPEAKER: + case CMPCI_MIC_RECVOL: + if (cp->un.value.num_channels != 1) + return EINVAL; + /* FALLTHROUGH */ + case CMPCI_DAC_VOL: case CMPCI_FM_VOL: case CMPCI_CD_VOL: + case CMPCI_LINE_IN_VOL: + case CMPCI_AUX_IN_VOL: case CMPCI_MASTER_VOL: if (cp->type != AUDIO_MIXER_VALUE) return EINVAL; - switch (cp->dev) { - case CMPCI_MIC_VOL: - if (cp->un.value.num_channels != 1) - return EINVAL; - - lgain = rgain = CMPCI_ADJUST_MIC_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + switch (cp->un.value.num_channels) { + case 1: + lgain = rgain = + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; break; - case CMPCI_PCSPEAKER: - if (cp->un.value.num_channels != 1) - return EINVAL; - /* FALLTHROUGH */ - case CMPCI_INPUT_GAIN: - case CMPCI_OUTPUT_GAIN: - lgain = rgain = CMPCI_ADJUST_2_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + case 2: + lgain = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; + rgain = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; break; default: - switch (cp->un.value.num_channels) { - case 1: - lgain = rgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); - break; - case 2: - lgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); - rgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]); - break; - default: - return EINVAL; - } - break; + return EINVAL; } - sc->gain[cp->dev][CMPCI_LEFT] = lgain; - sc->gain[cp->dev][CMPCI_RIGHT] = rgain; + sc->sc_gain[cp->dev][CMPCI_LEFT] = lgain; + sc->sc_gain[cp->dev][CMPCI_RIGHT] = rgain; cmpci_set_mixer_gain(sc, cp->dev); break; @@ -1328,121 +1584,103 @@ cmpci_set_port(handle, cp) case CMPCI_RECORD_SOURCE: if (cp->type != AUDIO_MIXER_SET) return EINVAL; -#ifdef CMPCI_SPDIF_SUPPORT - if ( cp->un.mask&(1<<CMPCI_SPDIF_IN) ) - cp->un.mask = 1<<CMPCI_SPDIF_IN; -#endif - return cmpci_set_in_ports(sc, cp->un.mask); - case CMPCI_AGC: - cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_AGC, cp->un.ord & 1); - break; - case CMPCI_CD_OUT_MUTE: - mask = CMPCI_SB16_SW_CD; - goto omute; - case CMPCI_MIC_OUT_MUTE: - mask = CMPCI_SB16_SW_MIC; - goto omute; - case CMPCI_LINE_OUT_MUTE: - mask = CMPCI_SB16_SW_LINE; - omute: - if (cp->type != AUDIO_MIXER_ENUM) + if (cp->un.mask & ~(CMPCI_RECORD_SOURCE_MIC | + CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN | + CMPCI_RECORD_SOURCE_AUX_IN | CMPCI_RECORD_SOURCE_WAVE | + CMPCI_RECORD_SOURCE_FM | CMPCI_RECORD_SOURCE_SPDIF)) return EINVAL; - bits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_OUTMIX); - sc->gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; - if (cp->un.ord) - bits = bits & ~mask; - else - bits = bits | mask; - cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX, bits); - break; - case CMPCI_MIC_IN_MUTE: - case CMPCI_MIC_SWAP: - lmask = rmask = CMPCI_SB16_SW_MIC; - goto imute; - case CMPCI_CD_IN_MUTE: - case CMPCI_CD_SWAP: - lmask = CMPCI_SB16_SW_CD_L; - rmask = CMPCI_SB16_SW_CD_R; - goto imute; + if (cp->un.mask & CMPCI_RECORD_SOURCE_SPDIF) + cp->un.mask = CMPCI_RECORD_SOURCE_SPDIF; + + sc->sc_in_mask = cp->un.mask; + return cmpci_set_in_ports(sc); + + /* boolean */ + case CMPCI_DAC_MUTE: + case CMPCI_FM_MUTE: + case CMPCI_CD_MUTE: case CMPCI_LINE_IN_MUTE: - case CMPCI_LINE_SWAP: - lmask = CMPCI_SB16_SW_LINE_L; - rmask = CMPCI_SB16_SW_LINE_R; - goto imute; - case CMPCI_FM_IN_MUTE: - case CMPCI_FM_SWAP: - lmask = CMPCI_SB16_SW_FM_L; - rmask = CMPCI_SB16_SW_FM_R; - imute: + case CMPCI_AUX_IN_MUTE: + case CMPCI_MIC_MUTE: + case CMPCI_MIC_PREAMP: + case CMPCI_PLAYBACK_MODE: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_PLAYBACK: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: if (cp->type != AUDIO_MIXER_ENUM) return EINVAL; - mask = lmask | rmask; - lbits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_ADCMIX_L) - & ~mask; - rbits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_ADCMIX_R) - & ~mask; - sc->gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; - if (CMPCI_IS_IN_MUTE(cp->dev)) { - mute = cp->dev; - swap = mute - CMPCI_CD_IN_MUTE + CMPCI_CD_SWAP; - } else { - swap = cp->dev; - mute = swap + CMPCI_CD_IN_MUTE - CMPCI_CD_SWAP; - } - if (sc->gain[swap][CMPCI_LR]) { - mask = lmask; - lmask = rmask; - rmask = mask; + sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; + cmpci_set_mixer_gain(sc, cp->dev); + break; + + case CMPCI_SPDIF_IN_SELECT: + switch (cp->un.ord) { + case CMPCI_SPDIF_IN_SPDIN1: + case CMPCI_SPDIF_IN_SPDIN2: + case CMPCI_SPDIF_IN_SPDOUT: + break; + default: + return EINVAL; } - if (!sc->gain[mute][CMPCI_LR]) { - lbits = lbits | lmask; - rbits = rbits | rmask; + goto xenum; + case CMPCI_MONITOR_DAC: + switch (cp->un.ord) { + case CMPCI_MONITOR_DAC_OFF: + case CMPCI_MONITOR_DAC_SPDIN: + case CMPCI_MONITOR_DAC_SPDOUT: + break; + default: + return EINVAL; } - cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, lbits); - cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, rbits); + xenum: + if (cp->type != AUDIO_MIXER_ENUM) + return EINVAL; + sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord; + cmpci_set_mixer_gain(sc, cp->dev); break; default: - return EINVAL; + return EINVAL; } return 0; } int -cmpci_get_port(handle, cp) - void *handle; - mixer_ctrl_t *cp; +cmpci_get_port(void *handle, mixer_ctrl_t *cp) { struct cmpci_softc *sc = handle; - + switch (cp->dev) { case CMPCI_MIC_VOL: - case CMPCI_LINE_IN_VOL: - if (cp->un.value.num_channels != 1) - return EINVAL; - /* FALLTHROUGH */ - case CMPCI_TREBLE: - case CMPCI_BASS: case CMPCI_PCSPEAKER: - case CMPCI_INPUT_GAIN: - case CMPCI_OUTPUT_GAIN: - case CMPCI_VOICE_VOL: + case CMPCI_MIC_RECVOL: + if (cp->un.value.num_channels != 1) + return EINVAL; + /*FALLTHROUGH*/ + case CMPCI_DAC_VOL: case CMPCI_FM_VOL: case CMPCI_CD_VOL: + case CMPCI_LINE_IN_VOL: + case CMPCI_AUX_IN_VOL: case CMPCI_MASTER_VOL: switch (cp->un.value.num_channels) { case 1: - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = - sc->gain[cp->dev][CMPCI_LEFT]; + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = + sc->sc_gain[cp->dev][CMPCI_LEFT]; break; case 2: - cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = - sc->gain[cp->dev][CMPCI_LEFT]; - cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = - sc->gain[cp->dev][CMPCI_RIGHT]; + cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = + sc->sc_gain[cp->dev][CMPCI_LEFT]; + cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = + sc->sc_gain[cp->dev][CMPCI_RIGHT]; break; default: return EINVAL; @@ -1450,25 +1688,28 @@ cmpci_get_port(handle, cp) break; case CMPCI_RECORD_SOURCE: - cp->un.mask = sc->in_mask; - break; - - case CMPCI_AGC: - cp->un.ord = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_AGC); + cp->un.mask = sc->sc_in_mask; break; - case CMPCI_CD_IN_MUTE: - case CMPCI_MIC_IN_MUTE: + case CMPCI_DAC_MUTE: + case CMPCI_FM_MUTE: + case CMPCI_CD_MUTE: case CMPCI_LINE_IN_MUTE: - case CMPCI_FM_IN_MUTE: - case CMPCI_CD_SWAP: - case CMPCI_MIC_SWAP: - case CMPCI_LINE_SWAP: - case CMPCI_FM_SWAP: - case CMPCI_CD_OUT_MUTE: - case CMPCI_MIC_OUT_MUTE: - case CMPCI_LINE_OUT_MUTE: - cp->un.ord = sc->gain[cp->dev][CMPCI_LR]; + case CMPCI_AUX_IN_MUTE: + case CMPCI_MIC_MUTE: + case CMPCI_MIC_PREAMP: + case CMPCI_PLAYBACK_MODE: + case CMPCI_SPDIF_IN_SELECT: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_PLAYBACK: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_MONITOR_DAC: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: + cp->un.ord = sc->sc_gain[cp->dev][CMPCI_LR]; break; default: @@ -1480,52 +1721,38 @@ cmpci_get_port(handle, cp) /* ARGSUSED */ size_t -cmpci_round_buffersize(handle, direction, bufsize) - void *handle; - int direction; - size_t bufsize; +cmpci_round_buffersize(void *handle, int direction, size_t bufsize) { if (bufsize > 0x10000) - bufsize = 0x10000; - + bufsize = 0x10000; + return bufsize; } paddr_t -cmpci_mappage(handle, addr, offset, prot) - void *handle; - void *addr; - off_t offset; - int prot; +cmpci_mappage(void *handle, void *addr, off_t offset, int prot) { struct cmpci_softc *sc = handle; struct cmpci_dmanode *p; - if ( offset < 0 || (p = cmpci_find_dmamem(sc, addr)) == NULL) + if (offset < 0 || NULL == (p = cmpci_find_dmamem(sc, addr))) return -1; return bus_dmamem_mmap(p->cd_tag, p->cd_segs, - sizeof(p->cd_segs)/sizeof(p->cd_segs[0]), - offset, prot, BUS_DMA_WAITOK); + sizeof(p->cd_segs)/sizeof(p->cd_segs[0]), + offset, prot, BUS_DMA_WAITOK); } /* ARGSUSED */ int -cmpci_get_props(handle) - void *handle; +cmpci_get_props(void *handle) { return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; } - int -cmpci_trigger_output(handle, start, end, blksize, intr, arg, param) - void *handle; - void *start, *end; - int blksize; - void (*intr)(void *); - void *arg; - struct audio_params *param; +cmpci_trigger_output(void *handle, void *start, void *end, int blksize, + void (*intr)(void *), void *arg, struct audio_params *param) { struct cmpci_softc *sc = handle; struct cmpci_dmanode *p; @@ -1541,33 +1768,28 @@ cmpci_trigger_output(handle, start, end, blksize, intr, arg, param) if (!(p = cmpci_find_dmamem(sc, start))) return EINVAL; bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BASE, - DMAADDR(p)); + DMAADDR(p)); delay(10); bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BYTES, - ((caddr_t)end-(caddr_t)start+1)/bps-1); + ((caddr_t)end - (caddr_t)start + 1) / bps - 1); delay(10); /* set interrupt count */ bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_SAMPLES, - (blksize+bps-1)/bps-1); + (blksize + bps - 1) / bps - 1); delay(10); /* start DMA */ cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); /* PLAY */ cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); - + return 0; } int -cmpci_trigger_input(handle, start, end, blksize, intr, arg, param) - void *handle; - void *start, *end; - int blksize; - void (*intr)(void *); - void *arg; - struct audio_params *param; +cmpci_trigger_input(void *handle, void *start, void *end, int blksize, + void (*intr)(void *), void *arg, struct audio_params *param) { struct cmpci_softc *sc = handle; struct cmpci_dmanode *p; @@ -1583,21 +1805,23 @@ cmpci_trigger_input(handle, start, end, blksize, intr, arg, param) if (!(p = cmpci_find_dmamem(sc, start))) return EINVAL; bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BASE, - DMAADDR(p)); + DMAADDR(p)); delay(10); bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BYTES, - ((caddr_t)end-(caddr_t)start+1)/bps-1); + ((caddr_t)end - (caddr_t)start + 1) / bps - 1); delay(10); /* set interrupt count */ bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_SAMPLES, - (blksize+bps-1)/bps-1); + (blksize + bps - 1) / bps - 1); delay(10); /* start DMA */ cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); /* REC */ cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); - + return 0; } + +/* end of file */ diff --git a/sys/dev/pci/cmpcireg.h b/sys/dev/pci/cmpcireg.h index 7bbb4606ac3..9ef92c206f0 100644 --- a/sys/dev/pci/cmpcireg.h +++ b/sys/dev/pci/cmpcireg.h @@ -1,9 +1,16 @@ -/* $OpenBSD: cmpcireg.h,v 1.1 2000/04/27 02:19:41 millert Exp $ */ +/* $OpenBSD: cmpcireg.h,v 1.2 2006/07/27 00:45:59 brad Exp $ */ +/* $NetBSD: cmpcireg.h,v 1.7 2005/12/11 12:22:48 christos Exp $ */ /* - * Copyright (c) 2000 Takuya SHIOZAKI + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Takuya SHIOZAKI <tshiozak@NetBSD.org> . + * + * This code is derived from software contributed to The NetBSD Foundation + * by ITOH Yasufumi. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -69,6 +76,7 @@ # define CMPCI_REG_ADC_FS_MASK 0x00000007 #define CMPCI_REG_CHANNEL_FORMAT 0x08 +# define CMPCI_REG_SPDIN_PHASE 0x80 # define CMPCI_REG_CH0_FORMAT_SHIFT 0 # define CMPCI_REG_CH0_FORMAT_MASK 0x00000003 # define CMPCI_REG_CH1_FORMAT_SHIFT 2 @@ -111,8 +119,13 @@ # define CMPCI_REG_VMPUSEL_MASK 0x00000003 #define CMPCI_REG_MISC 0x18 -# define CMPCI_REG_SPDIF_48K 0x00008000 +# define CMPCI_REG_2ND_SPDIFIN 0x00000100 +# define CMPCI_REG_SPDIFOUT_48K 0x00008000 # define CMPCI_REG_FM_ENABLE 0x00080000 +# define CMPCI_REG_SPDFLOOPI 0x00100000 +# define CMPCI_REG_SPDIF48K 0x01000000 +# define CMPCI_REG_5V 0x02000000 +# define CMPCI_REG_N4SPK3D 0x04000000 #define CMPCI_REG_SBDATA 0x22 @@ -129,7 +142,9 @@ # define CMPCI_SB16_MIXER_LINE_L 0x38 # define CMPCI_SB16_MIXER_LINE_R 0x39 # define CMPCI_SB16_MIXER_MIC 0x3A +# define CMPCI_SB16_MIXER_VALBITS 5 # define CMPCI_SB16_MIXER_SPEAKER 0x3B +# define CMPCI_SB16_MIXER_SPEAKER_VALBITS 2 # define CMPCI_SB16_MIXER_OUTMIX 0x3C # define CMPCI_SB16_SW_MIC 0x01 # define CMPCI_SB16_SW_CD_R 0x02 @@ -147,22 +162,42 @@ # define CMPCI_SB16_MIXER_LINE_SRC_R 0x08 # define CMPCI_SB16_MIXER_CD_SRC_R 0x02 # define CMPCI_SB16_MIXER_MIC_SRC 0x01 -# define CMPCI_SB16_MIXER_SRC_R_TO_L(v) ((v) << 1) - -# define CMPCI_SB16_MIXER_INGAIN_L 0x3F -# define CMPCI_SB16_MIXER_INGAIN_R 0x40 -# define CMPCI_SB16_MIXER_OUTGAIN_L 0x41 -# define CMPCI_SB16_MIXER_OUTGAIN_R 0x42 -# define CMPCI_SB16_MIXER_AGC 0x43 -# define CMPCI_SB16_MIXER_TREBLE_L 0x44 -# define CMPCI_SB16_MIXER_TREBLE_R 0x45 -# define CMPCI_SB16_MIXER_BASS_L 0x46 -# define CMPCI_SB16_MIXER_BASS_R 0x47 +# define CMPCI_SB16_MIXER_SRC_R_TO_L(v) ((v) << 1) + # define CMPCI_SB16_MIXER_L_TO_R(addr) ((addr)+1) -# define CMPCI_ADJUST_MIC_GAIN(sc, x) cmpci_adjust((x), 0xf8) -# define CMPCI_ADJUST_GAIN(sc, x) cmpci_adjust((x), 0xf8) -# define CMPCI_ADJUST_2_GAIN(sc, x) cmpci_adjust((x), 0xc0) +# define CMPCI_ADJUST_MIC_GAIN(sc, x) cmpci_adjust((x), 0xf8) +# define CMPCI_ADJUST_GAIN(sc, x) cmpci_adjust((x), 0xf8) +# define CMPCI_ADJUST_2_GAIN(sc, x) cmpci_adjust((x), 0xc0) + +#define CMPCI_REG_MIXER24 0x24 +# define CMPCI_REG_SPDIN_MONITOR 0x01 +# define CMPCI_REG_SURROUND 0x02 +# define CMPCI_REG_INDIVIDUAL 0x20 +# define CMPCI_REG_REVERSE_FR 0x10 +# define CMPCI_REG_FMMUTE 0x80 +# define CMPCI_REG_WSMUTE 0x40 +# define CMPCI_REG_WAVEINL 0x08 +# define CMPCI_REG_WAVEINR 0x04 + +#define CMPCI_REG_MIXER25 0x25 +# define CMPCI_REG_RAUXREN 0x80 +# define CMPCI_REG_RAUXLEN 0x40 +# define CMPCI_REG_VAUXRM 0x20 /* 0: mute, 1: unmute */ +# define CMPCI_REG_VAUXLM 0x10 +# define CMPCI_REG_VADMIC 0x0E +# define CMPCI_REG_MICGAINZ 0x01 /* 1: disable preamp */ + +# define CMPCI_ADJUST_ADMIC_GAIN(sc, x) (cmpci_adjust((x), 0xe0) >> 5) +# define CMPCI_REG_ADMIC_VALBITS 3 +# define CMPCI_REG_ADMIC_MASK 0x07 +# define CMPCI_REG_ADMIC_SHIFT 0x01 + +/* Note that the doc tells a lie */ +#define CMPCI_REG_MIXER_AUX 0x26 +# define CMPCI_ADJUST_AUX_GAIN(sc, l, r) \ + (cmpci_adjust((l), 0xc0) >> 4 | cmpci_adjust((r), 0xc0)) +# define CMPCI_REG_AUX_VALBITS 4 #define CMPCI_REG_MPU_BASE 0x40 #define CMPCI_REG_MPU_SIZE 0x10 @@ -189,3 +224,5 @@ #define CMPCI_REG_NUMRATE 8 #endif /* _DEV_PCI_CMPCIREG_H_ */ + +/* end of file */ diff --git a/sys/dev/pci/cmpcivar.h b/sys/dev/pci/cmpcivar.h index 2ce823052f0..96ae37926ef 100644 --- a/sys/dev/pci/cmpcivar.h +++ b/sys/dev/pci/cmpcivar.h @@ -1,9 +1,15 @@ -/* $OpenBSD: cmpcivar.h,v 1.3 2002/03/14 01:26:58 millert Exp $ */ +/* $NetBSD: cmpcivar.h,v 1.9 2005/12/11 12:22:48 christos Exp $ */ /* - * Copyright (c) 2000 Takuya SHIOZAKI + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Takuya SHIOZAKI <tshiozak@NetBSD.org> . + * + * This code is derived from software contributed to The NetBSD Foundation + * by ITOH Yasufumi. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -29,17 +35,21 @@ /* C-Media CMI8x38 Audio Chip Support */ +#ifndef _DEV_PCI_CMPCIVAR_H_ +#define _DEV_PCI_CMPCIVAR_H_ + + /* * DMA pool */ struct cmpci_dmanode { - bus_dma_tag_t cd_tag; - int cd_nsegs; - bus_dma_segment_t cd_segs[1]; - bus_dmamap_t cd_map; - caddr_t cd_addr; - size_t cd_size; - struct cmpci_dmanode *cd_next; + bus_dma_tag_t cd_tag; + int cd_nsegs; + bus_dma_segment_t cd_segs[1]; + bus_dmamap_t cd_map; + caddr_t cd_addr; + size_t cd_size; + struct cmpci_dmanode *cd_next; }; typedef struct cmpci_dmanode *cmpci_dmapool_t; @@ -48,81 +58,190 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t; /* - * Mixer - SoundBlaster16 Compatible + * Mixer device + * + * Note that cmpci_query_devinfo() is optimized depending on + * the order of this. Be careful if you change the values. */ -#define CMPCI_MASTER_VOL 0 -#define CMPCI_FM_VOL 1 -#define CMPCI_CD_VOL 2 -#define CMPCI_VOICE_VOL 3 -#define CMPCI_OUTPUT_CLASS 4 - -#define CMPCI_MIC_VOL 5 -#define CMPCI_LINE_IN_VOL 6 -#define CMPCI_RECORD_SOURCE 7 -#define CMPCI_TREBLE 8 -#define CMPCI_BASS 9 -#define CMPCI_RECORD_CLASS 10 -#define CMPCI_INPUT_CLASS 11 - -#define CMPCI_PCSPEAKER 12 -#define CMPCI_INPUT_GAIN 13 -#define CMPCI_OUTPUT_GAIN 14 -#define CMPCI_AGC 15 -#define CMPCI_EQUALIZATION_CLASS 16 - -#define CMPCI_CD_IN_MUTE 17 -#define CMPCI_MIC_IN_MUTE 18 -#define CMPCI_LINE_IN_MUTE 19 -#define CMPCI_FM_IN_MUTE 20 - -#define CMPCI_CD_SWAP 21 -#define CMPCI_MIC_SWAP 22 -#define CMPCI_LINE_SWAP 23 -#define CMPCI_FM_SWAP 24 - -#define CMPCI_CD_OUT_MUTE 25 -#define CMPCI_MIC_OUT_MUTE 26 -#define CMPCI_LINE_OUT_MUTE 27 - -#ifdef CMPCI_SPDIF_SUPPORT -#define CMPCI_SPDIF_IN 28 -#define CMPCI_SPDIF_IN_MUTE 29 -#define CmpciNspdif "spdif" -#define CMPCI_NDEVS 30 -#else +#define CMPCI_DAC_VOL 0 /* inputs.dac */ +#define CMPCI_FM_VOL 1 /* inputs.fmsynth */ +#define CMPCI_CD_VOL 2 /* inputs.cd */ +#define CMPCI_LINE_IN_VOL 3 /* inputs.line */ +#define CMPCI_AUX_IN_VOL 4 /* inputs.aux */ +#define CMPCI_MIC_VOL 5 /* inputs.mic */ + +#define CMPCI_DAC_MUTE 6 /* inputs.dac.mute */ +#define CMPCI_FM_MUTE 7 /* inputs.fmsynth.mute */ +#define CMPCI_CD_MUTE 8 /* inputs.cd.mute */ +#define CMPCI_LINE_IN_MUTE 9 /* inputs.line.mute */ +#define CMPCI_AUX_IN_MUTE 10 /* inputs.aux.mute */ +#define CMPCI_MIC_MUTE 11 /* inputs.mic.mute */ + +#define CMPCI_MIC_PREAMP 12 /* inputs.mic.preamp */ +#define CMPCI_PCSPEAKER 13 /* inputs.speaker */ + +#define CMPCI_RECORD_SOURCE 14 /* record.source */ +#define CMPCI_MIC_RECVOL 15 /* record.mic */ + +#define CMPCI_PLAYBACK_MODE 16 /* playback.mode */ +#define CMPCI_SPDIF_IN_SELECT 17 /* spdif.input */ +#define CMPCI_SPDIF_IN_PHASE 18 /* spdif.input.phase */ +#define CMPCI_SPDIF_LOOP 19 /* spdif.output */ +#define CMPCI_SPDIF_OUT_PLAYBACK 20 /* spdif.output.playback */ +#define CMPCI_SPDIF_OUT_VOLTAGE 21 /* spdif.output.voltage */ +#define CMPCI_MONITOR_DAC 22 /* spdif.monitor */ + +#define CMPCI_MASTER_VOL 23 /* outputs.master */ +#define CMPCI_REAR 24 /* outputs.rear */ +#define CMPCI_INDIVIDUAL 25 /* outputs.rear.individual */ +#define CMPCI_REVERSE 26 /* outputs.rear.reverse */ +#define CMPCI_SURROUND 27 /* outputs.surround */ + #define CMPCI_NDEVS 28 -#endif -#define CMPCI_IS_IN_MUTE(x) ((x) < CMPCI_CD_SWAP) +#define CMPCI_INPUT_CLASS 28 +#define CMPCI_OUTPUT_CLASS 29 +#define CMPCI_RECORD_CLASS 30 +#define CMPCI_PLAYBACK_CLASS 31 +#define CMPCI_SPDIF_CLASS 32 +#define CmpciNspdif "spdif" +#define CmpciCspdif "spdif" +#define CmpciNspdin "spdin" +#define CmpciNspdin1 "spdin1" +#define CmpciNspdin2 "spdin2" +#define CmpciNspdout "spdout" +#define CmpciNplayback "playback" +#define CmpciCplayback "playback" +#define CmpciNlegacy "legacy" +#define CmpciNvoltage "voltage" +#define CmpciNphase "phase" +#define CmpciNpositive "positive" +#define CmpciNnegative "negative" +#define CmpciNrear "rear" +#define CmpciNindividual "individual" +#define CmpciNreverse "reverse" +#define CmpciNhigh_v "5V" +#define CmpciNlow_v "0.5V" +#define CmpciNsurround "surround" + +/* record.source bitmap (see cmpci_set_in_ports()) */ +#define CMPCI_RECORD_SOURCE_MIC CMPCI_SB16_MIXER_MIC_SRC /* mic */ +#define CMPCI_RECORD_SOURCE_CD CMPCI_SB16_MIXER_CD_SRC_R /* cd */ +#define CMPCI_RECORD_SOURCE_LINE_IN CMPCI_SB16_MIXER_LINE_SRC_R /* line */ +#define CMPCI_RECORD_SOURCE_AUX_IN (1 << 8) /* aux */ +#define CMPCI_RECORD_SOURCE_WAVE (1 << 9) /* wave */ +#define CMPCI_RECORD_SOURCE_FM CMPCI_SB16_MIXER_FM_SRC_R /* fmsynth*/ +#define CMPCI_RECORD_SOURCE_SPDIF (1 << 10) /* spdif */ + +/* playback.mode */ +#define CMPCI_PLAYBACK_MODE_WAVE 0 /* dac */ +#define CMPCI_PLAYBACK_MODE_SPDIF 1 /* spdif */ + +/* spdif.input */ +#define CMPCI_SPDIFIN_SPDIFIN2 0x01 +#define CMPCI_SPDIFIN_SPDIFOUT 0x02 +#define CMPCI_SPDIF_IN_SPDIN1 0 /* spdin1 */ +#define CMPCI_SPDIF_IN_SPDIN2 CMPCI_SPDIFIN_SPDIFIN2 /* spdin2 */ +#define CMPCI_SPDIF_IN_SPDOUT (CMPCI_SPDIFIN_SPDIFIN2|CMPCI_SPDIFIN_SPDIFOUT) + /* spdout */ +/* spdif.input.phase */ +#define CMPCI_SPDIF_IN_PHASE_POSITIVE 0 /* positive */ +#define CMPCI_SPDIF_IN_PHASE_NEGATIVE 1 /* negative */ + +/* spdif.output */ +#define CMPCI_SPDIF_LOOP_OFF 0 /* playback */ +#define CMPCI_SPDIF_LOOP_ON 1 /* spdin */ + +/* spdif.output.playback */ +#define CMPCI_SPDIF_OUT_PLAYBACK_WAVE 0 /* wave */ +#define CMPCI_SPDIF_OUT_PLAYBACK_LEGACY 1 /* legacy */ + +/* spdif.output.voltage */ +#define CMPCI_SPDIF_OUT_VOLTAGE_HIGH 0 /* 5V */ +#define CMPCI_SPDIF_OUT_VOLTAGE_LOW 1 /* 0.5V */ + +/* spdif.monitor */ +#define CMPCI_MONDAC_ENABLE 0x01 +#define CMPCI_MONDAC_SPDOUT 0x02 +#define CMPCI_MONITOR_DAC_OFF 0 /* off */ +#define CMPCI_MONITOR_DAC_SPDIN CMPCI_MONDAC_ENABLE /* spdin */ +#define CMPCI_MONITOR_DAC_SPDOUT (CMPCI_MONDAC_ENABLE | CMPCI_MONDAC_SPDOUT) + /* spdout */ /* * softc */ struct cmpci_softc { - struct device sc_dev; + struct device sc_dev; + + /* model/rev */ + uint32_t sc_id; + uint32_t sc_class; + uint32_t sc_capable; +#define CMPCI_CAP_SPDIN 0x00000001 +#define CMPCI_CAP_SPDOUT 0x00000002 +#define CMPCI_CAP_SPDLOOP 0x00000004 +#define CMPCI_CAP_SPDLEGACY 0x00000008 +#define CMPCI_CAP_SPDIN_MONITOR 0x00000010 +#define CMPCI_CAP_XSPDOUT 0x00000020 +#define CMPCI_CAP_SPDOUT_VOLTAGE 0x00000040 +#define CMPCI_CAP_SPDOUT_48K 0x00000080 +#define CMPCI_CAP_SURROUND 0x00000100 +#define CMPCI_CAP_REAR 0x00000200 +#define CMPCI_CAP_INDIVIDUAL_REAR 0x00000400 +#define CMPCI_CAP_REVERSE_FR 0x00000800 +#define CMPCI_CAP_SPDIN_PHASE 0x00001000 +#define CMPCI_CAP_2ND_SPDIN 0x00002000 + +#define CMPCI_CAP_CMI8338 (CMPCI_CAP_SPDIN | CMPCI_CAP_SPDOUT | \ + CMPCI_CAP_SPDLOOP | CMPCI_CAP_SPDLEGACY) + +#define CMPCI_CAP_CMI8738 (CMPCI_CAP_CMI8338 | \ + CMPCI_CAP_SPDIN_MONITOR | \ + CMPCI_CAP_XSPDOUT | \ + CMPCI_CAP_SPDOUT_VOLTAGE | \ + CMPCI_CAP_SPDOUT_48K | CMPCI_CAP_SURROUND |\ + CMPCI_CAP_REAR | \ + CMPCI_CAP_INDIVIDUAL_REAR | \ + CMPCI_CAP_REVERSE_FR | \ + CMPCI_CAP_SPDIN_PHASE | \ + CMPCI_CAP_2ND_SPDIN /* XXX 6ch only */) +#define CMPCI_ISCAP(sc, name) (sc->sc_capable & CMPCI_CAP_ ## name) /* I/O Base device */ - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + bus_space_handle_t sc_mpu_ioh; + struct device *sc_mpudev; /* intr handle */ - pci_intr_handle_t * sc_ih; + pci_intr_handle_t *sc_ih; /* DMA */ - bus_dma_tag_t sc_dmat; - cmpci_dmapool_t sc_dmap; + bus_dma_tag_t sc_dmat; + cmpci_dmapool_t sc_dmap; /* each channel */ struct { - void (*intr)(void *); - void *intr_arg; + void (*intr)(void *); + void *intr_arg; + int md_divide; } sc_play, sc_rec; + /* value of CMPCI_REG_MISC register */ + uint32_t sc_reg_misc; + /* mixer */ - uint8_t gain[CMPCI_NDEVS][2]; -#define CMPCI_LEFT 0 -#define CMPCI_RIGHT 1 -#define CMPCI_LR 0 - uint16_t in_mask; + uint8_t sc_gain[CMPCI_NDEVS][2]; +#define CMPCI_LEFT 0 +#define CMPCI_RIGHT 1 +#define CMPCI_LR 0 + uint16_t sc_in_mask; }; + + +#endif /* _DEV_PCI_CMPCIVAR_H_ */ + +/* end of file */ diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 33ccc6a66a6..0161b1ad6d4 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.209 2006/06/29 22:14:41 dlg Exp $ +# $OpenBSD: files.pci,v 1.210 2006/07/27 00:45:59 brad Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -465,10 +465,13 @@ attach wpi at pci file dev/pci/if_wpi.c wpi # C-Media CMI8x38 Audio Chip -device cmpci: audio, auconv, mulaw +device cmpci {}: audio, auconv, mulaw attach cmpci at pci file dev/pci/cmpci.c cmpci +attach opl at cmpci with opl_cmpci +file dev/pci/opl_cmpci.c opl_cmpci + # Initio ULTRA WIDE/ULTRA2 WIDE SCSI Controllers attach iha at pci with iha_pci file dev/pci/iha_pci.c iha_pci diff --git a/sys/dev/pci/opl_cmpci.c b/sys/dev/pci/opl_cmpci.c new file mode 100644 index 00000000000..ae867ede6d0 --- /dev/null +++ b/sys/dev/pci/opl_cmpci.c @@ -0,0 +1,103 @@ +/* $OpenBSD: opl_cmpci.c,v 1.1 2006/07/27 00:45:59 brad Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (augustss@netbsd.org). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/selinfo.h> +#include <sys/audioio.h> +#include <sys/midiio.h> + +#include <machine/bus.h> + +#include <dev/audio_if.h> +#include <dev/midi_if.h> +#include <dev/ic/oplreg.h> +#include <dev/ic/oplvar.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/pci/cmpcireg.h> +#include <dev/pci/cmpcivar.h> + +int opl_cmpci_match(struct device *, void *, void *); +void opl_cmpci_attach(struct device *, struct device *, void *); + +struct cfdriver opl_cmpci_cd = { + NULL, "opl_cmpci", DV_DULL +}; + +struct cfattach opl_cmpci_ca = { + sizeof (struct opl_softc), opl_cmpci_match, opl_cmpci_attach +}; + +int +opl_cmpci_match(struct device *parent, void *match, void *aux) +{ + struct audio_attach_args *aa = (struct audio_attach_args *)aux; + struct cmpci_softc *ssc = (struct cmpci_softc *)parent; + struct opl_softc sc; + + if (aa->type != AUDIODEV_TYPE_OPL) + return (0); + memset(&sc, 0, sizeof sc); + sc.iot = ssc->sc_iot; + sc.ioh = ssc->sc_ioh; + sc.offs = CMPCI_REG_FM_BASE; + return (opl_find(&sc)); +} + +void +opl_cmpci_attach(struct device *parent, struct device *self, void *aux) +{ + struct cmpci_softc *ssc = (struct cmpci_softc *)parent; + struct opl_softc *sc = (struct opl_softc *)self; + + sc->ioh = ssc->sc_ioh; + sc->iot = ssc->sc_iot; + sc->offs = CMPCI_REG_FM_BASE; + strlcpy(sc->syn.name, "CMPCI ", sizeof sc->syn.name); + + opl_attach(sc); +} |