- 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.
@ -43,7 +43,7 @@
*/
#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)
#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 */

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.
@ -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

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.
@ -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