Index: uspace/drv/audio/sb16/Makefile
===================================================================
--- uspace/drv/audio/sb16/Makefile	(revision 3df0f750d5542c7d884412d96aff44b1dca293ea)
+++ uspace/drv/audio/sb16/Makefile	(revision 10f2b34a3816de7c624f0fa0a1fb46cc14d6c5c9)
@@ -42,4 +42,5 @@
 	main.c \
 	mixer.c \
+	mixer_iface.c \
 	sb16.c
 
Index: uspace/drv/audio/sb16/main.c
===================================================================
--- uspace/drv/audio/sb16/main.c	(revision 3df0f750d5542c7d884412d96aff44b1dca293ea)
+++ uspace/drv/audio/sb16/main.c	(revision 10f2b34a3816de7c624f0fa0a1fb46cc14d6c5c9)
@@ -120,5 +120,5 @@
 
 
-	ddf_fun_t *dsp_fun = NULL, *mixer_fun = NULL;
+	ddf_fun_t *dsp_fun = NULL;
 #define CHECK_RET_UNREG_DEST_RETURN(ret, msg...) \
 if (ret != EOK) { \
@@ -126,6 +126,4 @@
 	if (dsp_fun) \
 		ddf_fun_destroy(dsp_fun); \
-	if (mixer_fun) \
-		ddf_fun_destroy(mixer_fun); \
 	unregister_interrupt_handler(device, irq); \
 	return ret; \
@@ -139,9 +137,4 @@
 	ret = dsp_fun ? EOK : ENOMEM;
 	CHECK_RET_UNREG_DEST_RETURN(ret, "Failed to create dsp function.");
-
-
-	mixer_fun = ddf_fun_create(device, fun_exposed, "mixer");
-	ret = dsp_fun ? EOK : ENOMEM;
-	CHECK_RET_UNREG_DEST_RETURN(ret, "Failed to create mixer function.");
 
 	ret = sb16_init_sb16(
@@ -154,10 +147,5 @@
 	    "Failed to bind dsp function: %s.\n", str_error(ret));
 
-	ret = ddf_fun_bind(mixer_fun);
-	CHECK_RET_UNREG_DEST_RETURN(ret,
-	    "Failed to bind mixer function: %s.\n", str_error(ret));
-
 	/* Everything's OK assign driver_data. */
-	mixer_fun->driver_data = soft_state;
 	dsp_fun->driver_data = soft_state;
 
Index: uspace/drv/audio/sb16/mixer_iface.c
===================================================================
--- uspace/drv/audio/sb16/mixer_iface.c	(revision 10f2b34a3816de7c624f0fa0a1fb46cc14d6c5c9)
+++ uspace/drv/audio/sb16/mixer_iface.c	(revision 10f2b34a3816de7c624f0fa0a1fb46cc14d6c5c9)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvaudiosb16
+ * @{
+ */
+/** @file
+ * Main routines of Creative Labs SoundBlaster 16 driver
+ */
+
+#include <errno.h>
+#include <audio_mixer_iface.h>
+
+#include "mixer.h"
+
+static int sb_get_info(ddf_fun_t *fun, const char** name, unsigned *items)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	const sb_mixer_t *mixer = fun->driver_data;
+	if (name)
+		*name = sb_mixer_type_str(mixer->type);
+	if (items)
+		*items = sb_mixer_get_control_item_count(mixer);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int sb_get_item_info(ddf_fun_t *fun, unsigned item, const char** name,
+    unsigned *channels)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	const sb_mixer_t *mixer = fun->driver_data;
+	return
+	    sb_mixer_get_control_item_info(mixer, item, name, channels);
+}
+/*----------------------------------------------------------------------------*/
+static int sb_get_channel_info(ddf_fun_t *fun, unsigned item, unsigned channel,
+    const char** name, unsigned *levels)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	const sb_mixer_t *mixer = fun->driver_data;
+	return sb_mixer_get_channel_info(mixer, item, channel, name, levels);
+}
+/*----------------------------------------------------------------------------*/
+static int sb_channel_mute_set(ddf_fun_t *fun, unsigned item, unsigned channel,
+    bool mute)
+{
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+static int sb_channel_mute_get(ddf_fun_t *fun, unsigned item, unsigned channel,
+    bool *mute)
+{
+	*mute = false;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int sb_channel_volume_set(ddf_fun_t *fun, unsigned item, unsigned channel,
+    unsigned volume)
+{
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+static int sb_channel_volume_get(ddf_fun_t *fun, unsigned item, unsigned channel,
+    unsigned *level, unsigned *max)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	const sb_mixer_t *mixer = fun->driver_data;
+	unsigned levels;
+	const int ret =
+	    sb_mixer_get_channel_info(mixer, item, channel, NULL, &levels);
+	if (ret == EOK && max)
+		*max = --levels;
+	if (ret == EOK && level)
+		*level = sb_mixer_get_volume_level(mixer, item, channel);
+
+	return ret;
+}
+
+audio_mixer_iface_t sb_mixer_iface = {
+	.get_info = sb_get_info,
+	.get_item_info = sb_get_item_info,
+	.get_channel_info = sb_get_channel_info,
+
+	.channel_mute_set = sb_channel_mute_set,
+	.channel_mute_get = sb_channel_mute_get,
+
+	.channel_volume_set = sb_channel_volume_set,
+	.channel_volume_get = sb_channel_volume_get,
+
+};
+/**
+ * @}
+ */
Index: uspace/drv/audio/sb16/sb16.c
===================================================================
--- uspace/drv/audio/sb16/sb16.c	(revision 3df0f750d5542c7d884412d96aff44b1dca293ea)
+++ uspace/drv/audio/sb16/sb16.c	(revision 10f2b34a3816de7c624f0fa0a1fb46cc14d6c5c9)
@@ -29,4 +29,5 @@
 #include <errno.h>
 #include <str_error.h>
+#include <audio_mixer_iface.h>
 
 #include "beep.h"
@@ -35,4 +36,10 @@
 #include "dsp.h"
 #include "sb16.h"
+
+extern audio_mixer_iface_t sb_mixer_iface;
+
+static ddf_dev_ops_t sb_mixer_ops = {
+	.interfaces[AUDIO_MIXER_IFACE] = &sb_mixer_iface,
+};
 
 /* ISA interrupts should be edge-triggered so there should be no need for
@@ -85,4 +92,9 @@
 	    sb->dsp.version.major, sb->dsp.version.minor);
 
+	ddf_fun_t *mixer_fun = ddf_fun_create(dev, fun_exposed, "mixer");
+	if (!mixer_fun) {
+		ddf_log_error("Failed to create mixer function.\n");
+		return ENOMEM;
+	}
 	ret = sb_mixer_init(&sb->mixer, sb->regs, mixer_type);
 	if (ret != EOK) {
@@ -91,6 +103,18 @@
 		return ret;
 	}
+
 	ddf_log_note("Initialized mixer: %s.\n",
 	    sb_mixer_type_str(sb->mixer.type));
+	mixer_fun->driver_data = &sb->mixer;
+	mixer_fun->ops = &sb_mixer_ops;
+
+	ret = ddf_fun_bind(mixer_fun);
+	if (ret != EOK) {
+		ddf_log_error(
+		    "Failed to bind mixer function: %s.\n", str_error(ret));
+		mixer_fun->driver_data = NULL;
+		ddf_fun_destroy(mixer_fun);
+		return ret;
+	}
 
 	ddf_log_note("Playing startup sound.\n");
