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