- 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.
This commit is contained in:
itohy 2003-11-22 16:48:14 +00:00
parent 20d207b125
commit 1b7b873248
3 changed files with 72 additions and 31 deletions

View File

@ -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. * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -43,7 +43,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__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) #if defined(AUDIO_DEBUG) || defined(DEBUG)
#define DPRINTF(x) if (cmpcidebug) printf x #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)); int, uint32_t));
static __inline void cmpci_reg_clear_4 __P((struct cmpci_softc *, static __inline void cmpci_reg_clear_4 __P((struct cmpci_softc *,
int, uint32_t)); 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 int cmpci_rate_to_index __P((int));
static __inline int cmpci_index_to_rate __P((int)); static __inline int cmpci_index_to_rate __P((int));
static __inline int cmpci_index_to_divider __P((int)); static __inline int cmpci_index_to_divider __P((int));
@ -278,6 +282,9 @@ cmpci_reg_set_4(sc, no, mask)
int no; int no;
uint32_t mask; 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_write_4(sc->sc_iot, sc->sc_ioh, no,
(bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask)); (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask));
delay(10); delay(10);
@ -289,12 +296,42 @@ cmpci_reg_clear_4(sc, no, mask)
int no; int no;
uint32_t mask; 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_write_4(sc->sc_iot, sc->sc_ioh, no,
(bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask)); (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask));
delay(10); 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 */ /* rate */
static const struct { static const struct {
int rate; int rate;
@ -439,6 +476,10 @@ cmpci_attach(parent, self, aux)
CMPCI_REG_MPU_BASE, CMPCI_REG_MPU_SIZE, &sc->sc_mpu_ioh) == 0) CMPCI_REG_MPU_BASE, CMPCI_REG_MPU_SIZE, &sc->sc_mpu_ioh) == 0)
sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint); 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_RESET, 0);
cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, 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_ADCMIX_R, 0);
@ -1050,10 +1091,10 @@ cmpci_query_devinfo(handle, dip)
strcpy(dip->label.name, CmpciNvoltage); strcpy(dip->label.name, CmpciNvoltage);
dip->type = AUDIO_MIXER_ENUM; dip->type = AUDIO_MIXER_ENUM;
dip->un.e.num_mem = 2; dip->un.e.num_mem = 2;
strcpy(dip->un.e.member[0].label.name, CmpciNlow_v); strcpy(dip->un.e.member[0].label.name, CmpciNhigh_v);
dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW; dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH;
strcpy(dip->un.e.member[1].label.name, CmpciNhigh_v); strcpy(dip->un.e.member[1].label.name, CmpciNlow_v);
dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH; dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW;
return 0; return 0;
case CMPCI_MONITOR_DAC: case CMPCI_MONITOR_DAC:
dip->mixer_class = CMPCI_SPDIF_CLASS; dip->mixer_class = CMPCI_SPDIF_CLASS;
@ -1350,12 +1391,10 @@ cmpci_set_mixer_gain(sc, port)
case CMPCI_SPDIF_OUT_VOLTAGE: case CMPCI_SPDIF_OUT_VOLTAGE:
if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) { if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) {
if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR] if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR]
== CMPCI_SPDIF_OUT_VOLTAGE_LOW) == CMPCI_SPDIF_OUT_VOLTAGE_HIGH)
cmpci_reg_clear_4(sc, CMPCI_REG_MISC, cmpci_reg_clear_reg_misc(sc, CMPCI_REG_5V);
CMPCI_REG_5V);
else else
cmpci_reg_set_4(sc, CMPCI_REG_MISC, cmpci_reg_set_reg_misc(sc, CMPCI_REG_5V);
CMPCI_REG_5V);
} }
return; return;
case CMPCI_SURROUND: case CMPCI_SURROUND:
@ -1371,11 +1410,9 @@ cmpci_set_mixer_gain(sc, port)
case CMPCI_REAR: case CMPCI_REAR:
if (CMPCI_ISCAP(sc, REAR)) { if (CMPCI_ISCAP(sc, REAR)) {
if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) if (sc->sc_gain[CMPCI_REAR][CMPCI_LR])
cmpci_reg_set_4(sc, CMPCI_REG_MISC, cmpci_reg_set_reg_misc(sc, CMPCI_REG_N4SPK3D);
CMPCI_REG_N4SPK3D);
else else
cmpci_reg_clear_4(sc, CMPCI_REG_MISC, cmpci_reg_clear_reg_misc(sc, CMPCI_REG_N4SPK3D);
CMPCI_REG_N4SPK3D);
} }
return; return;
case CMPCI_INDIVIDUAL: case CMPCI_INDIVIDUAL:
@ -1441,13 +1478,13 @@ cmpci_set_out_ports(sc)
/* SPDIF in select */ /* SPDIF in select */
v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR]; v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR];
if (v & CMPCI_SPDIFIN_SPDIFIN2) 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 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) 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 else
cmpci_reg_clear_4(sc, CMPCI_REG_MISC, CMPCI_REG_SPDFLOOPI); cmpci_reg_clear_reg_misc(sc, CMPCI_REG_SPDFLOOPI);
/* playback to ... */ /* playback to ... */
if (CMPCI_ISCAP(sc, SPDOUT) && 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); cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF0_ENABLE);
enspdout = 1; enspdout = 1;
if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000) if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000)
cmpci_reg_set_4(sc, CMPCI_REG_MISC, cmpci_reg_set_reg_misc(sc,
CMPCI_REG_SPDIF_48K); CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
else else
cmpci_reg_clear_4(sc, CMPCI_REG_MISC, cmpci_reg_clear_reg_misc(sc,
CMPCI_REG_SPDIF_48K); CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
} else { } else {
/* playback to DAC */ /* playback to DAC */
cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1,
CMPCI_REG_SPDIF0_ENABLE); CMPCI_REG_SPDIF0_ENABLE);
if (CMPCI_ISCAP(sc, SPDOUT_48K)) if (CMPCI_ISCAP(sc, SPDOUT_48K))
cmpci_reg_clear_4(sc, CMPCI_REG_MISC, cmpci_reg_clear_reg_misc(sc,
CMPCI_REG_SPDIF_48K); CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
} }
/* legacy to SPDIF/out or not */ /* legacy to SPDIF/out or not */

View File

@ -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. * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -119,9 +119,10 @@
#define CMPCI_REG_MISC 0x18 #define CMPCI_REG_MISC 0x18
# define CMPCI_REG_2ND_SPDIFIN 0x00000100 # 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_FM_ENABLE 0x00080000
# define CMPCI_REG_SPDFLOOPI 0x00100000 # define CMPCI_REG_SPDFLOOPI 0x00100000
# define CMPCI_REG_SPDIF48K 0x01000000
# define CMPCI_REG_5V 0x02000000 # define CMPCI_REG_5V 0x02000000
# define CMPCI_REG_N4SPK3D 0x04000000 # define CMPCI_REG_N4SPK3D 0x04000000

View File

@ -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. * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -121,8 +121,8 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t;
#define CmpciNrear "rear" #define CmpciNrear "rear"
#define CmpciNindividual "individual" #define CmpciNindividual "individual"
#define CmpciNreverse "reverse" #define CmpciNreverse "reverse"
#define CmpciNlow_v "0.5V"
#define CmpciNhigh_v "5V" #define CmpciNhigh_v "5V"
#define CmpciNlow_v "0.5V"
#define CmpciNsurround "surround" #define CmpciNsurround "surround"
/* record.sorce bitmap (see cmpci_set_in_ports()) */ /* 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 */ #define CMPCI_SPDIF_OUT_PLAYBACK_LEGACY 1 /* legacy */
/* spdif.output.voltage */ /* spdif.output.voltage */
#define CMPCI_SPDIF_OUT_VOLTAGE_LOW 0 /* 0.5V */ #define CMPCI_SPDIF_OUT_VOLTAGE_HIGH 0 /* 5V */
#define CMPCI_SPDIF_OUT_VOLTAGE_HIGH 1 /* 5V */ #define CMPCI_SPDIF_OUT_VOLTAGE_LOW 1 /* 0.5V */
/* spdif.monitor */ /* spdif.monitor */
#define CMPCI_MONDAC_ENABLE 0x01 #define CMPCI_MONDAC_ENABLE 0x01
@ -230,6 +230,9 @@ struct cmpci_softc {
int md_divide; int md_divide;
} sc_play, sc_rec; } sc_play, sc_rec;
/* value of CMPCI_REG_MISC register */
uint32_t sc_reg_misc;
/* mixer */ /* mixer */
uint8_t sc_gain[CMPCI_NDEVS][2]; uint8_t sc_gain[CMPCI_NDEVS][2];
#define CMPCI_LEFT 0 #define CMPCI_LEFT 0