Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 Jun 2012 13:10:18 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r236753 - in stable/8: share/man/man4 sys/dev/sound/pci/hda sys/dev/sound/pcm
Message-ID:  <201206081310.q58DAIfk060994@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Fri Jun  8 13:10:18 2012
New Revision: 236753
URL: http://svn.freebsd.org/changeset/base/236753

Log:
  MFC r230181, r230312, r230326, r230331, r230451, r230465, r230488,
  r230507, r230511, r230513, r230532, r230537, r230551, r230554, r230571,
  r230574, r230585, r230641, r230768, r230807, r231024:
  Sync snd_hda(4) driver with HEAD.
  
  This includes major code refactoring, HDMI support, new volume control,
  automatic recording source selection, runtime reconfigureation, support
  for more then 4 PCM devices on controller, multichannel recording,
  additional playback/record streams, higher bandwidths support, more
  informative device names and many other things.
  
  Sponsored by:	iXsystems, Inc.

Modified:
  stable/8/share/man/man4/snd_hda.4
  stable/8/sys/dev/sound/pci/hda/hda_reg.h
  stable/8/sys/dev/sound/pci/hda/hdaa.c
  stable/8/sys/dev/sound/pci/hda/hdaa.h
  stable/8/sys/dev/sound/pci/hda/hdaa_patches.c
  stable/8/sys/dev/sound/pci/hda/hdac.c
  stable/8/sys/dev/sound/pci/hda/hdac.h
  stable/8/sys/dev/sound/pci/hda/hdac_if.m
  stable/8/sys/dev/sound/pci/hda/hdac_private.h
  stable/8/sys/dev/sound/pci/hda/hdacc.c
  stable/8/sys/dev/sound/pcm/channel.c
Directory Properties:
  stable/8/share/man/man4/   (props changed)
  stable/8/sys/   (props changed)

Modified: stable/8/share/man/man4/snd_hda.4
==============================================================================
--- stable/8/share/man/man4/snd_hda.4	Fri Jun  8 12:56:10 2012	(r236752)
+++ stable/8/share/man/man4/snd_hda.4	Fri Jun  8 13:10:18 2012	(r236753)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 11, 2012
+.Dd January 25, 2012
 .Dt SND_HDA 4
 .Os
 .Sh NAME
@@ -182,6 +182,18 @@ May be specified as a 32-bit hexadecimal
 or as a set of space-separated
 .Dq Ar option Ns = Ns Ar value
 pairs.
+.It Va hint.pcm.%d.rec.autosrc
+Controls automatic recording source feature:
+.Bl -tag -compact
+.It 0
+disabled,
+.It 1
+once on attach,
+.It 2
+enabled.
+.El
+When enabled, driver will automatically set recording source of the mixer to
+connected input using jack presence detection statuses.
 .El
 .Pp
 Pin configuration is the UAA driver's main source of information about codec
@@ -357,6 +369,16 @@ Original pin configuration written by BI
 Setting this to a non-zero value makes driver to destroy existing pcm devices
 and process new pins configuration set via
 .Va dev.hdaa.%d.nid%d_config.
+.It Va dev.pcm.%d.play.32bit , dev.pcm.%d.rec.32bit
+HDA controller uses 32bit representation for all samples of more then 16 bits.
+These variables allow to specify how many bits of these 32 should be
+used by CODEC.
+Depending on codec capabilities, possible values are 20, 24 and 32 bit.
+The default value is 24.
+.It Va dev.pcm.%d.rec.autosrc
+Run-time equivalent of the
+.Va hint.pcm.%d.rec.autosrc
+tunable.
 .El
 .Sh EXAMPLES
 Taking HP Compaq DX2300 with Realtek ALC888 HDA codec for example.

Modified: stable/8/sys/dev/sound/pci/hda/hda_reg.h
==============================================================================
--- stable/8/sys/dev/sound/pci/hda/hda_reg.h	Fri Jun  8 12:56:10 2012	(r236752)
+++ stable/8/sys/dev/sound/pci/hda/hda_reg.h	Fri Jun  8 13:10:18 2012	(r236753)
@@ -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: stable/8/sys/dev/sound/pci/hda/hdaa.c
==============================================================================
--- stable/8/sys/dev/sound/pci/hda/hdaa.c	Fri Jun  8 12:56:10 2012	(r236752)
+++ stable/8/sys/dev/sound/pci/hda/hdaa.c	Fri Jun  8 13:10:18 2012	(r236753)
@@ -74,17 +74,6 @@ static const struct {
 #define HDAA_QUIRKS_TAB_LEN	\
 		(sizeof(hdaa_quirks_tab) / sizeof(hdaa_quirks_tab[0]))
 
-#define HDA_BDL_MIN	2
-#define HDA_BDL_MAX	256
-#define HDA_BDL_DEFAULT	HDA_BDL_MIN
-
-#define HDA_BLK_MIN	HDA_DMA_ALIGNMENT
-#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
-
-#define HDA_BUFSZ_MIN		4096
-#define HDA_BUFSZ_MAX		65536
-#define HDA_BUFSZ_DEFAULT	16384
-
 #define HDA_PARSE_MAXDEPTH	10
 
 MALLOC_DEFINE(M_HDAA, "hdaa", "HDA Audio");
@@ -116,6 +105,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),
@@ -169,6 +164,8 @@ static const struct {
 };
 #define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
 
+const static char *ossnames[] = SOUND_DEVICE_NAMES;
+
 /****************************************************************************
  * Function prototypes
  ****************************************************************************/
@@ -187,7 +184,6 @@ static void	hdaa_dump_pin_config(struct 
 static char *
 hdaa_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
 {
-	static char *ossname[] = SOUND_DEVICE_NAMES;
 	int i, first = 1;
 
 	bzero(buf, len);
@@ -195,7 +191,7 @@ hdaa_audio_ctl_ossmixer_mask2allname(uin
 		if (mask & (1 << i)) {
 			if (first == 0)
 				strlcat(buf, ", ", len);
-			strlcat(buf, ossname[i], len);
+			strlcat(buf, ossnames[i], len);
 			first = 0;
 		}
 	}
@@ -243,49 +239,30 @@ hdaa_audio_ctl_amp_get(struct hdaa_devin
 }
 
 /*
- * Jack detection (Speaker/HP redirection) event handler.
+ * Headphones redirection change handler.
  */
 static void
-hdaa_hp_switch_handler(struct hdaa_devinfo *devinfo, int asid)
+hdaa_hpredir_handler(struct hdaa_widget *w)
 {
-	struct hdaa_audio_as *as;
-	struct hdaa_widget *w;
+	struct hdaa_devinfo *devinfo = w->devinfo;
+	struct hdaa_audio_as *as = &devinfo->as[w->bindas];
+	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 !=
-	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
-		return;
-
-	res = hda_command(devinfo->dev,
-	    HDA_CMD_GET_PIN_SENSE(0, as->pins[15]));
-
-	HDA_BOOTVERBOSE(
-		device_printf(devinfo->dev,
-		    "Pin sense: nid=%d sence=0x%08x",
-		    as->pins[15], res);
-	);
-
-	res = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
-	if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
-		res ^= 1;
+	uint32_t val;
+	int j, connected = w->wclass.pin.connected;
 
 	HDA_BOOTVERBOSE(
-		printf(" %sconnected\n", res == 0 ? "dis" : "");
+		device_printf((as->pdevinfo && as->pdevinfo->dev) ?
+		    as->pdevinfo->dev : devinfo->dev,
+		    "Redirect output to: %s\n",
+		    connected ? "headphones": "main");
 	);
-
 	/* (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;
+		val = connected ? 0 : 1;
 		if (val != ctl->forcemute) {
 			ctl->forcemute = val;
 			hdaa_audio_ctl_amp_set(ctl,
@@ -294,21 +271,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 (connected)
+			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. */
@@ -319,7 +292,7 @@ hdaa_hp_switch_handler(struct hdaa_devin
 		    as->pins[j], HDAA_CTL_IN, -1, 1);
 		if (ctl != NULL && ctl->mute) {
 			/* If pin has muter - use it. */
-			val = (res != 0) ? 1 : 0;
+			val = connected ? 1 : 0;
 			if (val == ctl->forcemute)
 				continue;
 			ctl->forcemute = val;
@@ -329,32 +302,142 @@ 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 ==
-		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
-			if (res != 0)
-				val = w->wclass.pin.ctrl &
+		w1 = hdaa_widget_get(devinfo, as->pins[j]);
+		if (w1 != NULL) {
+			if (connected)
+				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));
 			}
 		}
 	}
 }
 
 /*
- * Callback for poll based jack detection.
+ * Recording source change handler.
+ */
+static void
+hdaa_autorecsrc_handler(struct hdaa_audio_as *as, struct hdaa_widget *w)
+{
+	struct hdaa_pcm_devinfo *pdevinfo = as->pdevinfo;
+	struct hdaa_devinfo *devinfo;
+	struct hdaa_widget *w1;
+	int i, mask, fullmask, prio, bestprio;
+	char buf[128];
+
+	if (!as->mixed || pdevinfo == NULL || pdevinfo->mixer == NULL)
+		return;
+	/* Don't touch anything if we asked not to. */
+	if (pdevinfo->autorecsrc == 0 ||
+	    (pdevinfo->autorecsrc == 1 && w != NULL))
+		return;
+	/* Don't touch anything if "mix" or "speaker" selected. */
+	if (pdevinfo->recsrc & (SOUND_MASK_IMIX | SOUND_MASK_SPEAKER))
+		return;
+	/* Don't touch anything if several selected. */
+	if (ffs(pdevinfo->recsrc) != fls(pdevinfo->recsrc))
+		return;
+	devinfo = pdevinfo->devinfo;
+	mask = fullmask = 0;
+	bestprio = 0;
+	for (i = 0; i < 16; i++) {
+		if (as->pins[i] <= 0)
+			continue;
+		w1 = hdaa_widget_get(devinfo, as->pins[i]);
+		if (w1 == NULL || w1->enable == 0)
+			continue;
+		if (w1->wclass.pin.connected == 0)
+			continue;
+		prio = (w1->wclass.pin.connected == 1) ? 2 : 1;
+		if (prio < bestprio)
+			continue;
+		if (prio > bestprio) {
+			mask = 0;
+			bestprio = prio;
+		}
+		mask |= (1 << w1->ossdev);
+		fullmask |= (1 << w1->ossdev);
+	}
+	if (mask == 0)
+		return;
+	/* Prefer newly connected input. */
+	if (w != NULL && (mask & (1 << w->ossdev)))
+		mask = (1 << w->ossdev);
+	/* Prefer previously selected input */
+	if (mask & pdevinfo->recsrc)
+		mask &= pdevinfo->recsrc;
+	/* Prefer mic. */
+	if (mask & SOUND_MASK_MIC)
+		mask = SOUND_MASK_MIC;
+	/* Prefer monitor (2nd mic). */
+	if (mask & SOUND_MASK_MONITOR)
+		mask = SOUND_MASK_MONITOR;
+	/* Just take first one. */
+	mask = (1 << (ffs(mask) - 1));
+	HDA_BOOTVERBOSE(
+		hdaa_audio_ctl_ossmixer_mask2allname(mask, buf, sizeof(buf));
+		device_printf(pdevinfo->dev,
+		    "Automatically set rec source to: %s\n", buf);
+	);
+	hdaa_unlock(devinfo);
+	mix_setrecsrc(pdevinfo->mixer, mask);
+	hdaa_lock(devinfo);
+}
+
+/*
+ * Jack presence detection event handler.
+ */
+static void
+hdaa_presence_handler(struct hdaa_widget *w)
+{
+	struct hdaa_devinfo *devinfo = w->devinfo;
+	struct hdaa_audio_as *as;
+	uint32_t res;
+	int connected;
+
+	if (w->enable == 0 || w->type !=
+	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+		return;
+
+	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+	    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+		return;
+
+	res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
+	connected = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
+	if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
+		connected = !connected;
+	if (connected == w->wclass.pin.connected)
+		return;
+	w->wclass.pin.connected = connected;
+	HDA_BOOTVERBOSE(
+		device_printf(devinfo->dev,
+		    "Pin sense: nid=%d sence=0x%08x (%sconnected)\n",
+		    w->nid, res, !w->wclass.pin.connected ? "dis" : "");
+	);
+
+	as = &devinfo->as[w->bindas];
+	if (as->hpredir >= 0 && as->pins[15] == w->nid)
+		hdaa_hpredir_handler(w);
+	if (as->dir == HDAA_CTL_IN)
+		hdaa_autorecsrc_handler(as, w);
+}
+
+/*
+ * Callback for poll based presence detection.
  */
 static void
 hdaa_jack_poll_callback(void *arg)
 {
 	struct hdaa_devinfo *devinfo = arg;
+	struct hdaa_widget *w;
 	int i;
 
 	hdaa_lock(devinfo);
@@ -365,56 +448,203 @@ 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_presence_handler(w);
 	}
 	callout_reset(&devinfo->poll_jack, devinfo->poll_ival,
 	    hdaa_jack_poll_callback, devinfo);
 	hdaa_unlock(devinfo);
 }
 
+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 (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+	    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+		return;
+
+	res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
+	if ((w->eld != 0) == ((res & HDA_CMD_GET_PIN_SENSE_ELD_VALID) != 0))
+		return;
+	if (w->eld != NULL) {
+		w->eld_len = 0;
+		free(w->eld, M_HDAA);
+		w->eld = NULL;
+	}
+	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);
+	);
+}
+
 /*
- * Jack detection initializer.
+ * Pin sense initializer.
  */
 static void
-hdaa_hp_switch_init(struct hdaa_devinfo *devinfo)
+hdaa_sense_init(struct hdaa_devinfo *devinfo)
 {
-	struct hdaa_audio_as *as = devinfo->as;
-        struct hdaa_widget *w;
-        int i, poll = 0;
-
-	for (i = 0; i < devinfo->ascnt; i++) {
-		if (as[i].hpredir < 0)
-			continue;
+	struct hdaa_audio_as *as;
+	struct hdaa_widget *w;
+	int i, poll = 0;
 
-		w = hdaa_widget_get(devinfo, as[i].pins[15]);
+	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 (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
-		    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
-			device_printf(devinfo->dev,
-			    "No jack detection support at pin %d\n",
-			    as[i].pins[15]);
-			continue;
-		}
-		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
-			as[i].unsol = HDAC_UNSOL_ALLOC(
-			    device_get_parent(devinfo->dev), devinfo->dev,
-			    w->nid);
+		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
-			poll = 1;
-		HDA_BOOTVERBOSE(
-			device_printf(devinfo->dev,
-			    "Headphones redirection "
-			    "for as=%d nid=%d using %s.\n",
-			    i, w->nid,
-			    (poll != 0) ? "polling" : "unsolicited responses");
-		);
-		hdaa_hp_switch_handler(devinfo, i);
+			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE | w->unsol));
+		}
+		as = &devinfo->as[w->bindas];
+		if (as->hpredir >= 0 && as->pins[15] == w->nid) {
+			if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+			    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
+				device_printf(devinfo->dev,
+				    "No presence detection support at nid %d\n",
+				    as[i].pins[15]);
+			} else {
+				if (w->unsol < 0)
+					poll = 1;
+				HDA_BOOTVERBOSE(
+					device_printf(devinfo->dev,
+					    "Headphones redirection for "
+					    "association %d nid=%d using %s.\n",
+					    w->bindas, w->nid,
+					    (poll != 0) ? "polling" :
+					    "unsolicited responses");
+				);
+			};
+		}
+		hdaa_presence_handler(w);
+		if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
+		    !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+			continue;
+		hdaa_eld_handler(w);
 	}
 	if (poll) {
 		callout_reset(&devinfo->poll_jack, 1,
@@ -423,25 +653,25 @@ hdaa_hp_switch_init(struct hdaa_devinfo 
 }
 
 static void
-hdaa_hp_switch_deinit(struct hdaa_devinfo *devinfo)
+hdaa_sense_deinit(struct hdaa_devinfo *devinfo)
 {
-	struct hdaa_audio_as *as = devinfo->as;
-        struct hdaa_widget *w;
-        int i;
+	struct hdaa_widget *w;
+	int i;
 
-	for (i = 0; i < devinfo->ascnt; i++) {
-		if (as[i].unsol < 0)
-			continue;
-		w = hdaa_widget_get(devinfo, as[i].pins[15]);
+	callout_stop(&devinfo->poll_jack);
+	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 < 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;
 	}
 }
 
@@ -902,6 +1132,11 @@ hdaa_widget_parse(struct hdaa_widget *w)
 			w->param.supp_pcm_size_rate =
 			    w->devinfo->supp_pcm_size_rate;
 		}
+		if (HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(w->param.widget_cap)) {
+			w->wclass.conv.stripecap = hda_command(dev,
+			    HDA_CMD_GET_STRIPE_CONTROL(0, w->nid)) >> 20;
+		} else
+			w->wclass.conv.stripecap = 1;
 	} else {
 		w->param.supp_stream_formats = 0;
 		w->param.supp_pcm_size_rate = 0;
@@ -938,6 +1173,7 @@ hdaa_widget_parse(struct hdaa_widget *w)
 		    hdaa_sysctl_config, "A", "Original pin configuration");
 		hdaa_lock(w->devinfo);
 	}
+	w->unsol = -1;
 }
 
 static void
@@ -1001,6 +1237,10 @@ hdaa_widget_postprocess(struct hdaa_widg
 		}
 		strlcat(w->name, HDA_CONNS[conn], sizeof(w->name));
 		strlcat(w->name, ")", sizeof(w->name));
+
+		if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+		    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+			w->wclass.pin.connected = 2;
 	}
 }
 
@@ -1193,31 +1433,58 @@ hdaa_stream_format(struct hdaa_chan *ch)
 	return (fmt);
 }
 
+static int
+hdaa_allowed_stripes(uint16_t fmt)
+{
+	static const int bits[8] = { 8, 16, 20, 24, 32, 32, 32, 32 };
+	int size;
+
+	size = bits[(fmt >> 4) & 0x03];
+	size *= (fmt & 0x0f) + 1;
+	size *= ((fmt >> 11) & 0x07) + 1;
+	return (0xffffffffU >> (32 - fls(size / 8)));
+}
+
 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 +1501,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 +1519,112 @@ 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;
+		if (HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(w->param.widget_cap)) {
+			hda_command(ch->devinfo->dev,
+			    HDA_CMD_SET_STRIPE_CONTROL(0, w->nid, ch->stripectl));
+		}
+		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, stripe=%d\n",
+			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
+			    ch->io[i], fmt, dfmt, c, cchn, ch->stripectl);
+		);
+		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));
+			}
+
+			/*
+			 * Enable High Bit Rate (HBR) Encoded Packet Type
+			 * (EPT), if supported and needed (8ch data).
+			 */
+			if (HDA_PARAM_PIN_CAP_HDMI(wp->wclass.pin.cap) &&
+			    HDA_PARAM_PIN_CAP_HBR(wp->wclass.pin.cap)) {
+				wp->wclass.pin.ctrl &=
+				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK;
+				if ((ch->fmt & AFMT_AC3) && (cchn == 7))
+					wp->wclass.pin.ctrl |= 0x03;
+				hda_command(ch->devinfo->dev,
+				    HDA_CMD_SET_PIN_WIDGET_CTRL(0, nid,
+				    wp->wclass.pin.ctrl));
+			}
+
+			/* 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;
 	}
 }
 
@@ -1351,6 +1709,8 @@ hdaa_channel_stop(struct hdaa_chan *ch)
 	struct hdaa_widget *w;
 	int i;
 
+	if ((ch->flags & HDAA_CHN_RUNNING) == 0)
+		return;
 	ch->flags &= ~HDAA_CHN_RUNNING;
 	HDAC_STREAM_STOP(device_get_parent(devinfo->dev), devinfo->dev,
 	    ch->dir == PCMDIR_PLAY ? 1 : 0, ch->sid);
@@ -1374,11 +1734,12 @@ static int
 hdaa_channel_start(struct hdaa_chan *ch)
 {
 	struct hdaa_devinfo *devinfo = ch->devinfo;
+	uint32_t fmt;
 
-	ch->ptr = 0;
-	ch->prevptr = 0;
+	fmt = hdaa_stream_format(ch);
+	ch->stripectl = fls(ch->stripecap & hdaa_allowed_stripes(fmt)) - 1;
 	ch->sid = HDAC_STREAM_ALLOC(device_get_parent(devinfo->dev), devinfo->dev,
-	    ch->dir == PCMDIR_PLAY ? 1 : 0, hdaa_stream_format(ch), &ch->dmapos);
+	    ch->dir == PCMDIR_PLAY ? 1 : 0, fmt, ch->stripectl, &ch->dmapos);
 	if (ch->sid <= 0)
 		return (EBUSY);
 	hdaa_audio_setup(ch);
@@ -1468,11 +1829,11 @@ hdaa_audio_ctl_ossmixer_init(struct snd_
 	struct hdaa_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
 	struct hdaa_devinfo *devinfo = pdevinfo->devinfo;
 	struct hdaa_widget *w, *cw;
-	struct hdaa_audio_ctl *ctl;
 	uint32_t mask, recmask;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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