Index: uspace/drv/audio/hdaudio/hdactl.c
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.c	(revision 7978d1e7dd2d345124f5057ea7f3979ddcb6828a)
+++ uspace/drv/audio/hdaudio/hdactl.c	(revision 8d0707105ba3fdef10f2df188d7e4cf931cb0f78)
@@ -48,5 +48,6 @@
 enum {
 	ctrl_init_wait_max = 10,
-	codec_enum_wait_us = 512
+	codec_enum_wait_us = 512,
+	corb_wait_max = 10
 };
 
@@ -104,5 +105,5 @@
 	ddf_msg(LVL_NOTE, "hda_corb_init()");
 
-	/* Stop CORB if not stopped. */
+	/* Stop CORB if not stopped */
 	ctl = hda_reg8_read(&hda->regs->corbctl);
 	if ((ctl & BIT_V(uint8_t, corbctl_run)) != 0) {
@@ -148,5 +149,5 @@
 	hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys));
 
-	ddf_msg(LVL_NOTE, "Rset CORB Read/Write pointers");
+	ddf_msg(LVL_NOTE, "Reset CORB Read/Write pointers");
 
 	/* Reset CORB Read Pointer */
@@ -155,4 +156,10 @@
 	/* Reset CORB Write Poitner */
 	hda_reg16_write(&hda->regs->corbwp, 0);
+
+	/* Start CORB */
+	ctl = hda_reg8_read(&hda->regs->corbctl);
+	ddf_msg(LVL_NOTE, "CORBctl (0x%x) = 0x%x",
+	    (unsigned)((void *)&hda->regs->corbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, corbctl_run));
+	hda_reg8_write(&hda->regs->corbctl, ctl | BIT_V(uint8_t, corbctl_run));
 
 	ddf_msg(LVL_NOTE, "CORB initialized");
@@ -174,5 +181,5 @@
 	ddf_msg(LVL_NOTE, "hda_rirb_init()");
 
-	/* Stop RIRB if not stopped. */
+	/* Stop RIRB if not stopped */
 	ctl = hda_reg8_read(&hda->regs->rirbctl);
 	if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) {
@@ -218,8 +225,19 @@
 	hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys));
 
-	ddf_msg(LVL_NOTE, "Rset RIRB Write pointer");
+	ddf_msg(LVL_NOTE, "Reset RIRB Write pointer");
 
 	/* Reset RIRB Write Pointer */
 	hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst));
+
+	/* Set RINTCNT - Qemu won't read from CORB if this is zero */
+	hda_reg16_write(&hda->regs->rintcnt, 2);
+
+	hda->ctl->rirb_rp = 0;
+
+	/* Start RIRB */
+	ctl = hda_reg8_read(&hda->regs->rirbctl);
+	ddf_msg(LVL_NOTE, "RIRBctl (0x%x) = 0x%x",
+	    (unsigned)((void *)&hda->regs->rirbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, rirbctl_run));
+	hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run));
 
 	ddf_msg(LVL_NOTE, "RIRB initialized");
@@ -229,4 +247,113 @@
 }
 
+static size_t hda_get_corbrp(hda_t *hda)
+{
+	uint16_t corbrp;
+
+	corbrp = hda_reg16_read(&hda->regs->corbrp);
+	return BIT_RANGE_EXTRACT(uint16_t, corbrp_rp_h, corbrp_rp_l, corbrp);
+}
+
+static size_t hda_get_corbwp(hda_t *hda)
+{
+	uint16_t corbwp;
+
+	corbwp = hda_reg16_read(&hda->regs->corbwp);
+	return BIT_RANGE_EXTRACT(uint16_t, corbwp_wp_h, corbwp_wp_l, corbwp);
+}
+
+static void hda_set_corbwp(hda_t *hda, size_t wp)
+{
+	ddf_msg(LVL_NOTE, "Set CORBWP = %d", wp);
+	hda_reg16_write(&hda->regs->corbwp, wp);
+}
+
+static size_t hda_get_rirbwp(hda_t *hda)
+{
+	uint16_t rirbwp;
+
+	rirbwp = hda_reg16_read(&hda->regs->rirbwp);
+	return BIT_RANGE_EXTRACT(uint16_t, rirbwp_wp_h, rirbwp_wp_l, rirbwp);
+}
+
+/** Determine number of free entries in CORB */
+static size_t hda_corb_avail(hda_t *hda)
+{
+	int rp, wp;
+	int avail;
+
+	rp = hda_get_corbrp(hda);
+	wp = hda_get_corbwp(hda);
+
+	avail = rp - wp - 1;
+	while (avail < 0)
+		avail += hda->ctl->corb_entries;
+
+	return avail;
+}
+
+/** Write to CORB */
+static int hda_corb_write(hda_t *hda, uint32_t *data, size_t count)
+{
+	size_t avail;
+	size_t wp;
+	size_t idx;
+	size_t now;
+	size_t i;
+	uint32_t *corb;
+	int wcnt;
+
+	avail = hda_corb_avail(hda);
+	wp = hda_get_corbwp(hda);
+	corb = (uint32_t *)hda->ctl->corb_virt;
+
+	idx = 0;
+	while (idx < count) {
+		now = min(avail, count - idx);
+
+		for (i = 0; i < now; i++) {
+			wp = (wp + 1) % hda->ctl->corb_entries;
+			corb[wp] = data[idx++];
+		}
+
+		hda_set_corbwp(hda, wp);
+
+		if (idx < count) {
+			/* We filled up CORB but still data remaining */
+			wcnt = corb_wait_max;
+			while (hda_corb_avail(hda) < 1 && wcnt > 0) {
+				async_usleep(100);
+				--wcnt;
+			}
+
+			/* If CORB is still full return timeout error */
+			if (hda_corb_avail(hda) < 1)
+				return ETIMEOUT;
+		}
+	}
+
+	return EOK;
+}
+
+static void hda_rirb_read(hda_t *hda)
+{
+	size_t wp;
+	hda_rirb_entry_t resp;
+	hda_rirb_entry_t *rirb;
+
+	rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
+
+	wp = hda_get_rirbwp(hda);
+	ddf_msg(LVL_NOTE, "hda_rirb_read: wp=%d", wp);
+	while (hda->ctl->rirb_rp != wp) {
+		++hda->ctl->rirb_rp;
+		resp = rirb[hda->ctl->rirb_rp];
+
+		ddf_msg(LVL_NOTE, "RESPONSE resp=0x%x respex=0x%x",
+		    resp.resp, resp.respex);
+	}
+}
+
+#include "spec/codec.h"
 hda_ctl_t *hda_ctl_init(hda_t *hda)
 {
@@ -299,4 +426,18 @@
 		goto error;
 
+	uint32_t verb;
+	verb = (0 << 28) | (0 << 20) | ((hda_get_param) << 8) | (hda_sub_nc);
+	rc = hda_corb_write(hda, &verb, 1);
+	ddf_msg(LVL_NOTE, "hda_corb_write -> %d", rc);
+	rc = hda_corb_write(hda, &verb, 1);
+	ddf_msg(LVL_NOTE, "hda_corb_write -> %d", rc);
+	rc = hda_corb_write(hda, &verb, 1);
+	ddf_msg(LVL_NOTE, "hda_corb_write -> %d", rc);
+	rc = hda_corb_write(hda, &verb, 1);
+	ddf_msg(LVL_NOTE, "hda_corb_write -> %d", rc);
+
+	async_usleep(100*1000);
+	hda_rirb_read(hda);
+
 	return ctl;
 error:
Index: uspace/drv/audio/hdaudio/hdactl.h
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.h	(revision 7978d1e7dd2d345124f5057ea7f3979ddcb6828a)
+++ uspace/drv/audio/hdaudio/hdactl.h	(revision 8d0707105ba3fdef10f2df188d7e4cf931cb0f78)
@@ -46,4 +46,5 @@
 	void *rirb_virt;
 	size_t rirb_entries;
+	size_t rirb_rp;
 } hda_ctl_t;
 
Index: uspace/drv/audio/hdaudio/spec/codec.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/codec.h	(revision 7978d1e7dd2d345124f5057ea7f3979ddcb6828a)
+++ uspace/drv/audio/hdaudio/spec/codec.h	(revision 8d0707105ba3fdef10f2df188d7e4cf931cb0f78)
@@ -70,9 +70,9 @@
 	hda_spdif_ctl_set1 = 0x70d,
 	/** S/PDIF Converter Control / Set 2 */
-	hda_spdif_ctl_set1 = 0x70e,
+	hda_spdif_ctl_set2 = 0x70e,
 	/** S/PDIF Converter Control / Set 3 */
-	hda_spdif_ctl_set1 = 0x73e,
+	hda_spdif_ctl_set3 = 0x73e,
 	/** S/PDIF Converter Control / Set 4 */
-	hda_spdif_ctl_set1 = 0x73f,
+	hda_spdif_ctl_set4 = 0x73f,
 	/** Power State / Get */
 	hda_power_state_get = 0xf05,
@@ -91,8 +91,8 @@
 	/** Enable VRef / Set */
 	hda_enable_vref_set = 0x707,
-	/** Connection Select Control / Get */
-	hda_conn_sel_get = 0xf08,
-	/** Connection Select Control / Set */
-	hda_conn_sel_set = 0x708
+	/** Unsolicited Response Control / Get */
+	hda_unsol_resp_get = 0xf08,
+	/** Unsolicied Response Control / Set */
+	hda_unsol_resp_set = 0x708
 } hda_verb_t;
 
Index: uspace/drv/audio/hdaudio/spec/regs.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/regs.h	(revision 7978d1e7dd2d345124f5057ea7f3979ddcb6828a)
+++ uspace/drv/audio/hdaudio/spec/regs.h	(revision 8d0707105ba3fdef10f2df188d7e4cf931cb0f78)
@@ -201,4 +201,11 @@
 
 typedef enum {
+	/** CORB Write Pointer (H) */
+	corbwp_wp_h = 7,
+	/** CORB Write Pointer (L) */
+	corbwp_wp_l = 0
+} hda_corbwp_bits_t;
+
+typedef enum {
 	/** Enable CORB DMA Engine */
 	corbctl_run = 1,
@@ -224,5 +231,5 @@
 	rirbwp_wp_h = 7,
 	/** RIRB Write Pointer (L) */
-	rirbrp_wp_l = 0
+	rirbwp_wp_l = 0
 } hda_rirbwp_bits_t;
 
@@ -247,4 +254,20 @@
 } hda_rirbsize_bits_t;
 
+typedef struct {
+	/** Response - data received from codec */
+	uint32_t resp;
+	/** Response Extended - added by controller */
+	uint32_t respex;
+} hda_rirb_entry_t;
+
+typedef enum {
+	/** Unsolicited response */
+	respex_unsol = 4,
+	/** Codec Address (H) */
+	respex_addr_h = 3,
+	/** Codec Address (L) */
+	respex_addr_l = 0
+} hda_respex_bits_t;
+
 #endif
 
