Source-Changes-HG archive

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

[src/netbsd-3]: src/sys/dev/pci Pull up revision 1.2 (requested by kent in ti...



details:   https://anonhg.NetBSD.org/src/rev/7a6d406e1c35
branches:  netbsd-3
changeset: 576409:7a6d406e1c35
user:      tron <tron%NetBSD.org@localhost>
date:      Sat Jul 02 16:40:05 2005 +0000

description:
Pull up revision 1.2 (requested by kent in ticket #494):
partial support for mixer.
Still we have no ways to specify DACs or ADCs.

diffstat:

 sys/dev/pci/azalia.c |  891 ++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 743 insertions(+), 148 deletions(-)

diffs (truncated from 1265 to 300 lines):

diff -r 7b0ed29db414 -r 7a6d406e1c35 sys/dev/pci/azalia.c
--- a/sys/dev/pci/azalia.c      Sat Jul 02 16:39:31 2005 +0000
+++ b/sys/dev/pci/azalia.c      Sat Jul 02 16:40:05 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: azalia.c,v 1.7.2.2 2005/07/02 16:39:31 tron Exp $      */
+/*     $NetBSD: azalia.c,v 1.7.2.3 2005/07/02 16:40:05 tron Exp $      */
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -36,8 +36,16 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * TO DO:
+ *  o recording support
+ *  o mixer value scaling
+ *  o DAC selection
+ *  o ADC selection
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.7.2.2 2005/07/02 16:39:31 tron Exp $");
+__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.7.2.3 2005/07/02 16:40:05 tron Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -203,7 +211,13 @@
 /* CORB commands */
 #define CORB_GET_PARAMETER             0xf00
 #define                COP_VENDOR_ID                   0x00
+#define                        COP_VID_VENDOR(x)       (x >> 16)
+#define                        COP_VID_DEVICE(x)       (x & 0xffff)
 #define                COP_REVISION_ID                 0x02
+#define                        COP_RID_MAJ(x)          ((x >> 20) & 0x0f)
+#define                        COP_RID_MIN(x)          ((x >> 16) & 0x0f)
+#define                        COP_RID_REVISION(x)     ((x >> 8) & 0xff)
+#define                        COP_RID_STEPPING(x)     (x & 0xff)
 #define                COP_SUBORDINATE_NODE_COUNT      0x04
 #define                        COP_START_NID(x)        ((x & 0x00ff0000) >> 16)
 #define                        COP_NSUBNODES(x)        (x & 0x000000ff)
@@ -213,7 +227,7 @@
 #define                        COP_FTYPE_AUDIO         0x01
 #define                        COP_FTYPE_MODEM         0x02
 #define                COP_AUDIO_FUNCTION_GROUP_CAPABILITY     0x08
-#define                COP_AUDIO_WIDGET_CAPABILITIES   0x09
+#define                COP_AUDIO_WIDGET_CAP    0x09
 #define                        COP_AWCAP_TYPE(x)       ((x >> 20) & 0xf)
 #define                        COP_AWTYPE_AUDIO_OUTPUT         0x0
 #define                        COP_AWTYPE_AUDIO_INPUT          0x1
@@ -259,7 +273,7 @@
 #define                        COP_STREAM_FORMAT_PCM           0x00000001
 #define                        COP_STREAM_FORMAT_FLOAT32       0x00000002
 #define                        COP_STREAM_FORMAT_AC3           0x00000003
-#define                COP_PIN_CAPABILITIES            0x0c
+#define                COP_PINCAP              0x0c
 #define                        COP_PINCAP_IMPEDANCE    0x00000001
 #define                        COP_PINCAP_TRIGGER      0x00000002
 #define                        COP_PINCAP_PRESENCE     0x00000004
@@ -269,14 +283,18 @@
 #define                        COP_PINCAP_BALANCE      0x00000040
 #define                        COP_PINCAP_VREF(x)      ((x >> 8) & 0xff)
 #define                        COP_PINCAP_EAPD         0x00010000
-#define                COP_INPUT_AMPLIFIER_CAPABILITIES        0x0d
+#define                COP_INPUT_AMPCAP        0x0d
+#define                        COP_AMPCAP_OFFSET(x)    (x & 0x0000007f)
+#define                        COP_AMPCAP_NUMSTEPS(x)  ((x >> 8) & 0x7f)
+#define                        COP_AMPCAP_STEPSIZE(x)  ((x >> 16) & 0x7f)
+#define                        COP_AMPCAP_MUTE         0x80000000
 #define                COP_CONNECTION_LIST_LENGTH      0x0e
 #define                        COP_CLL_LONG            0x00000080
 #define                        COP_CLL_LENGTH(x)       (x & 0x0000007f)
 #define                COP_SUPPORTED_POWER_STATES      0x0f
 #define                COP_PROCESSING_CAPABILITIES     0x10
 #define                COP_GPIO_COUNT                  0x11
-#define                COP_OUTPUT_AMPLIFIER_CAPABILITIES       0x12
+#define                COP_OUTPUT_AMPCAP               0x12
 #define                COP_VOLUME_KNOB_CAPABILITIES    0x13
 #define CORB_GET_CONNECTION_SELECT_CONTROL     0xf01
 #define                CORB_CSC_INDEX(x)               (x & 0xff)
@@ -295,6 +313,12 @@
 #define CORB_GET_PROCESSING_COEFFICIENT        0xc00
 #define CORB_SET_PROCESSING_COEFFICIENT        0x400
 #define CORB_GET_AMPLIFIER_GAIN_MUTE   0xb00
+#define                CORB_GAGM_INPUT         0x0000
+#define                CORB_GAGM_OUTPUT        0x8000
+#define                CORB_GAGM_RIGHT         0x0000
+#define                CORB_GAGM_LEFT          0x2000
+#define                CORB_GAGM_MUTE          0x00000080
+#define                CORB_GAGM_GAIN(x)       (x & 0x0000007f)
 #define CORB_SET_AMPLIFIER_GAIN_MUTE   0x300
 #define                CORB_AGM_GAIN_MASK      0x007f
 #define                CORB_AGM_MUTE           0x0080
@@ -499,6 +523,9 @@
        int nconnections;
        nid_t *connections;
        int selected;
+       uint32_t inamp_cap;
+       uint32_t outamp_cap;
+       char name[MAX_AUDIO_DEV_LEN];
        union {
                struct {        /* for AUDIO_INPUT/OUTPUT */
                        uint32_t encodings;
@@ -525,17 +552,34 @@
        } d;
 } widget_t;
 
+typedef struct {
+       mixer_devinfo_t devinfo;
+       nid_t nid;              /* target NID; 0 is invalid. */
+       int target;             /* 0-15: inamp index, 0x100: outamp */
+#define IS_MI_TARGET_INAMP(x)  ((x) <= 15)
+#define MI_TARGET_INAMP(x)     (x)
+#define MI_TARGET_OUTAMP       0x100
+#define MI_TARGET_CONNLIST     0x101
+#define MI_TARGET_DIR          0x102 /* for bidirectional pin */
+} mixer_item_t;
+
 typedef struct codec_t {
        int (*comresp)(const struct codec_t *, nid_t, uint32_t, uint32_t, uint32_t *);
        struct azalia_t *az;
        int address;
        int nfunctions;
        nid_t audiofunc;        /* NID of an audio function node */
-       int nwidgets;           /* # of widgets in the audio function */
-       widget_t *widgets;      /* widgets in the audio function */
+       nid_t wstart;           /* start NID of audio widgets */
+       nid_t wend;             /* the last NID of audio widgets + 1 */
+       widget_t *w;            /* widgets in the audio function.
+                                * w[0] to w[wstart-1] are unused. */
+#define FOR_EACH_WIDGET(this, i)       for (i = (this)->wstart; i < (this)->wend; i++)
        int ndacindexes;
        int dacindexes[HDA_MAX_CHANNELS];
 
+       int nmixers, maxmixers;
+       mixer_item_t *mixers;
+
        struct audio_format* formats;
        int nformats;
        struct audio_encoding_set *encodings;
@@ -590,18 +634,21 @@
 static void    azalia_codec_add_format(codec_t *, int, int, int, uint32_t);
 static int     azalia_codec_find_pin(const codec_t *, uint32_t, int, int);
 static int     azalia_codec_find_dac(const codec_t *, int, int);
-static int     azalia_codec_nid2index(const codec_t *, nid_t);
 static int     azalia_codec_comresp(const codec_t *, nid_t, uint32_t,
        uint32_t, uint32_t *);
 static int     azalia_codec_connect_stream(codec_t *, int, uint16_t, int);
 
+static int     azalia_mixer_init(codec_t *);
+static int     azalia_mixer_get(const codec_t *, mixer_ctrl_t *);
+static int     azalia_mixer_set(const codec_t *, const mixer_ctrl_t *);
+static int     azalia_mixer_ensure_capacity(codec_t *, size_t);
+
 static int     azalia_widget_init(widget_t *, const codec_t *, int);
 static int     azalia_widget_init_audio(widget_t *, const codec_t *);
 static int     azalia_widget_print_audio(const widget_t *, const char *);
 static int     azalia_widget_init_pin(widget_t *, const codec_t *);
+static int     azalia_widget_print_pin(const widget_t *);
 static int     azalia_widget_init_connection(widget_t *, const codec_t *);
-static int     azalia_widget_nid2clindex(const widget_t *, nid_t);
-int    azalia_widget_set_connection(const widget_t *, const codec_t *, nid_t);
 
 static int     azalia_query_encoding(void *, audio_encoding_t *);
 static int     azalia_set_params(void *, int, int, audio_params_t *,
@@ -658,6 +705,19 @@
        NULL,                   /* dev_ioctl */
 };
 
+static const char *pin_colors[16] = {
+       "unknown", "black", "gray", "blue",
+       "green", "red", "orange", "yellow",
+       "purple", "pink", "0xa", "0xb",
+       "0xc", "0xd", "white", "other"};
+#ifdef AZALIA_DEBUG
+static const char *pin_devices[16] = {
+       "line-out", AudioNspeaker, AudioNheadphone, AudioNcd,
+       "SPDIF-out", "digital-out", "modem-line", "modem-handset",
+       "line-in", AudioNaux, AudioNmicrophone, "telephony",
+       "SPDIF-in", "digital-in", "0xe", "other"};
+#endif
+
 /* ================================================================
  * PCI functions
  * ================================================================ */
@@ -785,7 +845,7 @@
        uint16_t gcap;
        uint16_t statests;
 
-       aprint_normal("%s: High Definition Audio rev. %d.%d\n",
+       aprint_normal("%s: controller: High Definition Audio rev. %d.%d\n",
            XNAME(az), AZ_READ_1(az, VMAJ), AZ_READ_1(az, VMIN));
        gcap = AZ_READ_2(az, GCAP);
        az->nistreams = HDA_GCAP_ISS(gcap);
@@ -1183,7 +1243,7 @@
 static int
 azalia_codec_init(codec_t *this)
 {
-       uint32_t result, bits_rates;
+       uint32_t rev, result, bits_rates;
        int err, addr, n, i;
        int assoc, npin, dac, chan, seq, nbits;
        int pindexes[HDA_MAX_CHANNELS];
@@ -1193,13 +1253,20 @@
        addr = this->address;
        DPRINTF(("%s: information of codec[%d] follows:\n",
            XNAME(this->az), addr));
-       /* codec vendor/device */
+       /* codec vendor/device/revision */
+       err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
+           COP_REVISION_ID, &rev);
+       if (err)
+               return err;
        err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
            COP_VENDOR_ID, &result);
        if (err)
                return err;
-       aprint_normal("%s: vendor/device = 0x%4.4x/0x%4.4x\n",
-           XNAME(this->az), result >> 16, result & 0xffff);
+       aprint_normal("%s: codec: High Definition Audio rev. %u.%u\n", XNAME(this->az),
+           COP_RID_MAJ(rev), COP_RID_MIN(rev));
+       aprint_normal("%s: vendor/device = 0x%4.4x/0x%4.4x (rev. %u.%u)\n",
+           XNAME(this->az), result >> 16, result & 0xffff,
+           COP_RID_REVISION(rev), COP_RID_STEPPING(rev));
 
        /* identify function nodes */
        err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
@@ -1211,6 +1278,7 @@
                aprint_error("%s: No function groups\n", XNAME(this->az));
                return -1;
        }
+       /* iterate function nodes and find an audio function */
        n = COP_START_NID(result);
        DPRINTF(("%s: nidstart=%d #functions=%d\n",
            __func__, n, this->nfunctions));
@@ -1239,33 +1307,33 @@
                return err;
        DPRINTF(("%s: There are %d widgets in the audio function.\n",
           __func__, COP_NSUBNODES(result)));
-       if (COP_START_NID(result) < 2) {
+       this->wstart = COP_START_NID(result);
+       if (this->wstart < 2) {
                aprint_error("%s: invalid node structure\n", XNAME(this->az));
                return -1;
        }
-       this->nwidgets = COP_NSUBNODES(result);
-       this->widgets = malloc(sizeof(widget_t) * this->nwidgets,
-           M_DEVBUF, M_ZERO | M_NOWAIT);
-       if (this->widgets == NULL) {
+       this->wend = this->wstart + COP_NSUBNODES(result);
+       this->w = malloc(sizeof(widget_t) * this->wend, M_DEVBUF,
+           M_ZERO | M_NOWAIT);
+       if (this->w == NULL) {
                aprint_error("%s: out of memory\n", XNAME(this->az));
                return ENOMEM;
        }
-       n = COP_START_NID(result);
-       for (i = 0; i < this->nwidgets; i++) {
-               err = azalia_widget_init(&this->widgets[i], this, n + i);
+       FOR_EACH_WIDGET(this, i) {
+               err = azalia_widget_init(&this->w[i], this, i);
                if (err)
                        return err;
        }
 
        /* search pins for the lowest association */
        assoc = INT_MAX;
-       for (i = 0; i < this->nwidgets; i++) {
-               if (this->widgets[i].type != COP_AWTYPE_PIN_COMPLEX)
+       FOR_EACH_WIDGET(this, i) {
+               if (this->w[i].type != COP_AWTYPE_PIN_COMPLEX)
                        continue;
-               if ((this->widgets[i].d.pin.cap & COP_PINCAP_OUTPUT) == 0)
+               if ((this->w[i].d.pin.cap & COP_PINCAP_OUTPUT) == 0)
                        continue;
-               if (this->widgets[i].d.pin.association < assoc)
-                       assoc = this->widgets[i].d.pin.association;
+               if (this->w[i].d.pin.association < assoc)
+                       assoc = this->w[i].d.pin.association;
        }
        if (assoc == INT_MAX) {
                aprint_error("%s: no pins\n", XNAME(this->az));
@@ -1282,25 +1350,25 @@
                this->dacindexes[npin] = azalia_codec_find_dac(this, i, 0);
                if (this->dacindexes[npin] < 0) {
                        aprint_error("%s: a pin 0x%x does not connect to any DAC.",
-                           XNAME(this->az), this->widgets[i].nid);
+                           XNAME(this->az), this->w[i].nid);
                        return -1;
                }
                npin++;
        }
        for (i = 0; i < npin; i++) {
-               this->comresp(this, this->widgets[pindexes[i]].nid,
-                   CORB_SET_PIN_WIDGET_CONTROL, CORB_PWC_OUTPUT | CORB_PWC_VREF_100, &result);
+               this->comresp(this, pindexes[i], CORB_SET_PIN_WIDGET_CONTROL,
+                   CORB_PWC_OUTPUT | CORB_PWC_VREF_100, &result);
        }
        this->ndacindexes = npin;
        DPRINTF(("%s: DACs:", __func__));



Home | Main Index | Thread Index | Old Index