Index: uspace/app/wavplay/drec.c
===================================================================
--- uspace/app/wavplay/drec.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/app/wavplay/drec.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -47,5 +47,5 @@
 
 
-#define BUFFER_PARTS   2
+#define BUFFER_PARTS   16
 
 /** Recording format */
@@ -103,7 +103,7 @@
 			printf("Recording terminated\n");
 			record = false;
+			break;
 		case PCM_EVENT_FRAMES_CAPTURED:
 			printf("%" PRIun " frames\n", IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
 			break;
 		default:
@@ -111,5 +111,9 @@
 			async_answer_0(callid, ENOTSUP);
 			continue;
-
+		}
+
+		if (!record) {
+			async_answer_0(callid, EOK);
+			break;
 		}
 
@@ -156,4 +160,8 @@
 	printf("\n");
 	audio_pcm_stop_capture(rec->device);
+	/* XXX Control returns even before we can be sure callbacks finished */
+	printf("Delay before playback termination\n");
+	async_usleep(1000000);
+	printf("Terminate playback\n");
 }
 
Index: uspace/app/wavplay/main.c
===================================================================
--- uspace/app/wavplay/main.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/app/wavplay/main.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -308,4 +308,5 @@
 			if (direct) {
 				drecord(device, file);
+				continue;
 			} else {
 				printf("Indirect recording is not supported "
Index: uspace/app/wavplay/wave.c
===================================================================
--- uspace/app/wavplay/wave.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/app/wavplay/wave.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -116,5 +116,5 @@
 		*channels = uint16_t_le2host(header->channels);
 	if (format) {
-		const unsigned size = uint32_t_le2host(header->sample_size);
+		const unsigned size = uint16_t_le2host(header->sample_size);
 		switch (size) {
 		case 8: *format = PCM_SAMPLE_UINT8; break;
@@ -157,5 +157,5 @@
 	header->channels = host2uint32_t_le(format.channels);
 	header->sample_size =
-	    host2uint32_t_le(pcm_sample_format_size(format.sample_format));
+	    host2uint16_t_le(pcm_sample_format_size(format.sample_format) * 8);
 }
 /**
Index: uspace/drv/audio/hdaudio/codec.c
===================================================================
--- uspace/drv/audio/hdaudio/codec.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/codec.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -437,4 +437,9 @@
 	}
 
+	if ((pcaps & BIT_V(uint32_t, pwc_input)) != 0) {
+		ddf_msg(LVL_NOTE, "PIN %d will enable input", aw);
+	    	pctl = pctl | BIT_V(uint8_t, pctl_in_enable);
+	}
+
 	if ((pcaps & BIT_V(uint32_t, pwc_hpd)) != 0) {
 		ddf_msg(LVL_NOTE, "PIN %d will enable headphone drive", aw);
@@ -503,4 +508,5 @@
 	codec->hda = hda;
 	codec->address = address;
+	codec->in_aw = -1;
 
 	rc = hda_get_subnc(codec, 0, &sfg, &nfg);
@@ -587,4 +593,24 @@
 				ddf_msg(LVL_NOTE, "Output widget %d: rates=0x%x formats=0x%x",
 				    aw, rates, formats);
+			} else if (awtype == awt_audio_input) {
+				if (codec->in_aw < 0) {
+					ddf_msg(LVL_NOTE, "Selected input "
+					    "widget %d\n", aw);
+					codec->in_aw = aw;
+				} else {
+					ddf_msg(LVL_NOTE, "Ignoring input "
+					    "widget %d\n", aw);
+				}
+
+				rc = hda_get_supp_rates(codec, aw, &rates);
+				if (rc != EOK)
+					goto error;
+
+				rc = hda_get_supp_formats(codec, aw, &formats);
+				if (rc != EOK)
+					goto error;
+
+				ddf_msg(LVL_NOTE, "Input widget %d: rates=0x%x formats=0x%x",
+				    aw, rates, formats);
 			}
 
@@ -623,14 +649,35 @@
 		/* Configure converter */
 
-		ddf_msg(LVL_NOTE, "Configure converter format");
+		ddf_msg(LVL_NOTE, "Configure output converter format");
 		rc = hda_set_converter_fmt(codec, out_aw, stream->fmt);
 		if (rc != EOK)
 			goto error;
 
-		ddf_msg(LVL_NOTE, "Configure converter stream, channel");
+		ddf_msg(LVL_NOTE, "Configure output converter stream, channel");
 		rc = hda_set_converter_ctl(codec, out_aw, stream->sid, 0);
 		if (rc != EOK)
 			goto error;
 	}
+
+	return EOK;
+error:
+	return rc;
+}
+
+int hda_in_converter_setup(hda_codec_t *codec, hda_stream_t *stream)
+{
+	int rc;
+
+	/* Configure converter */
+
+	ddf_msg(LVL_NOTE, "Configure input converter format");
+	rc = hda_set_converter_fmt(codec, codec->in_aw, stream->fmt);
+	if (rc != EOK)
+		goto error;
+
+	ddf_msg(LVL_NOTE, "Configure input converter stream, channel");
+	rc = hda_set_converter_ctl(codec, codec->in_aw, stream->sid, 0);
+	if (rc != EOK)
+		goto error;
 
 	return EOK;
Index: uspace/drv/audio/hdaudio/codec.h
===================================================================
--- uspace/drv/audio/hdaudio/codec.h	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/codec.h	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -47,4 +47,5 @@
 	int out_aw_num;
 	int out_aw_sel;
+	int in_aw;
 } hda_codec_t;
 
@@ -52,4 +53,5 @@
 extern void hda_codec_fini(hda_codec_t *);
 extern int hda_out_converter_setup(hda_codec_t *, hda_stream_t *);
+extern int hda_in_converter_setup(hda_codec_t *, hda_stream_t *);
 
 #endif
Index: uspace/drv/audio/hdaudio/hdactl.c
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/hdactl.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -562,5 +562,6 @@
 	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);
-
+	ddf_msg(LVL_NOTE, "iss: %d, oss: %d, bss: %d\n",
+	    ctl->iss, ctl->oss, ctl->bss);
 	/* Give codecs enough time to enumerate themselves */
 	async_usleep(codec_enum_wait_us);
Index: uspace/drv/audio/hdaudio/hdaudio.c
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/hdaudio.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -385,5 +385,11 @@
 			hda_pcm_event(hda, PCM_EVENT_FRAMES_PLAYED);
 			hda_pcm_event(hda, PCM_EVENT_FRAMES_PLAYED);
+		} else if (hda->capturing) {
+			hda_pcm_event(hda, PCM_EVENT_FRAMES_CAPTURED);
+			hda_pcm_event(hda, PCM_EVENT_FRAMES_CAPTURED);
+			hda_pcm_event(hda, PCM_EVENT_FRAMES_CAPTURED);
+			hda_pcm_event(hda, PCM_EVENT_FRAMES_CAPTURED);
 		}
+
 		hda_unlock(hda);
 	}
Index: uspace/drv/audio/hdaudio/hdaudio.h
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.h	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/hdaudio.h	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -55,5 +55,7 @@
 	struct hda_ctl *ctl;
 	struct hda_stream *pcm_stream;
+	struct hda_stream_buffers *pcm_buffers;
 	bool playing;
+	bool capturing;
 } hda_t;
 
Index: uspace/drv/audio/hdaudio/pcm_iface.c
===================================================================
--- uspace/drv/audio/hdaudio/pcm_iface.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/pcm_iface.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -100,11 +100,16 @@
 static unsigned hda_query_cap(ddf_fun_t *fun, audio_cap_t cap)
 {
+	hda_t *hda = fun_to_hda(fun);
+
 	ddf_msg(LVL_NOTE, "hda_query_cap(%d)", cap);
 	switch (cap) {
 	case AUDIO_CAP_PLAYBACK:
 	case AUDIO_CAP_INTERRUPT:
+		/* XXX Only if we have an output converter */
 		return 1;
+	case AUDIO_CAP_CAPTURE:
+		/* Yes if we have an input converter */
+		return hda->ctl->codec->in_aw >= 0;
 	case AUDIO_CAP_BUFFER_POS:
-	case AUDIO_CAP_CAPTURE:
 		return 0;
 	case AUDIO_CAP_MAX_BUFFER:
@@ -148,8 +153,94 @@
 {
 	hda_t *hda = fun_to_hda(fun);
+	int rc;
 
 	hda_lock(hda);
 
 	ddf_msg(LVL_NOTE, "hda_get_buffer(): hda=%p", hda);
+	if (hda->pcm_buffers != NULL) {
+		hda_unlock(hda);
+		return EBUSY;
+	}
+
+	ddf_msg(LVL_NOTE, "hda_get_buffer() - allocate stream buffers");
+	rc = hda_stream_buffers_alloc(hda, &hda->pcm_buffers);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		hda_unlock(hda);
+		return ENOMEM;
+	}
+
+	ddf_msg(LVL_NOTE, "hda_get_buffer() - fill info");
+	/* XXX This is only one buffer */
+	*buffer = hda->pcm_buffers->buf[0];
+	*size = hda->pcm_buffers->bufsize * hda->pcm_buffers->nbuffers;
+
+	ddf_msg(LVL_NOTE, "hda_get_buffer() returing EOK, buffer=%p, size=%zu",
+	    *buffer, *size);
+
+	hda_unlock(hda);
+	return EOK;
+}
+
+static int hda_get_buffer_position(ddf_fun_t *fun, size_t *pos)
+{
+	ddf_msg(LVL_NOTE, "hda_get_buffer_position()");
+	return ENOTSUP;
+}
+
+static int hda_set_event_session(ddf_fun_t *fun, async_sess_t *sess)
+{
+	hda_t *hda = fun_to_hda(fun);
+
+	ddf_msg(LVL_NOTE, "hda_set_event_session()");
+	hda_lock(hda);
+	hda->ev_sess = sess;
+	hda_unlock(hda);
+
+	return EOK;
+}
+
+static async_sess_t *hda_get_event_session(ddf_fun_t *fun)
+{
+	hda_t *hda = fun_to_hda(fun);
+	async_sess_t *sess;
+
+	ddf_msg(LVL_NOTE, "hda_get_event_session()");
+
+	hda_lock(hda);
+	sess = hda->ev_sess;
+	hda_unlock(hda);
+
+	return sess;
+}
+
+static int hda_release_buffer(ddf_fun_t *fun)
+{
+	hda_t *hda = fun_to_hda(fun);
+
+	hda_lock(hda);
+
+	ddf_msg(LVL_NOTE, "hda_release_buffer()");
+	if (hda->pcm_buffers == NULL) {
+		hda_unlock(hda);
+		return EINVAL;
+	}
+
+	hda_stream_buffers_free(hda->pcm_buffers);
+	hda->pcm_buffers = NULL;
+
+	hda_unlock(hda);
+	return EOK;
+}
+
+static int hda_start_playback(ddf_fun_t *fun, unsigned frames,
+    unsigned channels, unsigned rate, pcm_sample_format_t format)
+{
+	hda_t *hda = fun_to_hda(fun);
+	int rc;
+
+	ddf_msg(LVL_NOTE, "hda_start_playback()");
+	hda_lock(hda);
+
 	if (hda->pcm_stream != NULL) {
 		hda_unlock(hda);
@@ -162,91 +253,22 @@
 	fmt = (fmt_base_44khz << fmt_base) | (fmt_bits_16 << fmt_bits_l) | 1;
 
-	ddf_msg(LVL_NOTE, "hda_get_buffer() - create stream");
-	hda->pcm_stream = hda_stream_create(hda, sdir_output, fmt);
+	ddf_msg(LVL_NOTE, "hda_start_playback() - create output stream");
+	hda->pcm_stream = hda_stream_create(hda, sdir_output, hda->pcm_buffers,
+	    fmt);
 	if (hda->pcm_stream == NULL) {
 		hda_unlock(hda);
 		return EIO;
 	}
-
-	ddf_msg(LVL_NOTE, "hda_get_buffer() - fill info");
-	/* XXX This is only one buffer */
-	*buffer = hda->pcm_stream->buf[0];
-	*size = hda->pcm_stream->bufsize * hda->pcm_stream->nbuffers;
-
-	ddf_msg(LVL_NOTE, "hda_get_buffer() retturing EOK, buffer=%p, size=%zu",
-	    *buffer, *size);
-
-	hda_unlock(hda);
-	return EOK;
-}
-
-static int hda_get_buffer_position(ddf_fun_t *fun, size_t *pos)
-{
-	ddf_msg(LVL_NOTE, "hda_get_buffer_position()");
-	return ENOTSUP;
-}
-
-static int hda_set_event_session(ddf_fun_t *fun, async_sess_t *sess)
-{
-	hda_t *hda = fun_to_hda(fun);
-
-	ddf_msg(LVL_NOTE, "hda_set_event_session()");
-	hda_lock(hda);
-	hda->ev_sess = sess;
-	hda_unlock(hda);
-
-	return EOK;
-}
-
-static async_sess_t *hda_get_event_session(ddf_fun_t *fun)
-{
-	hda_t *hda = fun_to_hda(fun);
-	async_sess_t *sess;
-
-	ddf_msg(LVL_NOTE, "hda_get_event_session()");
-
-	hda_lock(hda);
-	sess = hda->ev_sess;
-	hda_unlock(hda);
-
-	return sess;
-}
-
-static int hda_release_buffer(ddf_fun_t *fun)
-{
-	hda_t *hda = fun_to_hda(fun);
-
-	hda_lock(hda);
-
-	ddf_msg(LVL_NOTE, "hda_release_buffer()");
-	if (hda->pcm_stream == NULL) {
-		hda_unlock(hda);
-		return EINVAL;
-	}
-
-	hda_stream_destroy(hda->pcm_stream);
-	hda->pcm_stream = NULL;
-
-	hda_unlock(hda);
-	return EOK;
-}
-
-static int hda_start_playback(ddf_fun_t *fun, unsigned frames,
-    unsigned channels, unsigned rate, pcm_sample_format_t format)
-{
-	hda_t *hda = fun_to_hda(fun);
-	int rc;
-
-	ddf_msg(LVL_NOTE, "hda_start_playback()");
-	hda_lock(hda);
 
 	rc = hda_out_converter_setup(hda->ctl->codec, hda->pcm_stream);
 	if (rc != EOK) {
+		hda_stream_destroy(hda->pcm_stream);
+		hda->pcm_stream = NULL;
 		hda_unlock(hda);
 		return rc;
 	}
 
+	hda->playing = true;
 	hda_stream_start(hda->pcm_stream);
-	hda->playing = true;
 	hda_unlock(hda);
 	return EOK;
@@ -262,4 +284,7 @@
 	hda_stream_reset(hda->pcm_stream);
 	hda->playing = false;
+	hda_stream_destroy(hda->pcm_stream);
+	hda->pcm_stream = NULL;
+
 	hda_unlock(hda);
 
@@ -271,12 +296,57 @@
     unsigned rate, pcm_sample_format_t format)
 {
+	hda_t *hda = fun_to_hda(fun);
+	int rc;
+
 	ddf_msg(LVL_NOTE, "hda_start_capture()");
-	return ENOTSUP;
+	hda_lock(hda);
+
+	if (hda->pcm_stream != NULL) {
+		hda_unlock(hda);
+		return EBUSY;
+	}
+
+	/* XXX Choose appropriate parameters */
+	uint32_t fmt;
+	/* 48 kHz, 16-bits, 1 channel */
+	fmt = (fmt_base_44khz << fmt_base) | (fmt_bits_16 << fmt_bits_l) | 1;
+
+	ddf_msg(LVL_NOTE, "hda_start_capture() - create input stream");
+	hda->pcm_stream = hda_stream_create(hda, sdir_input, hda->pcm_buffers,
+	    fmt);
+	if (hda->pcm_stream == NULL) {
+		hda_unlock(hda);
+		return EIO;
+	}
+
+	rc = hda_in_converter_setup(hda->ctl->codec, hda->pcm_stream);
+	if (rc != EOK) {
+		hda_stream_destroy(hda->pcm_stream);
+		hda->pcm_stream = NULL;
+		hda_unlock(hda);
+		return rc;
+	}
+
+	hda->capturing = true;
+	hda_stream_start(hda->pcm_stream);
+	hda_unlock(hda);
+	return EOK;
 }
 
 static int hda_stop_capture(ddf_fun_t *fun, bool immediate)
 {
+	hda_t *hda = fun_to_hda(fun);
+
 	ddf_msg(LVL_NOTE, "hda_stop_capture()");
-	return ENOTSUP;
+	hda_lock(hda);
+	hda_stream_stop(hda->pcm_stream);
+	hda_stream_reset(hda->pcm_stream);
+	hda->capturing = false;
+	hda_stream_destroy(hda->pcm_stream);
+	hda->pcm_stream = NULL;
+	hda_unlock(hda);
+
+	hda_pcm_event(hda, PCM_EVENT_CAPTURE_TERMINATED);
+	return EOK;
 }
 
Index: uspace/drv/audio/hdaudio/stream.c
===================================================================
--- uspace/drv/audio/hdaudio/stream.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/stream.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -48,15 +48,22 @@
 #include "stream.h"
 
-static int hda_stream_buffers_alloc(hda_stream_t *stream)
+int hda_stream_buffers_alloc(hda_t *hda, hda_stream_buffers_t **rbufs)
 {
 	void *bdl;
 	void *buffer;
 	uintptr_t buffer_phys;
+	hda_stream_buffers_t *bufs = NULL;
 	size_t i;
 //	size_t j, k;
 	int rc;
 
-	stream->nbuffers = 4;
-	stream->bufsize = 16384;
+	bufs = calloc(1, sizeof(hda_stream_buffers_t));
+	if (bufs == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	bufs->nbuffers = 4;
+	bufs->bufsize = 16384;
 
 	/*
@@ -65,28 +72,28 @@
 	 */
 	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);
+	rc = dmamem_map_anonymous(bufs->nbuffers * sizeof(hda_buffer_desc_t),
+	    hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
+	    0, &bufs->bdl_phys, &bdl);
 	if (rc != EOK)
 		goto error;
 
-	stream->bdl = bdl;
+	bufs->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)
+	bufs->buf = calloc(bufs->nbuffers, sizeof(void *));
+	if (bufs->buf == NULL)
+		goto error;
+
+	bufs->buf_phys = calloc(bufs->nbuffers, sizeof(uintptr_t));
+	if (bufs->buf_phys == NULL)
 		goto error;
 
 	/* Allocate buffers */
 /*
-	for (i = 0; i < stream->nbuffers; i++) {
+	for (i = 0; i < bufs->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,
+		rc = dmamem_map_anonymous(bufs->bufsize,
+		    bufs->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
 		    0, &buffer_phys, &buffer);
 		if (rc != EOK)
@@ -96,10 +103,10 @@
 		    (unsigned long long)buffer_phys, buffer);
 
-		stream->buf[i] = buffer;
-		stream->buf_phys[i] = buffer_phys;
+		bufs->buf[i] = buffer;
+		bufs->buf_phys[i] = buffer_phys;
 
 		k = 0;
-		for (j = 0; j < stream->bufsize / 2; j++) {
-			int16_t *bp = stream->buf[i];
+		for (j = 0; j < bufs->bufsize / 2; j++) {
+			int16_t *bp = bufs->buf[i];
 			bp[j] = (k > 128) ? -100 : 100;
 			++k;
@@ -111,6 +118,6 @@
 	/* audio_pcm_iface requires a single contiguous buffer */
 	buffer = AS_AREA_ANY;
-	rc = dmamem_map_anonymous(stream->bufsize * stream->nbuffers,
-	    stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
+	rc = dmamem_map_anonymous(bufs->bufsize * bufs->nbuffers,
+	    hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
 	    0, &buffer_phys, &buffer);
 	if (rc != EOK) {
@@ -119,14 +126,14 @@
 	}
 
-	for (i = 0; i < stream->nbuffers; i++) {
-		stream->buf[i] = buffer + i * stream->bufsize;
-		stream->buf_phys[i] = buffer_phys + i * stream->bufsize;
+	for (i = 0; i < bufs->nbuffers; i++) {
+		bufs->buf[i] = buffer + i * bufs->bufsize;
+		bufs->buf_phys[i] = buffer_phys + i * bufs->bufsize;
 
 		ddf_msg(LVL_NOTE, "Stream buf phys=0x%llx virt=%p",
-		    (long long unsigned)(uintptr_t)stream->buf[i],
-		    (void *)stream->buf_phys[i]);
+		    (long long unsigned)(uintptr_t)bufs->buf[i],
+		    (void *)bufs->buf_phys[i]);
 /*		k = 0;
-		for (j = 0; j < stream->bufsize / 2; j++) {
-			int16_t *bp = stream->buf[i];
+		for (j = 0; j < bufs->bufsize / 2; j++) {
+			int16_t *bp = bufs->buf[i];
 			bp[j] = (k > 128) ? -10000 : 10000;
 			++k;
@@ -138,18 +145,30 @@
 
 	/* Fill in BDL */
-	for (i = 0; i < stream->nbuffers; i++) {
-		stream->bdl[i].address = host2uint64_t_le(stream->buf_phys[i]);
-		stream->bdl[i].length = host2uint32_t_le(stream->bufsize);
-		stream->bdl[i].flags = BIT_V(uint32_t, bdf_ioc);
-	}
-
+	for (i = 0; i < bufs->nbuffers; i++) {
+		bufs->bdl[i].address = host2uint64_t_le(bufs->buf_phys[i]);
+		bufs->bdl[i].length = host2uint32_t_le(bufs->bufsize);
+		bufs->bdl[i].flags = BIT_V(uint32_t, bdf_ioc);
+	}
+
+	*rbufs = bufs;
 	return EOK;
 error:
+	hda_stream_buffers_free(bufs);
 	return ENOMEM;
 }
 
+void hda_stream_buffers_free(hda_stream_buffers_t *bufs)
+{
+	if (bufs == NULL)
+		return;
+
+	/* XXX */
+	free(bufs);
+}
+
 static void hda_stream_desc_configure(hda_stream_t *stream)
 {
 	hda_sdesc_regs_t *sdregs;
+	hda_stream_buffers_t *bufs = stream->buffers;
 	uint8_t ctl1;
 	uint8_t ctl3;
@@ -161,9 +180,9 @@
 	hda_reg8_write(&sdregs->ctl3, ctl3);
 	hda_reg8_write(&sdregs->ctl1, ctl1);
-	hda_reg32_write(&sdregs->cbl, stream->nbuffers * stream->bufsize);
-	hda_reg16_write(&sdregs->lvi, stream->nbuffers - 1);
+	hda_reg32_write(&sdregs->cbl, bufs->nbuffers * bufs->bufsize);
+	hda_reg16_write(&sdregs->lvi, bufs->nbuffers - 1);
 	hda_reg16_write(&sdregs->fmt, stream->fmt);
-	hda_reg32_write(&sdregs->bdpl, LOWER32(stream->bdl_phys));
-	hda_reg32_write(&sdregs->bdpu, UPPER32(stream->bdl_phys));
+	hda_reg32_write(&sdregs->bdpl, LOWER32(bufs->bdl_phys));
+	hda_reg32_write(&sdregs->bdpu, UPPER32(bufs->bdl_phys));
 }
 
@@ -205,8 +224,8 @@
 
 hda_stream_t *hda_stream_create(hda_t *hda, hda_stream_dir_t dir,
-    uint32_t fmt)
+    hda_stream_buffers_t *bufs, uint32_t fmt)
 {
 	hda_stream_t *stream;
-	int rc;
+	uint8_t sdid;
 
 	stream = calloc(1, sizeof(hda_stream_t));
@@ -214,22 +233,30 @@
 		return NULL;
 
+	sdid = 0;
+
+	switch (dir) {
+	case sdir_input:
+		sdid = 0; /* XXX Allocate - first input SDESC */
+		break;
+	case sdir_output:
+		sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
+		break;
+	case sdir_bidi:
+		sdid = hda->ctl->iss + hda->ctl->oss; /* XXX Allocate - First bidi SDESC */
+		break;
+	}
+
 	stream->hda = hda;
 	stream->dir = dir;
 	stream->sid = 1; /* XXX Allocate this */
-	stream->sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
+	stream->sdid = sdid;
 	stream->fmt = fmt;
+	stream->buffers = bufs;
 
 	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;
 }
 
Index: uspace/drv/audio/hdaudio/stream.h
===================================================================
--- uspace/drv/audio/hdaudio/stream.h	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/audio/hdaudio/stream.h	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -48,12 +48,5 @@
 } 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;
+typedef struct hda_stream_buffers {
 	/** Number of buffers */
 	size_t nbuffers;
@@ -68,9 +61,24 @@
 	/** Physical addresses of buffers */
 	uintptr_t *buf_phys;
+} hda_stream_buffers_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;
+	/** Buffers */
+	hda_stream_buffers_t *buffers;
 	/** Stream format */
 	uint32_t fmt;
 } hda_stream_t;
 
-extern hda_stream_t *hda_stream_create(hda_t *, hda_stream_dir_t, uint32_t);
+extern int hda_stream_buffers_alloc(hda_t *, hda_stream_buffers_t **);
+extern void hda_stream_buffers_free(hda_stream_buffers_t *);
+extern hda_stream_t *hda_stream_create(hda_t *, hda_stream_dir_t,
+    hda_stream_buffers_t *, uint32_t);
 extern void hda_stream_destroy(hda_stream_t *);
 extern void hda_stream_start(hda_stream_t *);
Index: uspace/drv/block/ata_bd/main.c
===================================================================
--- uspace/drv/block/ata_bd/main.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/block/ata_bd/main.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -81,5 +81,4 @@
 		rc = EINVAL;
 		goto error;
-		return EINVAL;
 	}
 
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/drv/bus/isa/isa.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -245,5 +245,6 @@
 	bool opened = false;
 	int fd;
-	size_t len = 0;
+	size_t len;
+	ssize_t r;
 
 	fd = open(conf_path, O_RDONLY);
@@ -269,5 +270,6 @@
 	}
 
-	if (0 >= read(fd, buf, len)) {
+	r = read_all(fd, buf, len);
+	if (r < 0) {
 		ddf_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
 		goto cleanup;
Index: uspace/lib/ext4/libext4_directory.c
===================================================================
--- uspace/lib/ext4/libext4_directory.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/lib/ext4/libext4_directory.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -390,13 +390,9 @@
 	    (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
 		int rc = ext4_directory_dx_add_entry(parent, child, name);
-		
+
 		/* Check if index is not corrupted */
-		if (rc != EXT4_ERR_BAD_DX_DIR) {
-			if (rc != EOK)
-				return rc;
-			
-			return EOK;
-		}
-		
+		if (rc != EXT4_ERR_BAD_DX_DIR)
+			return rc;
+
 		/* Needed to clear dir index flag if corrupted */
 		ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
Index: uspace/lib/ext4/libext4_extent.c
===================================================================
--- uspace/lib/ext4/libext4_extent.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/lib/ext4/libext4_extent.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -797,4 +797,5 @@
 			if (rc != EOK) {
 				ext4_balloc_free_block(inode_ref, fblock);
+				block_put(block);
 				return rc;
 			}
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -53,33 +53,30 @@
     enum cache_mode cmode)
 {
+	ext4_superblock_t *temp_superblock = NULL;
+
 	fs->device = service_id;
-	
+
 	/* Initialize block library (4096 is size of communication channel) */
 	int rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);
 	if (rc != EOK)
-		return rc;
-	
+		goto err;
+
 	/* Read superblock from device to memory */
-	ext4_superblock_t *temp_superblock;
 	rc = ext4_superblock_read_direct(fs->device, &temp_superblock);
-	if (rc != EOK) {
-		block_fini(fs->device);
-		return rc;
-	}
-	
+	if (rc != EOK)
+		goto err_1;
+
 	/* Read block size from superblock and check */
 	uint32_t block_size = ext4_superblock_get_block_size(temp_superblock);
 	if (block_size > EXT4_MAX_BLOCK_SIZE) {
-		block_fini(fs->device);
-		return ENOTSUP;
-	}
-	
+		rc = ENOTSUP;
+		goto err_1;
+	}
+
 	/* Initialize block caching by libblock */
 	rc = block_cache_init(service_id, block_size, 0, cmode);
-	if (rc != EOK) {
-		block_fini(fs->device);
-		return rc;
-	}
-	
+	if (rc != EOK)
+		goto err_1;
+
 	/* Compute limits for indirect block levels */
 	uint32_t block_ids_per_block = block_size / sizeof(uint32_t);
@@ -92,32 +89,37 @@
 		    fs->inode_blocks_per_level[i];
 	}
-	
+
 	/* Return loaded superblock */
 	fs->superblock = temp_superblock;
-	
+
 	uint16_t state = ext4_superblock_get_state(fs->superblock);
-	
+
 	if (((state & EXT4_SUPERBLOCK_STATE_VALID_FS) !=
 	    EXT4_SUPERBLOCK_STATE_VALID_FS) ||
 	    ((state & EXT4_SUPERBLOCK_STATE_ERROR_FS) ==
 	    EXT4_SUPERBLOCK_STATE_ERROR_FS)) {
-		block_cache_fini(fs->device);
-		block_fini(fs->device);
-		return ENOTSUP;
-	}
-	
+		rc = ENOTSUP;
+		goto err_2;
+	}
+
 	/* Mark system as mounted */
 	ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS);
 	rc = ext4_superblock_write_direct(fs->device, fs->superblock);
-	if (rc != EOK) {
-		block_cache_fini(fs->device);
-		block_fini(fs->device);
-		return rc;
-	}
-	
+	if (rc != EOK)
+		goto err_2;
+
 	uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock);
 	ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1);
-	
+
 	return EOK;
+
+err_2:
+	block_cache_fini(fs->device);
+err_1:
+	block_fini(fs->device);
+err:
+	if (temp_superblock)
+		ext4_superblock_release(temp_superblock);
+	return rc;
 }
 
@@ -845,6 +847,8 @@
 				
 				rc = block_put(subblock);
-				if (rc != EOK)
+				if (rc != EOK) {
+					block_put(block);
 					return rc;
+				}
 			}
 			
Index: uspace/lib/ext4/libext4_superblock.c
===================================================================
--- uspace/lib/ext4/libext4_superblock.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/lib/ext4/libext4_superblock.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -1178,4 +1178,14 @@
 }
 
+/** Release the memory allocated for the superblock structure
+ *
+ * @param sb         Superblock to be freed
+ *
+ */
+void ext4_superblock_release(ext4_superblock_t *sb)
+{
+	free(sb);
+}
+
 /** Check sanity of the superblock.
  *
Index: uspace/lib/ext4/libext4_superblock.h
===================================================================
--- uspace/lib/ext4/libext4_superblock.h	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/lib/ext4/libext4_superblock.h	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -145,4 +145,5 @@
 extern int ext4_superblock_read_direct(service_id_t, ext4_superblock_t **);
 extern int ext4_superblock_write_direct(service_id_t, ext4_superblock_t *);
+extern void ext4_superblock_release(ext4_superblock_t *);
 extern int ext4_superblock_check_sanity(ext4_superblock_t *);
 
Index: uspace/srv/devman/drv_conn.c
===================================================================
--- uspace/srv/devman/drv_conn.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/srv/devman/drv_conn.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -173,7 +173,7 @@
 	callid = async_get_call(&call);
 	if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR,
 		    "Invalid protocol when trying to receive match id.");
-		async_answer_0(callid, EINVAL); 
+		async_answer_0(callid, EINVAL);
 		delete_match_id(match_id);
 		return EINVAL;
@@ -246,5 +246,5 @@
 	if (ftype != fun_inner && ftype != fun_exposed) {
 		/* Unknown function type */
-		log_msg(LOG_DEFAULT, LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR,
 		    "Unknown function type %d provided by driver.",
 		    (int) ftype);
@@ -404,5 +404,5 @@
 	fibril_rwlock_read_unlock(&device_tree.rwlock);
 	
-	rc = fun_offline(fun);
+	rc = fun_online(fun);
 	if (rc != EOK) {
 		fun_busy_unlock(fun);
Index: uspace/srv/devman/fun.c
===================================================================
--- uspace/srv/devman/fun.c	(revision 73e894c72c36ba3b348210497c21ea78a3a183a3)
+++ uspace/srv/devman/fun.c	(revision 749fe15b74e83e98f982655fff497a808f7675f4)
@@ -348,4 +348,5 @@
 		loc_register_tree_function(fun, &device_tree);
 	
+	fun->state = FUN_ON_LINE;
 	fibril_rwlock_write_unlock(&device_tree.rwlock);
 	
