From 1b7b87324820c40e1c8be12f132d40e4ff89900b Mon Sep 17 00:00:00 2001 From: itohy Date: Sat, 22 Nov 2003 16:48:14 +0000 Subject: [PATCH] - Correctly handle bit 24 of miscellaneous control register, which has different meanings for read and write. This fixes 48kHz playback to SPDIF. - Fix the problem where the SPDIF output voltage setting (0.5V, 5V) was swapped. The default value is changed from 0.5V to 5V, which correctly selects 5V (so the default physical behavior is unchanged). Should fix PRs kern/16047 and kern/16817 (but not tested since I don't have other SPDIF hardware to test with). Approved by tshiozak. --- sys/dev/pci/cmpci.c | 87 ++++++++++++++++++++++++++++++------------ sys/dev/pci/cmpcireg.h | 5 ++- sys/dev/pci/cmpcivar.h | 11 ++++-- 3 files changed, 72 insertions(+), 31 deletions(-) diff --git a/sys/dev/pci/cmpci.c b/sys/dev/pci/cmpci.c index 8ad4acd8258c..b73f74fb171b 100644 --- a/sys/dev/pci/cmpci.c +++ b/sys/dev/pci/cmpci.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmpci.c,v 1.20 2003/10/25 21:31:43 christos Exp $ */ +/* $NetBSD: cmpci.c,v 1.21 2003/11/22 16:48:14 itohy Exp $ */ /* * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.20 2003/10/25 21:31:43 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.21 2003/11/22 16:48:14 itohy Exp $"); #if defined(AUDIO_DEBUG) || defined(DEBUG) #define DPRINTF(x) if (cmpcidebug) printf x @@ -98,6 +98,10 @@ static __inline void cmpci_reg_set_4 __P((struct cmpci_softc *, int, uint32_t)); static __inline void cmpci_reg_clear_4 __P((struct cmpci_softc *, int, uint32_t)); +static __inline void cmpci_reg_set_reg_misc __P((struct cmpci_softc *, + uint32_t)); +static __inline void cmpci_reg_clear_reg_misc __P((struct cmpci_softc *, + uint32_t)); static int cmpci_rate_to_index __P((int)); static __inline int cmpci_index_to_rate __P((int)); static __inline int cmpci_index_to_divider __P((int)); @@ -278,6 +282,9 @@ cmpci_reg_set_4(sc, no, mask) 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); @@ -289,12 +296,42 @@ cmpci_reg_clear_4(sc, no, mask) 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. + */ +static __inline void +cmpci_reg_set_reg_misc(sc, mask) + 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); +} + +static __inline void +cmpci_reg_clear_reg_misc(sc, mask) + 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 */ static const struct { int rate; @@ -439,6 +476,10 @@ cmpci_attach(parent, self, aux) 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); @@ -1050,10 +1091,10 @@ cmpci_query_devinfo(handle, dip) strcpy(dip->label.name, CmpciNvoltage); dip->type = AUDIO_MIXER_ENUM; dip->un.e.num_mem = 2; - strcpy(dip->un.e.member[0].label.name, CmpciNlow_v); - dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW; - strcpy(dip->un.e.member[1].label.name, CmpciNhigh_v); - dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH; + strcpy(dip->un.e.member[0].label.name, CmpciNhigh_v); + dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH; + strcpy(dip->un.e.member[1].label.name, CmpciNlow_v); + dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW; return 0; case CMPCI_MONITOR_DAC: dip->mixer_class = CMPCI_SPDIF_CLASS; @@ -1350,12 +1391,10 @@ cmpci_set_mixer_gain(sc, port) 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_LOW) - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, - CMPCI_REG_5V); + == CMPCI_SPDIF_OUT_VOLTAGE_HIGH) + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_5V); else - cmpci_reg_set_4(sc, CMPCI_REG_MISC, - CMPCI_REG_5V); + cmpci_reg_set_reg_misc(sc, CMPCI_REG_5V); } return; case CMPCI_SURROUND: @@ -1371,11 +1410,9 @@ cmpci_set_mixer_gain(sc, port) case CMPCI_REAR: if (CMPCI_ISCAP(sc, REAR)) { if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) - cmpci_reg_set_4(sc, CMPCI_REG_MISC, - CMPCI_REG_N4SPK3D); + cmpci_reg_set_reg_misc(sc, CMPCI_REG_N4SPK3D); else - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, - CMPCI_REG_N4SPK3D); + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_N4SPK3D); } return; case CMPCI_INDIVIDUAL: @@ -1441,13 +1478,13 @@ cmpci_set_out_ports(sc) /* SPDIF in select */ v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR]; if (v & CMPCI_SPDIFIN_SPDIFIN2) - cmpci_reg_set_4(sc, CMPCI_REG_MISC, CMPCI_REG_2ND_SPDIFIN); + cmpci_reg_set_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN); else - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, CMPCI_REG_2ND_SPDIFIN); + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN); if (v & CMPCI_SPDIFIN_SPDIFOUT) - cmpci_reg_set_4(sc, CMPCI_REG_MISC, CMPCI_REG_SPDFLOOPI); + cmpci_reg_set_reg_misc(sc, CMPCI_REG_SPDFLOOPI); else - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, CMPCI_REG_SPDFLOOPI); + cmpci_reg_clear_reg_misc(sc, CMPCI_REG_SPDFLOOPI); /* playback to ... */ if (CMPCI_ISCAP(sc, SPDOUT) && @@ -1460,18 +1497,18 @@ cmpci_set_out_ports(sc) 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_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); + cmpci_reg_set_reg_misc(sc, + CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K); else - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); + 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_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); + cmpci_reg_clear_reg_misc(sc, + CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K); } /* legacy to SPDIF/out or not */ diff --git a/sys/dev/pci/cmpcireg.h b/sys/dev/pci/cmpcireg.h index 7fe54030d220..611a2126f076 100644 --- a/sys/dev/pci/cmpcireg.h +++ b/sys/dev/pci/cmpcireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: cmpcireg.h,v 1.4 2001/11/04 06:57:40 itohy Exp $ */ +/* $NetBSD: cmpcireg.h,v 1.5 2003/11/22 16:48:14 itohy Exp $ */ /* * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. @@ -119,9 +119,10 @@ #define CMPCI_REG_MISC 0x18 # define CMPCI_REG_2ND_SPDIFIN 0x00000100 -# define CMPCI_REG_SPDIF_48K 0x00008000 +# 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 diff --git a/sys/dev/pci/cmpcivar.h b/sys/dev/pci/cmpcivar.h index 0496a8c7a1d2..7909c864bbb7 100644 --- a/sys/dev/pci/cmpcivar.h +++ b/sys/dev/pci/cmpcivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: cmpcivar.h,v 1.4 2001/11/04 06:57:40 itohy Exp $ */ +/* $NetBSD: cmpcivar.h,v 1.5 2003/11/22 16:48:14 itohy Exp $ */ /* * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. @@ -121,8 +121,8 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t; #define CmpciNrear "rear" #define CmpciNindividual "individual" #define CmpciNreverse "reverse" -#define CmpciNlow_v "0.5V" #define CmpciNhigh_v "5V" +#define CmpciNlow_v "0.5V" #define CmpciNsurround "surround" /* record.sorce bitmap (see cmpci_set_in_ports()) */ @@ -158,8 +158,8 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t; #define CMPCI_SPDIF_OUT_PLAYBACK_LEGACY 1 /* legacy */ /* spdif.output.voltage */ -#define CMPCI_SPDIF_OUT_VOLTAGE_LOW 0 /* 0.5V */ -#define CMPCI_SPDIF_OUT_VOLTAGE_HIGH 1 /* 5V */ +#define CMPCI_SPDIF_OUT_VOLTAGE_HIGH 0 /* 5V */ +#define CMPCI_SPDIF_OUT_VOLTAGE_LOW 1 /* 0.5V */ /* spdif.monitor */ #define CMPCI_MONDAC_ENABLE 0x01 @@ -230,6 +230,9 @@ struct cmpci_softc { int md_divide; } sc_play, sc_rec; + /* value of CMPCI_REG_MISC register */ + uint32_t sc_reg_misc; + /* mixer */ uint8_t sc_gain[CMPCI_NDEVS][2]; #define CMPCI_LEFT 0