summaryrefslogtreecommitdiff
path: root/sys/dev/pci/azalia_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/azalia_codec.c')
-rw-r--r--sys/dev/pci/azalia_codec.c126
1 files changed, 116 insertions, 10 deletions
diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c
index cb47be57c36..c2fb80fc434 100644
--- a/sys/dev/pci/azalia_codec.c
+++ b/sys/dev/pci/azalia_codec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia_codec.c,v 1.18 2006/07/23 20:23:51 brad Exp $ */
+/* $OpenBSD: azalia_codec.c,v 1.19 2007/05/02 17:01:22 deanna Exp $ */
/* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */
/*-
@@ -100,8 +100,8 @@ int azalia_ad1981hd_mixer_init(codec_t *);
int azalia_cmi9880_init_dacgroup(codec_t *);
int azalia_cmi9880_mixer_init(codec_t *);
int azalia_stac9221_init_dacgroup(codec_t *);
-int azalia_stac9220_mixer_init(codec_t *);
-
+int azalia_stac9200_mixer_init(codec_t *);
+int azalia_stac9200_unsol_event(codec_t *, int);
int
azalia_codec_init_vtbl(codec_t *this)
@@ -158,8 +158,13 @@ azalia_codec_init_vtbl(codec_t *this)
this->init_dacgroup = azalia_stac9221_init_dacgroup;
break;
case 0x83847690:
- this->name = "Sigmatel STAC9220";
- this->mixer_init = azalia_stac9220_mixer_init;
+ /* http://www.idt.com/products/getDoc.cfm?docID=17812077 */
+ this->name = "Sigmatel STAC9200";
+ this->mixer_init = azalia_stac9200_mixer_init;
+ this->unsol_event = azalia_stac9200_unsol_event;
+ break;
+ case 0x83847691:
+ this->name = "Sigmatel STAC9200D";
break;
}
return 0;
@@ -1189,6 +1194,28 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_
return err;
}
+ /*
+ * pin control: enable/disable. for bidirectional pins, set
+ * direction with MI_TARGET_PINDIR after enabling.
+ */
+
+ else if (target == MI_TARGET_PINCTRL) {
+ if (mc->un.ord >= 2)
+ return EINVAL;
+ err = this->comresp(this, nid,
+ CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
+ if (err)
+ return err;
+ if (mc->un.ord == 0) /* disable */
+ result &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT);
+ else
+ result |= CORB_PWC_OUTPUT | CORB_PWC_INPUT;
+ err = this->comresp(this, nid,
+ CORB_SET_PIN_WIDGET_CONTROL, result, &result);
+ if (err)
+ return err;
+ }
+
/* pin headphone-boost */
else if (target == MI_TARGET_PINBOOST) {
if (mc->un.ord >= 2)
@@ -2087,10 +2114,10 @@ azalia_stac9221_init_dacgroup(codec_t *this)
}
/* ----------------------------------------------------------------
- * Sigmatel STAC9220
+ * Sigmatel STAC9200
* ---------------------------------------------------------------- */
-static const mixer_item_t stac9220_mixer_items[] = {
+static const mixer_item_t stac9200_mixer_items[] = {
{{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
{{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
{{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
@@ -2133,11 +2160,13 @@ static const mixer_item_t stac9220_mixer_items[] = {
};
int
-azalia_stac9220_mixer_init(codec_t *this)
+azalia_stac9200_mixer_init(codec_t *this)
{
mixer_ctrl_t mc;
+ int err;
+ uint32_t value;
- this->nmixers = sizeof(stac9220_mixer_items) / sizeof(mixer_item_t);
+ this->nmixers = sizeof(stac9200_mixer_items) / sizeof(mixer_item_t);
this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
M_DEVBUF, M_NOWAIT);
if (this->mixers == NULL) {
@@ -2145,7 +2174,7 @@ azalia_stac9220_mixer_init(codec_t *this)
return ENOMEM;
}
bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
- memcpy(this->mixers, stac9220_mixer_items,
+ memcpy(this->mixers, stac9200_mixer_items,
sizeof(mixer_item_t) * this->nmixers);
azalia_generic_mixer_fix_indexes(this);
azalia_generic_mixer_default(this);
@@ -2164,5 +2193,82 @@ azalia_stac9220_mixer_init(codec_t *this)
mc.un.value.level[1] = mc.un.value.level[0];
azalia_generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc);
+#define STAC9200_EVENT_HP 0
+#define STAC9200_NID_HP 0x0d
+#define STAC9200_NID_SPEAKER 0x0e
+
+ /* register hp unsolicited event */
+ this->comresp(this, STAC9200_NID_HP,
+ CORB_SET_UNSOLICITED_RESPONSE,
+ CORB_UNSOL_ENABLE | STAC9200_EVENT_HP, NULL);
+
+ /* make initial hp vs speaker choice */
+
+ err = this->comresp(this, STAC9200_NID_HP,
+ CORB_GET_PIN_SENSE, 0, &value);
+ if (err)
+ return err;
+ if (value & CORB_PS_PRESENCE) {
+ mc.un.ord = 0;
+ azalia_generic_mixer_set(this, STAC9200_NID_SPEAKER,
+ MI_TARGET_PINCTRL, &mc);
+ mc.un.ord = 1;
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINCTRL, &mc);
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINDIR, &mc);
+ } else {
+ mc.un.ord = 0;
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINCTRL, &mc);
+ mc.un.ord = 1;
+ azalia_generic_mixer_set(this, STAC9200_NID_SPEAKER,
+ MI_TARGET_PINCTRL, &mc);
+ azalia_generic_mixer_set(this, STAC9200_NID_SPEAKER,
+ MI_TARGET_PINDIR, &mc);
+ }
+ return 0;
+}
+int
+azalia_stac9200_unsol_event(codec_t *this, int tag)
+{
+ int err;
+ uint32_t value;
+ mixer_ctrl_t mc;
+
+ switch (tag) {
+ case STAC9200_EVENT_HP:
+ err = this->comresp(this, STAC9200_NID_HP,
+ CORB_GET_PIN_SENSE, 0, &value);
+ if (err)
+ return err;
+ if (value & CORB_PS_PRESENCE) {
+ DPRINTF(("%s: headphone inserted\n", __func__));
+ mc.un.ord = 0; /* disable */
+ azalia_generic_mixer_set(this,
+ STAC9200_NID_SPEAKER,
+ MI_TARGET_PINCTRL, &mc);
+ mc.un.ord = 1; /* enable and direction output */
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINCTRL, &mc);
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINDIR, &mc);
+ } else {
+ DPRINTF(("%s: headphone pulled\n", __func__));
+ mc.un.ord = 0;
+ azalia_generic_mixer_set(this, STAC9200_NID_HP,
+ MI_TARGET_PINCTRL, &mc);
+ mc.un.ord = 1;
+ azalia_generic_mixer_set(this,
+ STAC9200_NID_SPEAKER,
+ MI_TARGET_PINCTRL, &mc);
+ azalia_generic_mixer_set(this,
+ STAC9200_NID_SPEAKER,
+ MI_TARGET_PINDIR, &mc);
+ }
+ break;
+ default:
+ DPRINTF(("%s: unknown tag: %d\n", __func__, tag));
+ }
return 0;
}