Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Jan 2012 19:12:33 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r230312 - head/sys/dev/sound/pci/hda
Message-ID:  <201201181912.q0IJCXk4053306@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Wed Jan 18 19:12:33 2012
New Revision: 230312
URL: http://svn.freebsd.org/changeset/base/230312

Log:
  Improve HDMI/DisplayPort audio support in snd_hda(4):
  
   - Enable and handle unsolicited responses from digital display pins,
  reporting connection and EDID-Like Data (ELD) validity status changes.
   - Fetch ELD data, describing connected digital display device audio
  capabilities. These data not really used at the moment (user is not
  denied to use audio formats not supported by the device), only printed to
  verbose logs. But they are useful for debugging. The fact that ELD was
  received tells that HDMI link was established and video driver enabled
  HDMI audio passthrough. Some old chips may not return ELD, so lack of it
  is not necessary a problem.
   - Add some more points to CODEC configuration sequence:
     - For converter widgets, supporting more then two channels (HDMI/DP
       converter widgets support 8), set number of channels to handle.
     - For digital display pins (HDMI/DP) fill audio infoframe, reporting
       connected device about number of channels and speakers allocation.
     - For digital display pins (HDMI/DP) set mapping between channels seen
       by software and channels transferred via HDMI/DisplayPort.
   - Allow more audio formats, not used for analog connections because of
  stereo pairs orientation, but easily applicable to HDMI/DisplayPort: 2.1,
  3.0, 3.1, 4.1, 5.0, 6.0, 6.1, 7.0. That list may be filtered later using
  info from ELD.
   - Disable MSI interrupts for NVIDIA HDA controllers before GT520.
  
  At this point I can successfully play audio over HDMI from NVIDIA GT210
  and GT520 cards with nvidia-driver-290.10 driver to Marantz SR4001
  receiver in 2.0, 2.1, 3.0, 4.0, 4.1, 5.0 and 5.1 PCM formats at 44, 48,
  88 and 96KHz at 16 and 24 bits, same as do AC3/DTS passthrough.
  6.0, 6.1, 7.0 and 7.1 PCM formats are not working for me, but I think
  it is because of receiver age.
  
  MFC after:	2 months
  Sponsored by:	iXsystems, Inc.

Modified:
  head/sys/dev/sound/pci/hda/hda_reg.h
  head/sys/dev/sound/pci/hda/hdaa.c
  head/sys/dev/sound/pci/hda/hdaa.h
  head/sys/dev/sound/pci/hda/hdac.c
  head/sys/dev/sound/pci/hda/hdac.h

Modified: head/sys/dev/sound/pci/hda/hda_reg.h
==============================================================================
--- head/sys/dev/sound/pci/hda/hda_reg.h	Wed Jan 18 18:26:56 2012	(r230311)
+++ head/sys/dev/sound/pci/hda/hda_reg.h	Wed Jan 18 19:12:33 2012	(r230312)
@@ -419,6 +419,7 @@
     HDA_CMD_VERB_SET_PIN_SENSE, (payload)))
 
 #define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT		0x80000000
+#define HDA_CMD_GET_PIN_SENSE_ELD_VALID			0x40000000
 #define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK		0x7fffffff
 #define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT		0
 
@@ -675,17 +676,47 @@
     HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload)))
 
 #define HDA_CMD_VERB_GET_HDMI_DIP_SIZE			0xf2e 
+
+#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg)			\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg)))
+
 #define HDA_CMD_VERB_GET_HDMI_ELDD			0xf2f 
 
+#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off)				\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_GET_HDMI_ELDD, (off)))
+
 #define HDA_CMD_VERB_GET_HDMI_DIP_INDEX			0xf30 
 #define HDA_CMD_VERB_SET_HDMI_DIP_INDEX			0x730 
 
+#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid)				\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_GET_HDMI_DIP_INDEX, 0x0))
+#define HDA_CMD_SET_HDMI_DIP_INDEX(cad, nid, payload)			\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload)))
+
 #define HDA_CMD_VERB_GET_HDMI_DIP_DATA			0xf31 
 #define HDA_CMD_VERB_SET_HDMI_DIP_DATA			0x731 
 
+#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid)				\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_GET_HDMI_DIP_DATA, 0x0))
+#define HDA_CMD_SET_HDMI_DIP_DATA(cad, nid, payload)			\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload)))
+
 #define HDA_CMD_VERB_GET_HDMI_DIP_XMIT			0xf32 
 #define HDA_CMD_VERB_SET_HDMI_DIP_XMIT			0x732 
 
+#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid)				\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_GET_HDMI_DIP_XMIT, 0x0))
+#define HDA_CMD_SET_HDMI_DIP_XMIT(cad, nid, payload)			\
+    (HDA_CMD_12BIT((cad), (nid),					\
+    HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload)))
+
 #define HDA_CMD_VERB_GET_HDMI_CP_CTRL			0xf33 
 #define HDA_CMD_VERB_SET_HDMI_CP_CTRL			0x733 
 
@@ -699,6 +730,23 @@
     (HDA_CMD_12BIT((cad), (nid),					\
     HDA_CMD_VERB_SET_HDMI_CHAN_SLOT, (payload)))
 
+#define	HDA_HDMI_CODING_TYPE_REF_STREAM_HEADER		0
+#define	HDA_HDMI_CODING_TYPE_LPCM			1
+#define	HDA_HDMI_CODING_TYPE_AC3			2
+#define	HDA_HDMI_CODING_TYPE_MPEG1			3
+#define	HDA_HDMI_CODING_TYPE_MP3			4
+#define	HDA_HDMI_CODING_TYPE_MPEG2			5
+#define	HDA_HDMI_CODING_TYPE_AACLC			6
+#define	HDA_HDMI_CODING_TYPE_DTS			7
+#define	HDA_HDMI_CODING_TYPE_ATRAC			8
+#define	HDA_HDMI_CODING_TYPE_SACD			9
+#define	HDA_HDMI_CODING_TYPE_EAC3			10
+#define	HDA_HDMI_CODING_TYPE_DTS_HD			11
+#define	HDA_HDMI_CODING_TYPE_MLP			12
+#define	HDA_HDMI_CODING_TYPE_DST			13
+#define	HDA_HDMI_CODING_TYPE_WMAPRO			14
+#define	HDA_HDMI_CODING_TYPE_REF_CTX			15
+
 /* Function Reset */
 #define HDA_CMD_VERB_FUNCTION_RESET			0x7ff
 

Modified: head/sys/dev/sound/pci/hda/hdaa.c
==============================================================================
--- head/sys/dev/sound/pci/hda/hdaa.c	Wed Jan 18 18:26:56 2012	(r230311)
+++ head/sys/dev/sound/pci/hda/hdaa.c	Wed Jan 18 19:12:33 2012	(r230312)
@@ -116,6 +116,12 @@ const char *HDA_LOCS[64] = {
 const char *HDA_GPIO_ACTIONS[8] = {
     "keep", "set", "clear", "disable", "input", "0x05", "0x06", "0x07"};
 
+const char *HDA_HDMI_CODING_TYPES[18] = {
+    "undefined", "LPCM", "AC-3", "MPEG1", "MP3", "MPEG2", "AAC-LC", "DTS",
+    "ATRAC", "DSD", "E-AC-3", "DTS-HD", "MLP", "DST", "WMAPro", "HE-AAC",
+    "HE-AACv2", "MPEG-Surround"
+};
+
 /* Default */
 static uint32_t hdaa_fmt[] = {
 	SND_FORMAT(AFMT_S16_LE, 2, 0),
@@ -246,43 +252,38 @@ hdaa_audio_ctl_amp_get(struct hdaa_devin
  * Jack detection (Speaker/HP redirection) event handler.
  */
 static void
-hdaa_hp_switch_handler(struct hdaa_devinfo *devinfo, int asid)
+hdaa_hp_switch_handler(struct hdaa_widget *w)
 {
+	struct hdaa_devinfo *devinfo = w->devinfo;
 	struct hdaa_audio_as *as;
-	struct hdaa_widget *w;
+	struct hdaa_widget *w1;
 	struct hdaa_audio_ctl *ctl;
 	uint32_t val, res;
 	int j;
 
-	as = &devinfo->as[asid];
-	if (as->hpredir < 0)
-		return;
-
-	w = hdaa_widget_get(devinfo, as->pins[15]);
-	if (w == NULL || w->enable == 0 || w->type !=
+	if (w->enable == 0 || w->type !=
 	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
 		return;
 
-	res = hda_command(devinfo->dev,
-	    HDA_CMD_GET_PIN_SENSE(0, as->pins[15]));
-
+	res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
 	HDA_BOOTVERBOSE(
 		device_printf(devinfo->dev,
-		    "Pin sense: nid=%d sence=0x%08x",
-		    as->pins[15], res);
+		    "Pin sense: nid=%d sence=0x%08x", w->nid, res);
 	);
-
 	res = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
 	if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
 		res ^= 1;
-
 	HDA_BOOTVERBOSE(
-		printf(" %sconnected\n", res == 0 ? "dis" : "");
+		printf(" (%sconnected)\n", res == 0 ? "dis" : "");
 	);
 
+	as = &devinfo->as[w->bindas];
+	if (as->hpredir < 0 || as->pins[15] != w->nid)
+		return;
+
 	/* (Un)Mute headphone pin. */
 	ctl = hdaa_audio_ctl_amp_get(devinfo,
-	    as->pins[15], HDAA_CTL_IN, -1, 1);
+	    w->nid, HDAA_CTL_IN, -1, 1);
 	if (ctl != NULL && ctl->mute) {
 		/* If pin has muter - use it. */
 		val = (res != 0) ? 0 : 1;
@@ -294,21 +295,17 @@ hdaa_hp_switch_handler(struct hdaa_devin
 		}
 	} else {
 		/* If there is no muter - disable pin output. */
-		w = hdaa_widget_get(devinfo, as->pins[15]);
-		if (w != NULL && w->type ==
-		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
-			if (res != 0)
-				val = w->wclass.pin.ctrl |
-				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
-			else
-				val = w->wclass.pin.ctrl &
-				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
-			if (val != w->wclass.pin.ctrl) {
-				w->wclass.pin.ctrl = val;
-				hda_command(devinfo->dev,
-				    HDA_CMD_SET_PIN_WIDGET_CTRL(0,
-				    w->nid, w->wclass.pin.ctrl));
-			}
+		if (res != 0)
+			val = w->wclass.pin.ctrl |
+			    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+		else
+			val = w->wclass.pin.ctrl &
+			    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+		if (val != w->wclass.pin.ctrl) {
+			w->wclass.pin.ctrl = val;
+			hda_command(devinfo->dev,
+			    HDA_CMD_SET_PIN_WIDGET_CTRL(0,
+			    w->nid, w->wclass.pin.ctrl));
 		}
 	}
 	/* (Un)Mute other pins. */
@@ -329,20 +326,20 @@ hdaa_hp_switch_handler(struct hdaa_devin
 			continue;
 		}
 		/* If there is no muter - disable pin output. */
-		w = hdaa_widget_get(devinfo, as->pins[j]);
-		if (w != NULL && w->type ==
+		w1 = hdaa_widget_get(devinfo, as->pins[j]);
+		if (w1 != NULL && w1->type ==
 		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
 			if (res != 0)
-				val = w->wclass.pin.ctrl &
+				val = w1->wclass.pin.ctrl &
 				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
 			else
-				val = w->wclass.pin.ctrl |
+				val = w1->wclass.pin.ctrl |
 				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
-			if (val != w->wclass.pin.ctrl) {
-				w->wclass.pin.ctrl = val;
+			if (val != w1->wclass.pin.ctrl) {
+				w1->wclass.pin.ctrl = val;
 				hda_command(devinfo->dev,
 				    HDA_CMD_SET_PIN_WIDGET_CTRL(0,
-				    w->nid, w->wclass.pin.ctrl));
+				    w1->nid, w1->wclass.pin.ctrl));
 			}
 		}
 	}
@@ -355,6 +352,7 @@ static void
 hdaa_jack_poll_callback(void *arg)
 {
 	struct hdaa_devinfo *devinfo = arg;
+	struct hdaa_widget *w;
 	int i;
 
 	hdaa_lock(devinfo);
@@ -365,7 +363,11 @@ hdaa_jack_poll_callback(void *arg)
 	for (i = 0; i < devinfo->ascnt; i++) {
 		if (devinfo->as[i].hpredir < 0)
 			continue;
-		hdaa_hp_switch_handler(devinfo, i);
+		w = hdaa_widget_get(devinfo, devinfo->as[i].pins[15]);
+		if (w == NULL || w->enable == 0 || w->type !=
+		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+			continue;
+		hdaa_hp_switch_handler(w);
 	}
 	callout_reset(&devinfo->poll_jack, devinfo->poll_ival,
 	    hdaa_jack_poll_callback, devinfo);
@@ -397,15 +399,17 @@ hdaa_hp_switch_init(struct hdaa_devinfo 
 			    as[i].pins[15]);
 			continue;
 		}
-		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
-			as[i].unsol = HDAC_UNSOL_ALLOC(
+		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap) &&
+		    w->unsol < 0) {
+			w->unsol = HDAC_UNSOL_ALLOC(
 			    device_get_parent(devinfo->dev), devinfo->dev,
 			    w->nid);
 			hda_command(devinfo->dev,
 			    HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid,
 			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
-			    as[i].unsol));
-		} else
+			    w->unsol));
+		}
+		if (w->unsol < 0)
 			poll = 1;
 		HDA_BOOTVERBOSE(
 			device_printf(devinfo->dev,
@@ -414,7 +418,7 @@ hdaa_hp_switch_init(struct hdaa_devinfo 
 			    i, w->nid,
 			    (poll != 0) ? "polling" : "unsolicited responses");
 		);
-		hdaa_hp_switch_handler(devinfo, i);
+		hdaa_hp_switch_handler(w);
 	}
 	if (poll) {
 		callout_reset(&devinfo->poll_jack, 1,
@@ -430,18 +434,208 @@ hdaa_hp_switch_deinit(struct hdaa_devinf
         int i;
 
 	for (i = 0; i < devinfo->ascnt; i++) {
-		if (as[i].unsol < 0)
-			continue;
 		w = hdaa_widget_get(devinfo, as[i].pins[15]);
 		if (w == NULL || w->enable == 0 || w->type !=
 		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
 			continue;
+		if (HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) ||
+		    HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+			continue;
+		if (w->unsol < 0)
+			continue;
 		hda_command(devinfo->dev,
 		    HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid, 0));
 		HDAC_UNSOL_FREE(
 		    device_get_parent(devinfo->dev), devinfo->dev,
-		    as[i].unsol);
-		as[i].unsol = -1;
+		    w->unsol);
+		w->unsol = -1;
+	}
+}
+
+static void
+hdaa_eld_dump(struct hdaa_widget *w)
+{
+	struct hdaa_devinfo *devinfo = w->devinfo;
+	device_t dev = devinfo->dev;
+	uint8_t *sad;
+	int len, mnl, i, sadc, fmt;
+
+	if (w->eld == NULL || w->eld_len < 4)
+		return;
+	device_printf(dev,
+	    "ELD nid=%d: ELD_Ver=%u Baseline_ELD_Len=%u\n",
+	    w->nid, w->eld[0] >> 3, w->eld[2]);
+	if ((w->eld[0] >> 3) != 0x02)
+		return;
+	len = min(w->eld_len, (u_int)w->eld[2] * 4);
+	mnl = w->eld[4] & 0x1f;
+	device_printf(dev,
+	    "ELD nid=%d: CEA_EDID_Ver=%u MNL=%u\n",
+	    w->nid, w->eld[4] >> 5, mnl);
+	sadc = w->eld[5] >> 4;
+	device_printf(dev,
+	    "ELD nid=%d: SAD_Count=%u Conn_Type=%u S_AI=%u HDCP=%u\n",
+	    w->nid, sadc, (w->eld[5] >> 2) & 0x3,
+	    (w->eld[5] >> 1) & 0x1, w->eld[5] & 0x1);
+	device_printf(dev,
+	    "ELD nid=%d: Aud_Synch_Delay=%ums\n",
+	    w->nid, w->eld[6] * 2);
+	device_printf(dev,
+	    "ELD nid=%d: Channels=0x%b\n",
+	    w->nid, w->eld[7],
+	    "\020\07RLRC\06FLRC\05RC\04RLR\03FC\02LFE\01FLR");
+	device_printf(dev,
+	    "ELD nid=%d: Port_ID=0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+	    w->nid, w->eld[8], w->eld[9], w->eld[10], w->eld[11],
+	    w->eld[12], w->eld[13], w->eld[14], w->eld[15]);
+	device_printf(dev,
+	    "ELD nid=%d: Manufacturer_Name=0x%02x%02x\n",
+	    w->nid, w->eld[16], w->eld[17]);
+	device_printf(dev,
+	    "ELD nid=%d: Product_Code=0x%02x%02x\n",
+	    w->nid, w->eld[18], w->eld[19]);
+	device_printf(dev,
+	    "ELD nid=%d: Monitor_Name_String='%.*s'\n",
+	    w->nid, mnl, &w->eld[20]);
+	for (i = 0; i < sadc; i++) {
+		sad = &w->eld[20 + mnl + i * 3];
+		fmt = (sad[0] >> 3) & 0x0f;
+		if (fmt == HDA_HDMI_CODING_TYPE_REF_CTX) {
+			fmt = (sad[2] >> 3) & 0x1f;
+			if (fmt < 1 || fmt > 3)
+				fmt = 0;
+			else
+				fmt += 14;
+		}
+		device_printf(dev,
+		    "ELD nid=%d: %s %dch freqs=0x%b",
+		    w->nid, HDA_HDMI_CODING_TYPES[fmt], (sad[0] & 0x07) + 1,
+		    sad[1], "\020\007192\006176\00596\00488\00348\00244\00132");
+		switch (fmt) {
+		case HDA_HDMI_CODING_TYPE_LPCM:
+			printf(" sizes=0x%b",
+			    sad[2] & 0x07, "\020\00324\00220\00116");
+			break;
+		case HDA_HDMI_CODING_TYPE_AC3:
+		case HDA_HDMI_CODING_TYPE_MPEG1:
+		case HDA_HDMI_CODING_TYPE_MP3:
+		case HDA_HDMI_CODING_TYPE_MPEG2:
+		case HDA_HDMI_CODING_TYPE_AACLC:
+		case HDA_HDMI_CODING_TYPE_DTS:
+		case HDA_HDMI_CODING_TYPE_ATRAC:
+			printf(" max_bitrate=%d", sad[2] * 8000);
+			break;
+		case HDA_HDMI_CODING_TYPE_WMAPRO:
+			printf(" profile=%d", sad[2] & 0x07);
+			break;
+		}
+		printf("\n");
+	}
+}
+
+static void
+hdaa_eld_handler(struct hdaa_widget *w)
+{
+	struct hdaa_devinfo *devinfo = w->devinfo;
+	uint32_t res;
+	int i;
+
+	if (w->enable == 0 || w->type !=
+	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+		return;
+
+	if (w->eld != NULL) {
+		w->eld_len = 0;
+		free(w->eld, M_HDAA);
+		w->eld = NULL;
+	}
+
+	res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
+	HDA_BOOTVERBOSE(
+		device_printf(devinfo->dev,
+		    "Pin sense: nid=%d sence=0x%08x "
+		    "(%sconnected, ELD %svalid)\n",
+		    w->nid, res,
+		    (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) ? "" : "dis",
+		    (res & HDA_CMD_GET_PIN_SENSE_ELD_VALID) ? "" : "in");
+	);
+	if ((res & HDA_CMD_GET_PIN_SENSE_ELD_VALID) == 0)
+		return;
+
+	res = hda_command(devinfo->dev,
+	    HDA_CMD_GET_HDMI_DIP_SIZE(0, w->nid, 0x08));
+	if (res == HDA_INVALID)
+		return;
+	w->eld_len = res & 0xff;
+	if (w->eld_len != 0)
+		w->eld = malloc(w->eld_len, M_HDAA, M_ZERO | M_NOWAIT);
+	if (w->eld == NULL) {
+		w->eld_len = 0;
+		return;
+	}
+
+	for (i = 0; i < w->eld_len; i++) {
+		res = hda_command(devinfo->dev,
+		    HDA_CMD_GET_HDMI_ELDD(0, w->nid, i));
+		if (res & 0x80000000)
+			w->eld[i] = res & 0xff;
+	}
+	HDA_BOOTVERBOSE(
+		hdaa_eld_dump(w);
+	);
+}
+
+
+static void
+hdaa_eld_init(struct hdaa_devinfo *devinfo)
+{
+        struct hdaa_widget *w;
+        int i;
+
+	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+		w = hdaa_widget_get(devinfo, i);
+		if (w == NULL || w->type !=
+		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+			continue;
+		if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
+		    !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+			continue;
+		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap) &&
+		    w->unsol < 0) {
+			w->unsol = HDAC_UNSOL_ALLOC(
+			    device_get_parent(devinfo->dev), devinfo->dev,
+			    w->nid);
+			hda_command(devinfo->dev,
+			    HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid,
+			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
+			    w->unsol));
+		}
+		hdaa_eld_handler(w);
+	}
+}
+
+static void
+hdaa_eld_deinit(struct hdaa_devinfo *devinfo)
+{
+	struct hdaa_widget *w;
+	int i;
+
+	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+		w = hdaa_widget_get(devinfo, i);
+		if (w == NULL || w->type !=
+		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+			continue;
+		if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
+		    !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+			continue;
+		if (w->unsol < 0)
+			continue;
+		hda_command(devinfo->dev,
+		    HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid, 0));
+		HDAC_UNSOL_FREE(
+		    device_get_parent(devinfo->dev), devinfo->dev,
+		    w->unsol);
+		w->unsol = -1;
 	}
 }
 
@@ -938,6 +1132,7 @@ hdaa_widget_parse(struct hdaa_widget *w)
 		    hdaa_sysctl_config, "A", "Original pin configuration");
 		hdaa_lock(w->devinfo);
 	}
+	w->unsol = -1;
 }
 
 static void
@@ -1197,27 +1392,42 @@ static void
 hdaa_audio_setup(struct hdaa_chan *ch)
 {
 	struct hdaa_audio_as *as = &ch->devinfo->as[ch->as];
-	struct hdaa_widget *w;
-	int i, chn, totalchn, c;
+	struct hdaa_widget *w, *wp;
+	int i, j, k, chn, cchn, totalchn, totalextchn, c;
 	uint16_t fmt, dfmt;
-	uint16_t chmap[2][5] = {{ 0x0010, 0x0001, 0x0201, 0x0231, 0x0231 }, /* 5.1 */
-				{ 0x0010, 0x0001, 0x2001, 0x2031, 0x2431 }};/* 7.1 */
-	int map = -1;
+	/* Mapping channel pairs to codec pins/converters. */
+	const static uint16_t convmap[2][5] =
+	    {{ 0x0010, 0x0001, 0x0201, 0x0231, 0x0231 }, /* 5.1 */
+	     { 0x0010, 0x0001, 0x2001, 0x2031, 0x2431 }};/* 7.1 */
+	/* Mapping formats to HDMI channel allocations. */
+	const static uint8_t hdmica[2][8] =
+	    {{ 0x02, 0x00, 0x04, 0x08, 0x0a, 0x0e, 0x12, 0x12 }, /* x.0 */
+	     { 0x01, 0x03, 0x01, 0x03, 0x09, 0x0b, 0x0f, 0x13 }}; /* x.1 */
+	/* Mapping formats to HDMI channels order. */
+	const static uint32_t hdmich[2][8] =
+	    {{ 0xFFFF0F00, 0xFFFFFF10, 0xFFF2FF10, 0xFF32FF10,
+	       0xFF324F10, 0xF5324F10, 0x54326F10, 0x54326F10 }, /* x.0 */
+	     { 0xFFFFF000, 0xFFFF0100, 0xFFFFF210, 0xFFFF2310,
+	       0xFF32F410, 0xFF324510, 0xF6324510, 0x76325410 }}; /* x.1 */
+	int convmapid = -1;
+	nid_t nid;
+	uint8_t csum;
 
 	totalchn = AFMT_CHANNEL(ch->fmt);
+	totalextchn = AFMT_EXTCHANNEL(ch->fmt);
 	HDA_BOOTHVERBOSE(
 		device_printf(ch->pdevinfo->dev,
-		    "PCMDIR_%s: Stream setup fmt=%08x speed=%d\n",
+		    "PCMDIR_%s: Stream setup fmt=%08x (%d.%d) speed=%d\n",
 		    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
-		    ch->fmt, ch->spd);
+		    ch->fmt, totalchn - totalextchn, totalextchn, ch->spd);
 	);
 	fmt = hdaa_stream_format(ch);
 
-	/* Set channel mapping for known speaker setups. */
+	/* Set channels to I/O converters mapping for known speaker setups. */
 	if ((as->pinset == 0x0007 || as->pinset == 0x0013)) /* Standard 5.1 */
-		map = 0;
+		convmapid = 0;
 	else if (as->pinset == 0x0017) /* Standard 7.1 */
-		map = 1;
+		convmapid = 1;
 
 	dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
 	if (ch->fmt & AFMT_AC3)
@@ -1234,22 +1444,16 @@ hdaa_audio_setup(struct hdaa_chan *ch)
 		if (as->fakeredir && i == (as->pincnt - 1)) {
 			c = (ch->sid << 4);
 		} else {
-			if (map >= 0) /* Map known speaker setups. */
-				chn = (((chmap[map][totalchn / 2] >> i * 4) &
-				    0xf) - 1) * 2;
+			/* Map channels to I/O converters, if set. */
+			if (convmapid >= 0)
+				chn = (((convmap[convmapid][totalchn / 2]
+				    >> i * 4) & 0xf) - 1) * 2;
 			if (chn < 0 || chn >= totalchn) {
 				c = 0;
 			} else {
 				c = (ch->sid << 4) | chn;
 			}
 		}
-		HDA_BOOTHVERBOSE(
-			device_printf(ch->pdevinfo->dev,
-			    "PCMDIR_%s: Stream setup nid=%d: "
-			    "fmt=0x%04x, dfmt=0x%04x, chan=0x%04x\n",
-			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
-			    ch->io[i], fmt, dfmt, c);
-		);
 		hda_command(ch->devinfo->dev,
 		    HDA_CMD_SET_CONV_FMT(0, ch->io[i], fmt));
 		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
@@ -1258,15 +1462,93 @@ hdaa_audio_setup(struct hdaa_chan *ch)
 		}
 		hda_command(ch->devinfo->dev,
 		    HDA_CMD_SET_CONV_STREAM_CHAN(0, ch->io[i], c));
-#if 0
-		hda_command(ch->devinfo->dev,
-		    HDA_CMD_SET_CONV_CHAN_COUNT(0, ch->io[i], 1));
-		hda_command(ch->devinfo->dev,
-		    HDA_CMD_SET_HDMI_CHAN_SLOT(0, ch->io[i], 0x00));
-		hda_command(ch->devinfo->dev,
-		    HDA_CMD_SET_HDMI_CHAN_SLOT(0, ch->io[i], 0x11));
-#endif
-		chn += HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap) + 1;
+		cchn = HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap);
+		if (cchn > 1 && chn < totalchn) {
+			cchn = min(cchn, totalchn - chn - 1);
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_CONV_CHAN_COUNT(0, ch->io[i], cchn));
+		}
+		HDA_BOOTHVERBOSE(
+			device_printf(ch->pdevinfo->dev,
+			    "PCMDIR_%s: Stream setup nid=%d: "
+			    "fmt=0x%04x, dfmt=0x%04x, chan=0x%04x, "
+			    "chan_count=0x%02x\n",
+			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
+			    ch->io[i], fmt, dfmt, c, cchn);
+		);
+		for (j = 0; j < 16; j++) {
+			if (as->dacs[ch->asindex][j] != ch->io[i])
+				continue;
+			nid = as->pins[j];
+			wp = hdaa_widget_get(ch->devinfo, nid);
+			if (wp == NULL)
+				continue;
+			if (!HDA_PARAM_PIN_CAP_DP(wp->wclass.pin.cap) &&
+			    !HDA_PARAM_PIN_CAP_HDMI(wp->wclass.pin.cap))
+				continue;
+
+			/* Set channel mapping. */
+			for (k = 0; k < 8; k++) {
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_CHAN_SLOT(0, nid,
+				    (((hdmich[totalextchn == 0 ? 0 : 1][totalchn - 1]
+				     >> (k * 4)) & 0xf) << 4) | k));
+			}
+
+			/* Stop audio infoframe transmission. */
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_INDEX(0, nid, 0x00));
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_XMIT(0, nid, 0x00));
+
+			/* Clear audio infoframe buffer. */
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_INDEX(0, nid, 0x00));
+			for (k = 0; k < 32; k++)
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x00));
+
+			/* Write HDMI/DisplayPort audio infoframe. */
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_INDEX(0, nid, 0x00));
+			if (w->eld != NULL && w->eld_len >= 6 &&
+			    ((w->eld[5] >> 2) & 0x3) == 1) { /* DisplayPort */
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x84));
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x1b));
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x44));
+			} else {	/* HDMI */
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x84));
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x01));
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x0a));
+				csum = 0;
+				csum -= 0x84 + 0x01 + 0x0a + (totalchn - 1) +
+				    hdmica[totalextchn == 0 ? 0 : 1][totalchn - 1];
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, csum));
+			}
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, totalchn - 1));
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x00));
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_DATA(0, nid, 0x00));
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_DATA(0, nid,
+			    hdmica[totalextchn == 0 ? 0 : 1][totalchn - 1]));
+
+			/* Start audio infoframe transmission. */
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_INDEX(0, nid, 0x00));
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_HDMI_DIP_XMIT(0, nid, 0xc0));
+		}
+		chn += cchn + 1;
 	}
 }
 
@@ -2169,7 +2451,6 @@ hdaa_audio_as_parse(struct hdaa_devinfo 
 		as[i].hpredir = -1;
 		as[i].digital = 0;
 		as[i].num_chans = 1;
-		as[i].unsol = -1;
 		as[i].location = -1;
 	}
 
@@ -4277,21 +4558,51 @@ hdaa_pcmchannel_setup(struct hdaa_chan *
 				if (ch->bit32)
 					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 2, 0);
 			}
-			if (channels == 4 || /* Any 4-channel */
-			    pinset == 0x0007 || /* 5.1 */
-			    pinset == 0x0013 || /* 5.1 */
-			    pinset == 0x0017) {  /* 7.1 */
+			if (channels >= 3 && !onlystereo) {
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 3, 0);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 3, 0);
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 3, 1);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 3, 1);
+			}
+			if (channels >= 4) {
 				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 4, 0);
 				if (ch->bit32)
 					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 4, 0);
+				if (!onlystereo) {
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 4, 1);
+					if (ch->bit32)
+						ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 4, 1);
+				}
 			}
-			if (channels == 6 || /* Any 6-channel */
-			    pinset == 0x0017) {  /* 7.1 */
+			if (channels >= 5 && !onlystereo) {
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 5, 0);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 5, 0);
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 5, 1);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 5, 1);
+			}
+			if (channels >= 6) {
 				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 6, 1);
 				if (ch->bit32)
 					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 6, 1);
+				if (!onlystereo) {
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 6, 0);
+					if (ch->bit32)
+						ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 6, 0);
+				}
+			}
+			if (channels >= 7 && !onlystereo) {
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 7, 0);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 7, 0);
+				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 7, 1);
+				if (ch->bit32)
+					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 7, 1);
 			}
-			if (channels == 8) { /* Any 8-channel */
+			if (channels >= 8) {
 				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 8, 1);
 				if (ch->bit32)
 					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 8, 1);
@@ -4584,8 +4895,18 @@ hdaa_dump_pin(struct hdaa_widget *w)
 		printf(" IN");
 	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
 		printf(" OUT");
-	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK)
-		printf(" VREFs");
+	if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
+		if ((w->wclass.pin.ctrl &
+		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) == 0x03)
+			printf(" HBR");
+		else if ((w->wclass.pin.ctrl &
+		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) != 0)
+			printf(" EPTs");
+	} else {
+		if ((w->wclass.pin.ctrl &
+		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) != 0)
+			printf(" VREFs");
+	}
 	printf("\n");
 }
 
@@ -4956,9 +5277,12 @@ hdaa_pindump(device_t dev)
 				res = hda_command(dev, HDA_CMD_GET_PIN_SENSE(0,
 				    w->nid));
 			}
-			printf(" Sense: 0x%08x (%sconnected)", res,
+			printf(" Sense: 0x%08x (%sconnected%s)", res,
 			    (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) ?
-			     "" : "dis");
+			     "" : "dis",
+			    (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) &&
+			     (res & HDA_CMD_GET_PIN_SENSE_ELD_VALID)) ?
+			      ", ELD valid" : "");
 			if (delay > 0)
 				printf(" delay %dus", delay * 10);
 		}
@@ -5064,6 +5388,10 @@ hdaa_configure(device_t dev)
 	);
 	hdaa_patch_direct(devinfo);
 	HDA_BOOTHVERBOSE(
+		device_printf(dev, "ELD init...\n");
+	);
+	hdaa_eld_init(devinfo);
+	HDA_BOOTHVERBOSE(
 		device_printf(dev, "HP switch init...\n");
 	);
 	hdaa_hp_switch_init(devinfo);
@@ -5134,6 +5462,10 @@ hdaa_unconfigure(device_t dev)
 		device_printf(dev, "HP switch deinit...\n");
 	);
 	hdaa_hp_switch_deinit(devinfo);
+	HDA_BOOTHVERBOSE(
+		device_printf(dev, "ELD deinit...\n");
+	);
+	hdaa_eld_deinit(devinfo);
 	free(devinfo->ctl, M_HDAA);
 	devinfo->ctl = NULL;
 	devinfo->ctlcnt = 0;
@@ -5160,6 +5492,11 @@ hdaa_unconfigure(device_t dev)
 		for (j = 0; j < w->nconns; j++)
 			w->connsenable[j] = 1;
 		w->wclass.pin.config = w->wclass.pin.newconf;
+		if (w->eld != NULL) {
+			w->eld_len = 0;
+			free(w->eld, M_HDAA);
+			w->eld = NULL;
+		}
 	}
 }
 
@@ -5656,12 +5993,29 @@ static void
 hdaa_unsol_intr(device_t dev, uint32_t resp)
 {
 	struct hdaa_devinfo *devinfo = device_get_softc(dev);
-	int i, tag;
+	struct hdaa_widget *w;
+	int i, tag, flags;
 
+	HDA_BOOTHVERBOSE(
+		device_printf(dev, "Unsolicited response %08x\n", resp);
+	);
 	tag = resp >> 26;
-	for (i = 0; i < devinfo->ascnt; i++) {
-		if (devinfo->as[i].unsol == tag)
-			hdaa_hp_switch_handler(devinfo, i);
+	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+		w = hdaa_widget_get(devinfo, i);
+		if (w == NULL || w->enable == 0 || w->type !=
+		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+			continue;
+		if (w->unsol != tag)
+			continue;
+		if (HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) ||
+		    HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+			flags = resp & 0x03;
+		else
+			flags = 0x01;
+		if (flags & 0x01)
+			hdaa_hp_switch_handler(w);
+		if (flags & 0x02)
+			hdaa_eld_handler(w);
 	}
 }
 

Modified: head/sys/dev/sound/pci/hda/hdaa.h
==============================================================================
--- head/sys/dev/sound/pci/hda/hdaa.h	Wed Jan 18 18:26:56 2012	(r230311)
+++ head/sys/dev/sound/pci/hda/hdaa.h	Wed Jan 18 19:12:33 2012	(r230312)
@@ -93,9 +93,12 @@ struct hdaa_widget {
 	int bindseqmask;
 	int ossdev;
 	uint32_t ossmask;
+	int unsol;
 	nid_t conns[HDA_MAX_CONNS];
 	u_char connsenable[HDA_MAX_CONNS];
 	char name[HDA_MAX_NAMELEN];
+	uint8_t	*eld;
+	int	eld_len;
 	struct hdaa_devinfo *devinfo;
 	struct {
 		uint32_t widget_cap;
@@ -140,7 +143,6 @@ struct hdaa_audio_as {
 	nid_t dacs[2][16];
 	int num_chans;
 	int chans[2];
-	int unsol;
 	int location;	/* Pins location, if all have the same */
 	int mixed;	/* Mixed/multiplexed recording, not multichannel. */
 };
@@ -197,7 +199,7 @@ struct hdaa_chan {
 	struct pcmchan_caps caps;
 	struct hdaa_devinfo *devinfo;
 	struct hdaa_pcm_devinfo *pdevinfo;
-	uint32_t spd, fmt, fmtlist[16], pcmrates[16];
+	uint32_t spd, fmt, fmtlist[32], pcmrates[16];
 	uint32_t supp_stream_formats, supp_pcm_size_rate;
 	uint32_t ptr, prevptr, blkcnt, blksz;
 	uint32_t *dmapos;

Modified: head/sys/dev/sound/pci/hda/hdac.c
==============================================================================
--- head/sys/dev/sound/pci/hda/hdac.c	Wed Jan 18 18:26:56 2012	(r230311)
+++ head/sys/dev/sound/pci/hda/hdac.c	Wed Jan 18 19:12:33 2012	(r230312)
@@ -124,6 +124,17 @@ static const struct {
 	{ HDA_NVIDIA_MCP89_2, "NVIDIA MCP89",	0, 0 },
 	{ HDA_NVIDIA_MCP89_3, "NVIDIA MCP89",	0, 0 },
 	{ HDA_NVIDIA_MCP89_4, "NVIDIA MCP89",	0, 0 },
+	{ HDA_NVIDIA_0BE2,   "NVIDIA 0x0be2",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_0BE3,   "NVIDIA 0x0be3",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_0BE4,   "NVIDIA 0x0be4",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GT100,  "NVIDIA GT100",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GT104,  "NVIDIA GT104",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GT106,  "NVIDIA GT106",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GT108,  "NVIDIA GT108",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GT116,  "NVIDIA GT116",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GF119,  "NVIDIA GF119",	0, 0 },
+	{ HDA_NVIDIA_GF110_1, "NVIDIA GF110",	0, HDAC_QUIRK_MSI },
+	{ HDA_NVIDIA_GF110_2, "NVIDIA GF110",	0, HDAC_QUIRK_MSI },
 	{ HDA_ATI_SB450,     "ATI SB450",	0, 0 },
 	{ HDA_ATI_SB600,     "ATI SB600",	0, 0 },
 	{ HDA_ATI_RS600,     "ATI RS600",	0, 0 },

Modified: head/sys/dev/sound/pci/hda/hdac.h
==============================================================================
--- head/sys/dev/sound/pci/hda/hdac.h	Wed Jan 18 18:26:56 2012	(r230311)
+++ head/sys/dev/sound/pci/hda/hdac.h	Wed Jan 18 19:12:33 2012	(r230312)
@@ -76,10 +76,21 @@
 #define HDA_NVIDIA_MCP79_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac1)
 #define HDA_NVIDIA_MCP79_3	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac2)
 #define HDA_NVIDIA_MCP79_4	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac3)
+#define HDA_NVIDIA_0BE2		HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be2)
+#define HDA_NVIDIA_0BE3		HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be3)
+#define HDA_NVIDIA_0BE4		HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be4)
+#define HDA_NVIDIA_GT100	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be5)
+#define HDA_NVIDIA_GT106	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be9)
+#define HDA_NVIDIA_GT108	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0bea)
+#define HDA_NVIDIA_GT104	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0beb)
+#define HDA_NVIDIA_GT116	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0bee)
 #define HDA_NVIDIA_MCP89_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d94)
 #define HDA_NVIDIA_MCP89_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d95)
 #define HDA_NVIDIA_MCP89_3	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d96)
 #define HDA_NVIDIA_MCP89_4	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d97)
+#define HDA_NVIDIA_GF119	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e08)
+#define HDA_NVIDIA_GF110_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e09)
+#define HDA_NVIDIA_GF110_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e0c)
 #define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
 
 /* ATI */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201181912.q0IJCXk4053306>