Index: uspace/drv/audio/sb16/dsp.c
===================================================================
--- uspace/drv/audio/sb16/dsp.c	(revision f14e6ea74076aac209e1a2569d96de43527101f8)
+++ uspace/drv/audio/sb16/dsp.c	(revision dce7e416c651e4c6f2d7d6345fa3b88ad8ab24fb)
@@ -43,4 +43,5 @@
 
 #define BUFFER_SIZE (PAGE_SIZE / 4)
+#define PLAY_BLOCK_SIZE (BUFFER_SIZE / 2)
 
 #ifndef DSP_RETRY_COUNT
@@ -110,7 +111,8 @@
 	const int ret = dma_setup_channel(SB_DMA_CHAN_16, pa, BUFFER_SIZE);
 	if (ret == EOK) {
-		dsp->buffer.buffer_data = buffer;
-		dsp->buffer.buffer_position = buffer;
-		dsp->buffer.buffer_size = BUFFER_SIZE;
+		dsp->buffer.data = buffer;
+		dsp->buffer.position = buffer;
+		dsp->buffer.size = BUFFER_SIZE;
+		memset(buffer, 0x8f, BUFFER_SIZE);
 		dma_prepare_channel(SB_DMA_CHAN_16, false, true, BLOCK_DMA);
 		/* Set 8bit channel */
@@ -130,8 +132,8 @@
 static inline void sb_clear_buffer(sb_dsp_t *dsp)
 {
-	free24(dsp->buffer.buffer_data);
-	dsp->buffer.buffer_data = NULL;
-	dsp->buffer.buffer_position = NULL;
-	dsp->buffer.buffer_size = 0;
+	free24(dsp->buffer.data);
+	dsp->buffer.data = NULL;
+	dsp->buffer.position = NULL;
+	dsp->buffer.size = 0;
 }
 /*----------------------------------------------------------------------------*/
@@ -172,4 +174,38 @@
 	/* ACK dma8 transfer interrupt */
 	pio_read_8(&dsp->regs->dsp_read_status);
+
+	static size_t interrupt_count = 0;
+
+	const size_t remain_size = dsp->playing.size -
+	    (dsp->playing.position - dsp->playing.data);
+
+	ddf_log_note("Interrupt count %zu, remaining: %zu.\n",
+	    ++interrupt_count, remain_size);
+	if (remain_size == 0) {
+		ddf_log_note("Nothing more to play");
+		sb_dsp_write(dsp, DMA_16B_EXIT);
+		sb_clear_buffer(dsp);
+		return;
+	}
+	if (remain_size < PLAY_BLOCK_SIZE) {
+		ddf_log_note("Last %zu bytes to play.\n", remain_size);
+		/* This is the last block */
+		memcpy(dsp->buffer.position, dsp->playing.position, remain_size);
+		dsp->playing.position += remain_size;
+		dsp->buffer.position += remain_size;
+		sb_dsp_write(dsp, SINGLE_DMA_16B_DA);
+		sb_dsp_write(dsp, dsp->playing.mode);
+		sb_dsp_write(dsp, remain_size & 0xff);
+		sb_dsp_write(dsp, remain_size >> 8);
+		return;
+	}
+	ddf_log_note("Playing full block.\n");
+	memcpy(dsp->buffer.position, dsp->playing.position, PLAY_BLOCK_SIZE);
+	dsp->playing.position += PLAY_BLOCK_SIZE;
+	dsp->buffer.position += PLAY_BLOCK_SIZE;
+	/* Wrap around */
+	if (dsp->buffer.position == (dsp->buffer.data + dsp->buffer.size))
+		dsp->buffer.position = dsp->buffer.data;
+
 }
 /*----------------------------------------------------------------------------*/
@@ -203,7 +239,31 @@
 		return ENOTSUP;
 
+	ddf_log_fatal("Buffer prepare.\n");
 	const int ret = sb_setup_buffer(dsp);
-
-	return ret;
+	if (ret != EOK)
+		return ret;
+
+	const size_t play_size =
+	    size < PLAY_BLOCK_SIZE ? size : PLAY_BLOCK_SIZE;
+	memcpy(dsp->buffer.data, dsp->playing.data, play_size);
+
+	ddf_log_note("Playing sound: %zu(%zu) bytes.\n", play_size, size);
+
+	dsp->playing.data = data;
+	dsp->playing.position = data + play_size;
+	dsp->playing.size = size;
+	dsp->playing.mode =
+	    (bit_depth == 16 ? 0x10 : 0) | (channels == 2 ? 0x20 : 0);
+
+	sb_dsp_write(dsp, SET_SAMPLING_RATE_OUTPUT);
+	sb_dsp_write(dsp, sampling_rate >> 8);
+	sb_dsp_write(dsp, sampling_rate & 0xff);
+
+	sb_dsp_write(dsp, AUTO_DMA_16B_DA_FIFO);
+	sb_dsp_write(dsp, dsp->playing.mode);
+	sb_dsp_write(dsp, play_size & 0xff);
+	sb_dsp_write(dsp, play_size >> 8);
+
+	return EOK;
 }
 /**
Index: uspace/drv/audio/sb16/dsp.h
===================================================================
--- uspace/drv/audio/sb16/dsp.h	(revision f14e6ea74076aac209e1a2569d96de43527101f8)
+++ uspace/drv/audio/sb16/dsp.h	(revision dce7e416c651e4c6f2d7d6345fa3b88ad8ab24fb)
@@ -47,8 +47,14 @@
 	} version;
 	struct {
-		uint8_t *buffer_data;
-		uint8_t *buffer_position;
-		size_t buffer_size;
+		uint8_t *data;
+		uint8_t *position;
+		size_t size;
 	} buffer;
+	struct {
+		const uint8_t *data;
+		const uint8_t *position;
+		size_t size;
+		uint8_t mode;
+	} playing;
 } sb_dsp_t;
 
Index: uspace/drv/audio/sb16/sb16.c
===================================================================
--- uspace/drv/audio/sb16/sb16.c	(revision f14e6ea74076aac209e1a2569d96de43527101f8)
+++ uspace/drv/audio/sb16/sb16.c	(revision dce7e416c651e4c6f2d7d6345fa3b88ad8ab24fb)
@@ -103,5 +103,4 @@
 {
 	assert(drv);
-	ddf_log_note("SB16 interrupt.\n");
 	/* The acknowledgment of interrupts on DSP version 4.xx is different;
 	 * It can contain MPU-401 indicator and DMA16 transfers are acked
@@ -110,11 +109,12 @@
 		pio_write_8(&drv->regs->mixer_address, MIXER_IRQ_ADDRESS);
 		const uint8_t irq_mask = pio_read_8(&drv->regs->mixer_data);
-		ddf_log_note("SB16 IRQ mask %hhx.\n", irq_mask);
+		ddf_log_debug("SB16 IRQ mask %hhx.\n", irq_mask);
 		/* Third bit is MPU-401 interrupt */
 		if (irq_mask & 0x4) {
 			return;
 		}
+	} else {
+		ddf_log_debug("SB16 interrupt.\n");
 	}
 	sb_dsp_interrupt(&drv->dsp);
-
 }
