Index: uspace/drv/audio/hdaudio/hdactl.c
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/hdactl.c	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -39,4 +39,5 @@
 #include <ddi.h>
 #include <errno.h>
+#include <fibril_synch.h>
 #include <macros.h>
 #include <stdint.h>
@@ -222,13 +223,14 @@
 
 	/* Set RINTCNT - Qemu won't read from CORB if this is zero */
-	hda_reg16_write(&hda->regs->rintcnt, 128);
+	hda_reg16_write(&hda->regs->rintcnt, hda->ctl->rirb_entries / 2);
 
 	hda->ctl->rirb_rp = 0;
 
-	/* Start RIRB */
+	/* Start RIRB and enable RIRB interrupt */
 	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));
+	hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run) |
+	    BIT_V(uint8_t, rirbctl_int));
 
 	ddf_msg(LVL_NOTE, "RIRB initialized");
@@ -327,21 +329,41 @@
 }
 
-static int hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
+static int hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data)
 {
 	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_DEBUG2, "hda_rirb_read: wp=%d", wp);
+	if (hda->ctl->rirb_rp == wp)
+		return ENOENT;
+
+	++hda->ctl->rirb_rp;
+	resp = rirb[hda->ctl->rirb_rp];
+
+	ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
+	    resp.resp, resp.respex);
+	*data = resp;
+	return EOK;
+}
+
+static int hda_solrb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
+{
+	hda_rirb_entry_t resp;
 	int wcnt;
 
-	rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
+	wcnt = 10;
+
+	fibril_mutex_lock(&hda->ctl->solrb_lock);
 
 	while (count > 0) {
-		wp = hda_get_rirbwp(hda);
-		ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%d", wp);
-		while (count > 0 && hda->ctl->rirb_rp != wp) {
-			++hda->ctl->rirb_rp;
-			resp = rirb[hda->ctl->rirb_rp];
-
-			ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
+		while (count > 0 && hda->ctl->solrb_rp != hda->ctl->solrb_wp) {
+			++hda->ctl->solrb_rp;
+			resp = hda->ctl->solrb[hda->ctl->solrb_rp];
+
+			ddf_msg(LVL_DEBUG2, "solrb RESPONSE resp=0x%x respex=0x%x",
 			    resp.resp, resp.respex);
 			if ((resp.respex & BIT_V(uint32_t, respex_unsol)) == 0) {
@@ -353,15 +375,20 @@
 
 		if (count > 0) {
-			wcnt = rirb_wait_max;
-			while (wcnt > 0 && hda_get_rirbwp(hda) == hda->ctl->rirb_rp) {
+			while (wcnt > 0 && hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
+				fibril_mutex_unlock(&hda->ctl->solrb_lock);
 				async_usleep(100);
+				fibril_mutex_lock(&hda->ctl->solrb_lock);
 				--wcnt;
 			}
 
-			if (hda_get_rirbwp(hda) == hda->ctl->rirb_rp)
+			if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
+				ddf_msg(LVL_NOTE, "hda_solrb_read() time out");
+				fibril_mutex_unlock(&hda->ctl->solrb_lock);
 				return ETIMEOUT;
-		}
-	}
-
+			}
+		}
+	}
+
+	fibril_mutex_unlock(&hda->ctl->solrb_lock);
 	return EOK;
 }
@@ -371,4 +398,5 @@
 	hda_ctl_t *ctl;
 	uint32_t gctl;
+	uint32_t intctl;
 	int cnt;
 	int rc;
@@ -378,5 +406,9 @@
 		return NULL;
 
+	fibril_mutex_initialize(&ctl->solrb_lock);
+	fibril_condvar_initialize(&ctl->solrb_cv);
+
 	hda->ctl = ctl;
+	ctl->hda = hda;
 
 	uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
@@ -391,5 +423,15 @@
 
 	ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x",
-	    (void *)&hda->regs->statests - (void *)hda->regs, hda_reg16_read(&hda->regs->statests));
+	    (void *)&hda->regs->statests - (void *)hda->regs,
+		hda_reg16_read(&hda->regs->statests));
+	/**
+	  * Clear STATESTS bits so they don't generate an interrupt later
+	  * when we enable interrupts.
+	  */
+	hda_reg16_write(&hda->regs->statests, 0x7f);
+
+	ddf_msg(LVL_NOTE, "after clearing reg 0x%zx STATESTS = 0x%x",
+	    (void *)&hda->regs->statests - (void *)hda->regs,
+		hda_reg16_read(&hda->regs->statests));
 
 	gctl = hda_reg32_read(&hda->regs->gctl);
@@ -437,15 +479,35 @@
 	    hda_reg16_read(&hda->regs->statests));
 
+	async_usleep(1000*1000);
+
+	/* Enable interrupts */
+	intctl = hda_reg32_read(&hda->regs->intctl);
+	ddf_msg(LVL_NOTE, "intctl (0x%x) := 0x%x",
+	    (unsigned)((void *)&hda->regs->intctl - (void *)hda->regs),
+	    intctl | BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
+	hda_reg32_write(&hda->regs->intctl, intctl |
+	    BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
+
+	async_usleep(1000*1000);
+
 	rc = hda_corb_init(hda);
 	if (rc != EOK)
 		goto error;
 
+
+	async_usleep(1000*1000);
+
 	rc = hda_rirb_init(hda);
 	if (rc != EOK)
 		goto error;
 
+	async_usleep(1000*1000);
+
+	ddf_msg(LVL_NOTE, "call hda_codec_init()");
 	hda->ctl->codec = hda_codec_init(hda, 0);
-	if (hda->ctl->codec == NULL)
-		goto error;
+	if (hda->ctl->codec == NULL) {
+		ddf_msg(LVL_NOTE, "hda_codec_init() failed");
+		goto error;
+	}
 
 	return ctl;
@@ -466,5 +528,5 @@
 
 	if (resp != NULL) {
-		rc = hda_rirb_read(hda, &rentry, 1);
+		rc = hda_solrb_read(hda, &rentry, 1);
 		if (rc != EOK)
 			return rc;
@@ -483,4 +545,25 @@
 }
 
+void hda_ctl_interrupt(hda_ctl_t *ctl)
+{
+	hda_rirb_entry_t resp;
+	int rc;
+
+	while (true) {
+		rc = hda_rirb_read(ctl->hda, &resp);
+		if (rc != EOK) {
+//			ddf_msg(LVL_NOTE, "nothing in rirb");
+			break;
+		}
+
+		ddf_msg(LVL_NOTE, "writing to solrb");
+		fibril_mutex_lock(&ctl->solrb_lock);
+		ctl->solrb_wp = (ctl->solrb_wp + 1) % softrb_entries;
+		ctl->solrb[ctl->solrb_wp] = resp;
+		fibril_mutex_unlock(&ctl->solrb_lock);
+		fibril_condvar_broadcast(&ctl->solrb_cv);
+	}
+}
+
 /** @}
  */
Index: uspace/drv/audio/hdaudio/hdactl.h
===================================================================
--- uspace/drv/audio/hdaudio/hdactl.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/hdactl.h	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -36,6 +36,13 @@
 #define HDACTL_H
 
+#include <fibril_synch.h>
 #include <stdbool.h>
 #include "hdaudio.h"
+#include "spec/regs.h"
+
+enum {
+	/** Software response buffer size in entries */
+	softrb_entries = 128
+};
 
 typedef struct hda_ctl {
@@ -54,9 +61,21 @@
 	size_t rirb_rp;
 
+	fibril_mutex_t solrb_lock;
+	fibril_condvar_t solrb_cv;
+	hda_rirb_entry_t solrb[softrb_entries];
+	size_t solrb_rp;
+	size_t solrb_wp;
+
+	hda_rirb_entry_t unsolrb[softrb_entries];
+	size_t unsolrb_rp;
+	size_t unsolrb_wp;
+
 	struct hda_codec *codec;
+	struct hda *hda;
 } hda_ctl_t;
 
 extern hda_ctl_t *hda_ctl_init(hda_t *);
 extern void hda_ctl_fini(hda_ctl_t *);
+extern void hda_ctl_interrupt(hda_ctl_t *);
 extern int hda_cmd(hda_t *, uint32_t, uint32_t *);
 
Index: uspace/drv/audio/hdaudio/hdaudio.c
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/hdaudio.c	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -34,4 +34,5 @@
 
 #include <assert.h>
+#include <bitops.h>
 #include <ddi.h>
 #include <device/hw_res_parsed.h>
@@ -40,4 +41,5 @@
 #include <str_error.h>
 #include <ddf/driver.h>
+#include <ddf/interrupt.h>
 #include <ddf/log.h>
 
@@ -53,4 +55,6 @@
 static int hda_fun_online(ddf_fun_t *fun);
 static int hda_fun_offline(ddf_fun_t *fun);
+
+static void hdaudio_interrupt(ddf_dev_t *, ipc_callid_t, ipc_call_t *);
 
 static driver_ops_t driver_ops = {
@@ -67,4 +71,45 @@
 };
 
+irq_pio_range_t hdaudio_irq_pio_ranges[] = {
+	{
+		.base = 0,
+		.size = 8192
+	}
+};
+
+irq_cmd_t hdaudio_irq_commands[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_AND,
+		.value = BIT_V(uint8_t, rirbsts_intfl),
+		.srcarg = 2,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_WRITE_8,
+		.addr = NULL,
+		.value = BIT_V(uint8_t, rirbsts_intfl),
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+irq_code_t hdaudio_irq_code = {
+	.rangecount = sizeof(hdaudio_irq_pio_ranges) / sizeof(irq_pio_range_t),
+	.ranges = hdaudio_irq_pio_ranges,
+	.cmdcount = sizeof(hdaudio_irq_commands) / sizeof(irq_cmd_t),
+	.cmds = hdaudio_irq_commands
+};
+
 static int hda_dev_add(ddf_dev_t *dev)
 {
@@ -110,4 +155,7 @@
 	hda->rwsize = RNGSZ(res.mem_ranges.ranges[0]);
 
+	ddf_msg(LVL_NOTE, "hda reg base: %" PRIx64,
+	     RNGABS(res.mem_ranges.ranges[0]));
+
 	if (hda->rwsize < sizeof(hda_regs_t)) {
 		ddf_msg(LVL_ERROR, "Memory range is too small.");
@@ -124,4 +172,28 @@
 
 	hda->regs = (hda_regs_t *)regs;
+
+	ddf_msg(LVL_NOTE, "IRQs: %d", res.irqs.count);
+	if (res.irqs.count != 1) {
+		ddf_msg(LVL_ERROR, "Unexpected IRQ count %d (!= 1)",
+		    res.irqs.count);
+		goto error;
+	}
+	ddf_msg(LVL_NOTE, "interrupt no: %d", res.irqs.irqs[0]);
+
+	hda_regs_t *rphys = (hda_regs_t *)(uintptr_t)hda->rwbase;
+	hdaudio_irq_pio_ranges[0].base = (uintptr_t)hda->rwbase;
+	hdaudio_irq_commands[0].addr = (void *)&rphys->rirbsts;
+	hdaudio_irq_commands[3].addr = (void *)&rphys->rirbsts;
+	ddf_msg(LVL_NOTE, "range0.base=%x", hdaudio_irq_pio_ranges[0].base);
+	ddf_msg(LVL_NOTE, "cmd0.addr=%p", hdaudio_irq_commands[0].addr);
+	ddf_msg(LVL_NOTE, "cmd3.addr=%p", hdaudio_irq_commands[3].addr);
+
+	rc = register_interrupt_handler(dev, res.irqs.irqs[0],
+	    hdaudio_interrupt, &hdaudio_irq_code);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed registering interrupt handler. (%d)",
+		    rc);
+		goto error;
+	}
 
 	if (hda_ctl_init(hda) == NULL) {
@@ -157,4 +229,5 @@
 	}
 
+	ddf_msg(LVL_NOTE, "Failing hda_dev_add() -> %d", rc);
 	return rc;
 }
@@ -208,4 +281,13 @@
 }
 
+static void hdaudio_interrupt(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	hda_t *hda = (hda_t *)ddf_dev_data_get(dev);
+
+	ddf_msg(LVL_NOTE, "## interrupt ##");
+	hda_ctl_interrupt(hda->ctl);
+}
+
 int main(int argc, char *argv[])
 {
Index: uspace/drv/audio/hdaudio/hdaudio.h
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/hdaudio.h	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -43,5 +43,5 @@
 
 /** High Definition Audio driver instance */
-typedef struct {
+typedef struct hda {
 	async_sess_t *parent_sess;
 	ddf_fun_t *fun_a;
Index: uspace/drv/audio/hdaudio/hdaudio.ma
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.ma	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/hdaudio.ma	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -1,2 +1,3 @@
 10 pci/ven=1002&dev=4383
+10 pci/ven=8086&dev=1e20
 10 pci/ven=8086&dev=2668
Index: uspace/drv/audio/hdaudio/spec/regs.h
===================================================================
--- uspace/drv/audio/hdaudio/spec/regs.h	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/spec/regs.h	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -196,4 +196,13 @@
 
 typedef enum {
+	/** Global Interrupt Enable */
+	intctl_gie = 31,
+	/** Controller Interrupt Enable */
+	intctl_cie = 30,
+	/** Stream Interrupt Enable */
+	intctl_sie = 29
+} hda_intctl_bits_t;
+
+typedef enum {
 	/** CORB Read Pointer Reset */
 	corbrp_rst = 15,
@@ -248,4 +257,11 @@
 
 typedef enum {
+	/** Response Overrun Interrupt Status */
+	rirbsts_ois = 2,
+	/** Response Interrupt */
+	rirbsts_intfl = 0
+} hda_rirbsts_bits_t;
+
+typedef enum {
 	/** RIRB Size Capability (H) */
 	rirbsize_cap_h = 7,
Index: uspace/drv/audio/hdaudio/stream.c
===================================================================
--- uspace/drv/audio/hdaudio/stream.c	(revision 1412a184ceec2c69412551bb79d466c6637196ed)
+++ uspace/drv/audio/hdaudio/stream.c	(revision a333b7f4765719ce076d6da93346ae8130250dfc)
@@ -175,4 +175,5 @@
 void hda_stream_start(hda_stream_t *stream)
 {
+	ddf_msg(LVL_NOTE, "hda_stream_start()");
 	hda_stream_set_run(stream, true);
 }
