Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci - Correctly handle bit 24 of miscellaneous contr...



details:   https://anonhg.NetBSD.org/src/rev/42421108da1f
branches:  trunk
changeset: 555581:42421108da1f
user:      itohy <itohy%NetBSD.org@localhost>
date:      Sat Nov 22 16:48:14 2003 +0000

description:
- 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.

diffstat:

 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(-)

diffs (242 lines):

diff -r 68f00c8087a4 -r 42421108da1f sys/dev/pci/cmpci.c
--- a/sys/dev/pci/cmpci.c       Sat Nov 22 15:08:44 2003 +0000
+++ b/sys/dev/pci/cmpci.c       Sat Nov 22 16:48:14 2003 +0000
@@ -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 @@
                                          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 @@
        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 @@
        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_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 @@
                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 @@
        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 @@
        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 @@
        /* 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_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 -r 68f00c8087a4 -r 42421108da1f sys/dev/pci/cmpcireg.h
--- a/sys/dev/pci/cmpcireg.h    Sat Nov 22 15:08:44 2003 +0000
+++ b/sys/dev/pci/cmpcireg.h    Sat Nov 22 16:48:14 2003 +0000
@@ -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 -r 68f00c8087a4 -r 42421108da1f sys/dev/pci/cmpcivar.h
--- a/sys/dev/pci/cmpcivar.h    Sat Nov 22 15:08:44 2003 +0000
+++ b/sys/dev/pci/cmpcivar.h    Sat Nov 22 16:48:14 2003 +0000
@@ -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 @@
 #define CmpciNrear                     "rear"
 #define CmpciNindividual               "individual"
 #define CmpciNreverse                  "reverse"
+#define CmpciNhigh_v                   "5V"
 #define CmpciNlow_v                    "0.5V"
-#define CmpciNhigh_v                   "5V"
 #define CmpciNsurround                 "surround"
 
 /* record.sorce bitmap (see cmpci_set_in_ports()) */
@@ -158,8 +158,8 @@
 #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 @@
                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



Home | Main Index | Thread Index | Old Index