Index: uspace/drv/audio/sb16/dsp.c
===================================================================
--- uspace/drv/audio/sb16/dsp.c	(revision 018ab5018108207fc0601a6f793a0b0bb0a6995c)
+++ uspace/drv/audio/sb16/dsp.c	(revision fb6c98fec617c3dbf8d6c2b59023fb17187fbc23)
@@ -62,4 +62,29 @@
 #define AUTO_DMA_MODE
 
+static inline const char * dsp_state_to_str(dsp_state_t state)
+{
+	static const char* state_names[] = {
+		[DSP_PLAYBACK_ACTIVE_EVENTS] = "PLAYBACK w/ EVENTS",
+		[DSP_CAPTURE_ACTIVE_EVENTS] = "CAPTURE w/o ACTIVE",
+		[DSP_PLAYBACK_NOEVENTS] = "PLAYBACK w/. EVENTS",
+		[DSP_CAPTURE_NOEVENTS] = "CAPTURE w/o EVENTS",
+		[DSP_STOPPED] = "STOPPED",
+		[DSP_READY] = "READY",
+		[DSP_NO_BUFFER] = "NO BUFFER",
+	};
+	if (state < (sizeof(state_names) / sizeof(state_names[0])))
+		return state_names[state];
+	return "UNKNOWN";
+}
+
+
+static inline void sb_dsp_change_state(sb_dsp_t *dsp, dsp_state_t state)
+{
+	assert(dsp);
+	ddf_log_verbose("Changing state from %s to %s",
+	    dsp_state_to_str(dsp->state), dsp_state_to_str(state));
+	dsp->state = state;
+}
+
 static inline int sb_dsp_read(sb_dsp_t *dsp, uint8_t *data)
 {
@@ -162,12 +187,4 @@
 }
 
-static inline void sb_clear_buffer(sb_dsp_t *dsp)
-{
-	assert(dsp);
-	dmamem_unmap_anonymous(dsp->buffer.data);
-	dsp->buffer.data = NULL;
-	dsp->buffer.size = 0;
-}
-
 static inline size_t sample_count(pcm_sample_format_t format, size_t byte_count)
 {
@@ -185,6 +202,5 @@
 	dsp->event_exchange = NULL;
 	dsp->sb_dev = dev;
-	dsp->status = DSP_STOPPED;
-	dsp->ignore_interrupts = false;
+	dsp->state = DSP_NO_BUFFER;
 	sb_dsp_reset(dsp);
 	/* "DSP takes about 100 microseconds to initialize itself" */
@@ -213,39 +229,27 @@
 	assert(dsp);
 
-#ifndef AUTO_DMA_MODE
-	if (dsp->status == DSP_PLAYBACK) {
-		sb_dsp_start_active(dsp, SINGLE_DMA_16B_DA);
-	}
-
-	if (dsp->status == DSP_CAPTURE) {
-		sb_dsp_start_active(dsp, SINGLE_DMA_16B_AD);
-	}
-#endif
-
-	if (dsp->ignore_interrupts)
-		return;
-
 	dsp->active.frame_count +=
 	    dsp->active.samples / ((dsp->active.mode & DSP_MODE_STEREO) ? 2 : 1);
 
-	if (dsp->event_exchange) {
-		switch (dsp->status) {
-		case DSP_PLAYBACK:
-			async_msg_1(dsp->event_exchange,
-			    PCM_EVENT_FRAMES_PLAYED, dsp->active.frame_count);
-			break;
-		case DSP_CAPTURE:
-			async_msg_1(dsp->event_exchange,
-			    PCM_EVENT_FRAMES_CAPTURED, dsp->active.frame_count);
-			break;
-		default:
-		case DSP_STOPPED:
-			ddf_log_warning("Interrupt while DSP stopped and "
-			    "event exchange present. Terminating exchange");
-			async_exchange_end(dsp->event_exchange);
-			dsp->event_exchange = NULL;
-		}
-	} else {
-		ddf_log_warning("Interrupt with no event consumer.");
+	switch (dsp->state)
+	{
+	case DSP_PLAYBACK_ACTIVE_EVENTS:
+		async_msg_1(dsp->event_exchange,
+		    PCM_EVENT_FRAMES_PLAYED, dsp->active.frame_count);
+	case DSP_PLAYBACK_NOEVENTS:
+#ifndef AUTO_DMA_MODE
+	sb_dsp_start_active(dsp, SINGLE_DMA_16B_DA);
+#endif
+		break;
+	case DSP_CAPTURE_ACTIVE_EVENTS:
+		async_msg_1(dsp->event_exchange,
+		    PCM_EVENT_FRAMES_CAPTURED, dsp->active.frame_count);
+	case DSP_CAPTURE_NOEVENTS:
+#ifndef AUTO_DMA_MODE
+	sb_dsp_start_active(dsp, SINGLE_DMA_16B_DA);
+#endif
+		break;
+	default:
+		ddf_log_warning("Interrupt while DSP not active");
 	}
 }
@@ -273,7 +277,8 @@
 int sb_dsp_get_buffer_position(sb_dsp_t *dsp, size_t *pos)
 {
-	if (!dsp->buffer.data)
+	if (dsp->state == DSP_NO_BUFFER)
 		return ENOENT;
 
+	assert(dsp->buffer.data);
 	async_sess_t *sess = devman_parent_device_connect(EXCHANGE_ATOMIC,
 	    dsp->sb_dev->handle, IPC_FLAG_BLOCKING);
@@ -314,4 +319,21 @@
 }
 
+int sb_dsp_set_event_session(sb_dsp_t *dsp, async_sess_t *session)
+{
+	assert(dsp);
+	if (dsp->event_session)
+		return EBUSY;
+	dsp->event_session = session;
+	ddf_log_debug("Set event session to %p.", session);
+	return EOK;
+}
+
+async_sess_t * sb_dsp_get_event_session(sb_dsp_t *dsp)
+{
+	assert(dsp);
+	ddf_log_debug("Get event session: %p.", dsp->event_session);
+	return dsp->event_session;
+}
+
 int sb_dsp_get_buffer(sb_dsp_t *dsp, void **buffer, size_t *size)
 {
@@ -321,6 +343,7 @@
 	/* buffer is already setup by for someone, refuse to work until
 	 * it's released */
-	if (dsp->buffer.data)
+	if (dsp->state != DSP_NO_BUFFER)
 		return EBUSY;
+	assert(dsp->buffer.data == NULL);
 
 	const int ret = sb_setup_buffer(dsp, *size);
@@ -333,35 +356,20 @@
 		if (size)
 			*size = dsp->buffer.size;
+		sb_dsp_change_state(dsp, DSP_READY);
 	}
 	return ret;
 }
 
-int sb_dsp_set_event_session(sb_dsp_t *dsp, async_sess_t *session)
-{
-	assert(dsp);
-	if (dsp->event_session)
-		return EBUSY;
-	dsp->event_session = session;
-	ddf_log_debug("Set event session to %p.", session);
-	return EOK;
-}
-
-async_sess_t * sb_dsp_get_event_session(sb_dsp_t *dsp)
-{
-	assert(dsp);
-	ddf_log_debug("Get event session: %p.", dsp->event_session);
-	return dsp->event_session;
-}
-
 int sb_dsp_release_buffer(sb_dsp_t *dsp)
 {
 	assert(dsp);
-	sb_clear_buffer(dsp);
-	async_exchange_end(dsp->event_exchange);
-	dsp->event_exchange = NULL;
-	if (dsp->event_session)
-		async_hangup(dsp->event_session);
-	dsp->event_session = NULL;
+	if (dsp->state != DSP_READY && dsp->state != DSP_STOPPED)
+		return EINVAL;
+	assert(dsp->buffer.data);
+	dmamem_unmap_anonymous(dsp->buffer.data);
+	dsp->buffer.data = NULL;
+	dsp->buffer.size = 0;
 	ddf_log_debug("DSP buffer released.");
+	sb_dsp_change_state(dsp, DSP_NO_BUFFER);
 	return EOK;
 }
@@ -388,5 +396,4 @@
 		if (!dsp->event_exchange)
 			return ENOMEM;
-		dsp->ignore_interrupts = false;
 	}
 
@@ -409,5 +416,6 @@
 	    sampling_rate / (dsp->active.samples * channels));
 
-	dsp->status = DSP_PLAYBACK;
+	sb_dsp_change_state(dsp,
+	    frames ? DSP_PLAYBACK_ACTIVE_EVENTS : DSP_PLAYBACK_NOEVENTS);
 
 	return EOK;
@@ -422,4 +430,5 @@
 	async_exchange_end(dsp->event_exchange);
 	dsp->event_exchange = NULL;
+	sb_dsp_change_state(dsp, DSP_STOPPED);
 	return EOK;
 }
@@ -445,5 +454,4 @@
 		if (!dsp->event_exchange)
 			return ENOMEM;
-		dsp->ignore_interrupts = false;
 	}
 
@@ -465,6 +473,6 @@
 	    "(~1/%u sec)", dsp->active.samples,
 	    sampling_rate / (dsp->active.samples * channels));
-	dsp->status = DSP_CAPTURE;
-
+	sb_dsp_change_state(dsp,
+	    frames ? DSP_CAPTURE_ACTIVE_EVENTS : DSP_CAPTURE_NOEVENTS);
 	return EOK;
 }
@@ -478,4 +486,5 @@
 	async_exchange_end(dsp->event_exchange);
 	dsp->event_exchange = NULL;
+	sb_dsp_change_state(dsp, DSP_STOPPED);
 	return EOK;
 }
Index: uspace/drv/audio/sb16/dsp.h
===================================================================
--- uspace/drv/audio/sb16/dsp.h	(revision 018ab5018108207fc0601a6f793a0b0bb0a6995c)
+++ uspace/drv/audio/sb16/dsp.h	(revision fb6c98fec617c3dbf8d6c2b59023fb17187fbc23)
@@ -42,4 +42,13 @@
 
 #include "registers.h"
+typedef enum {
+	DSP_PLAYBACK_ACTIVE_EVENTS,
+	DSP_CAPTURE_ACTIVE_EVENTS,
+	DSP_PLAYBACK_NOEVENTS,
+	DSP_CAPTURE_NOEVENTS,
+	DSP_STOPPED,
+	DSP_READY,
+	DSP_NO_BUFFER,
+} dsp_state_t;
 
 typedef struct sb_dsp_t {
@@ -61,9 +70,5 @@
 		unsigned frame_count;
 	} active;
-	enum {
-		DSP_PLAYBACK,
-		DSP_CAPTURE,
-		DSP_STOPPED,
-	} status;
+	dsp_state_t state;
 	async_sess_t *event_session;
 	async_exch_t *event_exchange;
