Index: uspace/drv/audio/hdaudio/Makefile
===================================================================
--- uspace/drv/audio/hdaudio/Makefile	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/Makefile	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -36,5 +36,6 @@
 	regif.c \
 	hdactl.c \
-	hdaudio.c
+	hdaudio.c \
+	stream.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/audio/hdaudio/codec.c
===================================================================
--- uspace/drv/audio/hdaudio/codec.c	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/codec.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -42,12 +42,20 @@
 #include "hdactl.h"
 #include "spec/codec.h"
+#include "spec/fmt.h"
+#include "stream.h"
+
+static int hda_ccmd(hda_codec_t *codec, int node, uint32_t vid, uint32_t payload,
+    uint32_t *resp)
+{
+	uint32_t verb;
+
+	verb = (codec->address << 28) | (node << 20) | (vid << 8) | payload;
+	return hda_cmd(codec->hda, verb, resp);
+}
 
 static int hda_get_parameter(hda_codec_t *codec, int node, hda_param_id_t param,
     uint32_t *resp)
 {
-	uint32_t verb;
-
-	verb = (codec->address << 28) | (node << 20) | ((hda_param_get) << 8) | param;
-	return hda_cmd(codec->hda, verb, resp);
+	return hda_ccmd(codec, node, hda_param_get, param, resp);
 }
 
@@ -87,4 +95,30 @@
 }
 
+/** Get Suppported PCM Size, Rates */
+static int hda_get_supp_rates(hda_codec_t *codec, int node, uint32_t *rates)
+{
+	return hda_get_parameter(codec, node, hda_supp_rates, rates);
+}
+
+/** Get Suppported Stream Formats */
+static int hda_get_supp_formats(hda_codec_t *codec, int node, uint32_t *fmts)
+{
+	return hda_get_parameter(codec, node, hda_supp_formats, fmts);
+}
+
+static int hda_set_converter_fmt(hda_codec_t *codec, int node, uint16_t fmt)
+{
+	return hda_ccmd(codec, node, hda_converter_fmt_set, fmt, NULL);
+}
+
+static int hda_set_converter_ctl(hda_codec_t *codec, int node, uint8_t stream,
+    uint8_t channel)
+{
+	uint32_t ctl;
+
+	ctl = (stream << cctl_stream_l) | (channel << cctl_channel_l);
+	return hda_ccmd(codec, node, hda_converter_ctl_set, ctl, NULL);
+}
+
 /** Get Audio Widget Capabilities */
 static int hda_get_aw_caps(hda_codec_t *codec, int node,
@@ -107,8 +141,17 @@
 static int hda_get_cfg_def(hda_codec_t *codec, int node, uint32_t *cfgdef)
 {
-	uint32_t verb;
-
-	verb = (codec->address << 28) | (node << 20) | ((hda_cfg_def_get) << 8) | 0;
-	return hda_cmd(codec->hda, verb, cfgdef);
+	return hda_ccmd(codec, node, hda_cfg_def_get, 0, cfgdef);
+}
+
+/** Get Amplifier Gain / Mute  */
+static int hda_get_amp_gain_mute(hda_codec_t *codec, int node, uint16_t payload,
+    uint32_t *resp)
+{
+	return hda_ccmd(codec, node, hda_amp_gain_mute_get, payload, resp);
+}
+
+static int hda_set_amp_gain_mute(hda_codec_t *codec, int node, uint16_t payload)
+{
+	return hda_ccmd(codec, node, hda_amp_gain_mute_set, payload, NULL);
 }
 
@@ -125,4 +168,6 @@
 	uint32_t awcaps;
 	uint32_t cfgdef;
+	uint32_t rates;
+	uint32_t formats;
 
 	codec = calloc(1, sizeof(hda_codec_t));
@@ -171,8 +216,75 @@
 				    aw, cfgdef);
 
+			} else if (awtype == awt_audio_output) {
+				codec->out_aw = aw;
+			}
+
+			if ((awcaps & BIT_V(uint32_t, awc_out_amp_present)) != 0) {
+				uint32_t ampcaps;
+				uint32_t gmleft, gmright;
+
+				rc = hda_get_parameter(codec, aw,
+				    hda_out_amp_caps, &ampcaps);
+				if (rc != EOK)
+					goto error;
+
+				rc = hda_get_amp_gain_mute(codec, aw, 0x8000, &gmleft);
+				if (rc != EOK)
+					goto error;
+
+				rc = hda_get_amp_gain_mute(codec, aw, 0xc000, &gmright);
+				if (rc != EOK)
+					goto error;
+
+				ddf_msg(LVL_NOTE, "out amp caps 0x%x "
+				    "gain/mute: L:0x%x R:0x%x",
+				    ampcaps, gmleft, gmright);
+
+				rc = hda_set_amp_gain_mute(codec, aw, 0xb04a);
+				if (rc != EOK)
+					goto error;
 			}
 		}
 	}
 
+	rc = hda_get_supp_rates(codec, codec->out_aw, &rates);
+	if (rc != EOK)
+		goto error;
+
+	rc = hda_get_supp_formats(codec, codec->out_aw, &formats);
+	if (rc != EOK)
+		goto error;
+
+	ddf_msg(LVL_NOTE, "Output widget %d: rates=0x%x formats=0x%x",
+	    codec->out_aw, rates, formats);
+
+	/* XXX Choose appropriate parameters */
+	uint32_t fmt;
+	/* 48 kHz, 16-bits, 1 channel */
+	fmt = fmt_bits_16 << fmt_bits_l;
+
+	/* Create stream */
+	ddf_msg(LVL_NOTE, "Create stream");
+	hda_stream_t *stream;
+	stream = hda_stream_create(hda, sdir_output, fmt);
+	if (stream == NULL)
+		goto error;
+
+	/* Configure converter */
+
+	ddf_msg(LVL_NOTE, "Configure converter format");
+	rc = hda_set_converter_fmt(codec, codec->out_aw, fmt);
+	if (rc != EOK)
+		goto error;
+
+	ddf_msg(LVL_NOTE, "Configure converter stream, channel");
+	rc = hda_set_converter_ctl(codec, codec->out_aw, stream->sid, 0);
+	if (rc != EOK)
+		goto error;
+
+	ddf_msg(LVL_NOTE, "Start stream");
+	hda_stream_start(stream);
+
+	ddf_msg(LVL_NOTE, "Codec OK");
 	return codec;
 error:
Index: uspace/drv/audio/hdaudio/codec.h
===================================================================
--- uspace/drv/audio/hdaudio/codec.h	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/codec.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -41,4 +41,5 @@
 	hda_t *hda;
 	uint8_t address;
+	uint8_t out_aw;
 } hda_codec_t;
 
Index: uspace/drv/audio/hdaudio/hdactl.c
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.c	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/hdactl.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -102,5 +102,4 @@
 	uint8_t sizecap;
 	uint8_t selsz;
-	bool ok64bit;
 	int rc;
 
@@ -131,8 +130,4 @@
 	hda->ctl->corb_entries = hda_rb_entries(selsz);
 
-	ddf_msg(LVL_NOTE, "Read GCAP");
-	uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
-	ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0;
-	ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit);
 
 	/*
@@ -142,5 +137,5 @@
 	hda->ctl->corb_virt = AS_AREA_ANY;
 	rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t),
-	    ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
 	    &hda->ctl->corb_phys, &hda->ctl->corb_virt);
 
@@ -178,5 +173,4 @@
 	uint8_t sizecap;
 	uint8_t selsz;
-	bool ok64bit;
 	int rc;
 
@@ -207,9 +201,4 @@
 	hda->ctl->rirb_entries = hda_rb_entries(selsz);
 
-	ddf_msg(LVL_NOTE, "Read GCAP");
-	uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
-	ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0;
-	ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit);
-
 	/*
 	 * RIRB must be aligned to 128 bytes. If 64OK is not set,
@@ -218,5 +207,5 @@
 	hda->ctl->rirb_virt = AS_AREA_ANY;
 	rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t),
-	    ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
 	    &hda->ctl->rirb_phys, &hda->ctl->rirb_virt);
 
@@ -434,4 +423,12 @@
 	ddf_msg(LVL_NOTE, "Controller is out of reset.");
 
+	ddf_msg(LVL_NOTE, "Read GCAP");
+	uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
+	ctl->ok64bit = (gcap & BIT_V(uint16_t, gcap_64ok)) != 0;
+	ctl->oss = BIT_RANGE_EXTRACT(uint16_t, gcap_oss_h, gcap_oss_l, gcap);
+	ctl->iss = BIT_RANGE_EXTRACT(uint16_t, gcap_iss_h, gcap_iss_l, gcap);
+	ctl->bss = BIT_RANGE_EXTRACT(uint16_t, gcap_bss_h, gcap_bss_l, gcap);
+	ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ctl->ok64bit);
+
 	/* Give codecs enough time to enumerate themselves */
 	async_usleep(codec_enum_wait_us);
Index: uspace/drv/audio/hdaudio/hdactl.h
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.h	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/hdactl.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -36,7 +36,13 @@
 #define HDACTL_H
 
+#include <stdbool.h>
 #include "hdaudio.h"
 
 typedef struct hda_ctl {
+	bool ok64bit;
+	int iss;
+	int oss;
+	int bss;
+
 	uintptr_t corb_phys;
 	void *corb_virt;
Index: uspace/drv/audio/hdaudio/spec/bdl.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/bdl.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/spec/bdl.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup hdaudio
+ * @{
+ */
+/** @file High Definition Audio buffer descriptor list
+ */
+
+#ifndef SPEC_BDL_H
+#define SPEC_BDL_H
+
+/** Buffer descriptor */
+typedef struct {
+	uint64_t address;
+	uint32_t length;
+	uint32_t flags;
+} hda_buffer_desc_t;
+
+/** Buffer descriptor flags bits */
+typedef enum {
+	bdf_ioc = 0
+} hda_bd_flags_bits_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/audio/hdaudio/spec/codec.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/codec.h	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/spec/codec.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -336,4 +336,16 @@
 } hda_awidget_type_t;
 
+/** Converter Control bits */
+typedef enum {
+	/** Stream (H) */
+	cctl_stream_h = 7,
+	/** Stream (L) */
+	cctl_stream_l = 4,
+	/** Channel (H) */
+	cctl_channel_h = 3,
+	/** Channel (L) */
+	cctl_channel_l = 0
+} hda_converter_ctl_bits_t;
+
 #endif
 
Index: uspace/drv/audio/hdaudio/spec/fmt.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/fmt.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/spec/fmt.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup hdaudio
+ * @{
+ */
+/** @file High Definition Audio stream format
+ */
+
+#ifndef SPEC_FMT_H
+#define SPEC_FMT_H
+
+typedef enum {
+	/** Stream Type */
+	fmt_type = 15,
+	/** Sample Base Rate */
+	fmt_base = 14,
+	/** Sample Base Rate Multiple (H) */
+	fmt_mult_h = 13,
+	/** Sample Base Rate Multiple (L) */
+	fmt_mult_l = 11,
+	/** Sample Base Rate Divisor (H) */
+	fmt_div_h = 10,
+	/** Sample Base Rate Divisor (L) */
+	fmt_div_l = 8,
+	/** Bits per Sample (H) */
+	fmt_bits_h = 6,
+	/** Bits per Sample (L) */
+	fmt_bits_l = 4,
+	/** Number of Channels (H) */
+	fmt_chan_h = 3,
+	/** Number of Channels (L) */
+	fmt_chan_l = 0
+} hda_stream_fmt_bits_t;
+
+/** Stream Type */
+typedef enum {
+	/** PCM */
+	fmt_type_pcm = 0,
+	/** Non-PCM */
+	fmt_type_nonpcm = 1
+} hda_fmt_type_t;
+
+/** Sample Base Rate */
+typedef enum {
+	/** 48 kHz */
+	fmt_base_48khz = 0,
+	/** 44.1 kHz */
+	fmt_base_44khz = 1
+} hda_fmt_base_t;
+
+/** Sample Base Rate Multiple */
+typedef enum {
+	/** 48 kHz/44.1 kHz or less */
+	fmt_mult_x1 = 0,
+	/** x2 (96 kHz, 88.2 kHz, 32 kHz) */
+	fmt_mult_x2 = 1,
+	/** x3 (144 kHz) */
+	fmt_mult_x3 = 2,
+	/** x4 (192 kHz, 176.4 kHz) */
+	fmt_mult_x4 = 3
+} hda_fmt_mult_t;
+
+/** Sample Base Rate Divisor */
+typedef enum {
+	/** Divide by 1 (48 kHz, 44.1 kHz) */
+	fmt_div_1 = 0,
+	/** Divide by 2 (24 kHz, 22.05 kHz) */
+	fmt_div_2 = 1,
+	/** Divide by 3 (16 kHz, 32 kHz) */
+	fmt_div_3 = 2,
+	/** Divide by 4 (11.025 kHz) */
+	fmt_div_4 = 3,
+	/** Divide by 5 (9.6 kHz) */
+	fmt_div_5 = 4,
+	/** Divide by 6 (8 kHz) */
+	fmt_div_6 = 5,
+	/** Divide by 7 */
+	fmt_div_7 = 6,
+	/** Divide by 8 (6 kHz) */
+	fmt_div_8 = 7
+} hda_fmt_div_t;
+
+/** Bits per Sample */
+typedef enum {
+	/** 8 bits */
+	fmt_bits_8 = 0,
+	/** 16 bits */
+	fmt_bits_16 = 1,
+	/** 20 bits */
+	fmt_bits_20 = 2,
+	/** 24 bits */
+	fmt_bits_24 = 3,
+	/** 32 bits */
+	fmt_bits_32 = 4
+} hda_fmt_bits_t;
+
+/** Number of Channels */
+typedef enum {
+	fmt_chan_1 = 0,
+	fmt_chan_2 = 1,
+	fmt_chan_3 = 2,
+	fmt_chan_4 = 3,
+	fmt_chan_5 = 4,
+	fmt_chan_6 = 5,
+	fmt_chan_7 = 6,
+	fmt_chan_8 = 7,
+	fmt_chan_9 = 8,
+	fmt_chan_10 = 9,
+	fmt_chan_11 = 10,
+	fmt_chan_12 = 11,
+	fmt_chan_13 = 12,
+	fmt_chan_14 = 13,
+	fmt_chan_15 = 14,
+	fmt_chan_16 = 15
+} hda_fmt_chan_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/audio/hdaudio/spec/regs.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/regs.h	(revision 65b09c14be334017b5b9f87fee8d2e4f781ac19b)
+++ uspace/drv/audio/hdaudio/spec/regs.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -40,6 +40,10 @@
 /** Stream Descriptor registers */
 typedef struct {
-	/** Control */
-	uint16_t ctl;
+	/** Control 1 */
+	uint8_t ctl1;
+	/** Control 2 */
+	uint8_t ctl2;
+	/** Control 3 */
+	uint8_t ctl3;
 	/** Status */
 	uint8_t sts;
@@ -142,11 +146,11 @@
 	uint32_t icii;
 	/** Immediate Command Status */
-	uint32_t icis;
+	uint16_t icis;
 	/** Reserved */
 	uint8_t reserved8[6];
 	/** DMA Position Buffer Lower Base */
-	uint32_t dpiblbase;
+	uint32_t dplbase;
 	/** DMA Position Buffer Upper Base */
-	uint32_t dpibubase;
+	uint32_t dpubase;
 	/** Reserved */
 	uint8_t reserved9[8];
Index: uspace/drv/audio/hdaudio/stream.c
===================================================================
--- uspace/drv/audio/hdaudio/stream.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/stream.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2014 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup hdaudio
+ * @{
+ */
+/** @file High Definition Audio stream
+ */
+
+#include <as.h>
+#include <ddf/log.h>
+#include <ddi.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "hdactl.h"
+#include "hdaudio.h"
+#include "regif.h"
+#include "spec/bdl.h"
+#include "stream.h"
+
+static int hda_stream_buffers_alloc(hda_stream_t *stream)
+{
+	void *bdl;
+	void *buffer;
+	uintptr_t buffer_phys;
+	size_t i;
+	size_t j, k;
+	int rc;
+
+	stream->nbuffers = 2;
+	stream->bufsize = 16384;
+
+	/*
+	 * BDL must be aligned to 128 bytes. If 64OK is not set,
+	 * it must be within the 32-bit address space.
+	 */
+	bdl = AS_AREA_ANY;
+	rc = dmamem_map_anonymous(stream->nbuffers * sizeof(hda_buffer_desc_t),
+	    stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
+	    0, &stream->bdl_phys, &bdl);
+	if (rc != EOK)
+		goto error;
+
+	stream->bdl = bdl;
+
+	/* Allocate arrays of buffer pointers */
+
+	stream->buf = calloc(stream->nbuffers, sizeof(void *));
+	if (stream->buf == NULL)
+		goto error;
+
+	stream->buf_phys = calloc(stream->nbuffers, sizeof(uintptr_t));
+	if (stream->buf_phys == NULL)
+		goto error;
+
+	/* Allocate buffers */
+
+	for (i = 0; i < stream->nbuffers; i++) {
+		buffer = AS_AREA_ANY;
+		rc = dmamem_map_anonymous(stream->bufsize,
+		    stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
+		    0, &buffer_phys, &buffer);
+		if (rc != EOK)
+			goto error;
+
+		stream->buf[i] = buffer;
+		stream->buf_phys[i] = buffer_phys;
+
+		k = 0;
+		for (j = 0; j < stream->bufsize / 2; j++) {
+			int16_t *bp = stream->buf[i];
+			bp[j] = (k > 128) ? -10000 : 10000;
+			++k;
+			if (k >= 256)
+				k = 0;
+		}
+	}
+
+	/* Fill in BDL */
+	for (i = 0; i < stream->nbuffers; i++) {
+		stream->bdl[i].address = stream->buf_phys[i];
+		stream->bdl[i].length = stream->bufsize;
+		stream->bdl[i].flags = 0;
+	}
+
+	return EOK;
+error:
+	return ENOMEM;
+}
+
+static void hda_stream_desc_configure(hda_stream_t *stream)
+{
+	hda_sdesc_regs_t *sdregs;
+
+	sdregs = &stream->hda->regs->sdesc[stream->sdid];
+	hda_reg32_write(&sdregs->cbl, stream->nbuffers * stream->bufsize);
+	hda_reg16_write(&sdregs->lvi, stream->nbuffers - 1);
+	hda_reg16_write(&sdregs->fmt, stream->fmt);
+}
+
+static void hda_stream_set_run(hda_stream_t *stream, bool run)
+{
+	uint32_t ctl;
+	hda_sdesc_regs_t *sdregs;
+
+	sdregs = &stream->hda->regs->sdesc[stream->sdid];
+
+	ctl = hda_reg8_read(&sdregs->ctl1);
+	ctl = ctl | 2 /* XXX Run */;
+	hda_reg8_write(&sdregs->ctl1, ctl);
+}
+
+hda_stream_t *hda_stream_create(hda_t *hda, hda_stream_dir_t dir,
+    uint32_t fmt)
+{
+	hda_stream_t *stream;
+	int rc;
+
+	stream = calloc(1, sizeof(hda_stream_t));
+	if (stream == NULL)
+		return NULL;
+
+	stream->hda = hda;
+	stream->dir = dir;
+	stream->sid = 1; /* XXX Allocate this */
+	stream->sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
+	stream->fmt = fmt;
+
+	ddf_msg(LVL_NOTE, "snum=%d sdidx=%d", stream->sid, stream->sdid);
+
+	ddf_msg(LVL_NOTE, "Allocate buffers");
+	rc = hda_stream_buffers_alloc(stream);
+	if (rc != EOK)
+		goto error;
+
+	ddf_msg(LVL_NOTE, "Configure stream descriptor");
+	hda_stream_desc_configure(stream);
+	return stream;
+error:
+	return NULL;
+}
+
+void hda_stream_destroy(hda_stream_t *stream)
+{
+	ddf_msg(LVL_NOTE, "hda_stream_destroy()");
+	free(stream);
+}
+
+void hda_stream_start(hda_stream_t *stream)
+{
+	hda_stream_set_run(stream, true);
+}
+
+/** @}
+ */
Index: uspace/drv/audio/hdaudio/stream.h
===================================================================
--- uspace/drv/audio/hdaudio/stream.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/stream.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup hdaudio
+ * @{
+ */
+/** @file High Definition Audio stream
+ */
+
+#ifndef STREAM_H
+#define STERAM_H
+
+#include "hdaudio.h"
+#include "spec/bdl.h"
+
+typedef enum {
+	/** Input Stream */
+	sdir_input,
+	/** Output Stream */
+	sdir_output,
+	/** Bidirectional Stream */
+	sdir_bidi
+} hda_stream_dir_t;
+
+typedef struct hda_stream {
+	hda_t *hda;
+	/** Stream ID */
+	uint8_t sid;
+	/** Stream descriptor index */
+	uint8_t sdid;
+	/** Direction */
+	hda_stream_dir_t dir;
+	/** Number of buffers */
+	size_t nbuffers;
+	/** Buffer size */
+	size_t bufsize;
+	/** Buffer Descriptor List */
+	hda_buffer_desc_t *bdl;
+	/** Physical address of BDL */
+	uintptr_t bdl_phys;
+	/** Buffers */
+	void **buf;
+	/** Physical addresses of buffers */
+	uintptr_t *buf_phys;
+	/** Stream format */
+	uint32_t fmt;
+} hda_stream_t;
+
+extern hda_stream_t *hda_stream_create(hda_t *, hda_stream_dir_t, uint32_t);
+extern void hda_stream_start(hda_stream_t *);
+extern void hda_stream_destroy(hda_stream_t *);
+
+#endif
+
+/** @}
+ */
