79245: [PATCH 2/9] wineoss.drv: Remove wave; mixer; and dsound driver code

buildbot at kegel.com buildbot at kegel.com
Sun Sep 25 22:41:30 CDT 2011


This is an experimental automated build and test service.
Please feel free to ignore this email while we work the kinks out.

For more info about this message, see http://wiki.winehq.org/BuildBot

The Buildbot has detected a failed build on builder runtests-heaptest while building Wine.
Full details are available at: http://buildbot.kegel.com/builders/runtests-heaptest/builds/2 (though maybe not for long, as I'm still reinstalling the buildbot periodically while experimenting)
BUILD FAILED: failed shell_3

Errors:
alarum: failed command was ../../../wine comctl32_test.exe.so treeview.c 
treeview.c:1512: Test failed: got 0xd18a
treeview.c:1518: Test failed: got 0xd18a
make: *** [treeview.ok] Error 2
* Call to xpconnect wrapped JSObject produced this error:  *
* Call to xpconnect wrapped JSObject produced this error:  *
alarum: failed command was ../../../wine oleaut32_test.exe.so olepicture.c 
fixme:ole:OleLoadPictureEx (0x11d3c0,60,1,{7bf80980-bf32-101a-8bbb-00aa00300cab},x=100,y=100,f=0,0x34fcac), partially implemented.
fixme:ole:OleLoadPictureEx (0x11c368,50,1,{7bf80980-bf32-101a-8bbb-00aa00300cab},x=100,y=100,f=0,0x34fcd8), partially implemented.
fixme:ole:OLEPictureImpl_Load Unknown magic 0001, 50 read bytes:
01 00 09 00 00 03 19 00 01 00 
09 00 00 03 19 00 00 00 00 00 
0d 00 00 00 00 00 0d 00 00 00 
32 0a 16 00 0b 00 04 00 00 00 
54 65 73 74 03 00 05 00 08 00 
0c 00 03 00 00 00 00 00 
err:ole:OleLoadPictureEx IPersistStream_Load failed
fixme:ole:OleLoadPictureEx (0x11c4a8,244,1,{7bf80980-bf32-101a-8bbb-00aa00300cab},x=10,y=10,f=0,0x34fcb0), partially implemented.
err:ole:OLEPictureImpl_Invoke riid was {7bf80981-bf32-101a-8bbb-00aa00300cab} instead of IID_NULL
err:ole:OLEPictureImpl_Invoke riid was {00000000-0000-0000-c000-000000000046} instead of IID_NULL
err:ole:OLEPictureImpl_Invoke param count for DISPATCH_PROPERTYPUT was 0 instead of 1
err:ole:OLEPictureImpl_Invoke null pDispParams not allowed
err:ole:OLEPictureImpl_Invoke null pDispParams not allowed
err:ole:OLEPictureImpl_Invoke null pDispParams not allowed
err:ole:OLEPictureImpl_Invoke invalid dispid 0x2 or wFlags 0x1
err:ole:OLEPictureImpl_Invoke invalid dispid 0xdeadbeef or wFlags 0x2
err:ole:OLEPictureImpl_Invoke param count for DISPATCH_PROPERTYGET was 1 instead of 0
err:ole:OLEPictureImpl_Invoke param count for DISPATCH_PROPERTYGET was 1 instead of 0
fixme:ole:OLEPictureImpl_Render Not quite correct implementation of rendering icons...
olepicture.c:696: Test failed: Color at 5,5 should have changed, but still was 0x30F8A7
make: *** [olepicture.ok] Error 1

-------------- next part --------------
From: Andrew Eikum <aeikum at codeweavers.com>
Subject: [PATCH 1/9] winealsa.drv: Remove wave, mixer, and dsound driver code
Message-Id: <20110923200351.GC6146 at foghorn.codeweavers.com>
Date: Fri, 23 Sep 2011 15:03:51 -0500


Here it is. The first four patches remove hwaccel support, making
Emulation mode the only option. Then we reimplement Emulation mode
with MMDevAPI instead of WinMM. The goal was to make as few functional
changes as possible in this transition. Carefully cleaning up the mess
that is DSound can happen after.
---
 dlls/winealsa.drv/Makefile.in       |   11 +-
 dlls/winealsa.drv/alsa.c            |  755 ----------------
 dlls/winealsa.drv/alsa.h            |  197 -----
 dlls/winealsa.drv/dscapture.c       | 1095 ------------------------
 dlls/winealsa.drv/dsoutput.c        |  962 ---------------------
 dlls/winealsa.drv/midi.c            |   30 +-
 dlls/winealsa.drv/mixer.c           | 1612 -----------------------------------
 dlls/winealsa.drv/mmdevdrv.c        |   46 +-
 dlls/winealsa.drv/wavein.c          |  780 -----------------
 dlls/winealsa.drv/waveinit.c        | 1011 ----------------------
 dlls/winealsa.drv/waveout.c         | 1182 -------------------------
 dlls/winealsa.drv/winealsa.drv.spec |    3 -
 12 files changed, 74 insertions(+), 7610 deletions(-)
 delete mode 100644 dlls/winealsa.drv/alsa.c
 delete mode 100644 dlls/winealsa.drv/alsa.h
 delete mode 100644 dlls/winealsa.drv/dscapture.c
 delete mode 100644 dlls/winealsa.drv/dsoutput.c
 delete mode 100644 dlls/winealsa.drv/mixer.c
 delete mode 100644 dlls/winealsa.drv/wavein.c
 delete mode 100644 dlls/winealsa.drv/waveinit.c
 delete mode 100644 dlls/winealsa.drv/waveout.c

diff --git a/dlls/winealsa.drv/Makefile.in b/dlls/winealsa.drv/Makefile.in
index 7a74c36..c5f8cde 100644
--- a/dlls/winealsa.drv/Makefile.in
+++ b/dlls/winealsa.drv/Makefile.in
@@ -1,16 +1,9 @@
 MODULE    = winealsa.drv
-IMPORTS   = dxguid uuid winmm ole32 user32 advapi32
+IMPORTS   = uuid winmm ole32
 EXTRALIBS = @ALSALIBS@
 
 C_SRCS = \
-	alsa.c \
-	dscapture.c \
-	dsoutput.c \
 	midi.c \
-	mixer.c \
-	mmdevdrv.c \
-	wavein.c \
-	waveinit.c \
-	waveout.c
+	mmdevdrv.c
 
 @MAKE_DLL_RULES@
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
deleted file mode 100644
index ccb5064..0000000
--- a/dlls/winealsa.drv/alsa.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Wine Driver for ALSA
- *
- * Copyright	2002 Eric Pouech
- * Copyright	2006 Jaroslav Kysela
- * Copyright	2007 Maarten Lankhorst
- *
- * This file has a few shared generic subroutines shared among the alsa
- * implementation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-
-#include <stdarg.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "winerror.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "ks.h"
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-#include "alsa.h"
-
-#include "initguid.h"
-#include "ksmedia.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(alsa);
-/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
-#define USE_PIPE_SYNC
-
-#ifdef USE_PIPE_SYNC
-#define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
-#define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
-#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
-#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
-#define RESET_OMR(omr) do { } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
-       pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
-#else
-#define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
-#define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
-#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
-#define CLEAR_OMR(omr) do { } while (0)
-#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
-#endif
-
-#define ALSA_RING_BUFFER_INCREMENT      64
-
-/******************************************************************
- *		ALSA_InitRingMessage
- *
- * Initialize the ring of messages for passing between driver's caller and playback/record
- * thread
- */
-int ALSA_InitRingMessage(ALSA_MSG_RING* omr)
-{
-    omr->msg_toget = 0;
-    omr->msg_tosave = 0;
-    INIT_OMR(omr);
-    omr->ring_buffer_size = ALSA_RING_BUFFER_INCREMENT;
-    omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(ALSA_MSG));
-
-    InitializeCriticalSection(&omr->msg_crst);
-    omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_MSG_RING.msg_crst");
-    return 0;
-}
-
-/******************************************************************
- *		ALSA_DestroyRingMessage
- *
- */
-int ALSA_DestroyRingMessage(ALSA_MSG_RING* omr)
-{
-    CLOSE_OMR(omr);
-    HeapFree(GetProcessHeap(),0,omr->messages);
-    omr->ring_buffer_size = 0;
-    omr->msg_crst.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&omr->msg_crst);
-    return 0;
-}
-/******************************************************************
- *		ALSA_ResetRingMessage
- *
- */
-void ALSA_ResetRingMessage(ALSA_MSG_RING* omr)
-{
-    RESET_OMR(omr);
-}
-
-/******************************************************************
- *		ALSA_WaitRingMessage
- *
- */
-void ALSA_WaitRingMessage(ALSA_MSG_RING* omr, DWORD sleep)
-{
-    WAIT_OMR(omr, sleep);
-}
-
-/******************************************************************
- *		ALSA_AddRingMessage
- *
- * Inserts a new message into the ring (should be called from DriverProc derived routines)
- */
-int ALSA_AddRingMessage(ALSA_MSG_RING* omr, enum win_wm_message msg, DWORD_PTR param, BOOL wait)
-{
-    HANDLE	hEvent = NULL;
-
-    EnterCriticalSection(&omr->msg_crst);
-    if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
-    {
-	int old_ring_buffer_size = omr->ring_buffer_size;
-	omr->ring_buffer_size += ALSA_RING_BUFFER_INCREMENT;
-	omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(ALSA_MSG));
-	/* Now we need to rearrange the ring buffer so that the new
-	   buffers just allocated are in between omr->msg_tosave and
-	   omr->msg_toget.
-	*/
-	if (omr->msg_tosave < omr->msg_toget)
-	{
-	    memmove(&(omr->messages[omr->msg_toget + ALSA_RING_BUFFER_INCREMENT]),
-		    &(omr->messages[omr->msg_toget]),
-		    sizeof(ALSA_MSG)*(old_ring_buffer_size - omr->msg_toget)
-		    );
-	    omr->msg_toget += ALSA_RING_BUFFER_INCREMENT;
-	}
-    }
-    if (wait)
-    {
-        hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-        if (!hEvent)
-        {
-            ERR("can't create event !?\n");
-            LeaveCriticalSection(&omr->msg_crst);
-            return 0;
-        }
-        if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->msg_toget].msg != WINE_WM_HEADER)
-            FIXME("two fast messages in the queue!!!! toget = %d(%s), tosave=%d(%s)\n",
-                  omr->msg_toget,ALSA_getCmdString(omr->messages[omr->msg_toget].msg),
-                  omr->msg_tosave,ALSA_getCmdString(omr->messages[omr->msg_tosave].msg));
-
-        /* fast messages have to be added at the start of the queue */
-        omr->msg_toget = (omr->msg_toget + omr->ring_buffer_size - 1) % omr->ring_buffer_size;
-
-        omr->messages[omr->msg_toget].msg = msg;
-        omr->messages[omr->msg_toget].param = param;
-        omr->messages[omr->msg_toget].hEvent = hEvent;
-    }
-    else
-    {
-        omr->messages[omr->msg_tosave].msg = msg;
-        omr->messages[omr->msg_tosave].param = param;
-        omr->messages[omr->msg_tosave].hEvent = NULL;
-        omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
-    }
-    LeaveCriticalSection(&omr->msg_crst);
-    /* signal a new message */
-    SIGNAL_OMR(omr);
-    if (wait)
-    {
-        /* wait for playback/record thread to have processed the message */
-        WaitForSingleObject(hEvent, INFINITE);
-        CloseHandle(hEvent);
-    }
-    return 1;
-}
-
-/******************************************************************
- *		ALSA_RetrieveRingMessage
- *
- * Get a message from the ring. Should be called by the playback/record thread.
- */
-int ALSA_RetrieveRingMessage(ALSA_MSG_RING* omr, enum win_wm_message *msg,
-                             DWORD_PTR *param, HANDLE *hEvent)
-{
-    EnterCriticalSection(&omr->msg_crst);
-
-    if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
-    {
-        LeaveCriticalSection(&omr->msg_crst);
-	return 0;
-    }
-
-    *msg = omr->messages[omr->msg_toget].msg;
-    omr->messages[omr->msg_toget].msg = 0;
-    *param = omr->messages[omr->msg_toget].param;
-    *hEvent = omr->messages[omr->msg_toget].hEvent;
-    omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
-    CLEAR_OMR(omr);
-    LeaveCriticalSection(&omr->msg_crst);
-    return 1;
-}
-
-/*======================================================================*
- *                  Utility functions                                   *
- *======================================================================*/
-
-/* These strings used only for tracing */
-const char * ALSA_getCmdString(enum win_wm_message msg)
-{
-#define MSG_TO_STR(x) case x: return #x
-    switch(msg) {
-    MSG_TO_STR(WINE_WM_PAUSING);
-    MSG_TO_STR(WINE_WM_RESTARTING);
-    MSG_TO_STR(WINE_WM_RESETTING);
-    MSG_TO_STR(WINE_WM_HEADER);
-    MSG_TO_STR(WINE_WM_UPDATE);
-    MSG_TO_STR(WINE_WM_BREAKLOOP);
-    MSG_TO_STR(WINE_WM_CLOSING);
-    MSG_TO_STR(WINE_WM_STARTING);
-    MSG_TO_STR(WINE_WM_STOPPING);
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(0x%08x)", msg);
-}
-
-const char * ALSA_getMessage(UINT msg)
-{
-#define MSG_TO_STR(x) case x: return #x
-    switch(msg) {
-    MSG_TO_STR(DRVM_INIT);
-    MSG_TO_STR(DRVM_EXIT);
-    MSG_TO_STR(DRVM_ENABLE);
-    MSG_TO_STR(DRVM_DISABLE);
-    MSG_TO_STR(WIDM_OPEN);
-    MSG_TO_STR(WIDM_CLOSE);
-    MSG_TO_STR(WIDM_ADDBUFFER);
-    MSG_TO_STR(WIDM_PREPARE);
-    MSG_TO_STR(WIDM_UNPREPARE);
-    MSG_TO_STR(WIDM_GETDEVCAPS);
-    MSG_TO_STR(WIDM_GETNUMDEVS);
-    MSG_TO_STR(WIDM_GETPOS);
-    MSG_TO_STR(WIDM_RESET);
-    MSG_TO_STR(WIDM_START);
-    MSG_TO_STR(WIDM_STOP);
-    MSG_TO_STR(WODM_OPEN);
-    MSG_TO_STR(WODM_CLOSE);
-    MSG_TO_STR(WODM_WRITE);
-    MSG_TO_STR(WODM_PAUSE);
-    MSG_TO_STR(WODM_GETPOS);
-    MSG_TO_STR(WODM_BREAKLOOP);
-    MSG_TO_STR(WODM_PREPARE);
-    MSG_TO_STR(WODM_UNPREPARE);
-    MSG_TO_STR(WODM_GETDEVCAPS);
-    MSG_TO_STR(WODM_GETNUMDEVS);
-    MSG_TO_STR(WODM_GETPITCH);
-    MSG_TO_STR(WODM_SETPITCH);
-    MSG_TO_STR(WODM_GETPLAYBACKRATE);
-    MSG_TO_STR(WODM_SETPLAYBACKRATE);
-    MSG_TO_STR(WODM_GETVOLUME);
-    MSG_TO_STR(WODM_SETVOLUME);
-    MSG_TO_STR(WODM_RESTART);
-    MSG_TO_STR(WODM_RESET);
-    MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
-    MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
-    MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
-    MSG_TO_STR(DRV_QUERYDSOUNDDESC);
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(0x%04x)", msg);
-}
-
-const char * ALSA_getFormat(WORD wFormatTag)
-{
-#define FMT_TO_STR(x) case x: return #x
-    switch(wFormatTag) {
-    FMT_TO_STR(WAVE_FORMAT_PCM);
-    FMT_TO_STR(WAVE_FORMAT_EXTENSIBLE);
-    FMT_TO_STR(WAVE_FORMAT_MULAW);
-    FMT_TO_STR(WAVE_FORMAT_ALAW);
-    FMT_TO_STR(WAVE_FORMAT_ADPCM);
-    }
-#undef FMT_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(0x%04x)", wFormatTag);
-}
-
-/* Allow 1% deviation for sample rates (some ES137x cards) */
-BOOL ALSA_NearMatch(int rate1, int rate2)
-{
-    return (((100 * (rate1 - rate2)) / rate1) == 0);
-}
-
-DWORD ALSA_bytes_to_mmtime(LPMMTIME lpTime, DWORD position, WAVEFORMATPCMEX* format)
-{
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
-          lpTime->wType, format->Format.wBitsPerSample, format->Format.nSamplesPerSec,
-          format->Format.nChannels, format->Format.nAvgBytesPerSec);
-    TRACE("Position in bytes=%u\n", position);
-
-    switch (lpTime->wType) {
-    case TIME_SAMPLES:
-        lpTime->u.sample = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
-        TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
-        break;
-    case TIME_MS:
-        lpTime->u.ms = 1000.0 * position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels * format->Format.nSamplesPerSec);
-        TRACE("TIME_MS=%u\n", lpTime->u.ms);
-        break;
-    case TIME_SMPTE:
-        lpTime->u.smpte.fps = 30;
-        position = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
-        position += (format->Format.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
-        lpTime->u.smpte.sec = position / format->Format.nSamplesPerSec;
-        position -= lpTime->u.smpte.sec * format->Format.nSamplesPerSec;
-        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
-        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
-        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
-        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
-        lpTime->u.smpte.fps = 30;
-        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->Format.nSamplesPerSec;
-        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-              lpTime->u.smpte.hour, lpTime->u.smpte.min,
-              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-        break;
-    default:
-        WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
-        lpTime->wType = TIME_BYTES;
-        /* fall through */
-    case TIME_BYTES:
-        lpTime->u.cb = position;
-        TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
-        break;
-    }
-    return MMSYSERR_NOERROR;
-}
-
-void ALSA_copyFormat(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
-{
-    unsigned int iLength;
-
-    ZeroMemory(wf2, sizeof(*wf2));
-    if (wf1->wFormatTag == WAVE_FORMAT_PCM)
-        iLength = sizeof(PCMWAVEFORMAT);
-    else if (wf1->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-        iLength = sizeof(WAVEFORMATPCMEX);
-    else
-        iLength = sizeof(WAVEFORMATEX) + wf1->cbSize;
-    memcpy(wf2, wf1, iLength);
-}
-
-BOOL ALSA_supportedFormat(LPWAVEFORMATEX wf)
-{
-    TRACE("(%p)\n",wf);
-
-    if (wf->nSamplesPerSec<DSBFREQUENCY_MIN||wf->nSamplesPerSec>DSBFREQUENCY_MAX)
-        return FALSE;
-
-    if (wf->wFormatTag == WAVE_FORMAT_PCM) {
-        if (wf->nChannels==1||wf->nChannels==2) {
-            if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
-                return TRUE;
-        }
-    } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
-        WAVEFORMATEXTENSIBLE 	* wfex = (WAVEFORMATEXTENSIBLE *)wf;
-
-        if (wf->cbSize == 22 &&
-            (IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
-             IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) {
-            if (wf->nChannels>=1 && wf->nChannels<=6) {
-                if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
-                    if (wf->wBitsPerSample==8||wf->wBitsPerSample==16||
-                        wf->wBitsPerSample==24||wf->wBitsPerSample==32) {
-                        return TRUE;
-                    }
-                } else
-                    WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
-            }
-        } else
-            WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
-                 "supported\n");
-    } else
-        WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
-
-    return FALSE;
-}
-
-/*======================================================================*
- *                  Low level WAVE implementation			*
- *======================================================================*/
-
-/**************************************************************************
- * 			ALSA_CheckSetVolume		[internal]
- *
- *  Helper function for Alsa volume queries.  This tries to simplify
- * the process of managing the volume.  All parameters are optional
- * (pass NULL to ignore or not use).
- *  Return values are MMSYSERR_NOERROR on success, or !0 on failure;
- * error codes are normalized into the possible documented return
- * values from waveOutGetVolume.
- */
-int ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right,
-            int *out_min, int *out_max, int *out_step,
-            int *new_left, int *new_right)
-{
-    int rc = MMSYSERR_NOERROR;
-    int value_count = 0;
-    snd_hctl_elem_t *           elem = NULL;
-    snd_ctl_elem_info_t *       eleminfop = NULL;
-    snd_ctl_elem_value_t *      elemvaluep = NULL;
-    snd_ctl_elem_id_t *         elemidp = NULL;
-    const char *names[] = {"PCM Playback Volume", "Line Playback Volume", NULL};
-    const char **name;
-
-
-#define EXIT_ON_ERROR(f,txt,exitcode) do \
-{ \
-    int err; \
-    if ( (err = (f) ) < 0) \
-    { \
-	ERR(txt " failed: %s\n", snd_strerror(err)); \
-        rc = exitcode; \
-        goto out; \
-    } \
-} while(0)
-
-    if (! hctl)
-        return MMSYSERR_NOTSUPPORTED;
-
-    /* Allocate areas to return information about the volume */
-    EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM);
-    EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM);
-    EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM);
-    snd_ctl_elem_id_clear(elemidp);
-    snd_ctl_elem_value_clear(elemvaluep);
-    snd_ctl_elem_info_clear(eleminfop);
-
-    /* Setup and find an element id that exactly matches the characteristic we want
-    ** FIXME:  It is probably short sighted to hard code and fixate on PCM Playback Volume */
-
-    for( name = names; *name; name++ )
-    {
-	snd_ctl_elem_id_set_name(elemidp, *name);
-	snd_ctl_elem_id_set_interface(elemidp, SND_CTL_ELEM_IFACE_MIXER);
-	elem = snd_hctl_find_elem(hctl, elemidp);
-	if (elem)
-	{
-	    /* Read and return volume information */
-	    EXIT_ON_ERROR(snd_hctl_elem_info(elem, eleminfop), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED);
-	    value_count = snd_ctl_elem_info_get_count(eleminfop);
-	    if (out_min || out_max || out_step)
-	    {
-		if (!snd_ctl_elem_info_is_readable(eleminfop))
-		{
-		    ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n");
-		    rc = MMSYSERR_NOTSUPPORTED;
-		    goto out;
-		}
-
-		if (out_min)
-		    *out_min = snd_ctl_elem_info_get_min(eleminfop);
-
-		if (out_max)
-		    *out_max = snd_ctl_elem_info_get_max(eleminfop);
-
-		if (out_step)
-		    *out_step = snd_ctl_elem_info_get_step(eleminfop);
-	    }
-
-	    if (out_left || out_right)
-	    {
-		EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
-
-		if (out_left)
-		    *out_left = snd_ctl_elem_value_get_integer(elemvaluep, 0);
-
-		if (out_right)
-		{
-		    if (value_count == 1)
-			*out_right = snd_ctl_elem_value_get_integer(elemvaluep, 0);
-		    else if (value_count == 2)
-			*out_right = snd_ctl_elem_value_get_integer(elemvaluep, 1);
-		    else
-		    {
-			ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count);
-			rc = -1;
-			goto out;
-		    }
-		}
-	    }
-
-	    /* Set the volume */
-	    if (new_left || new_right)
-	    {
-		EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
-		if (new_left)
-		    snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_left);
-		if (new_right)
-		{
-		    if (value_count == 1)
-			snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_right);
-		    else if (value_count == 2)
-			snd_ctl_elem_value_set_integer(elemvaluep, 1, *new_right);
-		    else
-		    {
-			ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count);
-			rc = -1;
-			goto out;
-		    }
-		}
-
-		EXIT_ON_ERROR(snd_hctl_elem_write(elem, elemvaluep), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED);
-	    }
-
-	    break;
-	}
-    }
-
-    if( !*name )
-    {
-        ERR("Could not find '{PCM,Line} Playback Volume' element\n");
-        rc = MMSYSERR_NOTSUPPORTED;
-    }
-
-
-#undef EXIT_ON_ERROR
-
-out:
-
-    if (elemvaluep)
-        snd_ctl_elem_value_free(elemvaluep);
-    if (eleminfop)
-        snd_ctl_elem_info_free(eleminfop);
-    if (elemidp)
-        snd_ctl_elem_id_free(elemidp);
-
-    return rc;
-}
-
-
-/**************************************************************************
- * 			wine_snd_pcm_recover		[internal]
- *
- * Code slightly modified from alsa-lib v1.0.23 snd_pcm_recover implementation.
- * used to recover from XRUN errors (buffer underflow/overflow)
- */
-int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
-{
-    if (err > 0)
-        err = -err;
-    if (err == -EINTR)	/* nothing to do, continue */
-        return 0;
-    if (err == -EPIPE) {
-        const char *s;
-        if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
-            s = "underrun";
-        else
-            s = "overrun";
-        if (!silent)
-            ERR("%s occurred\n", s);
-        err = snd_pcm_prepare(pcm);
-        if (err < 0) {
-            ERR("cannot recover from %s, prepare failed: %s\n", s, snd_strerror(err));
-            return err;
-        }
-        return 0;
-    }
-    if (err == -ESTRPIPE) {
-        while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
-            /* wait until suspend flag is released */
-            poll(NULL, 0, 1000);
-        if (err < 0) {
-            err = snd_pcm_prepare(pcm);
-            if (err < 0) {
-                ERR("cannot recover from suspend, prepare failed: %s\n", snd_strerror(err));
-                return err;
-            }
-        }
-        return 0;
-    }
-    return err;
-}
-
-/**************************************************************************
- * 			ALSA_TraceParameters		[internal]
- *
- * used to trace format changes, hw and sw parameters
- */
-void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full)
-{
-    int err;
-    snd_pcm_format_t   format;
-    snd_pcm_access_t   access;
-
-#define X(x) ((x)? "true" : "false")
-    if (full)
-	TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s "
-	      "halfd=%s joint=%s\n",
-	      X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params)),
-	      X(snd_pcm_hw_params_can_overrange(hw_params)),
-	      X(snd_pcm_hw_params_can_pause(hw_params)),
-	      X(snd_pcm_hw_params_can_resume(hw_params)),
-	      X(snd_pcm_hw_params_can_sync_start(hw_params)),
-	      X(snd_pcm_hw_params_is_batch(hw_params)),
-	      X(snd_pcm_hw_params_is_block_transfer(hw_params)),
-	      X(snd_pcm_hw_params_is_double(hw_params)),
-	      X(snd_pcm_hw_params_is_half_duplex(hw_params)),
-	      X(snd_pcm_hw_params_is_joint_duplex(hw_params)));
-#undef X
-
-    err = snd_pcm_hw_params_get_access(hw_params, &access);
-    if (err >= 0)
-    {
-	TRACE("access=%s\n", snd_pcm_access_name(access));
-    }
-    else
-    {
-	snd_pcm_access_mask_t * acmask;
-
-        acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof());
-	snd_pcm_hw_params_get_access_mask(hw_params, acmask);
-	for ( access = SND_PCM_ACCESS_MMAP_INTERLEAVED; access <= SND_PCM_ACCESS_LAST; access++)
-	    if (snd_pcm_access_mask_test(acmask, access))
-		TRACE("access=%s\n", snd_pcm_access_name(access));
-        HeapFree( GetProcessHeap(), 0, acmask );
-    }
-
-    err = snd_pcm_hw_params_get_format(hw_params, &format);
-    if (err >= 0)
-    {
-	TRACE("format=%s\n", snd_pcm_format_name(format));
-
-    }
-    else
-    {
-	snd_pcm_format_mask_t *     fmask;
-
-        fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
-	snd_pcm_hw_params_get_format_mask(hw_params, fmask);
-	for ( format = SND_PCM_FORMAT_S8; format <= SND_PCM_FORMAT_LAST ; format++)
-	    if ( snd_pcm_format_mask_test(fmask, format) )
-		TRACE("format=%s\n", snd_pcm_format_name(format));
-        HeapFree( GetProcessHeap(), 0, fmask );
-    }
-
-    do {
-      int err=0;
-      unsigned int val=0;
-      err = snd_pcm_hw_params_get_channels(hw_params, &val);
-      if (err<0) {
-        unsigned int min = 0;
-        unsigned int max = 0;
-        err = snd_pcm_hw_params_get_channels_min(hw_params, &min),
-	err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
-        TRACE("channels_min=%u, channels_min_max=%u\n", min, max);
-      } else {
-        TRACE("channels=%d\n", val);
-      }
-    } while(0);
-    do {
-      int err=0;
-      snd_pcm_uframes_t val=0;
-      err = snd_pcm_hw_params_get_buffer_size(hw_params, &val);
-      if (err<0) {
-        snd_pcm_uframes_t min = 0;
-        snd_pcm_uframes_t max = 0;
-        err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &min),
-	err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &max);
-        TRACE("buffer_size_min=%lu, buffer_size_min_max=%lu\n", min, max);
-      } else {
-        TRACE("buffer_size=%lu\n", val);
-      }
-    } while(0);
-
-#define X(x) do { \
-int err=0; \
-int dir=0; \
-unsigned int val=0; \
-err = snd_pcm_hw_params_get_##x(hw_params,&val, &dir); \
-if (err<0) { \
-  unsigned int min = 0; \
-  unsigned int max = 0; \
-  err = snd_pcm_hw_params_get_##x##_min(hw_params, &min, &dir); \
-  err = snd_pcm_hw_params_get_##x##_max(hw_params, &max, &dir); \
-  TRACE(#x "_min=%u " #x "_max=%u\n", min, max); \
-} else \
-    TRACE(#x "=%d\n", val); \
-} while(0)
-
-    X(rate);
-    X(buffer_time);
-    X(periods);
-    do {
-      int err=0;
-      int dir=0;
-      snd_pcm_uframes_t val=0;
-      err = snd_pcm_hw_params_get_period_size(hw_params, &val, &dir);
-      if (err<0) {
-        snd_pcm_uframes_t min = 0;
-        snd_pcm_uframes_t max = 0;
-        err = snd_pcm_hw_params_get_period_size_min(hw_params, &min, &dir),
-	err = snd_pcm_hw_params_get_period_size_max(hw_params, &max, &dir);
-        TRACE("period_size_min=%lu, period_size_min_max=%lu\n", min, max);
-      } else {
-        TRACE("period_size=%lu\n", val);
-      }
-    } while(0);
-
-    X(period_time);
-#undef X
-
-    if (!sw)
-	return;
-}
-
-/**************************************************************************
- * 				DriverProc (WINEALSA.@)
- */
-LRESULT CALLBACK ALSA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
-                                 LPARAM dwParam1, LPARAM dwParam2)
-{
-/* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
-/* EPP 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
-
-    switch(wMsg) {
-    case DRV_LOAD:
-    case DRV_FREE:
-    case DRV_OPEN:
-    case DRV_CLOSE:
-    case DRV_ENABLE:
-    case DRV_DISABLE:
-    case DRV_QUERYCONFIGURE:
-        return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "ALSA MultiMedia Driver !", "ALSA Driver", MB_OK);	return 1;
-    case DRV_INSTALL:
-    case DRV_REMOVE:
-        return DRV_SUCCESS;
-    default:
-	return 0;
-    }
-}
diff --git a/dlls/winealsa.drv/alsa.h b/dlls/winealsa.drv/alsa.h
deleted file mode 100644
index bc21fbc..0000000
--- a/dlls/winealsa.drv/alsa.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/* Definition for ALSA drivers : wine multimedia system
- *
- * Copyright (C) 2002 Erich Pouech
- * Copyright (C) 2002 Marco Pietrobono
- * Copyright (C) 2003 Christian Costa
- * Copyright (C) 2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __WINE_CONFIG_H
-# error You must include config.h to use this header
-#endif
-
-#ifndef __ALSA_H
-#define __ALSA_H
-
-#ifdef interface
-#undef interface
-#endif
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-
-#ifdef HAVE_ALSA_ASOUNDLIB_H
-#include <alsa/asoundlib.h>
-#elif defined(HAVE_SYS_ASOUNDLIB_H)
-#include <sys/asoundlib.h>
-#endif
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-
-/* state diagram for waveOut writing:
- *
- * +---------+-------------+---------------+---------------------------------+
- * |  state  |  function   |     event     |            new state	     |
- * +---------+-------------+---------------+---------------------------------+
- * |	     | open()	   |		   | STOPPED		       	     |
- * | PAUSED  | write()	   | 		   | PAUSED		       	     |
- * | STOPPED | write()	   | <thrd create> | PLAYING		  	     |
- * | PLAYING | write()	   | HEADER        | PLAYING		  	     |
- * | (other) | write()	   | <error>       |		       		     |
- * | (any)   | pause()	   | PAUSING	   | PAUSED		       	     |
- * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
- * | (any)   | reset()	   | RESETTING     | STOPPED		      	     |
- * | (any)   | close()	   | CLOSING	   | CLOSED		      	     |
- * +---------+-------------+---------------+---------------------------------+
- */
-
-/* states of the playing device */
-#define	WINE_WS_PLAYING		0
-#define	WINE_WS_PAUSED		1
-#define	WINE_WS_STOPPED		2
-#define WINE_WS_CLOSED		3
-
-/* events to be send to device */
-enum win_wm_message {
-    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
-    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
-};
-
-typedef struct {
-    enum win_wm_message msg; /* message identifier */
-    DWORD_PTR param;         /* parameter for this message */
-    HANDLE hEvent;           /* if message is synchronous, handle of event for synchro */
-} ALSA_MSG;
-
-/* implement an in-process message ring for better performance
- * (compared to passing thru the server)
- * this ring will be used by the input (resp output) record (resp playback) routine
- */
-typedef struct {
-    ALSA_MSG			* messages;
-    int                         ring_buffer_size;
-    int				msg_tosave;
-    int				msg_toget;
-/* Either pipe or event is used, but that is defined in alsa.c,
- * since this is a global header we define both here */
-    int                         msg_pipe[2];
-    HANDLE                      msg_event;
-    CRITICAL_SECTION		msg_crst;
-} ALSA_MSG_RING;
-
-typedef struct {
-    volatile int		state;			/* one of the WINE_WS_ manifest constants */
-    WAVEOPENDESC		waveDesc;
-    WORD			wFlags;
-    WAVEFORMATPCMEX		format;
-
-    char*                       pcmname;                /* string name of alsa PCM device */
-    char*                       ctlname;                /* string name of alsa control device */
-    char                        interface_name[MAXPNAMELEN * 2];
-
-    snd_pcm_t*                  pcm;                    /* handle to ALSA playback device */
-
-    snd_pcm_hw_params_t *       hw_params;
-
-    DWORD                       dwBufferSize;           /* size of whole ALSA buffer in bytes */
-    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
-    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
-
-    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
-    DWORD			dwLoops;		/* private copy of loop counter */
-
-    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */
-    DWORD			dwWrittenTotal;		/* number of bytes written to ALSA buffer since opening */
-
-    /* synchronization stuff */
-    HANDLE			hStartUpEvent;
-    HANDLE			hThread;
-    DWORD			dwThreadID;
-    ALSA_MSG_RING		msgRing;
-
-    /* DirectSound stuff */
-    DSDRIVERDESC                ds_desc;
-    DSDRIVERCAPS                ds_caps;
-
-    /* Waveout only fields */
-    WAVEOUTCAPSW		outcaps;
-
-    snd_hctl_t *                hctl;                    /* control handle for the playback volume */
-
-    snd_pcm_sframes_t           (*write)(snd_pcm_t *, const void *, snd_pcm_uframes_t );
-
-    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
-
-    /* Wavein only fields */
-
-    WAVEINCAPSW                 incaps;
-    DWORD                       dwSupport;
-
-    snd_pcm_sframes_t           (*read)(snd_pcm_t *, void *, snd_pcm_uframes_t );
-
-    DWORD			dwPeriodSize;		/* size of OSS buffer period */
-    DWORD			dwTotalRecorded;
-
-}   WINE_WAVEDEV;
-
-/*----------------------------------------------------------------------------
-**  Global array of output and input devices, initialized via ALSA_WaveInit
-*/
-#define WAVEDEV_ALLOC_EXTENT_SIZE       10
-
-/* wavein.c */
-extern WINE_WAVEDEV	*WInDev DECLSPEC_HIDDEN;
-extern DWORD		ALSA_WidNumMallocedDevs DECLSPEC_HIDDEN;
-extern DWORD		ALSA_WidNumDevs DECLSPEC_HIDDEN;
-
-/* waveout.c */
-extern WINE_WAVEDEV	*WOutDev DECLSPEC_HIDDEN;
-extern DWORD		ALSA_WodNumMallocedDevs DECLSPEC_HIDDEN;
-extern DWORD		ALSA_WodNumDevs DECLSPEC_HIDDEN;
-
-/* alsa.c */
-int	ALSA_InitRingMessage(ALSA_MSG_RING* omr) DECLSPEC_HIDDEN;
-int	ALSA_DestroyRingMessage(ALSA_MSG_RING* omr) DECLSPEC_HIDDEN;
-void	ALSA_ResetRingMessage(ALSA_MSG_RING* omr) DECLSPEC_HIDDEN;
-void	ALSA_WaitRingMessage(ALSA_MSG_RING* omr, DWORD sleep) DECLSPEC_HIDDEN;
-int	ALSA_AddRingMessage(ALSA_MSG_RING* omr, enum win_wm_message msg, DWORD_PTR param, BOOL wait) DECLSPEC_HIDDEN;
-int	ALSA_RetrieveRingMessage(ALSA_MSG_RING* omr, enum win_wm_message *msg, DWORD_PTR *param, HANDLE *hEvent) DECLSPEC_HIDDEN;
-int	ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right, int *out_min, int *out_max, int *out_step, int *new_left, int *new_right) DECLSPEC_HIDDEN;
-
-const char * ALSA_getCmdString(enum win_wm_message msg) DECLSPEC_HIDDEN;
-const char * ALSA_getMessage(UINT msg) DECLSPEC_HIDDEN;
-const char * ALSA_getFormat(WORD wFormatTag) DECLSPEC_HIDDEN;
-BOOL	ALSA_NearMatch(int rate1, int rate2) DECLSPEC_HIDDEN;
-DWORD	ALSA_bytes_to_mmtime(LPMMTIME lpTime, DWORD position, WAVEFORMATPCMEX* format) DECLSPEC_HIDDEN;
-void	ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full) DECLSPEC_HIDDEN;
-int	wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent) DECLSPEC_HIDDEN;
-void	ALSA_copyFormat(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2) DECLSPEC_HIDDEN;
-BOOL	ALSA_supportedFormat(LPWAVEFORMATEX wf) DECLSPEC_HIDDEN;
-
-/* dscapture.c */
-DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv) DECLSPEC_HIDDEN;
-DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc) DECLSPEC_HIDDEN;
-
-/* dsoutput.c */
-DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv) DECLSPEC_HIDDEN;
-DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc) DECLSPEC_HIDDEN;
-
-/* waveinit.c */
-extern void ALSA_WaveInit(void) DECLSPEC_HIDDEN;
-
-#endif /* __ALSA_H */
diff --git a/dlls/winealsa.drv/dscapture.c b/dlls/winealsa.drv/dscapture.c
deleted file mode 100644
index 70e70ed..0000000
--- a/dlls/winealsa.drv/dscapture.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-/*
- * Sample Wine Driver for Advanced Linux Sound System (ALSA)
- *      Based on version <final> of the ALSA API
- *
- * Copyright 2007 - Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*======================================================================*
- *              Low level dsound input implementation			*
- *======================================================================*/
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winerror.h"
-#include "winuser.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-
-#include "alsa.h"
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-/* Notify timer checks every 10 ms with a resolution of 2 ms */
-#define DS_TIME_DEL 10
-#define DS_TIME_RES 2
-
-WINE_DEFAULT_DEBUG_CHANNEL(dsalsa);
-
-typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
-
-typedef struct IDsCaptureDriverImpl
-{
-    const IDsCaptureDriverVtbl *lpVtbl;
-    LONG ref;
-    IDsCaptureDriverBufferImpl* capture_buffer;
-    UINT wDevID;
-} IDsCaptureDriverImpl;
-
-typedef struct IDsCaptureDriverNotifyImpl
-{
-    const IDsDriverNotifyVtbl *lpVtbl;
-    LONG ref;
-    IDsCaptureDriverBufferImpl *buffer;
-    DSBPOSITIONNOTIFY *notifies;
-    DWORD nrofnotifies, playpos;
-    UINT timerID;
-} IDsCaptureDriverNotifyImpl;
-
-struct IDsCaptureDriverBufferImpl
-{
-    const IDsCaptureDriverBufferVtbl *lpVtbl;
-    LONG ref;
-    IDsCaptureDriverImpl *drv;
-    IDsCaptureDriverNotifyImpl *notify;
-
-    CRITICAL_SECTION pcm_crst;
-    LPBYTE mmap_buffer, presented_buffer;
-    DWORD mmap_buflen_bytes, play_looping, mmap_ofs_bytes;
-    BOOL mmap;
-
-    /* Note: snd_pcm_frames_to_bytes(This->pcm, mmap_buflen_frames) != mmap_buflen_bytes */
-    /* The actual buffer may differ in size from the wanted buffer size */
-
-    snd_pcm_t *pcm;
-    snd_pcm_hw_params_t *hw_params;
-    snd_pcm_sw_params_t *sw_params;
-    snd_pcm_uframes_t mmap_buflen_frames, mmap_pos;
-};
-
-static void Capture_CheckNotify(IDsCaptureDriverNotifyImpl *This, DWORD from, DWORD len)
-{
-    unsigned i;
-    for (i = 0; i < This->nrofnotifies; ++i) {
-        LPDSBPOSITIONNOTIFY event = This->notifies + i;
-        DWORD offset = event->dwOffset;
-        TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
-
-        if (offset == DSBPN_OFFSETSTOP) {
-            if (!from && !len) {
-                SetEvent(event->hEventNotify);
-                TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
-                return;
-            }
-            else return;
-        }
-
-        if (offset >= from && offset < (from + len))
-        {
-            TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
-            SetEvent(event->hEventNotify);
-        }
-    }
-}
-
-static void CALLBACK Capture_Notify(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)dwUser;
-    DWORD last_playpos, playpos;
-    PIDSCDRIVERBUFFER iface = (PIDSCDRIVERBUFFER)This;
-
-    /* **** */
-    /* Don't deadlock since there is a critical section can be held by the timer api itself while running this code */
-    if (!TryEnterCriticalSection(&This->pcm_crst)) return;
-
-    IDsDriverBuffer_GetPosition(iface, &playpos, NULL);
-    last_playpos = This->notify->playpos;
-    This->notify->playpos = playpos;
-
-    if (snd_pcm_state(This->pcm) != SND_PCM_STATE_RUNNING || last_playpos == playpos || !This->notify->nrofnotifies || !This->notify->notifies)
-        goto done;
-
-    if (playpos < last_playpos)
-    {
-        Capture_CheckNotify(This->notify, last_playpos, This->mmap_buflen_bytes);
-        if (playpos)
-            Capture_CheckNotify(This->notify, 0, playpos);
-    }
-    else Capture_CheckNotify(This->notify, last_playpos, playpos - last_playpos);
-
-done:
-    LeaveCriticalSection(&This->pcm_crst);
-    /* **** */
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(PIDSDRIVERNOTIFY iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
-        IDsDriverNotify_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid(riid));
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        This->buffer->notify = NULL;
-        if (This->timerID)
-        {
-            timeKillEvent(This->timerID);
-            timeEndPeriod(DS_TIME_RES);
-        }
-        HeapFree(GetProcessHeap(), 0, This->notifies);
-        HeapFree(GetProcessHeap(), 0, This);
-        TRACE("(%p) released\n", This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(PIDSDRIVERNOTIFY iface, DWORD howmuch, LPCDSBPOSITIONNOTIFY notify)
-{
-    DWORD len = howmuch * sizeof(DSBPOSITIONNOTIFY);
-    unsigned i;
-    LPVOID notifies;
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
-
-    if (!notify) {
-        WARN("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (TRACE_ON(dsalsa))
-        for (i=0;i<howmuch; ++i)
-            TRACE("notify at %d to %p\n", notify[i].dwOffset, notify[i].hEventNotify);
-
-    /* **** */
-    EnterCriticalSection(&This->buffer->pcm_crst);
-
-    /* Make an internal copy of the caller-supplied array.
-     * Replace the existing copy if one is already present. */
-    if (This->notifies)
-        notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies, len);
-    else
-        notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
-
-    if (!notifies)
-    {
-        LeaveCriticalSection(&This->buffer->pcm_crst);
-        /* **** */
-        return DSERR_OUTOFMEMORY;
-    }
-    This->notifies = notifies;
-    memcpy(This->notifies, notify, len);
-    This->nrofnotifies = howmuch;
-    IDsDriverBuffer_GetPosition((PIDSCDRIVERBUFFER)This->buffer, &This->playpos, NULL);
-
-    if (!This->timerID)
-    {
-        timeBeginPeriod(DS_TIME_RES);
-        This->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, Capture_Notify, (DWORD_PTR)This->buffer, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
-    }
-
-    LeaveCriticalSection(&This->buffer->pcm_crst);
-    /* **** */
-
-    return S_OK;
-}
-
-static const IDsDriverNotifyVtbl dscdnvt =
-{
-    IDsCaptureDriverNotifyImpl_QueryInterface,
-    IDsCaptureDriverNotifyImpl_AddRef,
-    IDsCaptureDriverNotifyImpl_Release,
-    IDsCaptureDriverNotifyImpl_SetNotificationPositions,
-};
-
-#if 0
-/** Convert the position an application sees into a position ALSA sees */
-static snd_pcm_uframes_t fakepos_to_realpos(const IDsCaptureDriverBufferImpl* This, DWORD fakepos)
-{
-    snd_pcm_uframes_t realpos;
-    if (fakepos < This->mmap_ofs_bytes)
-        realpos = This->mmap_buflen_bytes + fakepos - This->mmap_ofs_bytes;
-    else realpos = fakepos - This->mmap_ofs_bytes;
-    return snd_pcm_bytes_to_frames(This->pcm, realpos) % This->mmap_buflen_frames;
-}
-#endif
-
-/** Convert the position ALSA sees into a position an application sees */
-static DWORD realpos_to_fakepos(const IDsCaptureDriverBufferImpl* This, snd_pcm_uframes_t realpos)
-{
-    DWORD realposb = snd_pcm_frames_to_bytes(This->pcm, realpos);
-    return (realposb + This->mmap_ofs_bytes) % This->mmap_buflen_bytes;
-}
-
-/** Raw copy data, with buffer wrap around */
-static void CopyDataWrap(const IDsCaptureDriverBufferImpl* This, LPBYTE dest, DWORD fromwhere, DWORD copylen, DWORD buflen)
-{
-    DWORD remainder = buflen - fromwhere;
-    if (remainder >= copylen)
-    {
-        CopyMemory(dest, This->mmap_buffer + fromwhere, copylen);
-    }
-    else
-    {
-        CopyMemory(dest, This->mmap_buffer + fromwhere, remainder);
-        copylen -= remainder;
-        CopyMemory(dest, This->mmap_buffer, copylen);
-    }
-}
-
-/** Copy data from the mmap buffer to backbuffer, taking into account all wraparounds that may occur */
-static void CopyData(const IDsCaptureDriverBufferImpl* This, snd_pcm_uframes_t fromwhere, snd_pcm_uframes_t len)
-{
-    DWORD dlen = snd_pcm_frames_to_bytes(This->pcm, len) % This->mmap_buflen_bytes;
-
-    /* Backbuffer */
-    DWORD ofs = realpos_to_fakepos(This, fromwhere);
-    DWORD remainder = This->mmap_buflen_bytes - ofs;
-
-    /* MMAP buffer */
-    DWORD realbuflen = snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
-    DWORD realofs = snd_pcm_frames_to_bytes(This->pcm, fromwhere);
-
-    if (remainder >= dlen)
-    {
-       CopyDataWrap(This, This->presented_buffer + ofs, realofs, dlen, realbuflen);
-    }
-    else
-    {
-       CopyDataWrap(This, This->presented_buffer + ofs, realofs, remainder, realbuflen);
-       dlen -= remainder;
-       CopyDataWrap(This, This->presented_buffer, (realofs+remainder)%realbuflen, dlen, realbuflen);
-    }
-}
-
-/** Fill buffers, for starting and stopping
- * Alsa won't start playing until everything is filled up
- * This also updates mmap_pos
- *
- * Returns: Amount of periods in use so snd_pcm_avail_update
- * doesn't have to be called up to 4x in GetPosition()
- */
-static snd_pcm_uframes_t CommitAll(IDsCaptureDriverBufferImpl *This, DWORD forced)
-{
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_uframes_t used;
-    const snd_pcm_uframes_t commitahead = This->mmap_buflen_frames;
-
-    used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
-    TRACE("%p needs to commit to %lu, used: %lu\n", This, commitahead, used);
-    if (used < commitahead && (forced || This->play_looping))
-    {
-        snd_pcm_uframes_t done, putin = commitahead - used;
-        if (This->mmap)
-        {
-            snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-            CopyData(This, This->mmap_pos, putin);
-            done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
-
-            This->mmap_pos += done;
-            used += done;
-            putin = commitahead - used;
-
-            if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0 && This->play_looping)
-            {
-                This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
-                This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
-
-                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-                CopyData(This, This->mmap_pos, putin);
-                done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
-
-                This->mmap_pos += done;
-                used += done;
-            }
-        }
-        else
-        {
-            DWORD pos;
-            snd_pcm_sframes_t ret;
-
-            snd_pcm_uframes_t cap = snd_pcm_bytes_to_frames(This->pcm, This->mmap_buflen_bytes);
-            pos = realpos_to_fakepos(This, This->mmap_pos);
-            if (This->mmap_pos + putin > cap)
-                putin = cap - This->mmap_pos;
-            ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
-            if (ret == -EPIPE)
-            {
-                WARN("Underrun occurred\n");
-                snd_pcm_prepare(This->pcm);
-                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
-                snd_pcm_start(This->pcm);
-            }
-            if (ret < 0)
-            {
-                WARN("Committing data: %ld / %s (%ld)\n", ret, snd_strerror(ret), putin);
-                ret = 0;
-            }
-            This->mmap_pos += ret;
-            used += ret;
-            /* At this point mmap_pos may be >= This->mmap_pos this is harmless
-             * realpos_to_fakepos handles it well, and below it is truncated
-             */
-
-            putin = commitahead - used;
-            if (putin > 0)
-            {
-                pos = realpos_to_fakepos(This, This->mmap_pos);
-                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
-                if (ret > 0)
-                {
-                    This->mmap_pos += ret;
-                    used += ret;
-                }
-            }
-        }
-
-    }
-
-    if (This->mmap_pos >= This->mmap_buflen_frames)
-    {
-        This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
-        This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
-        This->mmap_pos -= This->mmap_buflen_frames;
-    }
-
-    return used;
-}
-
-static void CheckXRUN(IDsCaptureDriverBufferImpl* This)
-{
-    snd_pcm_state_t state = snd_pcm_state(This->pcm);
-    int err;
-
-    if ( state == SND_PCM_STATE_XRUN )
-    {
-        err = snd_pcm_prepare(This->pcm);
-        CommitAll(This, FALSE);
-        snd_pcm_start(This->pcm);
-        WARN("xrun occurred\n");
-        if ( err < 0 )
-            ERR("recovery from xrun failed, prepare failed: %s\n", snd_strerror(err));
-    }
-    else if ( state == SND_PCM_STATE_SUSPENDED )
-    {
-        int err = snd_pcm_resume(This->pcm);
-        TRACE("recovery from suspension occurred\n");
-        if (err < 0 && err != -EAGAIN){
-            err = snd_pcm_prepare(This->pcm);
-            if (err < 0)
-                ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err));
-        }
-    }
-    else if ( state != SND_PCM_STATE_RUNNING)
-    {
-        WARN("Unhandled state: %d\n", state);
-    }
-}
-
-/**
- * Allocate the memory-mapped buffer for direct sound, and set up the
- * callback.
- */
-static int CreateMMAP(IDsCaptureDriverBufferImpl* pdbi)
-{
-    snd_pcm_t *pcm = pdbi->pcm;
-    snd_pcm_format_t format;
-    snd_pcm_uframes_t frames, ofs, avail, psize, boundary;
-    unsigned int channels, bits_per_sample, bits_per_frame;
-    int err, mmap_mode;
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_hw_params_t *hw_params = pdbi->hw_params;
-    snd_pcm_sw_params_t *sw_params = pdbi->sw_params;
-
-    mmap_mode = snd_pcm_type(pcm);
-
-    if (mmap_mode == SND_PCM_TYPE_HW)
-        TRACE("mmap'd buffer is a direct hardware buffer.\n");
-    else if (mmap_mode == SND_PCM_TYPE_DMIX)
-        TRACE("mmap'd buffer is an ALSA dmix buffer\n");
-    else
-        TRACE("mmap'd buffer is an ALSA type %d buffer\n", mmap_mode);
-
-    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
-    err = snd_pcm_hw_params_get_format(hw_params, &format);
-    err = snd_pcm_hw_params_get_buffer_size(hw_params, &frames);
-    err = snd_pcm_hw_params_get_channels(hw_params, &channels);
-    bits_per_sample = snd_pcm_format_physical_width(format);
-    bits_per_frame = bits_per_sample * channels;
-
-    if (TRACE_ON(dsalsa))
-        ALSA_TraceParameters(hw_params, NULL, FALSE);
-
-    TRACE("format=%s  frames=%ld  channels=%d  bits_per_sample=%d  bits_per_frame=%d\n",
-          snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame);
-
-    pdbi->mmap_buflen_frames = frames;
-    snd_pcm_sw_params_current(pcm, sw_params);
-    snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 0);
-    snd_pcm_sw_params_get_boundary(sw_params, &boundary);
-    snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary);
-    snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, INT_MAX);
-    snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0);
-    snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0);
-    err = snd_pcm_sw_params(pcm, sw_params);
-
-    pdbi->mmap_ofs_bytes = 0;
-    if (!pdbi->mmap)
-    {
-        pdbi->mmap_buffer = NULL;
-
-        frames = snd_pcm_bytes_to_frames(pdbi->pcm, pdbi->mmap_buflen_bytes);
-        snd_pcm_format_set_silence(format, pdbi->presented_buffer, frames);
-        pdbi->mmap_pos = 0;
-    }
-    else
-    {
-        err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
-        if ( err < 0 )
-        {
-            ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
-            return DSERR_GENERIC;
-        }
-        snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
-        pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
-        pdbi->mmap_buffer = areas->addr;
-    }
-
-    TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
-        pdbi->mmap_buflen_frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(PIDSCDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
-        IDsCaptureDriverBuffer_AddRef(iface);
-        *ppobj = iface;
-        return DS_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
-        if (!This->notify)
-        {
-            This->notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDsCaptureDriverNotifyImpl));
-            if (!This->notify)
-                return DSERR_OUTOFMEMORY;
-            This->notify->lpVtbl = &dscdnvt;
-            This->notify->buffer = This;
-
-            /* Keep a lock on IDsDriverNotify for ourself, so it is destroyed when the buffer is */
-            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-        }
-        IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-        *ppobj = This->notify;
-        return DS_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
-        FIXME("Unsupported interface IID_IDsDriverPropertySet\n");
-        return E_FAIL;
-    }
-
-    FIXME("(): Unknown interface %s\n", debugstr_guid(riid));
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
-
-    if (refCount)
-        return refCount;
-
-    EnterCriticalSection(&This->pcm_crst);
-    if (This->notify)
-        IDsDriverNotify_Release((PIDSDRIVERNOTIFY)This->notify);
-    TRACE("mmap buffer %p destroyed\n", This->mmap_buffer);
-
-    This->drv->capture_buffer = NULL;
-    LeaveCriticalSection(&This->pcm_crst);
-    This->pcm_crst.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&This->pcm_crst);
-
-    snd_pcm_drop(This->pcm);
-    snd_pcm_close(This->pcm);
-    This->pcm = NULL;
-    HeapFree(GetProcessHeap(), 0, This->presented_buffer);
-    HeapFree(GetProcessHeap(), 0, This->sw_params);
-    HeapFree(GetProcessHeap(), 0, This->hw_params);
-    HeapFree(GetProcessHeap(), 0, This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(PIDSCDRIVERBUFFER iface, LPVOID*ppvAudio1,LPDWORD pdwLen1,LPVOID*ppvAudio2,LPDWORD pdwLen2, DWORD dwWritePosition,DWORD dwWriteLen, DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n", This, ppvAudio1, pdwLen1, ppvAudio2, pdwLen2, dwWritePosition, dwWriteLen, dwFlags);
-
-    if (ppvAudio1)
-        *ppvAudio1 = (LPBYTE)This->presented_buffer + dwWritePosition;
-
-    if (dwWritePosition + dwWriteLen <= This->mmap_buflen_bytes) {
-        if (pdwLen1)
-            *pdwLen1 = dwWriteLen;
-        if (ppvAudio2)
-            *ppvAudio2 = 0;
-        if (pdwLen2)
-            *pdwLen2 = 0;
-    } else {
-        if (pdwLen1)
-            *pdwLen1 = This->mmap_buflen_bytes - dwWritePosition;
-        if (ppvAudio2)
-            *ppvAudio2 = This->presented_buffer;
-        if (pdwLen2)
-            *pdwLen2 = dwWriteLen - (This->mmap_buflen_bytes - dwWritePosition);
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(PIDSCDRIVERBUFFER iface, LPVOID pvAudio1,DWORD dwLen1, LPVOID pvAudio2,DWORD dwLen2)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER iface, LPWAVEFORMATEX pwfx)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    WINE_WAVEDEV *wwi = &WInDev[This->drv->wDevID];
-    snd_pcm_t *pcm = NULL;
-    snd_pcm_hw_params_t *hw_params = This->hw_params;
-    snd_pcm_format_t format = -1;
-    snd_pcm_uframes_t buffer_size;
-    DWORD rate = pwfx->nSamplesPerSec;
-    int err=0;
-    BOOL mmap;
-
-    TRACE("(%p, %p)\n", iface, pwfx);
-
-    switch (pwfx->wBitsPerSample)
-    {
-        case  8: format = SND_PCM_FORMAT_U8; break;
-        case 16: format = SND_PCM_FORMAT_S16_LE; break;
-        case 24: format = SND_PCM_FORMAT_S24_3LE; break;
-        case 32: format = SND_PCM_FORMAT_S32_LE; break;
-        default: FIXME("Unsupported bpp: %d\n", pwfx->wBitsPerSample); return DSERR_GENERIC;
-    }
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-
-    err = snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-
-    if (err < 0)
-    {
-        if (errno != EBUSY || !This->pcm)
-        {
-            /* **** */
-            LeaveCriticalSection(&This->pcm_crst);
-            WARN("Cannot open sound device: %s\n", snd_strerror(err));
-            return DSERR_GENERIC;
-        }
-        snd_pcm_drop(This->pcm);
-        snd_pcm_close(This->pcm);
-        This->pcm = NULL;
-        err = snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-        if (err < 0)
-        {
-            /* **** */
-            LeaveCriticalSection(&This->pcm_crst);
-            WARN("Cannot open sound device: %s\n", snd_strerror(err));
-            return DSERR_BUFFERLOST;
-        }
-    }
-
-    /* Set some defaults */
-    snd_pcm_hw_params_any(pcm, hw_params);
-
-    err = snd_pcm_hw_params_set_channels(pcm, hw_params, pwfx->nChannels);
-    if (err < 0) { WARN("Could not set channels to %d\n", pwfx->nChannels); goto err; }
-
-    err = snd_pcm_hw_params_set_format(pcm, hw_params, format);
-    if (err < 0) { WARN("Could not set format to %d bpp\n", pwfx->wBitsPerSample); goto err; }
-
-    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, NULL);
-    if (err < 0) { rate = pwfx->nSamplesPerSec; WARN("Could not set rate\n"); goto err; }
-
-    if (!ALSA_NearMatch(rate, pwfx->nSamplesPerSec))
-    {
-        WARN("Could not set sound rate to %d, but instead to %d\n", pwfx->nSamplesPerSec, rate);
-        pwfx->nSamplesPerSec = rate;
-        pwfx->nAvgBytesPerSec = rate * pwfx->nBlockAlign;
-        /* Let DirectSound detect this */
-    }
-
-    snd_pcm_hw_params_set_periods_integer(pcm, hw_params);
-    buffer_size = This->mmap_buflen_bytes / pwfx->nBlockAlign;
-    snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, &buffer_size);
-    buffer_size = 5000;
-    snd_pcm_hw_params_set_period_time_near(pcm, hw_params, (unsigned int*)&buffer_size, NULL);
-
-    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err < 0)
-    {
-        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
-        if (err < 0) { WARN("Could not set access\n"); goto err; }
-        mmap = 0;
-    }
-    else
-        mmap = 1;
-
-    err = snd_pcm_hw_params(pcm, hw_params);
-    if (err < 0) { WARN("Could not set hw parameters\n"); goto err; }
-
-    if (This->pcm)
-    {
-        snd_pcm_drop(This->pcm);
-        snd_pcm_close(This->pcm);
-    }
-    This->pcm = pcm;
-    This->mmap = mmap;
-
-    snd_pcm_prepare(This->pcm);
-    CreateMMAP(This);
-
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return S_OK;
-
-    err:
-    if (err < 0)
-        WARN("Failed to apply changes: %s\n", snd_strerror(err));
-
-    if (!This->pcm)
-        This->pcm = pcm;
-    else
-        snd_pcm_close(pcm);
-
-    if (This->pcm)
-        snd_pcm_hw_params_current(This->pcm, This->hw_params);
-
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return DSERR_BADFORMAT;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(PIDSCDRIVERBUFFER iface, LPDWORD lpdwCappos, LPDWORD lpdwReadpos)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    snd_pcm_uframes_t hw_pptr, hw_wptr;
-
-    EnterCriticalSection(&This->pcm_crst);
-
-    if (!This->pcm)
-    {
-        FIXME("Bad pointer for pcm: %p\n", This->pcm);
-        LeaveCriticalSection(&This->pcm_crst);
-        return DSERR_GENERIC;
-    }
-
-    if (snd_pcm_state(This->pcm) != SND_PCM_STATE_RUNNING)
-    {
-        CheckXRUN(This);
-        hw_pptr = This->mmap_pos;
-    }
-    else
-    {
-        /* FIXME: Unused at the moment */
-        snd_pcm_uframes_t used = CommitAll(This, FALSE);
-
-        if (This->mmap_pos > used)
-            hw_pptr = This->mmap_pos - used;
-        else
-            hw_pptr = This->mmap_buflen_frames - used + This->mmap_pos;
-    }
-    hw_wptr = This->mmap_pos;
-
-    if (lpdwCappos)
-        *lpdwCappos = realpos_to_fakepos(This, hw_pptr);
-    if (lpdwReadpos)
-        *lpdwReadpos = realpos_to_fakepos(This, hw_wptr);
-
-    LeaveCriticalSection(&This->pcm_crst);
-
-    TRACE("hw_pptr=%u, hw_wptr=%u playpos=%u(%p), writepos=%u(%p)\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, realpos_to_fakepos(This, hw_pptr), lpdwCappos, realpos_to_fakepos(This, hw_wptr), lpdwReadpos);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(PIDSCDRIVERBUFFER iface, LPDWORD lpdwStatus)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    snd_pcm_state_t state;
-    TRACE("(%p,%p)\n",iface,lpdwStatus);
-
-    state = snd_pcm_state(This->pcm);
-    switch (state)
-    {
-    case SND_PCM_STATE_XRUN:
-    case SND_PCM_STATE_SUSPENDED:
-    case SND_PCM_STATE_RUNNING:
-        *lpdwStatus = DSCBSTATUS_CAPTURING | (This->play_looping ? DSCBSTATUS_LOOPING : 0);
-        break;
-    default:
-        *lpdwStatus = 0;
-        break;
-    }
-
-    TRACE("State: %d, flags: 0x%08x\n", state, *lpdwStatus);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(PIDSCDRIVERBUFFER iface, DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p,%x)\n",iface,dwFlags);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-    snd_pcm_start(This->pcm);
-    This->play_looping = !!(dwFlags & DSCBSTART_LOOPING);
-    if (!This->play_looping)
-        /* Not well supported because of the difference in ALSA size and DSOUND's notion of size
-         * what it does right now is fill the buffer once.. ALSA size */
-        FIXME("Non-looping buffers are not properly supported!\n");
-    CommitAll(This, TRUE);
-
-    if (This->notify && This->notify->nrofnotifies && This->notify->notifies)
-    {
-        DWORD playpos = realpos_to_fakepos(This, This->mmap_pos);
-        if (playpos)
-            Capture_CheckNotify(This->notify, 0, playpos);
-        This->notify->playpos = playpos;
-    }
-
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p)\n",iface);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-    This->play_looping = FALSE;
-    snd_pcm_drop(This->pcm);
-    snd_pcm_prepare(This->pcm);
-
-    if (This->notify && This->notify->notifies && This->notify->nrofnotifies)
-        Capture_CheckNotify(This->notify, 0, 0);
-
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return DS_OK;
-}
-
-static const IDsCaptureDriverBufferVtbl dsdbvt =
-{
-    IDsCaptureDriverBufferImpl_QueryInterface,
-    IDsCaptureDriverBufferImpl_AddRef,
-    IDsCaptureDriverBufferImpl_Release,
-    IDsCaptureDriverBufferImpl_Lock,
-    IDsCaptureDriverBufferImpl_Unlock,
-    IDsCaptureDriverBufferImpl_SetFormat,
-    IDsCaptureDriverBufferImpl_GetPosition,
-    IDsCaptureDriverBufferImpl_GetStatus,
-    IDsCaptureDriverBufferImpl_Start,
-    IDsCaptureDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(PIDSCDRIVER iface, REFIID riid, LPVOID *ppobj)
-{
-    /* IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface; */
-    FIXME("(%p): stub!\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
-
-    if (refCount)
-        return refCount;
-
-    HeapFree(GetProcessHeap(), 0, This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(PIDSCDRIVER iface, PDSDRIVERDESC pDesc)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p,%p)\n",iface,pDesc);
-    *pDesc			= WInDev[This->wDevID].ds_desc;
-    pDesc->dwFlags		= 0;
-    pDesc->dnDevNode		= WInDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId		= 0;
-    pDesc->wReserved		= 0;
-    pDesc->ulDeviceNum		= This->wDevID;
-    pDesc->dwHeapType		= DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap	= NULL;
-    pDesc->dwMemStartAddress	= 0xDEAD0000;
-    pDesc->dwMemEndAddress	= 0xDEAF0000;
-    pDesc->dwMemAllocExtra	= 0;
-    pDesc->pvReserved1		= NULL;
-    pDesc->pvReserved2		= NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
-{
-    HRESULT hr = S_OK;
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    int err=0;
-    snd_pcm_t *pcm = NULL;
-    snd_pcm_hw_params_t *hw_params;
-
-    /* While this is not really needed, it is a good idea to do this,
-     * to see if sound can be initialized */
-
-    hw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof());
-    if (!hw_params)
-    {
-        hr = DSERR_OUTOFMEMORY;
-        WARN("--> %08x\n", hr);
-        return hr;
-    }
-
-    err = snd_pcm_open(&pcm, WInDev[This->wDevID].pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-    if (err < 0) goto err;
-    err = snd_pcm_hw_params_any(pcm, hw_params);
-    if (err < 0) goto err;
-    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err < 0)
-    {
-        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
-        if (err < 0) goto err;
-    }
-
-    TRACE("Success\n");
-    snd_pcm_close(pcm);
-    HeapFree(GetProcessHeap(), 0, hw_params);
-    return hr;
-
-    err:
-    hr = DSERR_GENERIC;
-    WARN("Failed to open device: %s\n", snd_strerror(err));
-    if (pcm)
-        snd_pcm_close(pcm);
-    HeapFree(GetProcessHeap(), 0, hw_params);
-    WARN("--> %08x\n", hr);
-    return hr;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p) stub, harmless\n",This);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(PIDSCDRIVER iface, PDSCDRIVERCAPS pCaps)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    WINE_WAVEDEV *wwi = &WInDev[This->wDevID];
-    TRACE("(%p,%p)\n",iface,pCaps);
-    pCaps->dwSize = sizeof(DSCDRIVERCAPS);
-    pCaps->dwFlags = wwi->ds_caps.dwFlags;
-    pCaps->dwFormats = wwi->incaps.dwFormats;
-    pCaps->dwChannels = wwi->incaps.wChannels;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(PIDSCDRIVER iface,
-						      LPWAVEFORMATEX pwfx,
-						      DWORD dwFlags, DWORD dwCardAddress,
-						      LPDWORD pdwcbBufferSize,
-						      LPBYTE *ppbBuffer,
-						      LPVOID *ppvObj)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    IDsCaptureDriverBufferImpl** ippdsdb = (IDsCaptureDriverBufferImpl**)ppvObj;
-    HRESULT err;
-
-    TRACE("(%p,%p,%x,%x)\n",iface,pwfx,dwFlags,dwCardAddress);
-
-    if (This->capture_buffer)
-        return DSERR_ALLOCATED;
-
-    This->capture_buffer = *ippdsdb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDsCaptureDriverBufferImpl));
-    if (*ippdsdb == NULL)
-        return DSERR_OUTOFMEMORY;
-
-    (*ippdsdb)->hw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof());
-    (*ippdsdb)->sw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof());
-    (*ippdsdb)->presented_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pdwcbBufferSize);
-    if (!(*ippdsdb)->hw_params || !(*ippdsdb)->sw_params || !(*ippdsdb)->presented_buffer)
-    {
-        HeapFree(GetProcessHeap(), 0, (*ippdsdb)->sw_params);
-        HeapFree(GetProcessHeap(), 0, (*ippdsdb)->hw_params);
-        HeapFree(GetProcessHeap(), 0, (*ippdsdb)->presented_buffer);
-        return DSERR_OUTOFMEMORY;
-    }
-    (*ippdsdb)->lpVtbl = &dsdbvt;
-    (*ippdsdb)->ref = 1;
-    (*ippdsdb)->drv = This;
-    (*ippdsdb)->mmap_buflen_bytes = *pdwcbBufferSize;
-    InitializeCriticalSection(&(*ippdsdb)->pcm_crst);
-    (*ippdsdb)->pcm_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_DSCAPTURE.pcm_crst");
-
-    /* SetFormat initialises pcm */
-    err = IDsDriverBuffer_SetFormat((IDsDriverBuffer*)*ppvObj, pwfx);
-    if (FAILED(err))
-    {
-        WARN("Error occurred: %08x\n", err);
-        goto err;
-    }
-    *ppbBuffer = (*ippdsdb)->presented_buffer;
-
-    /* buffer is ready to go */
-    TRACE("buffer created at %p\n", *ippdsdb);
-    return err;
-
-    err:
-    HeapFree(GetProcessHeap(), 0, (*ippdsdb)->presented_buffer);
-    HeapFree(GetProcessHeap(), 0, (*ippdsdb)->sw_params);
-    HeapFree(GetProcessHeap(), 0, (*ippdsdb)->hw_params);
-    HeapFree(GetProcessHeap(), 0, *ippdsdb);
-    *ippdsdb = NULL;
-    return err;
-}
-
-static const IDsCaptureDriverVtbl dscdvt =
-{
-    IDsCaptureDriverImpl_QueryInterface,
-    IDsCaptureDriverImpl_AddRef,
-    IDsCaptureDriverImpl_Release,
-    IDsCaptureDriverImpl_GetDriverDesc,
-    IDsCaptureDriverImpl_Open,
-    IDsCaptureDriverImpl_Close,
-    IDsCaptureDriverImpl_GetCaps,
-    IDsCaptureDriverImpl_CreateCaptureBuffer
-};
-
-/**************************************************************************
- *                              widDsCreate                     [internal]
- */
-DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
-{
-    IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
-    TRACE("(%d,%p)\n",wDevID,drv);
-
-    *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
-    if (!*idrv)
-        return MMSYSERR_NOMEM;
-    (*idrv)->lpVtbl	= &dscdvt;
-    (*idrv)->ref	= 1;
-
-    (*idrv)->wDevID	= wDevID;
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- *                              widDsDesc                       [internal]
- */
-DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    *desc = WInDev[wDevID].ds_desc;
-    return MMSYSERR_NOERROR;
-}
diff --git a/dlls/winealsa.drv/dsoutput.c b/dlls/winealsa.drv/dsoutput.c
deleted file mode 100644
index 562853d..0000000
--- a/dlls/winealsa.drv/dsoutput.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Sample Wine Driver for Advanced Linux Sound System (ALSA)
- *      Based on version <final> of the ALSA API
- *
- * Copyright    2002 Eric Pouech
- *              2002 Marco Pietrobono
- *              2003 Christian Costa : WaveIn support
- *              2006-2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*======================================================================*
- *              Low level dsound output implementation			*
- *======================================================================*/
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winerror.h"
-#include "winuser.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-
-#include "alsa.h"
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(dsalsa);
-
-typedef struct IDsDriverImpl IDsDriverImpl;
-typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
-
-struct IDsDriverImpl
-{
-    /* IUnknown fields */
-    IDsDriver IDsDriver_iface;
-    LONG ref;
-
-    /* IDsDriverImpl fields */
-    IDsDriverBufferImpl* primary;
-    UINT wDevID;
-};
-
-struct IDsDriverBufferImpl
-{
-    IDsDriverBuffer IDsDriverBuffer_iface;
-    LONG ref;
-    IDsDriverImpl* drv;
-
-    CRITICAL_SECTION pcm_crst;
-    BYTE *mmap_buffer;
-    DWORD mmap_buflen_bytes;
-    BOOL mmap;
-
-    snd_pcm_t *pcm;
-    snd_pcm_hw_params_t *hw_params;
-    snd_pcm_sw_params_t *sw_params;
-    snd_pcm_uframes_t mmap_buflen_frames, mmap_pos, mmap_commitahead;
-};
-
-static inline IDsDriverImpl *impl_from_IDsDriver(IDsDriver *iface)
-{
-    return CONTAINING_RECORD(iface, IDsDriverImpl, IDsDriver_iface);
-}
-
-static inline IDsDriverBufferImpl *impl_from_IDsDriverBuffer(IDsDriverBuffer *iface)
-{
-    return CONTAINING_RECORD(iface, IDsDriverBufferImpl, IDsDriverBuffer_iface);
-}
-
-/** Fill buffers, for starting and stopping
- * Alsa won't start playing until everything is filled up
- * This also updates mmap_pos
- *
- * Returns: Amount of periods in use so snd_pcm_avail_update
- * doesn't have to be called up to 4x in GetPosition()
- */
-static snd_pcm_uframes_t CommitAll(IDsDriverBufferImpl *This)
-{
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_sframes_t used;
-    const snd_pcm_uframes_t commitahead = This->mmap_commitahead;
-
-    used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
-    if (used < 0) used = 0;
-    TRACE("%p needs to commit to %lu, used: %ld\n", This, commitahead, used);
-    if (used < commitahead)
-    {
-        snd_pcm_sframes_t done;
-        snd_pcm_uframes_t putin = commitahead - used;
-        if (This->mmap)
-        {
-            snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-            done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
-        }
-        else
-        {
-            if (putin + This->mmap_pos > This->mmap_buflen_frames)
-                putin = This->mmap_buflen_frames - This->mmap_pos;
-            done = snd_pcm_writei(This->pcm, This->mmap_buffer + snd_pcm_frames_to_bytes(This->pcm, This->mmap_pos), putin);
-            if (done < putin) WARN("Short write %ld/%ld\n", putin, done);
-        }
-        if (done < 0) done = 0;
-        This->mmap_pos += done;
-        used += done;
-        putin = commitahead - used;
-
-        if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0)
-        {
-            if (This->mmap)
-            {
-                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-                done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
-                This->mmap_pos += done;
-            }
-            else
-            {
-                done = snd_pcm_writei(This->pcm, This->mmap_buffer, putin);
-                if (done < putin) WARN("Short write %ld/%ld\n", putin, done);
-                if (done < 0) done = 0;
-                This->mmap_pos = done;
-            }
-            used += done;
-        }
-    }
-
-    if (This->mmap_pos == This->mmap_buflen_frames)
-        This->mmap_pos = 0;
-
-    return used;
-}
-
-static void CheckXRUN(IDsDriverBufferImpl* This)
-{
-    snd_pcm_state_t state = snd_pcm_state(This->pcm);
-    int err;
-
-    if ( state == SND_PCM_STATE_XRUN )
-    {
-        err = snd_pcm_prepare(This->pcm);
-        CommitAll(This);
-        snd_pcm_start(This->pcm);
-        WARN("xrun occurred\n");
-        if ( err < 0 )
-            ERR("recovery from xrun failed, prepare failed: %s\n", snd_strerror(err));
-    }
-    else if ( state == SND_PCM_STATE_SUSPENDED )
-    {
-        int err = snd_pcm_resume(This->pcm);
-        TRACE("recovery from suspension occurred\n");
-        if (err < 0 && err != -EAGAIN){
-            err = snd_pcm_prepare(This->pcm);
-            if (err < 0)
-                ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err));
-        }
-    } else if ( state != SND_PCM_STATE_RUNNING ) {
-        FIXME("Unhandled state: %d\n", state);
-    }
-}
-
-/**
- * Allocate the memory-mapped buffer for direct sound, and set up the
- * callback.
- */
-static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
-{
-    snd_pcm_t *pcm = pdbi->pcm;
-    snd_pcm_format_t format;
-    snd_pcm_uframes_t frames, ofs, avail, psize, boundary;
-    unsigned int channels, bits_per_sample, bits_per_frame;
-    int err, mmap_mode;
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_hw_params_t *hw_params = pdbi->hw_params;
-    snd_pcm_sw_params_t *sw_params = pdbi->sw_params;
-    void *buf;
-
-    mmap_mode = snd_pcm_type(pcm);
-
-    if (mmap_mode == SND_PCM_TYPE_HW)
-        TRACE("mmap'd buffer is a direct hardware buffer.\n");
-    else if (mmap_mode == SND_PCM_TYPE_DMIX)
-        TRACE("mmap'd buffer is an ALSA dmix buffer\n");
-    else
-        TRACE("mmap'd buffer is an ALSA type %d buffer\n", mmap_mode);
-
-    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
-
-    err = snd_pcm_hw_params_get_format(hw_params, &format);
-    err = snd_pcm_hw_params_get_buffer_size(hw_params, &frames);
-    err = snd_pcm_hw_params_get_channels(hw_params, &channels);
-    bits_per_sample = snd_pcm_format_physical_width(format);
-    bits_per_frame = bits_per_sample * channels;
-
-    if (TRACE_ON(dsalsa))
-        ALSA_TraceParameters(hw_params, NULL, FALSE);
-
-    TRACE("format=%s  frames=%ld  channels=%d  bits_per_sample=%d  bits_per_frame=%d\n",
-          snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame);
-
-    pdbi->mmap_buflen_frames = frames;
-    pdbi->mmap_buflen_bytes = snd_pcm_frames_to_bytes( pcm, frames );
-
-    snd_pcm_sw_params_current(pcm, sw_params);
-    snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 0);
-    snd_pcm_sw_params_get_boundary(sw_params, &boundary);
-    snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary);
-    snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, boundary);
-    snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0);
-    snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0);
-    err = snd_pcm_sw_params(pcm, sw_params);
-
-    avail = snd_pcm_avail_update(pcm);
-    if ((snd_pcm_sframes_t)avail < 0)
-    {
-        ERR("No buffer is available: %s.\n", snd_strerror(avail));
-        return DSERR_GENERIC;
-    }
-
-    if (!pdbi->mmap)
-    {
-        buf = pdbi->mmap_buffer = HeapAlloc(GetProcessHeap(), 0, pdbi->mmap_buflen_bytes);
-        if (!buf)
-            return DSERR_OUTOFMEMORY;
-
-        snd_pcm_format_set_silence(format, buf, pdbi->mmap_buflen_frames);
-        pdbi->mmap_pos = 0;
-    }
-    else
-    {
-        err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
-        if ( err < 0 )
-        {
-            ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
-            return DSERR_GENERIC;
-        }
-        snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
-        pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
-        pdbi->mmap_buffer = areas->addr;
-    }
-
-    TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
-        frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    FIXME("(): stub!\n");
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
-
-    if (refCount)
-        return refCount;
-
-    TRACE("mmap buffer %p destroyed\n", This->mmap_buffer);
-
-    if (This == This->drv->primary)
-        This->drv->primary = NULL;
-
-    This->pcm_crst.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&This->pcm_crst);
-
-    snd_pcm_drop(This->pcm);
-    snd_pcm_close(This->pcm);
-    This->pcm = NULL;
-    HeapFree(GetProcessHeap(), 0, This->sw_params);
-    HeapFree(GetProcessHeap(), 0, This->hw_params);
-    if (!This->mmap)
-        HeapFree(GetProcessHeap(), 0, This->mmap_buffer);
-    HeapFree(GetProcessHeap(), 0, This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
-					       LPVOID*ppvAudio1,LPDWORD pdwLen1,
-					       LPVOID*ppvAudio2,LPDWORD pdwLen2,
-					       DWORD dwWritePosition,DWORD dwWriteLen,
-					       DWORD dwFlags)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    snd_pcm_uframes_t writepos;
-
-    TRACE("%d bytes from %d\n", dwWriteLen, dwWritePosition);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-
-    if (dwFlags & DSBLOCK_ENTIREBUFFER)
-        dwWriteLen = This->mmap_buflen_bytes;
-
-    if (dwWriteLen > This->mmap_buflen_bytes || dwWritePosition >= This->mmap_buflen_bytes)
-    {
-        /* **** */
-        LeaveCriticalSection(&This->pcm_crst);
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (ppvAudio2) *ppvAudio2 = NULL;
-    if (pdwLen2) *pdwLen2 = 0;
-
-    *ppvAudio1 = This->mmap_buffer + dwWritePosition;
-    *pdwLen1 = dwWriteLen;
-
-    if (dwWritePosition+dwWriteLen > This->mmap_buflen_bytes)
-    {
-        DWORD remainder = This->mmap_buflen_bytes - dwWritePosition;
-        *pdwLen1 = remainder;
-
-        if (ppvAudio2 && pdwLen2)
-        {
-            *ppvAudio2 = This->mmap_buffer;
-            *pdwLen2 = dwWriteLen - remainder;
-        }
-        else dwWriteLen = remainder;
-    }
-
-    writepos = snd_pcm_bytes_to_frames(This->pcm, dwWritePosition);
-    if (writepos == This->mmap_pos)
-    {
-        const snd_pcm_channel_area_t *areas;
-        snd_pcm_uframes_t writelen = snd_pcm_bytes_to_frames(This->pcm, dwWriteLen), putin = writelen;
-        TRACE("Hit mmap_pos, locking data!\n");
-        if (This->mmap)
-            snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-    }
-    else
-        WARN("mmap_pos (%lu) != writepos (%lu) not locking data!\n", This->mmap_pos, writepos);
-
-    LeaveCriticalSection(&This->pcm_crst);
-    /* **** */
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
-						 LPVOID pvAudio1,DWORD dwLen1,
-						 LPVOID pvAudio2,DWORD dwLen2)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    snd_pcm_uframes_t writepos;
-
-    if (!dwLen1)
-        return DS_OK;
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-
-    writepos = snd_pcm_bytes_to_frames(This->pcm, (DWORD_PTR)pvAudio1 - (DWORD_PTR)This->mmap_buffer);
-    if (writepos == This->mmap_pos)
-    {
-        const snd_pcm_channel_area_t *areas;
-        snd_pcm_uframes_t writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen1);
-        TRACE("Committing data\n");
-        if (This->mmap)
-            This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
-        else
-        {
-            int ret;
-            ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);
-            if (ret == -EPIPE)
-            {
-                WARN("Underrun occurred\n");
-                wine_snd_pcm_recover(This->pcm, -EPIPE, 1);
-                ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);
-
-                /* Advance mmap pointer a little to make dsound notice the underrun and respond to it */
-                if (ret < writelen) WARN("Short write %ld/%d\n", writelen, ret);
-                This->mmap_pos += This->mmap_commitahead + ret;
-                This->mmap_pos %= This->mmap_buflen_frames;
-            }
-            else if (ret > 0)
-                This->mmap_pos += ret;
-            if (ret < 0)
-                WARN("Committing data: %d / %s (%p %ld)\n", ret, snd_strerror(ret), pvAudio1, writelen);
-        }
-
-        if (This->mmap_pos == This->mmap_buflen_frames)
-            This->mmap_pos = 0;
-        if (dwLen2)
-        {
-            writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen2);
-            if (This->mmap)
-            {
-                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &writelen);
-                This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
-            }
-            else
-            {
-                int ret;
-                ret = snd_pcm_writei(This->pcm, pvAudio2, writelen);
-                if (ret < writelen) WARN("Short write %ld/%d\n", writelen, ret);
-                This->mmap_pos = ret > 0 ? ret : 0;
-            }
-            assert(This->mmap_pos < This->mmap_buflen_frames);
-        }
-    }
-    LeaveCriticalSection(&This->pcm_crst);
-    /* **** */
-
-    return DS_OK;
-}
-
-static HRESULT SetFormat(IDsDriverBufferImpl *This, LPWAVEFORMATEX pwfx)
-{
-    snd_pcm_t *pcm = NULL;
-    snd_pcm_hw_params_t *hw_params = This->hw_params;
-    unsigned int buffer_time = 500000;
-    snd_pcm_format_t format = -1;
-    snd_pcm_uframes_t psize;
-    DWORD rate = pwfx->nSamplesPerSec;
-    int err=0;
-
-    switch (pwfx->wBitsPerSample)
-    {
-        case  8: format = SND_PCM_FORMAT_U8; break;
-        case 16: format = SND_PCM_FORMAT_S16_LE; break;
-        case 24: format = SND_PCM_FORMAT_S24_3LE; break;
-        case 32: format = SND_PCM_FORMAT_S32_LE; break;
-        default: FIXME("Unsupported bpp: %d\n", pwfx->wBitsPerSample); return DSERR_GENERIC;
-    }
-
-    err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-    if (err < 0)
-    {
-        if (errno != EBUSY || !This->pcm)
-        {
-            WARN("Cannot open sound device: %s\n", snd_strerror(err));
-            return DSERR_GENERIC;
-        }
-        snd_pcm_drop(This->pcm);
-        snd_pcm_close(This->pcm);
-        This->pcm = NULL;
-        err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-        if (err < 0)
-        {
-            WARN("Cannot open sound device: %s\n", snd_strerror(err));
-            return DSERR_BUFFERLOST;
-        }
-    }
-
-    /* Set some defaults */
-    snd_pcm_hw_params_any(pcm, hw_params);
-    err = snd_pcm_hw_params_set_channels(pcm, hw_params, pwfx->nChannels);
-    if (err < 0) { WARN("Could not set channels to %d\n", pwfx->nChannels); goto err; }
-
-    err = snd_pcm_hw_params_set_format(pcm, hw_params, format);
-    if (err < 0) { WARN("Could not set format to %d bpp\n", pwfx->wBitsPerSample); goto err; }
-
-    /* Alsa's rate resampling is only used if the application specifically requests
-     * a buffer at a certain frequency, else it is better to disable it due to unwanted
-     * side effects, which may include: Less granular pointer, changing buffer sizes, etc
-     */
-#if SND_LIB_VERSION >= 0x010009
-    snd_pcm_hw_params_set_rate_resample(pcm, hw_params, 0);
-#endif
-
-    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, NULL);
-    if (err < 0) { rate = pwfx->nSamplesPerSec; WARN("Could not set rate\n"); goto err; }
-
-    if (!ALSA_NearMatch(rate, pwfx->nSamplesPerSec))
-    {
-        WARN("Could not set sound rate to %d, but instead to %d\n", pwfx->nSamplesPerSec, rate);
-        pwfx->nSamplesPerSec = rate;
-        pwfx->nAvgBytesPerSec = rate * pwfx->nBlockAlign;
-        /* Let DirectSound detect this */
-    }
-
-    snd_pcm_hw_params_set_periods_integer(pcm, hw_params);
-    snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, NULL);
-    buffer_time = 10000;
-    snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &buffer_time, NULL);
-
-    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
-    buffer_time = 16;
-    snd_pcm_hw_params_set_periods_near(pcm, hw_params, &buffer_time, NULL);
-
-    if (!This->mmap)
-    {
-        HeapFree(GetProcessHeap(), 0, This->mmap_buffer);
-        This->mmap_buffer = NULL;
-    }
-
-    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err >= 0)
-        This->mmap = 1;
-    else
-    {
-        This->mmap = 0;
-        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
-    }
-
-    err = snd_pcm_hw_params(pcm, hw_params);
-
-    /* ALSA needs at least 3 buffers to work successfully */
-    This->mmap_commitahead = 3 * psize;
-    while (This->mmap_commitahead <= 512)
-        This->mmap_commitahead += psize;
-
-    if (This->pcm)
-    {
-        snd_pcm_drop(This->pcm);
-        snd_pcm_close(This->pcm);
-    }
-    This->pcm = pcm;
-    snd_pcm_prepare(This->pcm);
-    DSDB_CreateMMAP(This);
-    return S_OK;
-
-    err:
-    if (err < 0)
-        WARN("Failed to apply changes: %s\n", snd_strerror(err));
-
-    if (!This->pcm)
-        This->pcm = pcm;
-    else
-        snd_pcm_close(pcm);
-
-    if (This->pcm)
-        snd_pcm_hw_params_current(This->pcm, This->hw_params);
-
-    return DSERR_BADFORMAT;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface, LPWAVEFORMATEX pwfx)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("(%p, %p)\n", iface, pwfx);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-    hr = SetFormat(This, pwfx);
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-
-    if (hr == DS_OK)
-        return S_FALSE;
-    return hr;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    FIXME("(%p,%d): stub\n",iface,dwFreq);
-    return S_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    FIXME("(%p,%p): stub\n",This,pVolPan);
-    /* TODO: Bring volume control back */
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    /* I don't even think alsa allows this */
-    FIXME("(%p,%d): stub\n",iface,dwNewPos);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
-						      LPDWORD lpdwPlay, LPDWORD lpdwWrite)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    snd_pcm_uframes_t hw_pptr, hw_wptr;
-    snd_pcm_state_t state;
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-
-    if (!This->pcm)
-    {
-        FIXME("Bad pointer for pcm: %p\n", This->pcm);
-        LeaveCriticalSection(&This->pcm_crst);
-        return DSERR_GENERIC;
-    }
-
-    if (!lpdwPlay && !lpdwWrite)
-        CommitAll(This);
-
-    state = snd_pcm_state(This->pcm);
-
-    if (state != SND_PCM_STATE_PREPARED && state != SND_PCM_STATE_RUNNING)
-    {
-        CheckXRUN(This);
-        state = snd_pcm_state(This->pcm);
-    }
-    if (state == SND_PCM_STATE_RUNNING)
-    {
-        snd_pcm_sframes_t used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
-
-        if (used < 0)
-        {
-            WARN("Underrun: %ld / %ld\n", used, snd_pcm_avail_update(This->pcm));
-            if (This->mmap)
-            {
-                snd_pcm_forward(This->pcm, -used);
-                This->mmap_pos += -used;
-                This->mmap_pos %= This->mmap_buflen_frames;
-            }
-            used = 0;
-        }
-
-        if (This->mmap_pos > used)
-            hw_pptr = This->mmap_pos - used;
-        else
-            hw_pptr = This->mmap_buflen_frames + This->mmap_pos - used;
-        hw_pptr %= This->mmap_buflen_frames;
-
-        TRACE("At position: %ld (%ld) - Used %ld\n", hw_pptr, This->mmap_pos, used);
-    }
-    else hw_pptr = This->mmap_pos;
-    hw_wptr = This->mmap_pos;
-
-    LeaveCriticalSection(&This->pcm_crst);
-    /* **** */
-
-    if (lpdwPlay)
-        *lpdwPlay = snd_pcm_frames_to_bytes(This->pcm, hw_pptr);
-    if (lpdwWrite)
-        *lpdwWrite = snd_pcm_frames_to_bytes(This->pcm, hw_wptr);
-
-    TRACE("hw_pptr=0x%08x, hw_wptr=0x%08x playpos=%d, writepos=%d\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
-{
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    TRACE("(%p,%x,%x,%x)\n",iface,dwRes1,dwRes2,dwFlags);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-    snd_pcm_start(This->pcm);
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
-{
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_uframes_t avail;
-    snd_pcm_format_t format;
-    IDsDriverBufferImpl *This = impl_from_IDsDriverBuffer(iface);
-    TRACE("(%p)\n",iface);
-
-    /* **** */
-    EnterCriticalSection(&This->pcm_crst);
-    avail = This->mmap_buflen_frames;
-    snd_pcm_drop(This->pcm);
-    snd_pcm_prepare(This->pcm);
-    avail = snd_pcm_avail_update(This->pcm);
-    snd_pcm_hw_params_get_format(This->hw_params, &format);
-    if (This->mmap)
-    {
-        snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &avail);
-        snd_pcm_format_set_silence(format, areas->addr, This->mmap_buflen_frames);
-        snd_pcm_mmap_commit(This->pcm, This->mmap_pos, 0);
-    }
-    else
-    {
-        snd_pcm_format_set_silence(format, This->mmap_buffer, This->mmap_buflen_frames);
-        snd_pcm_writei(This->pcm, This->mmap_buffer, This->mmap_buflen_frames);
-        This->mmap_pos = 0;
-    }
-
-    /* **** */
-    LeaveCriticalSection(&This->pcm_crst);
-    return DS_OK;
-}
-
-static const IDsDriverBufferVtbl dsdbvt =
-{
-    IDsDriverBufferImpl_QueryInterface,
-    IDsDriverBufferImpl_AddRef,
-    IDsDriverBufferImpl_Release,
-    IDsDriverBufferImpl_Lock,
-    IDsDriverBufferImpl_Unlock,
-    IDsDriverBufferImpl_SetFormat,
-    IDsDriverBufferImpl_SetFrequency,
-    IDsDriverBufferImpl_SetVolumePan,
-    IDsDriverBufferImpl_SetPosition,
-    IDsDriverBufferImpl_GetPosition,
-    IDsDriverBufferImpl_Play,
-    IDsDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
-{
-    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
-    FIXME("(%p): stub!\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
-
-    if (refCount)
-        return refCount;
-
-    HeapFree(GetProcessHeap(), 0, This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface, PDSDRIVERDESC pDesc)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    TRACE("(%p,%p)\n",iface,pDesc);
-    *pDesc			= WOutDev[This->wDevID].ds_desc;
-    pDesc->dwFlags		= DSDDESC_DONTNEEDSECONDARYLOCK | DSDDESC_DONTNEEDWRITELEAD;
-    pDesc->dnDevNode		= WOutDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId		= 0;
-    pDesc->wReserved		= 0;
-    pDesc->ulDeviceNum		= This->wDevID;
-    pDesc->dwHeapType		= DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap	= NULL;
-    pDesc->dwMemStartAddress	= 0xDEAD0000;
-    pDesc->dwMemEndAddress	= 0xDEAF0000;
-    pDesc->dwMemAllocExtra	= 0;
-    pDesc->pvReserved1		= NULL;
-    pDesc->pvReserved2		= NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
-{
-    HRESULT hr = S_OK;
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    int err=0;
-    snd_pcm_t *pcm = NULL;
-    snd_pcm_hw_params_t *hw_params;
-
-    /* While this is not really needed, it is a good idea to do this,
-     * to see if sound can be initialized */
-
-    hw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof());
-
-    if (!hw_params)
-    {
-        hr = DSERR_OUTOFMEMORY;
-        goto unalloc;
-    }
-
-    err = snd_pcm_open(&pcm, WOutDev[This->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-    if (err < 0) goto err;
-    err = snd_pcm_hw_params_any(pcm, hw_params);
-    if (err < 0) goto err;
-    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err < 0)
-        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
-    if (err < 0) goto err;
-
-    TRACE("Success\n");
-    snd_pcm_close(pcm);
-    goto unalloc;
-
-    err:
-    hr = DSERR_GENERIC;
-    FIXME("Failed to open device: %s\n", snd_strerror(err));
-    if (pcm)
-        snd_pcm_close(pcm);
-    unalloc:
-    HeapFree(GetProcessHeap(), 0, hw_params);
-    if (hr != S_OK)
-        WARN("--> %08x\n", hr);
-    return hr;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    TRACE("(%p) stub, harmless\n",This);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    TRACE("(%p,%p)\n",iface,pCaps);
-    *pCaps = WOutDev[This->wDevID].ds_caps;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
-						      LPWAVEFORMATEX pwfx,
-						      DWORD dwFlags, DWORD dwCardAddress,
-						      LPDWORD pdwcbBufferSize,
-						      LPBYTE *ppbBuffer,
-						      LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
-    HRESULT err;
-
-    TRACE("(%p,%p,%x,%x)\n",iface,pwfx,dwFlags,dwCardAddress);
-    /* we only support primary buffers... for now */
-    if (!(dwFlags & DSBCAPS_PRIMARYBUFFER))
-        return DSERR_UNSUPPORTED;
-    if (This->primary)
-        return DSERR_ALLOCATED;
-
-    *ippdsdb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDsDriverBufferImpl));
-    if (*ippdsdb == NULL)
-        return DSERR_OUTOFMEMORY;
-
-    (*ippdsdb)->hw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof());
-    (*ippdsdb)->sw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof());
-    if (!(*ippdsdb)->hw_params || !(*ippdsdb)->sw_params)
-    {
-        HeapFree(GetProcessHeap(), 0, (*ippdsdb)->sw_params);
-        HeapFree(GetProcessHeap(), 0, (*ippdsdb)->hw_params);
-        return DSERR_OUTOFMEMORY;
-    }
-    (*ippdsdb)->IDsDriverBuffer_iface.lpVtbl = &dsdbvt;
-    (*ippdsdb)->ref	= 1;
-    (*ippdsdb)->drv	= This;
-    InitializeCriticalSection(&(*ippdsdb)->pcm_crst);
-    (*ippdsdb)->pcm_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_DSOUTPUT.pcm_crst");
-
-    /* SetFormat has to re-initialize pcm here anyway */
-    err = SetFormat(*ippdsdb, pwfx);
-    if (FAILED(err))
-    {
-        WARN("Error occurred: %08x\n", err);
-        goto err;
-    }
-
-    if (dwFlags & DSBCAPS_PRIMARYBUFFER)
-        This->primary = *ippdsdb;
-
-    *pdwcbBufferSize = (*ippdsdb)->mmap_buflen_bytes;
-    *ppbBuffer = (*ippdsdb)->mmap_buffer;
-
-    /* buffer is ready to go */
-    TRACE("buffer created at %p\n", *ippdsdb);
-    return err;
-
-    err:
-    HeapFree(GetProcessHeap(), 0, (*ippdsdb)->sw_params);
-    HeapFree(GetProcessHeap(), 0, (*ippdsdb)->hw_params);
-    HeapFree(GetProcessHeap(), 0, *ippdsdb);
-    *ippdsdb = NULL;
-    return err;
-}
-
-static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
-							 PIDSDRIVERBUFFER pBuffer,
-							 LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = impl_from_IDsDriver(iface);
-    FIXME("(%p,%p): stub\n",This,pBuffer);
-    return DSERR_INVALIDCALL;
-}
-
-static const IDsDriverVtbl dsdvt =
-{
-    IDsDriverImpl_QueryInterface,
-    IDsDriverImpl_AddRef,
-    IDsDriverImpl_Release,
-    IDsDriverImpl_GetDriverDesc,
-    IDsDriverImpl_Open,
-    IDsDriverImpl_Close,
-    IDsDriverImpl_GetCaps,
-    IDsDriverImpl_CreateSoundBuffer,
-    IDsDriverImpl_DuplicateSoundBuffer
-};
-
-DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
-{
-    IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
-
-    TRACE("driver created\n");
-
-    *idrv = HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverImpl));
-    if (!*idrv)
-        return MMSYSERR_NOMEM;
-    (*idrv)->IDsDriver_iface.lpVtbl = &dsdvt;
-    (*idrv)->ref	= 1;
-
-    (*idrv)->wDevID	= wDevID;
-    (*idrv)->primary	= NULL;
-    return MMSYSERR_NOERROR;
-}
-
-DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    *desc = WOutDev[wDevID].ds_desc;
-    return MMSYSERR_NOERROR;
-}
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index ceae2d7..42586b1 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -51,9 +51,10 @@
 #include "mmreg.h"
 #include "dsound.h"
 #include "dsdriver.h"
-#include "alsa.h"
 #include "wine/debug.h"
 
+#include <alsa/asoundlib.h>
+
 WINE_DEFAULT_DEBUG_CHANNEL(midi);
 
 #ifndef SND_SEQ_PORT_TYPE_PORT
@@ -1390,4 +1391,29 @@ DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
     return MMSYSERR_NOTSUPPORTED;
 }
 
-/*-----------------------------------------------------------------------*/
+/**************************************************************************
+ * 				DriverProc (WINEALSA.@)
+ */
+LRESULT CALLBACK ALSA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
+                                 LPARAM dwParam1, LPARAM dwParam2)
+{
+/* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
+/* EPP 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
+
+    switch(wMsg) {
+    case DRV_LOAD:
+    case DRV_FREE:
+    case DRV_OPEN:
+    case DRV_CLOSE:
+    case DRV_ENABLE:
+    case DRV_DISABLE:
+    case DRV_QUERYCONFIGURE:
+    case DRV_CONFIGURE:
+        return 1;
+    case DRV_INSTALL:
+    case DRV_REMOVE:
+        return DRV_SUCCESS;
+    default:
+	return 0;
+    }
+}
diff --git a/dlls/winealsa.drv/mixer.c b/dlls/winealsa.drv/mixer.c
deleted file mode 100644
index 0541637..0000000
--- a/dlls/winealsa.drv/mixer.c
+++ /dev/null
@@ -1,1612 +0,0 @@
-/*
- * Alsa MIXER Wine Driver for Linux
- * Very loosely based on wineoss mixer driver
- *
- * Copyright 2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <fcntl.h>
-#include <errno.h>
-#include <assert.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "mmsystem.h"
-#include "alsa.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(mixer);
-
-#define	WINE_MIXER_MANUF_ID      0xAA
-#define	WINE_MIXER_PRODUCT_ID    0x55
-#define	WINE_MIXER_VERSION       0x0100
-
-/* Generic notes:
- * In windows it seems to be required for all controls to have a volume switch
- * In alsa that's optional
- *
- * I assume for playback controls, that there is always a playback volume switch available
- * Mute is optional
- *
- * For capture controls, it is needed that there is a capture switch and a volume switch,
- * It doesn't matter whether it is a playback volume switch or a capture volume switch.
- * The code will first try to get/adjust capture volume, if that fails it tries playback volume
- * It is not pretty, but under my 3 test cards it seems that there is no other choice:
- * Most capture controls don't have a capture volume setting
- *
- * MUX means that only capture source can be exclusively selected,
- * MIXER means that multiple sources can be selected simultaneously.
- */
-
-static const char * getMessage(UINT uMsg)
-{
-#define MSG_TO_STR(x) case x: return #x;
-    switch (uMsg){
-    MSG_TO_STR(DRVM_INIT);
-    MSG_TO_STR(DRVM_EXIT);
-    MSG_TO_STR(DRVM_ENABLE);
-    MSG_TO_STR(DRVM_DISABLE);
-    MSG_TO_STR(MXDM_GETDEVCAPS);
-    MSG_TO_STR(MXDM_GETLINEINFO);
-    MSG_TO_STR(MXDM_GETNUMDEVS);
-    MSG_TO_STR(MXDM_OPEN);
-    MSG_TO_STR(MXDM_CLOSE);
-    MSG_TO_STR(MXDM_GETLINECONTROLS);
-    MSG_TO_STR(MXDM_GETCONTROLDETAILS);
-    MSG_TO_STR(MXDM_SETCONTROLDETAILS);
-    default: break;
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", uMsg);
-}
-
-static const char * getControlType(DWORD dwControlType)
-{
-#define TYPE_TO_STR(x) case x: return #x;
-    switch (dwControlType) {
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME);
-    }
-#undef TYPE_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", dwControlType);
-}
-
-/* A simple declaration of a line control
- * These are each of the channels that show up
- */
-typedef struct line {
-    /* Name we present to outside world */
-    WCHAR name[MAXPNAMELEN];
-
-    DWORD component;
-    DWORD dst;
-    DWORD capt;
-    DWORD chans;
-    snd_mixer_elem_t *elem;
-} line;
-
-/* A control structure, with toggle enabled switch
- * Control structures control volume, muted, which capture source
- */
-typedef struct control {
-    BOOL enabled;
-    MIXERCONTROLW c;
-} control;
-
-/* Mixer device */
-typedef struct mixer
-{
-    snd_mixer_t *mix;
-    WCHAR mixername[MAXPNAMELEN];
-
-    int chans, dests;
-    LPDRVCALLBACK callback;
-    DWORD_PTR callbackpriv;
-    HDRVR hmx;
-
-    line *lines;
-    control *controls;
-} mixer;
-
-#define MAX_MIXERS 32
-#define CONTROLSPERLINE 3
-#define OFS_MUTE 2
-#define OFS_MUX 1
-
-static int cards = 0;
-static mixer mixdev[MAX_MIXERS];
-static HANDLE thread;
-static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask);
-static DWORD WINAPI ALSA_MixerPollThread(LPVOID lParam);
-static CRITICAL_SECTION elem_crst;
-static int msg_pipe[2];
-static LONG refcnt;
-
-/* found channel names in alsa lib, alsa api doesn't have another way for this
- * map name -> componenttype, worst case we get a wrong componenttype which is
- * mostly harmless
- */
-
-static const struct mixerlinetype {
-    const char *name;  DWORD cmpt;
-} converttable[] = {
-    { "Master",     MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,    },
-    { "Capture",    MIXERLINE_COMPONENTTYPE_DST_WAVEIN,      },
-    { "PCM",        MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,     },
-    { "PC Speaker", MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER,   },
-    { "Synth",      MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER, },
-    { "Headphone",  MIXERLINE_COMPONENTTYPE_DST_HEADPHONES,  },
-    { "Mic",        MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE,  },
-    { "Aux",        MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED,   },
-    { "CD",         MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC, },
-    { "Line",       MIXERLINE_COMPONENTTYPE_SRC_LINE,        },
-    { "Phone",      MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE,   },
-    { "Digital",    MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE,  },
-    { "Front Mic",  MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE,  },
-};
-
-/* Map name to MIXERLINE_COMPONENTTYPE_XXX */
-static int getcomponenttype(const char *name)
-{
-    int x;
-    for (x=0; x< sizeof(converttable)/sizeof(converttable[0]); ++x)
-        if (!strcasecmp(name, converttable[x].name))
-        {
-            TRACE("%d -> %s\n", x, name);
-            return converttable[x].cmpt;
-        }
-    WARN("Unknown mixer name %s, probably harmless\n", name);
-    return MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
-}
-
-/* Is this control suited for showing up? */
-static int blacklisted(snd_mixer_elem_t *elem)
-{
-    const char *name = snd_mixer_selem_get_name(elem);
-    BOOL blisted = 0;
-
-    if (!snd_mixer_selem_has_playback_volume(elem) &&
-        !snd_mixer_selem_has_capture_volume(elem))
-        blisted = 1;
-
-    TRACE("%s: %x\n", name, blisted);
-    return blisted;
-}
-
-static void fillcontrols(mixer *mmixer)
-{
-    int id;
-    for (id = 0; id < mmixer->chans; ++id)
-    {
-        line *mline = &mmixer->lines[id];
-        int ofs = CONTROLSPERLINE * id;
-        int x;
-        long min, max;
-
-        TRACE("Filling control %d\n", id);
-        if (!mline->elem)
-            break;
-        if (id == 1 && !mline->elem)
-            continue;
-
-        if (mline->capt && snd_mixer_selem_has_capture_volume(mline->elem))
-            snd_mixer_selem_get_capture_volume_range(mline->elem, &min, &max);
-        else
-            snd_mixer_selem_get_playback_volume_range(mline->elem, &min, &max);
-
-        /* (!snd_mixer_selem_has_playback_volume(elem) || snd_mixer_selem_has_capture_volume(elem)) */
-        /* Volume, always enabled by definition of blacklisted channels */
-        mmixer->controls[ofs].enabled = 1;
-        mmixer->controls[ofs].c.cbStruct = sizeof(mmixer->controls[ofs].c);
-        mmixer->controls[ofs].c.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
-        mmixer->controls[ofs].c.dwControlID = ofs;
-        mmixer->controls[ofs].c.Bounds.s1.dwMinimum = 0;
-        mmixer->controls[ofs].c.Bounds.s1.dwMaximum = 65535;
-        mmixer->controls[ofs].c.Metrics.cSteps = 65536/(max-min);
-
-        if ((id == 1 && snd_mixer_selem_has_capture_switch(mline->elem)) ||
-            (!mline->capt && snd_mixer_selem_has_playback_switch(mline->elem)))
-        { /* MUTE button optional, main capture channel should have one too */
-            mmixer->controls[ofs+OFS_MUTE].enabled = 1;
-            mmixer->controls[ofs+OFS_MUTE].c.cbStruct = sizeof(mmixer->controls[ofs].c);
-            mmixer->controls[ofs+OFS_MUTE].c.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
-            mmixer->controls[ofs+OFS_MUTE].c.dwControlID = ofs+OFS_MUTE;
-            mmixer->controls[ofs+OFS_MUTE].c.Bounds.s1.dwMaximum = 1;
-        }
-
-        if (mline->capt && snd_mixer_selem_has_capture_switch_exclusive(mline->elem))
-            mmixer->controls[CONTROLSPERLINE+OFS_MUX].c.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
-
-        if (id == 1)
-        { /* Capture select, in case cMultipleItems is 0, it means capture is disabled anyway */
-            mmixer->controls[ofs+OFS_MUX].enabled = 1;
-            mmixer->controls[ofs+OFS_MUX].c.cbStruct = sizeof(mmixer->controls[ofs].c);
-            mmixer->controls[ofs+OFS_MUX].c.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER;
-            mmixer->controls[ofs+OFS_MUX].c.dwControlID = ofs+OFS_MUX;
-            mmixer->controls[ofs+OFS_MUX].c.fdwControl = MIXERCONTROL_CONTROLF_MULTIPLE;
-
-            for (x = 0; x<mmixer->chans; ++x)
-                if (x != id && mmixer->lines[x].dst == id)
-                    ++(mmixer->controls[ofs+OFS_MUX].c.cMultipleItems);
-            if (!mmixer->controls[ofs+OFS_MUX].c.cMultipleItems)
-                mmixer->controls[ofs+OFS_MUX].enabled = 0;
-
-            mmixer->controls[ofs+OFS_MUX].c.Bounds.s1.dwMaximum = mmixer->controls[ofs+OFS_MUX].c.cMultipleItems - 1;
-            mmixer->controls[ofs+OFS_MUX].c.Metrics.cSteps = mmixer->controls[ofs+OFS_MUX].c.cMultipleItems;
-        }
-        for (x=0; x<CONTROLSPERLINE; ++x)
-        {
-            lstrcpynW(mmixer->controls[ofs+x].c.szShortName, mline->name, sizeof(mmixer->controls[ofs+x].c.szShortName)/sizeof(WCHAR));
-            lstrcpynW(mmixer->controls[ofs+x].c.szName, mline->name, sizeof(mmixer->controls[ofs+x].c.szName)/sizeof(WCHAR));
-        }
-    }
-}
-
-/* get amount of channels for elem */
-/* Officially we should keep capture/playback separated,
- * but that's not going to work in the alsa api */
-static int chans(mixer *mmixer, snd_mixer_elem_t * elem, DWORD capt)
-{
-    int ret=0, chn;
-
-    if (capt && snd_mixer_selem_has_capture_volume(elem)) {
-        for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-            if (snd_mixer_selem_has_capture_channel(elem, chn))
-                ++ret;
-    } else {
-        for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-            if (snd_mixer_selem_has_playback_channel(elem, chn))
-                ++ret;
-    }
-    if (!ret)
-        FIXME("Mixer channel %s was found for %s, but no channels were found? Wrong selection!\n", snd_mixer_selem_get_name(elem), (snd_mixer_selem_has_playback_volume(elem) ? "playback" : "capture"));
-    return ret;
-}
-
-static void filllines(mixer *mmixer, snd_mixer_elem_t *mastelem, snd_mixer_elem_t *captelem, int capt)
-{
-    snd_mixer_elem_t *elem;
-    line *mline = mmixer->lines;
-
-    if (mastelem) {
-        /* Master control */
-        MultiByteToWideChar(CP_UNIXCP, 0, snd_mixer_selem_get_name(mastelem), -1, mline->name, sizeof(mline->name)/sizeof(WCHAR));
-        mline->component = getcomponenttype(snd_mixer_selem_get_name(mastelem));
-        mline->dst = 0;
-        mline->capt = 0;
-        mline->elem = mastelem;
-        mline->chans = chans(mmixer, mastelem, 0);
-
-        snd_mixer_elem_set_callback(mastelem, elem_callback);
-        snd_mixer_elem_set_callback_private(mastelem, mmixer);
-    } else {
-        MultiByteToWideChar(CP_UNIXCP, 0, "Empty Master Element", -1, mline->name, sizeof(mline->name)/sizeof(WCHAR));
-    }
-
-    /* Capture control
-     * Note: since mmixer->dests = 1, it means only playback control is visible
-     * This makes sense, because if there are no capture sources capture control
-     * can't do anything and should be invisible */
-
-    /* Control 1 is reserved for capture even when not enabled */
-    ++mline;
-    if (capt)
-    {
-        MultiByteToWideChar(CP_UNIXCP, 0, snd_mixer_selem_get_name(captelem), -1, mline->name, sizeof(mline->name)/sizeof(WCHAR));
-        mline->component = getcomponenttype(snd_mixer_selem_get_name(captelem));
-        mline->dst = 1;
-        mline->capt = 1;
-        mline->elem = captelem;
-        mline->chans = chans(mmixer, captelem, 1);
-
-        snd_mixer_elem_set_callback(captelem, elem_callback);
-        snd_mixer_elem_set_callback_private(captelem, mmixer);
-    }
-
-    for (elem = snd_mixer_first_elem(mmixer->mix); elem; elem = snd_mixer_elem_next(elem))
-        if (elem != mastelem && elem != captelem && !blacklisted(elem))
-        {
-            const char * name = snd_mixer_selem_get_name(elem);
-            DWORD comp = getcomponenttype(name);
-
-            if (snd_mixer_selem_has_playback_volume(elem) &&
-               (snd_mixer_selem_has_capture_volume(elem) || comp != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE))
-            {
-                (++mline)->component = comp;
-                MultiByteToWideChar(CP_UNIXCP, 0, name, -1, mline->name, MAXPNAMELEN);
-                mline->capt = mline->dst = 0;
-                mline->elem = elem;
-                mline->chans = chans(mmixer, elem, 0);
-            }
-            else if (!capt)
-                continue;
-
-            if (capt && (snd_mixer_selem_has_capture_volume(elem) || comp == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE))
-            {
-                (++mline)->component = comp;
-                MultiByteToWideChar(CP_UNIXCP, 0, name, -1, mline->name, MAXPNAMELEN);
-                mline->capt = mline->dst = 1;
-                mline->elem = elem;
-                mline->chans = chans(mmixer, elem, 1);
-            }
-
-            snd_mixer_elem_set_callback(elem, elem_callback);
-            snd_mixer_elem_set_callback_private(elem, mmixer);
-        }
-}
-
-static void filllines_no_master(mixer *mmixer, snd_mixer_elem_t *captelem, int capt)
-{
-    line *mline = mmixer->lines;
-
-    MultiByteToWideChar(CP_UNIXCP, 0, snd_mixer_selem_get_name(captelem), -1, mline->name, sizeof(mline->name)/sizeof(WCHAR));
-    mline->component = getcomponenttype(snd_mixer_selem_get_name(captelem));
-    mline->dst = 0;
-    mline->capt = 1;
-    mline->elem = captelem;
-    mline->chans = chans(mmixer, captelem, 1);
-
-    snd_mixer_elem_set_callback(captelem, elem_callback);
-    snd_mixer_elem_set_callback_private(captelem, mmixer);
-}
-
-/* Windows api wants to have a 'master' device to which all slaves are attached
- * There are 2 ones in this code:
- * - 'Master', fall back to 'Headphone' if unavailable, and if that's not available 'PCM'
- * - 'Capture'
- * Capture might not always be available, so should be prepared to be without if needed
- */
-
-static void ALSA_MixerInit(void)
-{
-    int x, mixnum = 0;
-    snd_ctl_card_info_t *info;
-
-    info = HeapAlloc( GetProcessHeap(), 0, snd_ctl_card_info_sizeof());
-    for (x = 0; x < MAX_MIXERS; ++x)
-    {
-        int card, err, capcontrols = 0, total_elems = 0;
-        char cardind[6], cardname[10];
-
-        snd_ctl_t *ctl;
-        snd_mixer_elem_t *elem, *mastelem = NULL, *headelem = NULL, *captelem = NULL, *pcmelem = NULL, *lineelem = NULL, *micelem = NULL;
-
-        memset(info, 0, snd_ctl_card_info_sizeof());
-        memset(&mixdev[mixnum], 0, sizeof(*mixdev));
-        snprintf(cardind, sizeof(cardind), "%d", x);
-        card = snd_card_get_index(cardind);
-        if (card < 0)
-            continue;
-
-        snprintf(cardname, sizeof(cardname), "hw:%d", card);
-
-        err = snd_ctl_open(&ctl, cardname, 0);
-        if (err < 0)
-        {
-            WARN("Cannot open card: %s\n", snd_strerror(err));
-            continue;
-        }
-
-        err = snd_ctl_card_info(ctl, info);
-        if (err < 0)
-        {
-            WARN("Cannot get card info: %s\n", snd_strerror(err));
-            snd_ctl_close(ctl);
-            continue;
-        }
-
-        MultiByteToWideChar(CP_UNIXCP, 0, snd_ctl_card_info_get_name(info), -1, mixdev[mixnum].mixername, sizeof(mixdev[mixnum].mixername)/sizeof(WCHAR));
-        snd_ctl_close(ctl);
-
-        err = snd_mixer_open(&mixdev[mixnum].mix, 0);
-        if (err < 0)
-        {
-            WARN("Error occurred opening mixer: %s\n", snd_strerror(err));
-            continue;
-        }
-
-        err = snd_mixer_attach(mixdev[mixnum].mix, cardname);
-        if (err < 0)
-            goto eclose;
-
-        err = snd_mixer_selem_register(mixdev[mixnum].mix, NULL, NULL);
-        if (err < 0)
-            goto eclose;
-
-        err = snd_mixer_load(mixdev[mixnum].mix);
-        if (err < 0)
-            goto eclose;
-
-        /* First, lets see what's available..
-         * If there are multiple Master or Captures, all except 1 will be added as slaves
-         */
-        total_elems = snd_mixer_get_count(mixdev[mixnum].mix);
-        TRACE("Total elems: %d\n", total_elems);
-
-        for (elem = snd_mixer_first_elem(mixdev[mixnum].mix); elem; elem = snd_mixer_elem_next(elem))
-            if (!strcasecmp(snd_mixer_selem_get_name(elem), "Master") && !mastelem)
-            {
-                mastelem = elem;
-                ++(mixdev[mixnum].chans);
-            }
-            else if (!strcasecmp(snd_mixer_selem_get_name(elem), "Capture") && !captelem)
-                captelem = elem;
-            else if (!strcasecmp(snd_mixer_selem_get_name(elem), "Mic") && !micelem && !mastelem && total_elems == 1)
-                /* this is what snd-usb-audio mics look like; just a Mic control and that's it.*/
-                micelem = elem;
-            else if (!blacklisted(elem))
-            {
-                DWORD comp = getcomponenttype(snd_mixer_selem_get_name(elem));
-                DWORD skip = 0;
-
-                /* Work around buggy drivers: Make this a capture control if the name is recognised as a microphone */
-                if (snd_mixer_selem_has_capture_volume(elem))
-                    ++capcontrols;
-                else if (comp == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
-                {
-                    ++capcontrols;
-                    skip = 1;
-                }
-
-                if (!skip && snd_mixer_selem_has_playback_volume(elem))
-                {
-                    if (!strcasecmp(snd_mixer_selem_get_name(elem), "Headphone") && !headelem)
-                        headelem = elem;
-                    else if (!strcasecmp(snd_mixer_selem_get_name(elem), "PCM") && !pcmelem)
-                        pcmelem = elem;
-                    else if (!strcasecmp(snd_mixer_selem_get_name(elem), "Line") && !lineelem)
-                        lineelem = elem;
-                    ++(mixdev[mixnum].chans);
-                }
-            }
-
-        /* Add dummy capture channel, wanted by Windows  */
-        mixdev[mixnum].chans += 1;
-
-        /* If there is only 'Capture' and 'Master', this device is not worth it */
-        if (mixdev[mixnum].chans == 2)
-        {
-            WARN("No channels found, skipping device!\n");
-            goto close;
-        }
-
-        /* Master element can't have a capture control in this code, so
-         * if Headphone or PCM is promoted to master, unset its capture control */
-        if (headelem && !mastelem)
-        {
-            /* Using 'Headphone' as master device */
-            mastelem = headelem;
-            capcontrols -= !!snd_mixer_selem_has_capture_switch(mastelem);
-        }
-        else if (pcmelem && !mastelem)
-        {
-            /* Use 'PCM' as master device */
-            mastelem = pcmelem;
-            capcontrols -= !!snd_mixer_selem_has_capture_switch(mastelem);
-        }
-        else if (lineelem && !mastelem)
-        {
-            /* Use 'Line' as master device */
-            mastelem = lineelem;
-            capcontrols -= !!snd_mixer_selem_has_capture_switch(mastelem);
-        }
-        else if (!mastelem && !captelem && !micelem)
-        {
-            /* If there is nothing sensible that can act as 'Master' control, something is wrong */
-            FIXME("No master control found on %s, disabling mixer\n", snd_ctl_card_info_get_name(info));
-            goto close;
-        }
-
-        if (!captelem || !capcontrols)
-        {
-            /* Can't enable capture, so disabling it
-             * Note: capture control will still exist because
-             * dwLineID 0 and 1 are reserved for Master and Capture
-             */
-            WARN("No use enabling capture part of mixer, capture control found: %s, amount of capture controls: %d\n",
-                 (!captelem ? "no" : "yes"), capcontrols);
-            capcontrols = 0;
-            mixdev[mixnum].dests = 1;
-        }
-        else
-        {
-            mixdev[mixnum].chans += capcontrols;
-            mixdev[mixnum].dests = 2;
-        }
-
-        mixdev[mixnum].lines = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(line) * mixdev[mixnum].chans);
-        mixdev[mixnum].controls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(control) * CONTROLSPERLINE*mixdev[mixnum].chans);
-        err = -ENOMEM;
-        if (!mixdev[mixnum].lines || !mixdev[mixnum].controls)
-            goto close;
-
-        if (mastelem)
-            filllines(&mixdev[mixnum], mastelem, captelem, capcontrols);
-        else if (micelem)
-            filllines_no_master(&mixdev[mixnum], micelem, 1);
-        fillcontrols(&mixdev[mixnum]);
-
-        TRACE("%s: Amount of controls: %i/%i, name: %s\n", cardname, mixdev[mixnum].dests, mixdev[mixnum].chans, debugstr_w(mixdev[mixnum].mixername));
-        mixnum++;
-        continue;
-
-        eclose:
-        WARN("Error occurred initialising mixer: %s\n", snd_strerror(err));
-        close:
-        HeapFree(GetProcessHeap(), 0, mixdev[mixnum].lines);
-        HeapFree(GetProcessHeap(), 0, mixdev[mixnum].controls);
-        snd_mixer_close(mixdev[mixnum].mix);
-    }
-    cards = mixnum;
-    HeapFree( GetProcessHeap(), 0, info );
-
-    /* There is no trouble with already assigning callbacks without initialising critsect:
-     * Callbacks only occur when snd_mixer_handle_events is called (only happens in thread)
-     */
-    InitializeCriticalSection(&elem_crst);
-    elem_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_MIXER.elem_crst");
-    TRACE("\n");
-}
-
-static void ALSA_MixerExit(void)
-{
-    int x;
-
-    if (refcnt)
-    {
-        WARN("Callback thread still alive, terminating uncleanly, refcnt: %d\n", refcnt);
-        /* Least we can do is making sure we're not in 'foreign' code */
-        EnterCriticalSection(&elem_crst);
-        TerminateThread(thread, 1);
-        refcnt = 0;
-        LeaveCriticalSection(&elem_crst);
-    }
-
-    TRACE("Cleaning up\n");
-
-    elem_crst.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&elem_crst);
-    for (x = 0; x < cards; ++x)
-    {
-        snd_mixer_close(mixdev[x].mix);
-        HeapFree(GetProcessHeap(), 0, mixdev[x].lines);
-        HeapFree(GetProcessHeap(), 0, mixdev[x].controls);
-    }
-    cards = 0;
-}
-
-static mixer* MIX_GetMix(UINT wDevID)
-{
-    mixer *mmixer;
-
-    if (wDevID >= cards)
-    {
-        WARN("Invalid mixer id: %d\n", wDevID);
-        return NULL;
-    }
-
-    mmixer = &mixdev[wDevID];
-    return mmixer;
-}
-
-/* Since alsa doesn't tell what exactly changed, just assume all affected controls changed */
-static int elem_callback(snd_mixer_elem_t *elem, unsigned int type)
-{
-    mixer *mmixer = snd_mixer_elem_get_callback_private(elem);
-    int x;
-    BOOL captchanged = 0;
-
-    if (type != SND_CTL_EVENT_MASK_VALUE)
-        return 0;
-
-    assert(mmixer);
-
-    EnterCriticalSection(&elem_crst);
-
-    if (!mmixer->callback)
-        goto out;
-
-    for (x=0; x<mmixer->chans; ++x)
-    {
-        const int ofs = CONTROLSPERLINE*x;
-        if (elem != mmixer->lines[x].elem)
-            continue;
-
-        if (mmixer->lines[x].capt)
-            ++captchanged;
-
-        TRACE("Found changed control %s\n", debugstr_w(mmixer->lines[x].name));
-        mmixer->callback(mmixer->hmx, MM_MIXM_LINE_CHANGE, mmixer->callbackpriv, x, 0);
-        mmixer->callback(mmixer->hmx, MM_MIXM_CONTROL_CHANGE, mmixer->callbackpriv, ofs, 0);
-
-        if (mmixer->controls[ofs+OFS_MUTE].enabled)
-            mmixer->callback(mmixer->hmx, MM_MIXM_CONTROL_CHANGE, mmixer->callbackpriv, ofs+OFS_MUTE, 0);
-    }
-    if (captchanged)
-        mmixer->callback(mmixer->hmx, MM_MIXM_CONTROL_CHANGE, mmixer->callbackpriv, CONTROLSPERLINE+OFS_MUX, 0);
-
-    out:
-    LeaveCriticalSection(&elem_crst);
-
-    return 0;
-}
-
-static DWORD WINAPI ALSA_MixerPollThread(LPVOID lParam)
-{
-    struct pollfd *pfds = NULL;
-    int x, y, err, mcnt, count = 1;
-
-    TRACE("%p\n", lParam);
-
-    for (x = 0; x < cards; ++x)
-        count += snd_mixer_poll_descriptors_count(mixdev[x].mix);
-
-    TRACE("Counted %d descriptors\n", count);
-    pfds = HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct pollfd));
-
-    if (!pfds)
-    {
-        WARN("Out of memory\n");
-        goto die;
-    }
-
-    pfds[0].fd = msg_pipe[0];
-    pfds[0].events = POLLIN;
-
-    y = 1;
-    for (x = 0; x < cards; ++x)
-        y += snd_mixer_poll_descriptors(mixdev[x].mix, &pfds[y], count - y);
-
-    while ((err = poll(pfds, (unsigned int) count, -1)) >= 0 || errno == EINTR || errno == EAGAIN)
-    {
-        if (pfds[0].revents & POLLIN)
-            break;
-
-        mcnt = 1;
-        for (x = y = 0; x < cards; ++x)
-        {
-            int j, max = snd_mixer_poll_descriptors_count(mixdev[x].mix);
-            for (j = 0; j < max; ++j)
-                if (pfds[mcnt+j].revents)
-                {
-                    y += snd_mixer_handle_events(mixdev[x].mix);
-                    break;
-                }
-            mcnt += max;
-        }
-        if (y)
-            TRACE("Handled %d events\n", y);
-    }
-
-    die:
-    TRACE("Shutting down\n");
-    HeapFree(GetProcessHeap(), 0, pfds);
-
-    y = read(msg_pipe[0], &x, sizeof(x));
-    close(msg_pipe[1]);
-    close(msg_pipe[0]);
-    return 0;
-}
-
-static DWORD MIX_Open(UINT wDevID, LPMIXEROPENDESC desc, DWORD_PTR flags)
-{
-    mixer *mmixer = MIX_GetMix(wDevID);
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    flags &= CALLBACK_TYPEMASK;
-    switch (flags)
-    {
-    case CALLBACK_NULL:
-        goto done;
-
-    case CALLBACK_FUNCTION:
-        break;
-
-    default:
-        FIXME("Unhandled callback type: %08lx\n", flags & CALLBACK_TYPEMASK);
-        return MIXERR_INVALVALUE;
-    }
-
-    mmixer->callback = (LPDRVCALLBACK)desc->dwCallback;
-    mmixer->callbackpriv = desc->dwInstance;
-    mmixer->hmx = (HDRVR)desc->hmx;
-
-    done:
-    if (InterlockedIncrement(&refcnt) == 1)
-    {
-        if (pipe(msg_pipe) >= 0)
-        {
-            thread = CreateThread(NULL, 0, ALSA_MixerPollThread, NULL, 0, NULL);
-            if (!thread)
-            {
-                close(msg_pipe[0]);
-                close(msg_pipe[1]);
-                msg_pipe[0] = msg_pipe[1] = -1;
-            }
-        }
-        else
-            msg_pipe[0] = msg_pipe[1] = -1;
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD MIX_Close(UINT wDevID)
-{
-    int x = 0;
-    mixer *mmixer = MIX_GetMix(wDevID);
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    EnterCriticalSection(&elem_crst);
-    mmixer->callback = 0;
-    LeaveCriticalSection(&elem_crst);
-
-    if (!InterlockedDecrement(&refcnt))
-    {
-        if (write(msg_pipe[1], &x, sizeof(x)) > 0)
-        {
-            TRACE("Shutting down thread...\n");
-            WaitForSingleObject(thread, INFINITE);
-            TRACE("Done\n");
-        }
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD MIX_GetDevCaps(UINT wDevID, LPMIXERCAPS2W caps, DWORD_PTR parm2)
-{
-    mixer *mmixer = MIX_GetMix(wDevID);
-    MIXERCAPS2W capsW;
-
-    if (!caps)
-        return MMSYSERR_INVALPARAM;
-
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    memset(&capsW, 0, sizeof(MIXERCAPS2W));
-
-    capsW.wMid = WINE_MIXER_MANUF_ID;
-    capsW.wPid = WINE_MIXER_PRODUCT_ID;
-    capsW.vDriverVersion = WINE_MIXER_VERSION;
-
-    lstrcpynW(capsW.szPname, mmixer->mixername, sizeof(capsW.szPname)/sizeof(WCHAR));
-    capsW.cDestinations = mmixer->dests;
-    memcpy(caps, &capsW, min(parm2, sizeof(capsW)));
-    return MMSYSERR_NOERROR;
-}
-
-/* convert win32 volume to alsa volume, and vice versa */
-static INT normalized(INT value, INT prevmax, INT nextmax)
-{
-    int ret = MulDiv(value, nextmax, prevmax);
-
-    /* Have to stay in range */
-    TRACE("%d/%d -> %d/%d\n", value, prevmax, ret, nextmax);
-    if (ret > nextmax)
-        ret = nextmax;
-    else if (ret < 0)
-        ret = 0;
-
-    return ret;
-}
-
-/* get amount of sources for dest */
-static int getsrccntfromchan(mixer *mmixer, int dad)
-{
-    int i, j=0;
-
-    for (i=0; i<mmixer->chans; ++i)
-        if (i != dad && mmixer->lines[i].dst == dad)
-        {
-            ++j;
-        }
-    if (!j)
-        FIXME("No src found for %i (%s)?\n", dad, debugstr_w(mmixer->lines[dad].name));
-    return j;
-}
-
-/* find lineid for source 'num' with dest 'dad' */
-static int getsrclinefromchan(mixer *mmixer, int dad, int num)
-{
-    int i, j=0;
-    for (i=0; i<mmixer->chans; ++i)
-        if (i != dad && mmixer->lines[i].dst == dad)
-        {
-            if (num == j)
-                return i;
-            ++j;
-        }
-    WARN("No src found for src %i from dest %i\n", num, dad);
-    return 0;
-}
-
-/* get the source number belonging to line */
-static int getsrcfromline(mixer *mmixer, int line)
-{
-    int i, j=0, dad = mmixer->lines[line].dst;
-
-    for (i=0; i<mmixer->chans; ++i)
-        if (i != dad && mmixer->lines[i].dst == dad)
-        {
-            if (line == i)
-                return j;
-            ++j;
-        }
-    WARN("No src found for line %i with dad %i\n", line, dad);
-    return 0;
-}
-
-/* Get volume/muted/capture channel */
-static DWORD MIX_GetControlDetails(UINT wDevID, LPMIXERCONTROLDETAILS mctrld, DWORD_PTR flags)
-{
-    mixer *mmixer = MIX_GetMix(wDevID);
-    DWORD ctrl;
-    DWORD line;
-    control *ct;
-
-    if (!mctrld)
-        return MMSYSERR_INVALPARAM;
-
-    ctrl = mctrld->dwControlID;
-    line = ctrl/CONTROLSPERLINE;
-
-    if (mctrld->cbStruct != sizeof(*mctrld))
-        return MMSYSERR_INVALPARAM;
-
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    if (line >= mmixer->chans || !mmixer->controls[ctrl].enabled)
-        return MIXERR_INVALCONTROL;
-
-    ct = &mmixer->controls[ctrl];
-
-    flags &= MIXER_GETCONTROLDETAILSF_QUERYMASK;
-
-    switch (flags) {
-    case MIXER_GETCONTROLDETAILSF_VALUE:
-        TRACE("MIXER_GETCONTROLDETAILSF_VALUE (%d/%d)\n", ctrl, line);
-        switch (ct->c.dwControlType)
-        {
-        case MIXERCONTROL_CONTROLTYPE_VOLUME:
-        {
-            long min = 0, max = 0, vol = 0;
-            int chn;
-            LPMIXERCONTROLDETAILS_UNSIGNED mcdu;
-            snd_mixer_elem_t * elem = mmixer->lines[line].elem;
-
-            if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_UNSIGNED))
-            {
-                WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-                return MMSYSERR_INVALPARAM;
-            }
-
-            TRACE("%s MIXERCONTROLDETAILS_UNSIGNED[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-
-            mcdu = mctrld->paDetails;
-
-            if (mctrld->cChannels != 1 && mmixer->lines[line].chans != mctrld->cChannels)
-            {
-                WARN("Unsupported cChannels (%d instead of %d)\n", mctrld->cChannels, mmixer->lines[line].chans);
-                return MMSYSERR_INVALPARAM;
-            }
-
-            if (mmixer->lines[line].capt && snd_mixer_selem_has_capture_volume(elem)) {
-                snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
-                for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                    if (snd_mixer_selem_has_capture_channel(elem, chn))
-                    {
-                        snd_mixer_selem_get_capture_volume(elem, chn, &vol);
-                        mcdu->dwValue = normalized(vol - min, max, 65535);
-                        if (mctrld->cChannels == 1)
-                            break;
-                        ++mcdu;
-                    }
-            } else {
-                snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
-
-                for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                    if (snd_mixer_selem_has_playback_channel(elem, chn))
-                    {
-                        snd_mixer_selem_get_playback_volume(elem, chn, &vol);
-                        mcdu->dwValue = normalized(vol - min, max, 65535);
-                        if (mctrld->cChannels == 1)
-                            break;
-                        ++mcdu;
-                    }
-            }
-
-            return MMSYSERR_NOERROR;
-        }
-
-        case MIXERCONTROL_CONTROLTYPE_ONOFF:
-        case MIXERCONTROL_CONTROLTYPE_MUTE:
-        {
-            LPMIXERCONTROLDETAILS_BOOLEAN mcdb;
-            int chn, ival;
-            snd_mixer_elem_t * elem = mmixer->lines[line].elem;
-
-            if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
-            {
-                WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-                return MMSYSERR_INVALPARAM;
-            }
-
-            TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-
-            mcdb = mctrld->paDetails;
-
-            if (line == 1)
-                for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                {
-                    if (!snd_mixer_selem_has_capture_channel(elem, chn))
-                        continue;
-                    snd_mixer_selem_get_capture_switch(elem, chn, &ival);
-                    break;
-                }
-            else
-                for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                {
-                    if (!snd_mixer_selem_has_playback_channel(elem, chn))
-                        continue;
-                    snd_mixer_selem_get_playback_switch(elem, chn, &ival);
-                    break;
-                }
-
-	    if (chn > SND_MIXER_SCHN_LAST)
-	    {
-		TRACE("can't find active channel\n");
-		return MMSYSERR_INVALPARAM;  /* fixme: what's right error? */
-	    }
-
-            mcdb->fValue = !ival;
-            TRACE("=> %s\n", mcdb->fValue ? "on" : "off");
-            return MMSYSERR_NOERROR;
-        }
-        case MIXERCONTROL_CONTROLTYPE_MIXER:
-        case MIXERCONTROL_CONTROLTYPE_MUX:
-        {
-            LPMIXERCONTROLDETAILS_BOOLEAN mcdb;
-            int x, i=0, ival = 0, chn;
-
-            if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
-            {
-                WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-                return MMSYSERR_INVALPARAM;
-            }
-
-            TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-
-            mcdb = mctrld->paDetails;
-
-            for (x = 0; x<mmixer->chans; ++x)
-                if (line != x && mmixer->lines[x].dst == line)
-                {
-                    ival = 0;
-                    for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                    {
-                        if (!snd_mixer_selem_has_capture_channel(mmixer->lines[x].elem, chn))
-                            continue;
-                        snd_mixer_selem_get_capture_switch(mmixer->lines[x].elem, chn, &ival);
-                        if (ival)
-                            break;
-                    }
-                    if (i >= mctrld->u.cMultipleItems)
-                    {
-                        TRACE("overflow\n");
-                        return MMSYSERR_INVALPARAM;
-                    }
-                    TRACE("fVal[%i] = %sselected\n", i, (!ival ? "un" : ""));
-                    mcdb[i++].fValue = ival;
-                }
-            break;
-        }
-        default:
-
-            FIXME("Unhandled controltype %s\n", getControlType(ct->c.dwControlType));
-            return MMSYSERR_INVALPARAM;
-        }
-        return MMSYSERR_NOERROR;
-
-    case MIXER_GETCONTROLDETAILSF_LISTTEXT:
-        TRACE("MIXER_GETCONTROLDETAILSF_LISTTEXT (%d)\n", ctrl);
-
-        if (ct->c.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX || ct->c.dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
-        {
-            LPMIXERCONTROLDETAILS_LISTTEXTW mcdlt = mctrld->paDetails;
-            int i, j;
-
-            for (i = j = 0; j < mmixer->chans; ++j)
-                if (j != line && mmixer->lines[j].dst == line)
-                {
-                    if (i > mctrld->u.cMultipleItems)
-                        return MMSYSERR_INVALPARAM;
-                    mcdlt->dwParam1 = j;
-                    mcdlt->dwParam2 = mmixer->lines[j].component;
-                    lstrcpynW(mcdlt->szName, mmixer->lines[j].name, sizeof(mcdlt->szName) / sizeof(WCHAR));
-                    TRACE("Adding %i as %s\n", j, debugstr_w(mcdlt->szName));
-                    ++i; ++mcdlt;
-                }
-            if (i < mctrld->u.cMultipleItems)
-                return MMSYSERR_INVALPARAM;
-            return MMSYSERR_NOERROR;
-        }
-        FIXME ("Imagine this code being horribly broken and incomplete, introducing: reality\n");
-        return MMSYSERR_INVALPARAM;
-
-    default:
-        WARN("Unknown flag (%08lx)\n", flags);
-        return MMSYSERR_INVALPARAM;
-    }
-}
-
-/* Set volume/capture channel/muted for control */
-static DWORD MIX_SetControlDetails(UINT wDevID, LPMIXERCONTROLDETAILS mctrld, DWORD_PTR flags)
-{
-    mixer *mmixer = MIX_GetMix(wDevID);
-    DWORD ctrl, line, i;
-    control *ct;
-    snd_mixer_elem_t * elem;
-
-    if (!mctrld)
-        return MMSYSERR_INVALPARAM;
-
-    ctrl = mctrld->dwControlID;
-    line = ctrl/CONTROLSPERLINE;
-
-    if (mctrld->cbStruct != sizeof(*mctrld))
-    {
-        WARN("Invalid size of mctrld %d\n", mctrld->cbStruct);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    if (line >= mmixer->chans)
-    {
-        WARN("Invalid line id: %d not in range of 0-%d\n", line, mmixer->chans-1);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (!mmixer->controls[ctrl].enabled)
-    {
-        WARN("Control %d not enabled\n", ctrl);
-        return MIXERR_INVALCONTROL;
-    }
-
-    ct = &mmixer->controls[ctrl];
-    elem = mmixer->lines[line].elem;
-    flags &= MIXER_SETCONTROLDETAILSF_QUERYMASK;
-
-    switch (flags) {
-    case MIXER_SETCONTROLDETAILSF_VALUE:
-        TRACE("MIXER_SETCONTROLDETAILSF_VALUE (%d)\n", ctrl);
-        break;
-
-    default:
-        WARN("Unknown flag (%08lx)\n", flags);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    switch (ct->c.dwControlType)
-    {
-    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-    {
-        long min = 0, max = 0;
-        int chn;
-        LPMIXERCONTROLDETAILS_UNSIGNED mcdu;
-        snd_mixer_elem_t * elem = mmixer->lines[line].elem;
-
-        if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_UNSIGNED))
-        {
-            WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-            return MMSYSERR_INVALPARAM;
-        }
-
-        if (mctrld->cChannels != 1 && mmixer->lines[line].chans != mctrld->cChannels)
-        {
-            WARN("Unsupported cChannels (%d instead of %d)\n", mctrld->cChannels, mmixer->lines[line].chans);
-            return MMSYSERR_INVALPARAM;
-        }
-
-        TRACE("%s MIXERCONTROLDETAILS_UNSIGNED[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-        mcdu = mctrld->paDetails;
-
-        for (chn=0; chn<mctrld->cChannels;++chn)
-        {
-            TRACE("Chan %d value %d\n", chn, mcdu[chn].dwValue);
-        }
-
-        /* There isn't always a capture volume, so in that case change playback volume */
-        if (mmixer->lines[line].capt && snd_mixer_selem_has_capture_volume(elem))
-        {
-            snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
-
-            for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                if (snd_mixer_selem_has_capture_channel(elem, chn))
-                {
-                    snd_mixer_selem_set_capture_volume(elem, chn, min + normalized(mcdu->dwValue, 65535, max));
-                    if (mctrld->cChannels != 1)
-                        mcdu++;
-                }
-        }
-        else
-        {
-            snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
-
-            for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                if (snd_mixer_selem_has_playback_channel(elem, chn))
-                {
-                    snd_mixer_selem_set_playback_volume(elem, chn, min + normalized(mcdu->dwValue, 65535, max));
-                    if (mctrld->cChannels != 1)
-                        mcdu++;
-                }
-        }
-
-        break;
-    }
-    case MIXERCONTROL_CONTROLTYPE_MUTE:
-    case MIXERCONTROL_CONTROLTYPE_ONOFF:
-    {
-        LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-
-        if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
-        {
-            WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-            return MMSYSERR_INVALPARAM;
-        }
-
-        TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-
-        mcdb = mctrld->paDetails;
-        if (line == 1) /* Mute/unmute capturing */
-            for (i = 0; i <= SND_MIXER_SCHN_LAST; ++i)
-            {
-                if (snd_mixer_selem_has_capture_channel(elem, i))
-                    snd_mixer_selem_set_capture_switch(elem, i, !mcdb->fValue);
-            }
-        else
-            for (i = 0; i <= SND_MIXER_SCHN_LAST; ++i)
-                if (snd_mixer_selem_has_playback_channel(elem, i))
-                    snd_mixer_selem_set_playback_switch(elem, i, !mcdb->fValue);
-        break;
-    }
-
-    case MIXERCONTROL_CONTROLTYPE_MIXER:
-    case MIXERCONTROL_CONTROLTYPE_MUX:
-    {
-        LPMIXERCONTROLDETAILS_BOOLEAN mcdb;
-        int x, i=0, chn;
-        int didone = 0, canone = (ct->c.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX);
-
-        if (mctrld->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
-        {
-            WARN("invalid parameter: cbDetails %d\n", mctrld->cbDetails);
-            return MMSYSERR_INVALPARAM;
-        }
-
-        TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n", getControlType(ct->c.dwControlType), mctrld->cChannels);
-        mcdb = mctrld->paDetails;
-
-        for (x=i=0; x < mmixer->chans; ++x)
-            if (line != x && mmixer->lines[x].dst == line)
-            {
-                TRACE("fVal[%i] (%s) = %i\n", i, debugstr_w(mmixer->lines[x].name), mcdb[i].fValue);
-                if (i >= mctrld->u.cMultipleItems)
-                {
-                    TRACE("Too many items to fit, overflowing\n");
-                    return MIXERR_INVALVALUE;
-                }
-                if (mcdb[i].fValue && canone && didone)
-                {
-                    TRACE("Nice try, but it's not going to work\n");
-                    elem_callback(mmixer->lines[1].elem, SND_CTL_EVENT_MASK_VALUE);
-                    return MIXERR_INVALVALUE;
-                }
-                if (mcdb[i].fValue)
-                    didone = 1;
-                ++i;
-            }
-
-        if (canone && !didone)
-        {
-            TRACE("Nice try, this is not going to work either\n");
-            elem_callback(mmixer->lines[1].elem, SND_CTL_EVENT_MASK_VALUE);
-            return MIXERR_INVALVALUE;
-        }
-
-        for (x = i = 0; x<mmixer->chans; ++x)
-            if (line != x && mmixer->lines[x].dst == line)
-            {
-                if (mcdb[i].fValue)
-                    for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                    {
-                        if (!snd_mixer_selem_has_capture_channel(mmixer->lines[x].elem, chn))
-                            continue;
-                        snd_mixer_selem_set_capture_switch(mmixer->lines[x].elem, chn, mcdb[i].fValue);
-                    }
-                ++i;
-            }
-
-        /* If it's a MUX, it means that only 1 channel can be selected
-         * and the other channels are unselected
-         *
-         * For MIXER multiple sources are allowed, so unselect here
-         */
-        if (canone)
-            break;
-
-        for (x = i = 0; x<mmixer->chans; ++x)
-            if (line != x && mmixer->lines[x].dst == line)
-            {
-                if (!mcdb[i].fValue)
-                    for (chn = 0; chn <= SND_MIXER_SCHN_LAST; ++chn)
-                    {
-                        if (!snd_mixer_selem_has_capture_channel(mmixer->lines[x].elem, chn))
-                            continue;
-                        snd_mixer_selem_set_capture_switch(mmixer->lines[x].elem, chn, mcdb[i].fValue);
-                    }
-                ++i;
-            }
-        break;
-    }
-    default:
-        FIXME("Unhandled type %s\n", getControlType(ct->c.dwControlType));
-        return MMSYSERR_INVALPARAM;
-    }
-    return MMSYSERR_NOERROR;
-}
-
-/* Here we give info over the source/dest line given by dwSource+dwDest or dwDest, respectively
- * It is also possible that a line is found by componenttype or target type, latter is not implemented yet
- * Most important values returned in struct:
- * dwLineID
- * sz(Short)Name
- * line control count
- * amount of channels
- */
-static DWORD MIX_GetLineInfo(UINT wDevID, LPMIXERLINEW Ml, DWORD_PTR flags)
-{
-    DWORD_PTR qf = flags & MIXER_GETLINEINFOF_QUERYMASK;
-    mixer *mmixer = MIX_GetMix(wDevID);
-    line *mline;
-    int idx, i;
-
-    if (!Ml)
-    {
-        WARN("No Ml\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (!mmixer)
-    {
-        WARN("Device %u not found\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    if (Ml->cbStruct != sizeof(*Ml))
-    {
-        WARN("invalid parameter: Ml->cbStruct = %d\n", Ml->cbStruct);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    Ml->dwUser  = 0;
-    Ml->fdwLine = MIXERLINE_LINEF_DISCONNECTED;
-    switch (qf)
-    {
-    case MIXER_GETLINEINFOF_COMPONENTTYPE:
-    {
-        Ml->dwLineID = 0xFFFF;
-        TRACE("Looking for componenttype %d/%x\n", Ml->dwComponentType, Ml->dwComponentType);
-        for (idx = 0; idx < mmixer->chans; ++idx)
-            if (mmixer->lines[idx].component == Ml->dwComponentType)
-            {
-                Ml->dwLineID = idx;
-                break;
-            }
-        if (Ml->dwLineID == 0xFFFF)
-            return MMSYSERR_KEYNOTFOUND;
-        /* Now that we have lineid, fallback to lineid*/
-    }
-
-    case MIXER_GETLINEINFOF_LINEID:
-        if (Ml->dwLineID >= mmixer->chans)
-            return MIXERR_INVALLINE;
-
-        TRACE("MIXER_GETLINEINFOF_LINEID %d\n", Ml->dwLineID);
-        Ml->dwDestination = mmixer->lines[Ml->dwLineID].dst;
-
-        if (Ml->dwDestination != Ml->dwLineID)
-        {
-            Ml->dwSource = getsrcfromline(mmixer, Ml->dwLineID);
-            Ml->cConnections = 1;
-        }
-        else
-        {
-            Ml->cConnections = getsrccntfromchan(mmixer, Ml->dwLineID);
-            Ml->dwSource = 0xFFFFFFFF;
-        }
-        TRACE("Connections %d, source %d\n", Ml->cConnections, Ml->dwSource);
-        break;
-
-    case MIXER_GETLINEINFOF_DESTINATION:
-        if (Ml->dwDestination >= mmixer->dests)
-        {
-            WARN("dest %d out of bounds\n", Ml->dwDestination);
-            return MIXERR_INVALLINE;
-        }
-
-        Ml->dwLineID = Ml->dwDestination;
-        Ml->cConnections = getsrccntfromchan(mmixer, Ml->dwLineID);
-        Ml->dwSource = 0xFFFFFFFF;
-        break;
-
-    case MIXER_GETLINEINFOF_SOURCE:
-        if (Ml->dwDestination >= mmixer->dests)
-        {
-            WARN("dest %d for source out of bounds\n", Ml->dwDestination);
-            return MIXERR_INVALLINE;
-        }
-
-        if (Ml->dwSource >= getsrccntfromchan(mmixer, Ml->dwDestination))
-        {
-            WARN("src %d out of bounds\n", Ml->dwSource);
-            return MIXERR_INVALLINE;
-        }
-
-        Ml->dwLineID = getsrclinefromchan(mmixer, Ml->dwDestination, Ml->dwSource);
-        Ml->cConnections = 1;
-        break;
-
-    case MIXER_GETLINEINFOF_TARGETTYPE:
-        FIXME("TODO: TARGETTYPE, stub\n");
-        return MMSYSERR_INVALPARAM;
-
-    default:
-        FIXME("Unknown query flag: %08lx\n", qf);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    Ml->fdwLine &= ~MIXERLINE_LINEF_DISCONNECTED;
-    Ml->fdwLine |= MIXERLINE_LINEF_ACTIVE;
-    if (Ml->dwLineID >= mmixer->dests)
-        Ml->fdwLine |= MIXERLINE_LINEF_SOURCE;
-
-    mline = &mmixer->lines[Ml->dwLineID];
-    Ml->dwComponentType = mline->component;
-    Ml->cChannels = mmixer->lines[Ml->dwLineID].chans;
-    Ml->cControls = 0;
-
-    for (i=CONTROLSPERLINE*Ml->dwLineID;i<CONTROLSPERLINE*(Ml->dwLineID+1); ++i)
-        if (mmixer->controls[i].enabled)
-            ++(Ml->cControls);
-
-    lstrcpynW(Ml->szShortName, mmixer->lines[Ml->dwLineID].name, sizeof(Ml->szShortName)/sizeof(WCHAR));
-    lstrcpynW(Ml->szName, mmixer->lines[Ml->dwLineID].name, sizeof(Ml->szName)/sizeof(WCHAR));
-    if (mline->capt)
-        Ml->Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
-    else
-        Ml->Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
-    Ml->Target.dwDeviceID = 0xFFFFFFFF;
-    Ml->Target.wMid = WINE_MIXER_MANUF_ID;
-    Ml->Target.wPid = WINE_MIXER_PRODUCT_ID;
-    Ml->Target.vDriverVersion = WINE_MIXER_VERSION;
-    lstrcpynW(Ml->Target.szPname, mmixer->mixername, sizeof(Ml->Target.szPname)/sizeof(WCHAR));
-    return MMSYSERR_NOERROR;
-}
-
-/* Get the controls that belong to a certain line, either all or 1 */
-static DWORD MIX_GetLineControls(UINT wDevID, LPMIXERLINECONTROLSW mlc, DWORD_PTR flags)
-{
-    mixer *mmixer = MIX_GetMix(wDevID);
-    int i,j = 0;
-    DWORD ct;
-
-    if (!mlc || mlc->cbStruct != sizeof(*mlc))
-    {
-        WARN("Invalid mlc %p, cbStruct: %d\n", mlc, (!mlc ? -1 : mlc->cbStruct));
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (mlc->cbmxctrl != sizeof(MIXERCONTROLW))
-    {
-        WARN("cbmxctrl %d\n", mlc->cbmxctrl);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (!mmixer)
-        return MMSYSERR_BADDEVICEID;
-
-    flags &= MIXER_GETLINECONTROLSF_QUERYMASK;
-
-    if (flags == MIXER_GETLINECONTROLSF_ONEBYID)
-        mlc->dwLineID = mlc->u.dwControlID / CONTROLSPERLINE;
-
-    if (mlc->dwLineID >= mmixer->chans)
-    {
-        TRACE("Invalid dwLineID %d\n", mlc->dwLineID);
-        return MIXERR_INVALLINE;
-    }
-
-    switch (flags)
-    {
-    case MIXER_GETLINECONTROLSF_ALL:
-       TRACE("line=%08x MIXER_GETLINECONTROLSF_ALL (%d)\n", mlc->dwLineID, mlc->cControls);
-       for (i = 0; i < CONTROLSPERLINE; ++i)
-           if (mmixer->controls[i+mlc->dwLineID * CONTROLSPERLINE].enabled)
-           {
-               memcpy(&mlc->pamxctrl[j], &mmixer->controls[i+mlc->dwLineID * CONTROLSPERLINE].c, sizeof(MIXERCONTROLW));
-               TRACE("Added %s (%s)\n", debugstr_w(mlc->pamxctrl[j].szShortName), debugstr_w(mlc->pamxctrl[j].szName));
-               ++j;
-               if (j > mlc->cControls)
-               {
-                   WARN("invalid parameter\n");
-                   return MMSYSERR_INVALPARAM;
-               }
-           }
-
-        if (!j || mlc->cControls > j)
-        {
-            WARN("invalid parameter\n");
-            return MMSYSERR_INVALPARAM;
-        }
-        break;
-    case MIXER_GETLINECONTROLSF_ONEBYID:
-        TRACE("line=%08x MIXER_GETLINECONTROLSF_ONEBYID (%x)\n", mlc->dwLineID, mlc->u.dwControlID);
-
-        if (!mmixer->controls[mlc->u.dwControlID].enabled)
-           return MIXERR_INVALCONTROL;
-
-        mlc->pamxctrl[0] = mmixer->controls[mlc->u.dwControlID].c;
-        break;
-    case MIXER_GETLINECONTROLSF_ONEBYTYPE:
-        TRACE("line=%08x MIXER_GETLINECONTROLSF_ONEBYTYPE (%s)\n", mlc->dwLineID, getControlType(mlc->u.dwControlType));
-
-        ct = mlc->u.dwControlType & MIXERCONTROL_CT_CLASS_MASK;
-        for (i = 0; i <= CONTROLSPERLINE; ++i)
-        {
-            const int ofs = i+mlc->dwLineID*CONTROLSPERLINE;
-            if (i == CONTROLSPERLINE)
-            {
-                WARN("invalid parameter: control %s not found\n", getControlType(mlc->u.dwControlType));
-                return MIXERR_INVALCONTROL;
-            }
-            if (mmixer->controls[ofs].enabled && (mmixer->controls[ofs].c.dwControlType & MIXERCONTROL_CT_CLASS_MASK) == ct)
-            {
-                mlc->pamxctrl[0] = mmixer->controls[ofs].c;
-                break;
-            }
-        }
-    break;
-    default:
-        FIXME("Unknown flag %08lx\n", flags & MIXER_GETLINECONTROLSF_QUERYMASK);
-        return MMSYSERR_INVALPARAM;
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- *                        mxdMessage (WINEALSA.3)
- */
-DWORD WINAPI ALSA_mxdMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
-                             DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    DWORD ret;
-    TRACE("(%04X, %s, %08lX, %08lX, %08lX);\n", wDevID, getMessage(wMsg),
-          dwUser, dwParam1, dwParam2);
-
-    switch (wMsg)
-    {
-    case DRVM_INIT: ALSA_MixerInit(); ret = MMSYSERR_NOERROR; break;
-    case DRVM_EXIT: ALSA_MixerExit(); ret = MMSYSERR_NOERROR; break;
-    /* All taken care of by driver initialisation */
-    /* Unimplemented, and not needed */
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-        ret = MMSYSERR_NOERROR; break;
-
-    case MXDM_OPEN:
-        ret = MIX_Open(wDevID, (LPMIXEROPENDESC) dwParam1, dwParam2); break;
-
-    case MXDM_CLOSE:
-        ret = MIX_Close(wDevID); break;
-
-    case MXDM_GETDEVCAPS:
-        ret = MIX_GetDevCaps(wDevID, (LPMIXERCAPS2W)dwParam1, dwParam2); break;
-
-    case MXDM_GETLINEINFO:
-        ret = MIX_GetLineInfo(wDevID, (LPMIXERLINEW)dwParam1, dwParam2); break;
-
-    case MXDM_GETLINECONTROLS:
-        ret = MIX_GetLineControls(wDevID, (LPMIXERLINECONTROLSW)dwParam1, dwParam2); break;
-
-    case MXDM_GETCONTROLDETAILS:
-        ret = MIX_GetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2); break;
-
-    case MXDM_SETCONTROLDETAILS:
-        ret = MIX_SetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2); break;
-
-    case MXDM_GETNUMDEVS:
-        ret = cards; break;
-
-    default:
-        WARN("unknown message %s!\n", getMessage(wMsg));
-        return MMSYSERR_NOTSUPPORTED;
-    }
-
-    TRACE("Returning %08X\n", ret);
-    return ret;
-}
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 8118103..ccb723b 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -37,9 +37,9 @@
 #include "devpkey.h"
 #include "dshow.h"
 #include "dsound.h"
-#include "endpointvolume.h"
 
 #include "initguid.h"
+#include "endpointvolume.h"
 #include "audioclient.h"
 #include "audiopolicy.h"
 #include "dsdriver.h"
@@ -158,7 +158,6 @@ static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
 
-int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent);
 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
 
 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
@@ -237,6 +236,49 @@ int WINAPI AUDDRV_GetPriority(void)
     return Priority_Neutral;
 }
 
+/**************************************************************************
+ * 			wine_snd_pcm_recover		[internal]
+ *
+ * Code slightly modified from alsa-lib v1.0.23 snd_pcm_recover implementation.
+ * used to recover from XRUN errors (buffer underflow/overflow)
+ */
+static int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
+{
+    if (err > 0)
+        err = -err;
+    if (err == -EINTR)	/* nothing to do, continue */
+        return 0;
+    if (err == -EPIPE) {
+        const char *s;
+        if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
+            s = "underrun";
+        else
+            s = "overrun";
+        if (!silent)
+            ERR("%s occurred\n", s);
+        err = snd_pcm_prepare(pcm);
+        if (err < 0) {
+            ERR("cannot recover from %s, prepare failed: %s\n", s, snd_strerror(err));
+            return err;
+        }
+        return 0;
+    }
+    if (err == -ESTRPIPE) {
+        while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
+            /* wait until suspend flag is released */
+            poll(NULL, 0, 1000);
+        if (err < 0) {
+            err = snd_pcm_prepare(pcm);
+            if (err < 0) {
+                ERR("cannot recover from suspend, prepare failed: %s\n", snd_strerror(err));
+                return err;
+            }
+        }
+        return 0;
+    }
+    return err;
+}
+
 static BOOL alsa_try_open(const char *devnode, snd_pcm_stream_t stream)
 {
     snd_pcm_t *handle;
diff --git a/dlls/winealsa.drv/wavein.c b/dlls/winealsa.drv/wavein.c
deleted file mode 100644
index 86e8c75..0000000
--- a/dlls/winealsa.drv/wavein.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Sample Wine Driver for Advanced Linux Sound System (ALSA)
- *      Based on version <final> of the ALSA API
- *
- * Copyright    2002 Eric Pouech
- *              2002 Marco Pietrobono
- *              2003 Christian Costa : WaveIn support
- *              2006-2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*======================================================================*
- *                  Low level WAVE IN implementation			*
- *======================================================================*/
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "ks.h"
-#include "ksmedia.h"
-
-#include "alsa.h"
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wave);
-
-WINE_WAVEDEV	*WInDev;
-DWORD            ALSA_WidNumMallocedDevs;
-DWORD            ALSA_WidNumDevs;
-
-/**************************************************************************
-* 			widNotifyClient			[internal]
-*/
-static void widNotifyClient(WINE_WAVEDEV* wwi, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-   TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
-
-   switch (wMsg) {
-   case WIM_OPEN:
-   case WIM_CLOSE:
-   case WIM_DATA:
-       DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags, (HDRVR)wwi->waveDesc.hWave,
-                      wMsg, wwi->waveDesc.dwInstance, dwParam1, dwParam2);
-       break;
-   default:
-       FIXME("Unknown callback message %u\n", wMsg);
-   }
-}
-
-/**************************************************************************
- * 			widGetDevCaps				[internal]
- */
-static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
-{
-    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
-
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    memcpy(lpCaps, &WInDev[wDevID].incaps, min(dwSize, sizeof(*lpCaps)));
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widRecorder_ReadHeaders		[internal]
- */
-static void widRecorder_ReadHeaders(WINE_WAVEDEV * wwi)
-{
-    enum win_wm_message tmp_msg;
-    DWORD_PTR		tmp_param;
-    HANDLE		tmp_ev;
-    WAVEHDR*		lpWaveHdr;
-
-    while (ALSA_RetrieveRingMessage(&wwi->msgRing, &tmp_msg, &tmp_param, &tmp_ev)) {
-        if (tmp_msg == WINE_WM_HEADER) {
-	    LPWAVEHDR*	wh;
-	    lpWaveHdr = (LPWAVEHDR)tmp_param;
-	    lpWaveHdr->lpNext = 0;
-
-	    if (wwi->lpQueuePtr == 0)
-		wwi->lpQueuePtr = lpWaveHdr;
-	    else {
-	        for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-	        *wh = lpWaveHdr;
-	    }
-	} else {
-            ERR("should only have headers left\n");
-        }
-    }
-}
-
-/**************************************************************************
- * 				widRecorder			[internal]
- */
-static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
-{
-    WORD		uDevID = (DWORD_PTR)pmt;
-    WINE_WAVEDEV*	wwi = &WInDev[uDevID];
-    WAVEHDR*		lpWaveHdr;
-    DWORD		dwSleepTime;
-    DWORD		bytesRead;
-    enum win_wm_message msg;
-    DWORD_PTR		param;
-    HANDLE		ev;
-
-    wwi->state = WINE_WS_STOPPED;
-    InterlockedExchange((LONG*)&wwi->dwTotalRecorded, 0);
-    wwi->lpQueuePtr = NULL;
-
-    SetEvent(wwi->hStartUpEvent);
-
-    /* make sleep time to be # of ms to output a period */
-    dwSleepTime = (wwi->dwPeriodSize * 1000) / wwi->format.Format.nAvgBytesPerSec;
-    TRACE("sleeptime=%d ms, total buffer length=%d ms (%d bytes)\n", dwSleepTime, wwi->dwBufferSize * 1000 / wwi->format.Format.nAvgBytesPerSec, wwi->dwBufferSize);
-
-    for (;;) {
-	/* wait for dwSleepTime or an event in thread's queue */
-	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
-        {
-            DWORD frames;
-            DWORD bytes;
-            DWORD read;
-
-            lpWaveHdr = wwi->lpQueuePtr;
-            /* read all the fragments accumulated so far */
-            frames = snd_pcm_avail_update(wwi->pcm);
-            bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);
-
-            TRACE("frames = %d  bytes = %d state=%d\n", frames, bytes, snd_pcm_state(wwi->pcm));
-            if (snd_pcm_state(wwi->pcm) == SND_PCM_STATE_XRUN)
-            {
-                FIXME("Recovering from XRUN!\n");
-                snd_pcm_prepare(wwi->pcm);
-                frames = snd_pcm_avail_update(wwi->pcm);
-                bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);
-                snd_pcm_start(wwi->pcm);
-                snd_pcm_forward(wwi->pcm, frames - snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize));
-                continue;
-            }
-            while (frames > 0 && wwi->lpQueuePtr)
-            {
-                TRACE("bytes = %d\n", bytes);
-                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded < bytes)
-                {
-                    bytes = lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded;
-                    frames = snd_pcm_bytes_to_frames(wwi->pcm, bytes);
-                }
-                /* directly read fragment in wavehdr */
-                read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames);
-                bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read);
-
-                TRACE("bytesRead=(%d(%d)/(%d)) -> (%d/%d)\n", bytesRead, read, frames, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
-                if (read != (DWORD) -1)
-                {
-                    /* update number of bytes recorded in current buffer and by this device */
-                    lpWaveHdr->dwBytesRecorded += bytesRead;
-                    InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead);
-                    frames -= read;
-                    bytes -= bytesRead;
-
-                    /* buffer is full. notify client */
-                    if (!snd_pcm_bytes_to_frames(wwi->pcm, lpWaveHdr->dwBytesRecorded - lpWaveHdr->dwBufferLength))
-                    {
-                        /* must copy the value of next waveHdr, because we have no idea of what
-                         * will be done with the content of lpWaveHdr in callback
-                         */
-                        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-
-                        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-                        lpWaveHdr->dwFlags |=  WHDR_DONE;
-
-                        wwi->lpQueuePtr = lpNext;
-                        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-                        lpWaveHdr = lpNext;
-                    }
-                } else {
-                    WARN("read(%s, %p, %d) failed (%d/%s)\n", wwi->pcmname,
-                        lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                        frames, frames, snd_strerror(read));
-                }
-            }
-        }
-
-        ALSA_WaitRingMessage(&wwi->msgRing, dwSleepTime);
-
-	while (ALSA_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev))
-	{
-            TRACE("msg=%s param=0x%lx\n", ALSA_getCmdString(msg), param);
-	    switch (msg) {
-	    case WINE_WM_PAUSING:
-		wwi->state = WINE_WS_PAUSED;
-                /*FIXME("Device should stop recording\n");*/
-		SetEvent(ev);
-		break;
-	    case WINE_WM_STARTING:
-		wwi->state = WINE_WS_PLAYING;
-		snd_pcm_start(wwi->pcm);
-		SetEvent(ev);
-		break;
-	    case WINE_WM_HEADER:
-		lpWaveHdr = (LPWAVEHDR)param;
-		lpWaveHdr->lpNext = 0;
-
-		/* insert buffer at the end of queue */
-		{
-		    LPWAVEHDR*	wh;
-		    for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-		    *wh = lpWaveHdr;
-		}
-		break;
-	    case WINE_WM_STOPPING:
-		if (wwi->state != WINE_WS_STOPPED)
-		{
-		    snd_pcm_drain(wwi->pcm);
-
-		    /* read any headers in queue */
-		    widRecorder_ReadHeaders(wwi);
-
-		    /* return current buffer to app */
-		    lpWaveHdr = wwi->lpQueuePtr;
-		    if (lpWaveHdr)
-		    {
-		        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-		        TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
-		        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-		        lpWaveHdr->dwFlags |= WHDR_DONE;
-		        wwi->lpQueuePtr = lpNext;
-		        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-		    }
-		}
-		wwi->state = WINE_WS_STOPPED;
-		SetEvent(ev);
-		break;
-	    case WINE_WM_RESETTING:
-		if (wwi->state != WINE_WS_STOPPED)
-		{
-		    snd_pcm_drain(wwi->pcm);
-		}
-		wwi->state = WINE_WS_STOPPED;
-		wwi->dwTotalRecorded = 0;
-
-		/* read any headers in queue */
-		widRecorder_ReadHeaders(wwi);
-
-		/* return all buffers to the app */
-		while (wwi->lpQueuePtr) {
-		    lpWaveHdr = wwi->lpQueuePtr;
-		    TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
-                    wwi->lpQueuePtr = lpWaveHdr->lpNext;
-		    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-		    lpWaveHdr->dwFlags |= WHDR_DONE;
-		    widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-		}
-
-		SetEvent(ev);
-		break;
-	    case WINE_WM_CLOSING:
-		wwi->hThread = 0;
-		wwi->state = WINE_WS_CLOSED;
-		SetEvent(ev);
-		ExitThread(0);
-		/* shouldn't go here */
-	    default:
-		FIXME("unknown message %d\n", msg);
-		break;
-	    }
-	}
-    }
-    ExitThread(0);
-    /* just for not generating compilation warnings... should never be executed */
-    return 0;
-}
-
-/**************************************************************************
- * 				widOpen				[internal]
- */
-static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
-{
-    WINE_WAVEDEV*	        wwi;
-    snd_pcm_hw_params_t *       hw_params;
-    snd_pcm_sw_params_t *       sw_params;
-    snd_pcm_access_t            access;
-    snd_pcm_format_t            format;
-    unsigned int                rate;
-    unsigned int                buffer_time = 500000;
-    unsigned int                period_time = 10000;
-    snd_pcm_uframes_t           buffer_size;
-    snd_pcm_uframes_t           period_size;
-    int                         flags;
-    snd_pcm_t *                 pcm;
-    int                         err;
-    int                         dir;
-    DWORD                       ret;
-
-    /* JPW TODO - review this code */
-    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
-    if (lpDesc == NULL) {
-	WARN("Invalid Parameter !\n");
-	return MMSYSERR_INVALPARAM;
-    }
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    /* only PCM format is supported so far... */
-    if (!ALSA_supportedFormat(lpDesc->lpFormat)) {
-	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return WAVERR_BADFORMAT;
-    }
-
-    if (dwFlags & WAVE_FORMAT_QUERY) {
-	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return MMSYSERR_NOERROR;
-    }
-
-    wwi = &WInDev[wDevID];
-
-    if (wwi->pcm != NULL) {
-        WARN("already allocated\n");
-        return MMSYSERR_ALLOCATED;
-    }
-
-    flags = SND_PCM_NONBLOCK;
-
-    if ( (err=snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, flags)) < 0 )
-    {
-        ERR("Error open: %s\n", snd_strerror(err));
-	return MMSYSERR_NOTENABLED;
-    }
-
-    wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-
-    wwi->waveDesc = *lpDesc;
-    ALSA_copyFormat(lpDesc->lpFormat, &wwi->format);
-
-    if (wwi->format.Format.wBitsPerSample == 0) {
-	WARN("Resetting zeroed wBitsPerSample\n");
-	wwi->format.Format.wBitsPerSample = 8 *
-	    (wwi->format.Format.nAvgBytesPerSec /
-	     wwi->format.Format.nSamplesPerSec) /
-	    wwi->format.Format.nChannels;
-    }
-
-    hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() );
-    sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() );
-    if (!hw_params || !sw_params)
-    {
-        ret = MMSYSERR_NOMEM;
-        goto error;
-    }
-    snd_pcm_hw_params_any(pcm, hw_params);
-
-#define EXIT_ON_ERROR(f,e,txt) do \
-{ \
-    int err; \
-    if ( (err = (f) ) < 0) \
-    { \
-	WARN(txt ": %s\n", snd_strerror(err)); \
-	ret = (e); \
-        goto error; \
-    } \
-} while(0)
-
-    access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-    if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) {
-        WARN("mmap not available. switching to standard write.\n");
-        access = SND_PCM_ACCESS_RW_INTERLEAVED;
-	EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback");
-	wwi->read = snd_pcm_readi;
-    }
-    else
-	wwi->read = snd_pcm_mmap_readi;
-
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwi->format.Format.nChannels), WAVERR_BADFORMAT, "unable to set required channels");
-
-    if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
-        ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
-        IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) {
-        format = (wwi->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 :
-                 (wwi->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE :
-                 (wwi->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE :
-                 (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1;
-    } else if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
-        IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){
-        format = (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1;
-    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_MULAW) {
-        FIXME("unimplemented format: WAVE_FORMAT_MULAW\n");
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ALAW) {
-        FIXME("unimplemented format: WAVE_FORMAT_ALAW\n");
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ADPCM) {
-        FIXME("unimplemented format: WAVE_FORMAT_ADPCM\n");
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    } else {
-        ERR("invalid format: %0x04x\n", wwi->format.Format.wFormatTag);
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    }
-
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format");
-
-    rate = wwi->format.Format.nSamplesPerSec;
-    dir = 0;
-    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir);
-    if (err < 0) {
-	WARN("Rate %d Hz not available for playback: %s\n", wwi->format.Format.nSamplesPerSec, snd_strerror(rate));
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    }
-    if (!ALSA_NearMatch(rate, wwi->format.Format.nSamplesPerSec)) {
-	WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwi->format.Format.nSamplesPerSec, rate);
-        ret = WAVERR_BADFORMAT;
-        goto error;
-    }
-
-    dir=0;
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time");
-    dir=0;
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time");
-
-    EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback");
-
-    dir=0;
-    err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
-    err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
-
-    snd_pcm_sw_params_current(pcm, sw_params);
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold");
-    EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
-#undef EXIT_ON_ERROR
-
-    snd_pcm_prepare(pcm);
-
-    if (TRACE_ON(wave))
-	ALSA_TraceParameters(hw_params, sw_params, FALSE);
-
-    /* now, we can save all required data for later use... */
-
-    wwi->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size);
-    wwi->lpQueuePtr = wwi->lpPlayPtr = wwi->lpLoopPtr = NULL;
-
-    ALSA_InitRingMessage(&wwi->msgRing);
-
-    wwi->dwPeriodSize = snd_pcm_frames_to_bytes(pcm, period_size);
-    TRACE("dwPeriodSize=%u\n", wwi->dwPeriodSize);
-    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
-	  wwi->format.Format.wBitsPerSample, wwi->format.Format.nAvgBytesPerSec,
-	  wwi->format.Format.nSamplesPerSec, wwi->format.Format.nChannels,
-	  wwi->format.Format.nBlockAlign);
-
-    wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwi->dwThreadID));
-    if (!wwi->hThread) {
-        ERR("Thread creation for the widRecorder failed!\n");
-        CloseHandle(wwi->hStartUpEvent);
-        ret = MMSYSERR_NOMEM;
-        goto error;
-    }
-    SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL);
-    WaitForSingleObject(wwi->hStartUpEvent, INFINITE);
-    CloseHandle(wwi->hStartUpEvent);
-    wwi->hStartUpEvent = NULL;
-
-    HeapFree( GetProcessHeap(), 0, sw_params );
-    wwi->hw_params = hw_params;
-    wwi->pcm = pcm;
-
-    widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
-    return MMSYSERR_NOERROR;
-
-error:
-    snd_pcm_close(pcm);
-    HeapFree( GetProcessHeap(), 0, hw_params );
-    HeapFree( GetProcessHeap(), 0, sw_params );
-    if (wwi->msgRing.ring_buffer_size > 0)
-        ALSA_DestroyRingMessage(&wwi->msgRing);
-    return ret;
-}
-
-
-/**************************************************************************
- * 				widClose			[internal]
- */
-static DWORD widClose(WORD wDevID)
-{
-    WINE_WAVEDEV*	wwi;
-
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    wwi = &WInDev[wDevID];
-    if (wwi->pcm == NULL) {
-	WARN("Requested to close already closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (wwi->lpQueuePtr) {
-	WARN("buffers still playing !\n");
-	return WAVERR_STILLPLAYING;
-    } else {
-	if (wwi->hThread) {
-	    ALSA_AddRingMessage(&wwi->msgRing, WINE_WM_CLOSING, 0, TRUE);
-	}
-        ALSA_DestroyRingMessage(&wwi->msgRing);
-
-	HeapFree( GetProcessHeap(), 0, wwi->hw_params );
-	wwi->hw_params = NULL;
-
-        snd_pcm_close(wwi->pcm);
-	wwi->pcm = NULL;
-
-	widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widAddBuffer			[internal]
- *
- */
-static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    /* first, do the sanity checks... */
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WInDev[wDevID].pcm == NULL) {
-	WARN("Requested to add buffer to already closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
-	return WAVERR_UNPREPARED;
-
-    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
-	return WAVERR_STILLPLAYING;
-
-    lpWaveHdr->dwFlags &= ~WHDR_DONE;
-    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
-    lpWaveHdr->dwBytesRecorded = 0;
-    lpWaveHdr->lpNext = 0;
-
-    ALSA_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD_PTR)lpWaveHdr, FALSE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widStart			[internal]
- *
- */
-static DWORD widStart(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    /* first, do the sanity checks... */
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WInDev[wDevID].pcm == NULL) {
-	WARN("Requested to start closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STARTING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widStop			[internal]
- *
- */
-static DWORD widStop(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    /* first, do the sanity checks... */
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WInDev[wDevID].pcm == NULL) {
-	WARN("Requested to stop closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STOPPING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			widReset				[internal]
- */
-static DWORD widReset(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WInDev[wDevID].pcm == NULL) {
-	WARN("Requested to reset closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widGetPosition			[internal]
- */
-static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
-{
-    WINE_WAVEDEV*	wwi;
-
-    TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
-
-    if (wDevID >= ALSA_WidNumDevs) {
-	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("Requested position of closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpTime == NULL)	{
-        WARN("invalid parameter: lpTime = NULL\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    wwi = &WInDev[wDevID];
-    return ALSA_bytes_to_mmtime(lpTime, wwi->dwTotalRecorded, &wwi->format);
-}
-
-/**************************************************************************
- * 				widGetNumDevs			[internal]
- */
-static	DWORD	widGetNumDevs(void)
-{
-    return ALSA_WidNumDevs;
-}
-
-/**************************************************************************
- *                              widDevInterfaceSize             [internal]
- */
-static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
-{
-    TRACE("(%u, %p)\n", wDevID, dwParam1);
-
-    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
-                                    NULL, 0 ) * sizeof(WCHAR);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- *                              widDevInterface                 [internal]
- */
-static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
-{
-    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
-                                        NULL, 0 ) * sizeof(WCHAR))
-    {
-        MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
-                            dwParam1, dwParam2 / sizeof(WCHAR));
-        return MMSYSERR_NOERROR;
-    }
-    return MMSYSERR_INVALPARAM;
-}
-
-/**************************************************************************
- * 				widMessage (WINEALSA.@)
- */
-DWORD WINAPI ALSA_widMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
-                             DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("(%u, %s, %08lX, %08lX, %08lX);\n",
-	  wDevID, ALSA_getMessage(wMsg), dwUser, dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case DRVM_INIT:
-        ALSA_WaveInit();
-    case DRVM_EXIT:
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
-    case WIDM_OPEN:	 	return widOpen		(wDevID, (LPWAVEOPENDESC)dwParam1,	dwParam2);
-    case WIDM_CLOSE:	 	return widClose		(wDevID);
-    case WIDM_ADDBUFFER:	return widAddBuffer	(wDevID, (LPWAVEHDR)dwParam1,		dwParam2);
-    case WIDM_PREPARE:	 	return MMSYSERR_NOTSUPPORTED;
-    case WIDM_UNPREPARE: 	return MMSYSERR_NOTSUPPORTED;
-    case WIDM_GETDEVCAPS:	return widGetDevCaps	(wDevID, (LPWAVEINCAPSW)dwParam1,	dwParam2);
-    case WIDM_GETNUMDEVS:	return widGetNumDevs	();
-    case WIDM_GETPOS:	 	return widGetPosition	(wDevID, (LPMMTIME)dwParam1, 		dwParam2);
-    case WIDM_RESET:		return widReset		(wDevID);
-    case WIDM_START: 		return widStart	(wDevID, (LPWAVEHDR)dwParam1, 		dwParam2);
-    case WIDM_STOP: 		return widStop	(wDevID, (LPWAVEHDR)dwParam1, 		dwParam2);
-    case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
-    case DRV_QUERYDEVICEINTERFACE:     return widDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
-    case DRV_QUERYDSOUNDIFACE:	return widDsCreate   (wDevID, (PIDSCDRIVER*)dwParam1);
-    case DRV_QUERYDSOUNDDESC:	return widDsDesc     (wDevID, (PDSDRIVERDESC)dwParam1);
-    default:
-	FIXME("unknown message %d!\n", wMsg);
-    }
-    return MMSYSERR_NOTSUPPORTED;
-}
diff --git a/dlls/winealsa.drv/waveinit.c b/dlls/winealsa.drv/waveinit.c
deleted file mode 100644
index e4c81f2..0000000
--- a/dlls/winealsa.drv/waveinit.c
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Sample Wine Driver for Advanced Linux Sound System (ALSA)
- *      Based on version <final> of the ALSA API
- *
- * This file performs the initialisation and scanning of the sound subsystem.
- *
- * Copyright    2002 Eric Pouech
- *              2002 Marco Pietrobono
- *              2003 Christian Costa : WaveIn support
- *              2006-2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winerror.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "winreg.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-
-#include "alsa.h"
-
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wave);
-
-/*----------------------------------------------------------------------------
-**  ALSA_TestDeviceForWine
-**
-**      Test to see if a given device is sufficient for Wine.
-*/
-static int ALSA_TestDeviceForWine(int card, int device,  snd_pcm_stream_t streamtype)
-{
-    snd_pcm_t *pcm = NULL;
-    char pcmname[256];
-    int retcode;
-    snd_pcm_hw_params_t *hwparams;
-    const char *reason = NULL;
-    unsigned int rrate;
-
-    hwparams = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() );
-
-    /* Note that the plug: device masks out a lot of info, we want to avoid that */
-    sprintf(pcmname, "hw:%d,%d", card, device);
-    retcode = snd_pcm_open(&pcm, pcmname, streamtype, SND_PCM_NONBLOCK);
-    if (retcode < 0)
-    {
-        /* Note that a busy device isn't automatically disqualified */
-        if (retcode == (-1 * EBUSY))
-            retcode = 0;
-        goto exit;
-    }
-
-    retcode = snd_pcm_hw_params_any(pcm, hwparams);
-    if (retcode < 0)
-    {
-        reason = "Could not retrieve hw_params";
-        goto exit;
-    }
-
-    /* set the count of channels */
-    retcode = snd_pcm_hw_params_set_channels(pcm, hwparams, 2);
-    if (retcode < 0)
-    {
-        retcode = snd_pcm_hw_params_set_channels(pcm, hwparams, 1); /* If we can't open stereo, try mono; this is vital for snd_usb_audio microphones */
-    }
-    if (retcode < 0)
-    {
-        reason = "Could not set channels";
-        goto exit;
-    }
-
-    rrate = 44100;
-    retcode = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rrate, 0);
-    if (retcode < 0)
-    {
-        reason = "Could not set rate";
-        goto exit;
-    }
-
-    if (rrate == 0)
-    {
-        reason = "Rate came back as 0";
-        goto exit;
-    }
-
-    /* write the parameters to device */
-    retcode = snd_pcm_hw_params(pcm, hwparams);
-    if (retcode < 0)
-    {
-        reason = "Could not set hwparams";
-        goto exit;
-    }
-
-    retcode = 0;
-
-exit:
-    if (pcm)
-        snd_pcm_close(pcm);
-    HeapFree( GetProcessHeap(), 0, hwparams );
-
-    if (retcode != 0 && retcode != (-1 * ENOENT))
-        TRACE("Discarding card %d/device %d:  %s [%d(%s)]\n", card, device, reason, retcode, snd_strerror(retcode));
-
-    return retcode;
-}
-
-/*----------------------------------------------------------------------------
-** ALSA_RegGetString
-**  Retrieve a string from a registry key
-*/
-static int ALSA_RegGetString(HKEY key, const char *value, char **bufp)
-{
-    DWORD rc;
-    DWORD type;
-    DWORD bufsize;
-
-    *bufp = NULL;
-    rc = RegQueryValueExA(key, value, NULL, &type, NULL, &bufsize);
-    if (rc != ERROR_SUCCESS)
-        return(rc);
-
-    if (type != REG_SZ)
-        return 1;
-
-    *bufp = HeapAlloc(GetProcessHeap(), 0, bufsize);
-    if (! *bufp)
-        return 1;
-
-    rc = RegQueryValueExA(key, value, NULL, NULL, (LPBYTE)*bufp, &bufsize);
-    return rc;
-}
-
-/*----------------------------------------------------------------------------
-** ALSA_RegGetBoolean
-**  Get a string and interpret it as a boolean
-*/
-
-/* Possible truths:
-   Y(es), T(rue), 1, E(nabled) */
-
-#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1' || (ch) == 'e' || (ch) == 'E')
-static int ALSA_RegGetBoolean(HKEY key, const char *value, BOOL *answer)
-{
-    DWORD rc;
-    char *buf = NULL;
-
-    rc = ALSA_RegGetString(key, value, &buf);
-    if (buf)
-    {
-        *answer = FALSE;
-        if (IS_OPTION_TRUE(*buf))
-            *answer = TRUE;
-
-        HeapFree(GetProcessHeap(), 0, buf);
-    }
-
-    return rc;
-}
-
-/*----------------------------------------------------------------------------
-** ALSA_RegGetInt
-**  Get a string and interpret it as a DWORD
-*/
-static int ALSA_RegGetInt(HKEY key, const char *value, DWORD *answer)
-{
-    DWORD rc;
-    char *buf = NULL;
-
-    rc = ALSA_RegGetString(key, value, &buf);
-    if (buf)
-    {
-        *answer = atoi(buf);
-        HeapFree(GetProcessHeap(), 0, buf);
-    }
-
-    return rc;
-}
-
-/* return a string duplicated on the win32 process heap, free with HeapFree */
-static char* ALSA_strdup(const char *s) {
-    char *result = HeapAlloc(GetProcessHeap(), 0, strlen(s)+1);
-    if (!result)
-        return NULL;
-    strcpy(result, s);
-    return result;
-}
-
-#define ALSA_RETURN_ONFAIL(mycall)                                      \
-{                                                                       \
-    int rc;                                                             \
-    {rc = mycall;}                                                      \
-    if ((rc) < 0)                                                       \
-    {                                                                   \
-        ERR("%s failed:  %s(%d)\n", #mycall, snd_strerror(rc), rc);     \
-        return(rc);                                                     \
-    }                                                                   \
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_ComputeCaps
-**
-**      Given an ALSA PCM, figure out our HW CAPS structure info.
-**  ctl can be null, pcm is required, as is all output parms.
-**
-*/
-static int ALSA_ComputeCaps(snd_ctl_t *ctl, snd_pcm_t *pcm,
-        WORD *channels, DWORD *flags, DWORD *formats, DWORD *supports)
-{
-    snd_pcm_hw_params_t *hw_params;
-    snd_pcm_format_mask_t *fmask;
-    snd_pcm_access_mask_t *acmask;
-    unsigned int ratemin = 0;
-    unsigned int ratemax = 0;
-    unsigned int chmin = 0;
-    unsigned int chmax = 0;
-    int rc, dir = 0;
-
-    hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() );
-    fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof() );
-    acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof() );
-
-    if ((rc = snd_pcm_hw_params_any(pcm, hw_params)) < 0) goto done;
-
-    snd_pcm_hw_params_get_format_mask(hw_params, fmask);
-
-    if ((rc = snd_pcm_hw_params_get_access_mask(hw_params, acmask)) < 0) goto done;
-
-    if ((rc = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir)) < 0) goto done;
-    if ((rc = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir)) < 0) goto done;
-    if ((rc = snd_pcm_hw_params_get_channels_min(hw_params, &chmin)) < 0) goto done;
-    if ((rc = snd_pcm_hw_params_get_channels_max(hw_params, &chmax)) < 0) goto done;
-
-#define X(r,v) \
-    if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
-    { \
-       if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
-       { \
-          if (chmin <= 1 && 1 <= chmax) \
-              *formats |= WAVE_FORMAT_##v##M08; \
-          if (chmin <= 2 && 2 <= chmax) \
-              *formats |= WAVE_FORMAT_##v##S08; \
-       } \
-       if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
-       { \
-          if (chmin <= 1 && 1 <= chmax) \
-              *formats |= WAVE_FORMAT_##v##M16; \
-          if (chmin <= 2 && 2 <= chmax) \
-              *formats |= WAVE_FORMAT_##v##S16; \
-       } \
-    }
-    X(11025,1);
-    X(22050,2);
-    X(44100,4);
-    X(48000,48);
-    X(96000,96);
-#undef X
-
-    if (chmin > 1)
-        FIXME("Device has a minimum of %d channels\n", chmin);
-    *channels = chmax;
-
-    /* FIXME: is sample accurate always true ?
-    ** Can we do WAVECAPS_PITCH, WAVECAPS_SYNC, or WAVECAPS_PLAYBACKRATE? */
-    *supports |= WAVECAPS_SAMPLEACCURATE;
-
-    *supports |= WAVECAPS_DIRECTSOUND;
-
-    /* check for volume control support */
-    if (ctl) {
-        if (snd_ctl_name(ctl))
-        {
-            snd_hctl_t *hctl;
-            if (snd_hctl_open(&hctl, snd_ctl_name(ctl), 0) >= 0)
-            {
-                snd_hctl_load(hctl);
-                if (!ALSA_CheckSetVolume( hctl, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
-                {
-                    *supports |= WAVECAPS_VOLUME;
-                    if (chmin <= 2 && 2 <= chmax)
-                        *supports |= WAVECAPS_LRVOLUME;
-                }
-                snd_hctl_free(hctl);
-                snd_hctl_close(hctl);
-            }
-        }
-    }
-
-    *flags = DSCAPS_CERTIFIED | DSCAPS_CONTINUOUSRATE;
-    *flags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
-    *flags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
-
-    if (*formats & (WAVE_FORMAT_1M08  | WAVE_FORMAT_2M08  |
-                               WAVE_FORMAT_4M08  | WAVE_FORMAT_48M08 |
-                               WAVE_FORMAT_96M08 | WAVE_FORMAT_1M16  |
-                               WAVE_FORMAT_2M16  | WAVE_FORMAT_4M16  |
-                               WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16) )
-        *flags |= DSCAPS_PRIMARYMONO;
-
-    if (*formats & (WAVE_FORMAT_1S08  | WAVE_FORMAT_2S08  |
-                               WAVE_FORMAT_4S08  | WAVE_FORMAT_48S08 |
-                               WAVE_FORMAT_96S08 | WAVE_FORMAT_1S16  |
-                               WAVE_FORMAT_2S16  | WAVE_FORMAT_4S16  |
-                               WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) )
-        *flags |= DSCAPS_PRIMARYSTEREO;
-
-    if (*formats & (WAVE_FORMAT_1M08  | WAVE_FORMAT_2M08  |
-                               WAVE_FORMAT_4M08  | WAVE_FORMAT_48M08 |
-                               WAVE_FORMAT_96M08 | WAVE_FORMAT_1S08  |
-                               WAVE_FORMAT_2S08  | WAVE_FORMAT_4S08  |
-                               WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08) )
-        *flags |= DSCAPS_PRIMARY8BIT;
-
-    if (*formats & (WAVE_FORMAT_1M16  | WAVE_FORMAT_2M16  |
-                               WAVE_FORMAT_4M16  | WAVE_FORMAT_48M16 |
-                               WAVE_FORMAT_96M16 | WAVE_FORMAT_1S16  |
-                               WAVE_FORMAT_2S16  | WAVE_FORMAT_4S16  |
-                               WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) )
-        *flags |= DSCAPS_PRIMARY16BIT;
-
-    rc = 0;
-
-done:
-    if (rc < 0) ERR("failed: %s(%d)\n", snd_strerror(rc), rc);
-    HeapFree( GetProcessHeap(), 0, hw_params );
-    HeapFree( GetProcessHeap(), 0, fmask );
-    HeapFree( GetProcessHeap(), 0, acmask );
-    return rc;
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_AddCommonDevice
-**
-**      Perform Alsa initialization common to both capture and playback
-**
-**  Side Effect:  ww->pcname and ww->ctlname may need to be freed.
-**
-**  Note:  this was originally coded by using snd_pcm_name(pcm), until
-**         I discovered that with at least one version of alsa lib,
-**         the use of a pcm named default:0 would cause snd_pcm_name() to fail.
-**         So passing the name in is logically extraneous.  Sigh.
-*/
-static int ALSA_AddCommonDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, WINE_WAVEDEV *ww)
-{
-    snd_pcm_info_t *infop;
-    int rc;
-
-    infop = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_info_sizeof() );
-    if ((rc = snd_pcm_info(pcm, infop)) < 0)
-    {
-        HeapFree( GetProcessHeap(), 0, infop );
-        return rc;
-    }
-
-    if (pcm && pcmname)
-        ww->pcmname = ALSA_strdup(pcmname);
-    else
-    {
-        HeapFree( GetProcessHeap(), 0, infop );
-        return -1;
-    }
-
-    if (ctl && snd_ctl_name(ctl))
-        ww->ctlname = ALSA_strdup(snd_ctl_name(ctl));
-
-    strcpy(ww->interface_name, "winealsa: ");
-    memcpy(ww->interface_name + strlen(ww->interface_name),
-            ww->pcmname,
-            min(strlen(ww->pcmname), sizeof(ww->interface_name) - strlen("winealsa:   ")));
-
-    strcpy(ww->ds_desc.szDrvname, "winealsa.drv");
-
-    memcpy(ww->ds_desc.szDesc, snd_pcm_info_get_name(infop),
-            min( (sizeof(ww->ds_desc.szDesc) - 1), strlen(snd_pcm_info_get_name(infop))) );
-
-    ww->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
-    ww->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
-    ww->ds_caps.dwPrimaryBuffers = 1;
-
-    HeapFree( GetProcessHeap(), 0, infop );
-    return 0;
-}
-
-/*----------------------------------------------------------------------------
-** ALSA_FreeDevice
-*/
-static void ALSA_FreeDevice(WINE_WAVEDEV *ww)
-{
-    HeapFree(GetProcessHeap(), 0, ww->pcmname);
-    ww->pcmname = NULL;
-
-    HeapFree(GetProcessHeap(), 0, ww->ctlname);
-    ww->ctlname = NULL;
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_AddDeviceToArray
-**
-**      Dynamically size one of the wavein or waveout arrays of devices,
-**  and add a fully configured device node to the array.
-**
-*/
-static int ALSA_AddDeviceToArray(WINE_WAVEDEV *ww, WINE_WAVEDEV **array,
-        DWORD *count, DWORD *alloced, int isdefault)
-{
-    int i = *count;
-
-    if (*count >= *alloced)
-    {
-        (*alloced) += WAVEDEV_ALLOC_EXTENT_SIZE;
-        if (! (*array))
-            *array = HeapAlloc(GetProcessHeap(), 0, sizeof(*ww) * (*alloced));
-        else
-            *array = HeapReAlloc(GetProcessHeap(), 0, *array, sizeof(*ww) * (*alloced));
-
-        if (!*array)
-        {
-            return -1;
-        }
-    }
-
-    /* If this is the default, arrange for it to be the first element */
-    if (isdefault && i > 0)
-    {
-        (*array)[*count] = (*array)[0];
-        i = 0;
-    }
-
-    (*array)[i] = *ww;
-
-    (*count)++;
-    return 0;
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_AddPlaybackDevice
-**
-**      Add a given Alsa device to Wine's internal list of Playback
-**  devices.
-*/
-static int ALSA_AddPlaybackDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, int isdefault)
-{
-    WINE_WAVEDEV    wwo;
-    int rc;
-
-    memset(&wwo, '\0', sizeof(wwo));
-
-    rc = ALSA_AddCommonDevice(ctl, pcm, pcmname, &wwo);
-    if (rc)
-        return(rc);
-
-    MultiByteToWideChar(CP_UNIXCP, 0, wwo.ds_desc.szDesc, -1,
-                        wwo.outcaps.szPname, sizeof(wwo.outcaps.szPname)/sizeof(WCHAR));
-    wwo.outcaps.szPname[sizeof(wwo.outcaps.szPname)/sizeof(WCHAR) - 1] = '\0';
-
-    wwo.outcaps.wMid = MM_CREATIVE;
-    wwo.outcaps.wPid = MM_CREATIVE_SBP16_WAVEOUT;
-    wwo.outcaps.vDriverVersion = 0x0100;
-
-    rc = ALSA_ComputeCaps(ctl, pcm, &wwo.outcaps.wChannels, &wwo.ds_caps.dwFlags,
-            &wwo.outcaps.dwFormats, &wwo.outcaps.dwSupport);
-    if (rc)
-    {
-        WARN("Error calculating device caps for pcm [%s]\n", wwo.pcmname);
-        ALSA_FreeDevice(&wwo);
-        return(rc);
-    }
-
-    rc = ALSA_AddDeviceToArray(&wwo, &WOutDev, &ALSA_WodNumDevs, &ALSA_WodNumMallocedDevs, isdefault);
-    if (rc)
-        ALSA_FreeDevice(&wwo);
-    return (rc);
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_AddCaptureDevice
-**
-**      Add a given Alsa device to Wine's internal list of Capture
-**  devices.
-*/
-static int ALSA_AddCaptureDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, int isdefault)
-{
-    WINE_WAVEDEV    wwi;
-    int rc;
-
-    memset(&wwi, '\0', sizeof(wwi));
-
-    rc = ALSA_AddCommonDevice(ctl, pcm, pcmname, &wwi);
-    if (rc)
-        return(rc);
-
-    MultiByteToWideChar(CP_UNIXCP, 0, wwi.ds_desc.szDesc, -1,
-                        wwi.incaps.szPname, sizeof(wwi.incaps.szPname) / sizeof(WCHAR));
-    wwi.incaps.szPname[sizeof(wwi.incaps.szPname)/sizeof(WCHAR) - 1] = '\0';
-
-    wwi.incaps.wMid = MM_CREATIVE;
-    wwi.incaps.wPid = MM_CREATIVE_SBP16_WAVEOUT;
-    wwi.incaps.vDriverVersion = 0x0100;
-
-    rc = ALSA_ComputeCaps(ctl, pcm, &wwi.incaps.wChannels, &wwi.ds_caps.dwFlags,
-            &wwi.incaps.dwFormats, &wwi.dwSupport);
-    if (rc)
-    {
-        WARN("Error calculating device caps for pcm [%s]\n", wwi.pcmname);
-        ALSA_FreeDevice(&wwi);
-        return(rc);
-    }
-
-    rc = ALSA_AddDeviceToArray(&wwi, &WInDev, &ALSA_WidNumDevs, &ALSA_WidNumMallocedDevs, isdefault);
-    if (rc)
-        ALSA_FreeDevice(&wwi);
-    return(rc);
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_CheckEnvironment
-**
-**      Given an Alsa style configuration node, scan its subitems
-**  for environment variable names, and use them to find an override,
-**  if appropriate.
-**      This is essentially a long and convoluted way of doing:
-**          getenv("ALSA_CARD")
-**          getenv("ALSA_CTL_CARD")
-**          getenv("ALSA_PCM_CARD")
-**          getenv("ALSA_PCM_DEVICE")
-**
-**  The output value is set with the atoi() of the first environment
-**  variable found to be set, if any; otherwise, it is left alone
-*/
-static void ALSA_CheckEnvironment(snd_config_t *node, int *outvalue)
-{
-    snd_config_iterator_t iter;
-
-    for (iter = snd_config_iterator_first(node);
-         iter != snd_config_iterator_end(node);
-         iter = snd_config_iterator_next(iter))
-    {
-        snd_config_t *leaf = snd_config_iterator_entry(iter);
-        if (snd_config_get_type(leaf) == SND_CONFIG_TYPE_STRING)
-        {
-            const char *value;
-            if (snd_config_get_string(leaf, &value) >= 0)
-            {
-                char *p = getenv(value);
-                if (p)
-                {
-                    *outvalue = atoi(p);
-                    return;
-                }
-            }
-        }
-    }
-}
-
-/*----------------------------------------------------------------------------
-**  ALSA_DefaultDevices
-**
-**      Jump through Alsa style hoops to (hopefully) properly determine
-**  Alsa defaults for CTL Card #, as well as for PCM Card + Device #.
-**  We'll also find out if the user has set any of the environment
-**  variables that specify we're to use a specific card or device.
-**
-**  Parameters:
-**      directhw        Whether to use a direct hardware device or not;
-**                      essentially switches the pcm device name from
-**                      one of 'default:X' or 'plughw:X' to "hw:X"
-**      defctlcard      If !NULL, will hold the ctl card number given
-**                      by the ALSA config as the default
-**      defpcmcard      If !NULL, default pcm card #
-**      defpcmdev       If !NULL, default pcm device #
-**      fixedctlcard    If !NULL, and the user set the appropriate
-**                          environment variable, we'll set to the
-**                          card the user specified.
-**      fixedpcmcard    If !NULL, and the user set the appropriate
-**                          environment variable, we'll set to the
-**                          card the user specified.
-**      fixedpcmdev     If !NULL, and the user set the appropriate
-**                          environment variable, we'll set to the
-**                          device the user specified.
-**
-**  Returns:  0 on success, < 0 on failure
-*/
-static int ALSA_DefaultDevices(int directhw,
-            long *defctlcard,
-            long *defpcmcard, long *defpcmdev,
-            int *fixedctlcard,
-            int *fixedpcmcard, int *fixedpcmdev)
-{
-    snd_config_t   *configp;
-    char pcmsearch[256];
-
-    ALSA_RETURN_ONFAIL(snd_config_update());
-
-    if (defctlcard)
-        if (snd_config_search(snd_config, "defaults.ctl.card", &configp) >= 0)
-            snd_config_get_integer(configp, defctlcard);
-
-    if (defpcmcard)
-        if (snd_config_search(snd_config, "defaults.pcm.card", &configp) >= 0)
-            snd_config_get_integer(configp, defpcmcard);
-
-    if (defpcmdev)
-        if (snd_config_search(snd_config, "defaults.pcm.device", &configp) >= 0)
-            snd_config_get_integer(configp, defpcmdev);
-
-
-    if (fixedctlcard)
-    {
-        if (snd_config_search(snd_config, "ctl.hw. at args.CARD.default.vars", &configp) >= 0)
-            ALSA_CheckEnvironment(configp, fixedctlcard);
-    }
-
-    if (fixedpcmcard)
-    {
-        sprintf(pcmsearch, "pcm.%s. at args.CARD.default.vars", directhw ? "hw" : "plughw");
-        if (snd_config_search(snd_config, pcmsearch, &configp) >= 0)
-            ALSA_CheckEnvironment(configp, fixedpcmcard);
-    }
-
-    if (fixedpcmdev)
-    {
-        sprintf(pcmsearch, "pcm.%s. at args.DEV.default.vars", directhw ? "hw" : "plughw");
-        if (snd_config_search(snd_config, pcmsearch, &configp) >= 0)
-            ALSA_CheckEnvironment(configp, fixedpcmdev);
-    }
-
-    return 0;
-}
-
-
-/*----------------------------------------------------------------------------
-**  ALSA_ScanDevices
-**
-**      Iterate through all discoverable ALSA cards, searching
-**  for usable PCM devices.
-**
-**  Parameters:
-**      directhw        Whether to use a direct hardware device or not;
-**                      essentially switches the pcm device name from
-**                      one of 'default:X' or 'plughw:X' to "hw:X"
-**      defctlcard      Alsa's notion of the default ctl card.
-**      defpcmcard         . pcm card
-**      defpcmdev          . pcm device
-**      fixedctlcard    If not -1, then gives the value of ALSA_CTL_CARD
-**                          or equivalent environment variable
-**      fixedpcmcard    If not -1, then gives the value of ALSA_PCM_CARD
-**                          or equivalent environment variable
-**      fixedpcmdev     If not -1, then gives the value of ALSA_PCM_DEVICE
-**                          or equivalent environment variable
-**
-**  Returns:  0 on success, < 0 on failure
-*/
-static int ALSA_ScanDevices(int directhw,
-        long defctlcard, long defpcmcard, long defpcmdev,
-        int fixedctlcard, int fixedpcmcard, int fixedpcmdev)
-{
-    int card = fixedpcmcard;
-    int scan_devices = (fixedpcmdev == -1);
-
-    /*------------------------------------------------------------------------
-    ** Loop through all available cards
-    **----------------------------------------------------------------------*/
-    if (card == -1)
-        snd_card_next(&card);
-
-    for (; card != -1; snd_card_next(&card))
-    {
-        char ctlname[256];
-        snd_ctl_t *ctl;
-        int rc;
-        int device;
-
-        /*--------------------------------------------------------------------
-        ** Try to open a ctl handle; Wine doesn't absolutely require one,
-        **  but it does allow for volume control and for device scanning
-        **------------------------------------------------------------------*/
-        sprintf(ctlname, "hw:%d", fixedctlcard == -1 ? card : fixedctlcard);
-        rc = snd_ctl_open(&ctl, ctlname, SND_CTL_NONBLOCK);
-        if (rc < 0)
-        {
-            ctl = NULL;
-            WARN("Unable to open an alsa ctl for [%s] (pcm card %d): %s; not scanning devices\n",
-                    ctlname, card, snd_strerror(rc));
-            if (fixedpcmdev == -1)
-                fixedpcmdev = 0;
-        }
-
-        /*--------------------------------------------------------------------
-        ** Loop through all available devices on this card
-        **------------------------------------------------------------------*/
-        device = fixedpcmdev;
-        if (device == -1)
-            snd_ctl_pcm_next_device(ctl, &device);
-
-        for (; device != -1; snd_ctl_pcm_next_device(ctl, &device))
-        {
-            char defaultpcmname[256];
-            char plugpcmname[256];
-            char hwpcmname[256];
-            char *pcmname = NULL;
-            snd_pcm_t *pcm;
-
-            sprintf(defaultpcmname, "default");
-            sprintf(plugpcmname,    "plughw:%d,%d", card, device);
-            sprintf(hwpcmname,      "hw:%d,%d", card, device);
-
-            /*----------------------------------------------------------------
-            ** See if it's a valid playback device
-            **--------------------------------------------------------------*/
-            if (ALSA_TestDeviceForWine(card, device, SND_PCM_STREAM_PLAYBACK) == 0)
-            {
-                /* If we can, try the default:X device name first */
-                if (! scan_devices && ! directhw)
-                {
-                    pcmname = defaultpcmname;
-                    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-                }
-                else
-                    rc = -1;
-
-                if (rc < 0)
-                {
-                    pcmname = directhw ? hwpcmname : plugpcmname;
-                    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-                }
-
-                if (rc >= 0)
-                {
-                    if (defctlcard == card && defpcmcard == card && defpcmdev == device)
-                        ALSA_AddPlaybackDevice(ctl, pcm, pcmname, TRUE);
-                    else
-                        ALSA_AddPlaybackDevice(ctl, pcm, pcmname, FALSE);
-                    snd_pcm_close(pcm);
-                }
-                else
-                {
-                    TRACE("Device [%s/%s] failed to open for playback: %s\n",
-                        directhw || scan_devices ? "(N/A)" : defaultpcmname,
-                        directhw ? hwpcmname : plugpcmname,
-                        snd_strerror(rc));
-                }
-            }
-
-            /*----------------------------------------------------------------
-            ** See if it's a valid capture device
-            **--------------------------------------------------------------*/
-            if (ALSA_TestDeviceForWine(card, device, SND_PCM_STREAM_CAPTURE) == 0)
-            {
-                /* If we can, try the default:X device name first */
-                if (! scan_devices && ! directhw)
-                {
-                    pcmname = defaultpcmname;
-                    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-                }
-                else
-                    rc = -1;
-
-                if (rc < 0)
-                {
-                    pcmname = directhw ? hwpcmname : plugpcmname;
-                    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-                }
-
-                if (rc >= 0)
-                {
-                    if (defctlcard == card && defpcmcard == card && defpcmdev == device)
-                        ALSA_AddCaptureDevice(ctl, pcm, pcmname, TRUE);
-                    else
-                        ALSA_AddCaptureDevice(ctl, pcm, pcmname, FALSE);
-
-                    snd_pcm_close(pcm);
-                }
-                else
-                {
-                    TRACE("Device [%s/%s] failed to open for capture: %s\n",
-                        directhw || scan_devices ? "(N/A)" : defaultpcmname,
-                        directhw ? hwpcmname : plugpcmname,
-                        snd_strerror(rc));
-                }
-            }
-
-            if (! scan_devices)
-                break;
-        }
-
-        if (ctl)
-            snd_ctl_close(ctl);
-
-        /*--------------------------------------------------------------------
-        ** If the user has set env variables such that we're pegged to
-        **  a specific card, then break after we've examined it
-        **------------------------------------------------------------------*/
-        if (fixedpcmcard != -1)
-            break;
-    }
-
-    return 0;
-
-}
-
-/*----------------------------------------------------------------------------
-** ALSA_PerformDefaultScan
-**  Perform the basic default scanning for devices within ALSA.
-**  The hope is that this routine implements a 'correct'
-**  scanning algorithm from the Alsalib point of view.
-**
-**      Note that Wine, overall, has other mechanisms to
-**  override and specify exact CTL and PCM device names,
-**  but this routine is imagined as the default that
-**  99% of users will use.
-**
-**      The basic algorithm is simple:
-**  Use snd_card_next to iterate cards; within cards, use
-**  snd_ctl_pcm_next_device to iterate through devices.
-**
-**      We add a little complexity by taking into consideration
-**  environment variables such as ALSA_CARD (et all), and by
-**  detecting when a given device matches the default specified
-**  by Alsa.
-**
-**  Parameters:
-**      directhw        If !0, indicates we should use the hw:X
-**                      PCM interface, rather than first try
-**                      the 'default' device followed by the plughw
-**                      device.  (default and plughw do fancy mixing
-**                      and audio scaling, if they are available).
-**      devscan         If TRUE, we should scan all devices, not
-**                      juse use device 0 on each card
-**
-**  Returns:
-**      0   on success
-**
-**  Effects:
-**      Invokes the ALSA_AddXXXDevice functions on valid
-**  looking devices
-*/
-static int ALSA_PerformDefaultScan(int directhw, BOOL devscan)
-{
-    long defctlcard = -1, defpcmcard = -1, defpcmdev = -1;
-    int fixedctlcard = -1, fixedpcmcard = -1, fixedpcmdev = -1;
-    int rc;
-
-    /* FIXME:  We should dlsym the new snd_names_list/snd_names_list_free 1.0.9 apis,
-    **          and use them instead of this scan mechanism if they are present         */
-
-    rc = ALSA_DefaultDevices(directhw, &defctlcard, &defpcmcard, &defpcmdev,
-            &fixedctlcard, &fixedpcmcard, &fixedpcmdev);
-    if (rc)
-        return(rc);
-
-    if (fixedpcmdev == -1 && ! devscan)
-        fixedpcmdev = 0;
-
-    return(ALSA_ScanDevices(directhw, defctlcard, defpcmcard, defpcmdev, fixedctlcard, fixedpcmcard, fixedpcmdev));
-}
-
-
-/*----------------------------------------------------------------------------
-** ALSA_AddUserSpecifiedDevice
-**  Add a device given from the registry
-*/
-static int ALSA_AddUserSpecifiedDevice(const char *ctlname, const char *pcmname)
-{
-    int rc;
-    int okay = 0;
-    snd_ctl_t *ctl = NULL;
-    snd_pcm_t *pcm = NULL;
-
-    if (ctlname)
-    {
-        rc = snd_ctl_open(&ctl, ctlname, SND_CTL_NONBLOCK);
-        if (rc < 0)
-            ctl = NULL;
-    }
-
-    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
-    if (rc >= 0)
-    {
-        ALSA_AddPlaybackDevice(ctl, pcm, pcmname, FALSE);
-        okay++;
-        snd_pcm_close(pcm);
-    }
-
-    rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
-    if (rc >= 0)
-    {
-        ALSA_AddCaptureDevice(ctl, pcm, pcmname, FALSE);
-        okay++;
-        snd_pcm_close(pcm);
-    }
-
-    if (ctl)
-        snd_ctl_close(ctl);
-
-    return (okay == 0);
-}
-
-
-/*----------------------------------------------------------------------------
-** ALSA_WaveInit
-**  Initialize the Wine Alsa sub system.
-** The main task is to probe for and store a list of all appropriate playback
-** and capture devices.
-**  Key control points are from the registry key:
-**  [Software\Wine\Alsa Driver]
-**  AutoScanCards           Whether or not to scan all known sound cards
-**                          and add them to Wine's list (default yes)
-**  AutoScanDevices         Whether or not to scan all known PCM devices
-**                          on each card (default no)
-**  UseDirectHW             Whether or not to use the hw:X device,
-**                          instead of the fancy default:X or plughw:X device.
-**                          The hw:X device goes straight to the hardware
-**                          without any fancy mixing or audio scaling in between.
-**  DeviceCount             If present, specifies the number of hard coded
-**                          Alsa devices to add to Wine's list; default 0
-**  DevicePCMn              Specifies the Alsa PCM devices to open for
-**                          Device n (where n goes from 1 to DeviceCount)
-**  DeviceCTLn              Specifies the Alsa control devices to open for
-**                          Device n (where n goes from 1 to DeviceCount)
-**
-**                          Using AutoScanCards no, and then Devicexxx info
-**                          is a way to exactly specify the devices used by Wine.
-**
-*/
-void ALSA_WaveInit(void)
-{
-    DWORD rc;
-    BOOL  AutoScanCards = TRUE;
-    BOOL  AutoScanDevices = FALSE;
-    BOOL  UseDirectHW = FALSE;
-    DWORD DeviceCount = 0;
-    HKEY  key = 0;
-    int   i;
-    static int loaded;
-
-    if (loaded++)
-        return;
-
-    /* @@ Wine registry key: HKCU\Software\Wine\Alsa Driver */
-    rc = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Alsa Driver", 0, KEY_QUERY_VALUE, &key);
-    if (rc == ERROR_SUCCESS)
-    {
-        ALSA_RegGetBoolean(key, "AutoScanCards", &AutoScanCards);
-        ALSA_RegGetBoolean(key, "AutoScanDevices", &AutoScanDevices);
-        ALSA_RegGetBoolean(key, "UseDirectHW", &UseDirectHW);
-        ALSA_RegGetInt(key, "DeviceCount", &DeviceCount);
-    }
-
-    if (AutoScanCards)
-        ALSA_PerformDefaultScan(UseDirectHW, AutoScanDevices);
-
-    for (i = 0; i < DeviceCount; i++)
-    {
-        char *ctl_name = NULL;
-        char *pcm_name = NULL;
-        char value[30];
-
-        sprintf(value, "DevicePCM%d", i + 1);
-        if (ALSA_RegGetString(key, value, &pcm_name) == ERROR_SUCCESS)
-        {
-            sprintf(value, "DeviceCTL%d", i + 1);
-            ALSA_RegGetString(key, value, &ctl_name);
-            ALSA_AddUserSpecifiedDevice(ctl_name, pcm_name);
-        }
-
-        HeapFree(GetProcessHeap(), 0, ctl_name);
-        HeapFree(GetProcessHeap(), 0, pcm_name);
-    }
-
-    if (key)
-        RegCloseKey(key);
-}
diff --git a/dlls/winealsa.drv/waveout.c b/dlls/winealsa.drv/waveout.c
deleted file mode 100644
index 88153e7..0000000
--- a/dlls/winealsa.drv/waveout.c
+++ /dev/null
@@ -1,1182 +0,0 @@
-/*
- * Sample Wine Driver for Advanced Linux Sound System (ALSA)
- *      Based on version <final> of the ALSA API
- *
- * Copyright    2002 Eric Pouech
- *              2002 Marco Pietrobono
- *              2003 Christian Costa : WaveIn support
- *              2006-2007 Maarten Lankhorst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*======================================================================*
- *                  Low level WAVE OUT implementation			*
- *======================================================================*/
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "ks.h"
-#include "ksmedia.h"
-
-#include "alsa.h"
-
-#include "wine/library.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wave);
-
-WINE_WAVEDEV	*WOutDev;
-DWORD            ALSA_WodNumMallocedDevs;
-DWORD            ALSA_WodNumDevs;
-
-/**************************************************************************
- * 			wodNotifyClient			[internal]
- */
-static void wodNotifyClient(WINE_WAVEDEV* wwo, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("wMsg = 0x%04x dwParm1 = %lx dwParam2 = %lx\n", wMsg, dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case WOM_OPEN:
-    case WOM_CLOSE:
-    case WOM_DONE:
-        DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags, (HDRVR)wwo->waveDesc.hWave,
-                       wMsg, wwo->waveDesc.dwInstance, dwParam1, dwParam2);
-	break;
-    default:
-	FIXME("Unknown callback message %u\n", wMsg);
-    }
-}
-
-/**************************************************************************
- * 				wodUpdatePlayedTotal	[internal]
- *
- */
-static BOOL wodUpdatePlayedTotal(WINE_WAVEDEV* wwo, snd_pcm_status_t* ps)
-{
-    snd_pcm_sframes_t delay;
-    snd_pcm_sframes_t avail;
-    snd_pcm_uframes_t buf_size = 0;
-    snd_pcm_state_t state;
-
-    state = snd_pcm_state(wwo->pcm);
-    avail = snd_pcm_avail_update(wwo->pcm);
-    snd_pcm_hw_params_get_buffer_size(wwo->hw_params, &buf_size);
-    delay = buf_size - avail;
-
-    if (state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED)
-    {
-        WARN("Unexpected state (%d) while updating Total Played, resetting\n", state);
-        wine_snd_pcm_recover(wwo->pcm, -EPIPE, 0);
-        delay=0;
-    }
-
-    /* A delay < 0 indicates an underrun; for our purposes that's 0.  */
-    if (delay < 0)
-    {
-        WARN("Unexpected delay (%ld) while updating Total Played, resetting\n", delay);
-        delay=0;
-    }
-
-    InterlockedExchange((LONG*)&wwo->dwPlayedTotal, wwo->dwWrittenTotal - snd_pcm_frames_to_bytes(wwo->pcm, delay));
-    return TRUE;
-}
-
-/**************************************************************************
- * 				wodPlayer_BeginWaveHdr          [internal]
- *
- * Makes the specified lpWaveHdr the currently playing wave header.
- * If the specified wave header is a begin loop and we're not already in
- * a loop, setup the loop.
- */
-static void wodPlayer_BeginWaveHdr(WINE_WAVEDEV* wwo, LPWAVEHDR lpWaveHdr)
-{
-    wwo->lpPlayPtr = lpWaveHdr;
-
-    if (!lpWaveHdr) return;
-
-    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP) {
-	if (wwo->lpLoopPtr) {
-	    WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
-	} else {
-            TRACE("Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
-	    wwo->lpLoopPtr = lpWaveHdr;
-	    /* Windows does not touch WAVEHDR.dwLoops,
-	     * so we need to make an internal copy */
-	    wwo->dwLoops = lpWaveHdr->dwLoops;
-	}
-    }
-    wwo->dwPartialOffset = 0;
-}
-
-/**************************************************************************
- * 				wodPlayer_PlayPtrNext	        [internal]
- *
- * Advance the play pointer to the next waveheader, looping if required.
- */
-static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEDEV* wwo)
-{
-    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
-
-    wwo->dwPartialOffset = 0;
-    if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {
-	/* We're at the end of a loop, loop if required */
-	if (--wwo->dwLoops > 0) {
-	    wwo->lpPlayPtr = wwo->lpLoopPtr;
-	} else {
-	    /* Handle overlapping loops correctly */
-	    if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
-		FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
-		/* shall we consider the END flag for the closing loop or for
-		 * the opening one or for both ???
-		 * code assumes for closing loop only
-		 */
-	    } else {
-                lpWaveHdr = lpWaveHdr->lpNext;
-            }
-            wwo->lpLoopPtr = NULL;
-            wodPlayer_BeginWaveHdr(wwo, lpWaveHdr);
-	}
-    } else {
-	/* We're not in a loop.  Advance to the next wave header */
-	wodPlayer_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
-    }
-
-    return lpWaveHdr;
-}
-
-/**************************************************************************
- * 			     wodPlayer_DSPWait			[internal]
- * Returns the number of milliseconds to wait for the DSP buffer to play a
- * period
- */
-static DWORD wodPlayer_DSPWait(const WINE_WAVEDEV *wwo)
-{
-    /* time for one period to be played */
-    unsigned int val=0;
-    int dir=0;
-    int err=0;
-    err = snd_pcm_hw_params_get_period_time(wwo->hw_params, &val, &dir);
-    return val / 1000;
-}
-
-/**************************************************************************
- * 			     wodPlayer_NotifyWait               [internal]
- * Returns the number of milliseconds to wait before attempting to notify
- * completion of the specified wavehdr.
- * This is based on the number of bytes remaining to be written in the
- * wave.
- */
-static DWORD wodPlayer_NotifyWait(const WINE_WAVEDEV* wwo, LPWAVEHDR lpWaveHdr)
-{
-    DWORD dwMillis;
-
-    if (lpWaveHdr->reserved < wwo->dwPlayedTotal) {
-        dwMillis = 1;
-    } else {
-        dwMillis = (lpWaveHdr->reserved - wwo->dwPlayedTotal) * 1000 / wwo->format.Format.nAvgBytesPerSec;
-        if (!dwMillis) dwMillis = 1;
-    }
-
-    return dwMillis;
-}
-
-
-/**************************************************************************
- * 			     wodPlayer_WriteMaxFrags            [internal]
- * Writes the maximum number of frames possible to the DSP and returns
- * the number of frames written.
- */
-static int wodPlayer_WriteMaxFrags(WINE_WAVEDEV* wwo, DWORD* frames)
-{
-    /* Only attempt to write to free frames */
-    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
-    DWORD dwLength = snd_pcm_bytes_to_frames(wwo->pcm, lpWaveHdr->dwBufferLength - wwo->dwPartialOffset);
-    int toWrite = min(dwLength, *frames);
-    int written;
-
-    TRACE("Writing wavehdr %p.%u[%u]\n", lpWaveHdr, wwo->dwPartialOffset, lpWaveHdr->dwBufferLength);
-
-    if (toWrite > 0) {
-	written = (wwo->write)(wwo->pcm, lpWaveHdr->lpData + wwo->dwPartialOffset, toWrite);
-	if ( written < 0) {
-	    /* XRUN occurred. let's try to recover */
-	    wine_snd_pcm_recover(wwo->pcm, written, 0);
-	    written = (wwo->write)(wwo->pcm, lpWaveHdr->lpData + wwo->dwPartialOffset, toWrite);
-	}
-	if (written <= 0) {
-	    /* still in error */
-	    ERR("Error in writing wavehdr. Reason: %s\n", snd_strerror(written));
-	    return written;
-	}
-    } else
-	written = 0;
-
-    wwo->dwPartialOffset += snd_pcm_frames_to_bytes(wwo->pcm, written);
-    if (wwo->dwPartialOffset + wwo->format.Format.nBlockAlign - 1 >= lpWaveHdr->dwBufferLength) {
-	/* this will be used to check if the given wave header has been fully played or not... */
-	wwo->dwPartialOffset = lpWaveHdr->dwBufferLength;
-	/* If we wrote all current wavehdr, skip to the next one */
-	wodPlayer_PlayPtrNext(wwo);
-    }
-    *frames -= written;
-    wwo->dwWrittenTotal += snd_pcm_frames_to_bytes(wwo->pcm, written);
-    TRACE("dwWrittenTotal=%u\n", wwo->dwWrittenTotal);
-
-    return written;
-}
-
-
-/**************************************************************************
- * 				wodPlayer_NotifyCompletions	[internal]
- *
- * Notifies and remove from queue all wavehdrs which have been played to
- * the speaker (ie. they have cleared the ALSA buffer).  If force is true,
- * we notify all wavehdrs and remove them all from the queue even if they
- * are unplayed or part of a loop.
- */
-static DWORD wodPlayer_NotifyCompletions(WINE_WAVEDEV* wwo, BOOL force)
-{
-    LPWAVEHDR		lpWaveHdr;
-
-    /* Start from lpQueuePtr and keep notifying until:
-     * - we hit an unwritten wavehdr
-     * - we hit the beginning of a running loop
-     * - we hit a wavehdr which hasn't finished playing
-     */
-    for (;;)
-    {
-        lpWaveHdr = wwo->lpQueuePtr;
-        if (!lpWaveHdr) {TRACE("Empty queue\n"); break;}
-        if (!force)
-        {
-            snd_pcm_uframes_t frames;
-            snd_pcm_hw_params_get_period_size(wwo->hw_params, &frames, NULL);
-
-            if (lpWaveHdr == wwo->lpPlayPtr) {TRACE("play %p\n", lpWaveHdr); break;}
-            if (lpWaveHdr == wwo->lpLoopPtr) {TRACE("loop %p\n", lpWaveHdr); break;}
-            if (lpWaveHdr->reserved > wwo->dwPlayedTotal + frames) {TRACE("still playing %p (%lu/%u)\n", lpWaveHdr, lpWaveHdr->reserved, wwo->dwPlayedTotal);break;}
-        }
-        wwo->dwPlayedTotal += lpWaveHdr->reserved - wwo->dwPlayedTotal;
-	wwo->lpQueuePtr = lpWaveHdr->lpNext;
-
-	lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-	lpWaveHdr->dwFlags |= WHDR_DONE;
-
-	wodNotifyClient(wwo, WOM_DONE, (DWORD_PTR)lpWaveHdr, 0);
-    }
-    return  (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != wwo->lpLoopPtr) ?
-        wodPlayer_NotifyWait(wwo, lpWaveHdr) : INFINITE;
-}
-
-
-/**************************************************************************
- * 				wodPlayer_Reset			[internal]
- *
- * wodPlayer helper. Resets current output stream.
- */
-static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
-{
-    int                         err;
-    TRACE("(%p)\n", wwo);
-
-    wodUpdatePlayedTotal(wwo, NULL);
-    /* updates current notify list */
-    wodPlayer_NotifyCompletions(wwo, FALSE);
-
-    if ( (err = snd_pcm_drop(wwo->pcm)) < 0) {
-	FIXME("flush: %s\n", snd_strerror(err));
-	wwo->hThread = 0;
-	wwo->state = WINE_WS_STOPPED;
-	ExitThread(-1);
-    }
-    if ( (err = snd_pcm_prepare(wwo->pcm)) < 0 )
-        ERR("pcm prepare failed: %s\n", snd_strerror(err));
-
-    if (reset) {
-        enum win_wm_message	msg;
-        DWORD_PTR	        param;
-        HANDLE		        ev;
-
-        /* remove any buffer */
-        wodPlayer_NotifyCompletions(wwo, TRUE);
-
-        wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
-        wwo->state = WINE_WS_STOPPED;
-        wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
-        /* Clear partial wavehdr */
-        wwo->dwPartialOffset = 0;
-
-        /* remove any existing message in the ring */
-        EnterCriticalSection(&wwo->msgRing.msg_crst);
-        /* return all pending headers in queue */
-        while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
-        {
-            if (msg != WINE_WM_HEADER)
-            {
-                FIXME("shouldn't have headers left\n");
-                SetEvent(ev);
-                continue;
-            }
-            ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
-            ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
-
-            wodNotifyClient(wwo, WOM_DONE, param, 0);
-        }
-        ALSA_ResetRingMessage(&wwo->msgRing);
-        LeaveCriticalSection(&wwo->msgRing.msg_crst);
-    } else {
-        if (wwo->lpLoopPtr) {
-            /* complicated case, not handled yet (could imply modifying the loop counter */
-            FIXME("Pausing while in loop isn't correctly handled yet, expect strange results\n");
-            wwo->lpPlayPtr = wwo->lpLoopPtr;
-            wwo->dwPartialOffset = 0;
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
-        } else {
-            LPWAVEHDR   ptr;
-            DWORD       sz = wwo->dwPartialOffset;
-
-            /* reset all the data as if we had written only up to lpPlayedTotal bytes */
-            /* compute the max size playable from lpQueuePtr */
-            for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext) {
-                sz += ptr->dwBufferLength;
-            }
-            /* because the reset lpPlayPtr will be lpQueuePtr */
-            if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("grin\n");
-            wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal;
-            wwo->lpPlayPtr = wwo->lpQueuePtr;
-        }
-        wwo->state = WINE_WS_PAUSED;
-    }
-}
-
-/**************************************************************************
- * 		      wodPlayer_ProcessMessages			[internal]
- */
-static void wodPlayer_ProcessMessages(WINE_WAVEDEV* wwo)
-{
-    LPWAVEHDR           lpWaveHdr;
-    enum win_wm_message	msg;
-    DWORD_PTR		param;
-    HANDLE		ev;
-    int                 err;
-
-    while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev)) {
-     TRACE("Received %s %lx\n", ALSA_getCmdString(msg), param);
-
-	switch (msg) {
-	case WINE_WM_PAUSING:
-	    if ( snd_pcm_state(wwo->pcm) == SND_PCM_STATE_RUNNING )
-	     {
-                if ( snd_pcm_hw_params_can_pause(wwo->hw_params) )
-		{
-		    err = snd_pcm_pause(wwo->pcm, 1);
-		    if ( err < 0 )
-			ERR("pcm_pause failed: %s\n", snd_strerror(err));
-		    wwo->state = WINE_WS_PAUSED;
-		}
-		else
-		{
-		    wodPlayer_Reset(wwo,FALSE);
-		}
-	     }
-	    SetEvent(ev);
-	    break;
-	case WINE_WM_RESTARTING:
-            if (wwo->state == WINE_WS_PAUSED)
-            {
-		if ( snd_pcm_state(wwo->pcm) == SND_PCM_STATE_PAUSED )
-		 {
-		    err = snd_pcm_pause(wwo->pcm, 0);
-		    if ( err < 0 )
-		        ERR("pcm_pause failed: %s\n", snd_strerror(err));
-		 }
-                wwo->state = WINE_WS_PLAYING;
-            }
-	    SetEvent(ev);
-	    break;
-	case WINE_WM_HEADER:
-	    lpWaveHdr = (LPWAVEHDR)param;
-
-	    /* insert buffer at the end of queue */
-	    {
-		LPWAVEHDR*	wh;
-		for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-		*wh = lpWaveHdr;
-	    }
-            if (!wwo->lpPlayPtr)
-                wodPlayer_BeginWaveHdr(wwo,lpWaveHdr);
-	    if (wwo->state == WINE_WS_STOPPED)
-		wwo->state = WINE_WS_PLAYING;
-	    break;
-	case WINE_WM_RESETTING:
-	    wodPlayer_Reset(wwo,TRUE);
-	    SetEvent(ev);
-	    break;
-        case WINE_WM_BREAKLOOP:
-            if (wwo->state == WINE_WS_PLAYING && wwo->lpLoopPtr != NULL) {
-                /* ensure exit at end of current loop */
-                wwo->dwLoops = 1;
-            }
-	    SetEvent(ev);
-            break;
-	case WINE_WM_CLOSING:
-	    /* sanity check: this should not happen since the device must have been reset before */
-	    if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
-	    wwo->hThread = 0;
-	    wwo->state = WINE_WS_CLOSED;
-	    SetEvent(ev);
-	    ExitThread(0);
-	    /* shouldn't go here */
-	default:
-	    FIXME("unknown message %d\n", msg);
-	    break;
-	}
-    }
-}
-
-/**************************************************************************
- * 			     wodPlayer_FeedDSP			[internal]
- * Feed as much sound data as we can into the DSP and return the number of
- * milliseconds before it will be necessary to feed the DSP again.
- */
-static DWORD wodPlayer_FeedDSP(WINE_WAVEDEV* wwo)
-{
-    DWORD               availInQ;
-
-    wodUpdatePlayedTotal(wwo, NULL);
-    availInQ = snd_pcm_avail_update(wwo->pcm);
-
-    /* no more room... no need to try to feed */
-    if (availInQ > 0) {
-        /* Feed from partial wavehdr */
-        if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) {
-            wodPlayer_WriteMaxFrags(wwo, &availInQ);
-        }
-
-        /* Feed wavehdrs until we run out of wavehdrs or DSP space */
-        if (wwo->dwPartialOffset == 0 && wwo->lpPlayPtr) {
-            do {
-                TRACE("Setting time to elapse for %p to %u\n",
-                      wwo->lpPlayPtr, wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength);
-                /* note the value that dwPlayedTotal will return when this wave finishes playing */
-                wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength;
-            } while (wodPlayer_WriteMaxFrags(wwo, &availInQ) && wwo->lpPlayPtr && availInQ > 0);
-        }
-    }
-
-    return wodPlayer_DSPWait(wwo);
-}
-
-/**************************************************************************
- * 				wodPlayer			[internal]
- */
-static	DWORD	CALLBACK	wodPlayer(LPVOID pmt)
-{
-    WORD	  uDevID = (DWORD_PTR)pmt;
-    WINE_WAVEDEV* wwo = &WOutDev[uDevID];
-    DWORD         dwNextFeedTime = INFINITE;   /* Time before DSP needs feeding */
-    DWORD         dwNextNotifyTime = INFINITE; /* Time before next wave completion */
-    DWORD         dwSleepTime;
-
-    wwo->state = WINE_WS_STOPPED;
-    SetEvent(wwo->hStartUpEvent);
-
-    for (;;) {
-        /** Wait for the shortest time before an action is required.  If there
-         *  are no pending actions, wait forever for a command.
-         */
-        dwSleepTime = min(dwNextFeedTime, dwNextNotifyTime);
-        TRACE("waiting %ums (%u,%u)\n", dwSleepTime, dwNextFeedTime, dwNextNotifyTime);
-        ALSA_WaitRingMessage(&wwo->msgRing, dwSleepTime);
-	wodPlayer_ProcessMessages(wwo);
-	if (wwo->state == WINE_WS_PLAYING) {
-	    dwNextFeedTime = wodPlayer_FeedDSP(wwo);
-	    dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE);
-	    if (dwNextFeedTime == INFINITE) {
-		/* FeedDSP ran out of data, but before giving up, */
-		/* check that a notification didn't give us more */
-		wodPlayer_ProcessMessages(wwo);
-		if (wwo->lpPlayPtr) {
-		    TRACE("recovering\n");
-		    dwNextFeedTime = wodPlayer_FeedDSP(wwo);
-		}
-	    }
-	} else {
-	    dwNextFeedTime = dwNextNotifyTime = INFINITE;
-	}
-    }
-    return 0;
-}
-
-/**************************************************************************
- * 			wodGetDevCaps				[internal]
- */
-static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
-{
-    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    memcpy(lpCaps, &WOutDev[wDevID].outcaps, min(dwSize, sizeof(*lpCaps)));
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodOpen				[internal]
- */
-static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
-{
-    WINE_WAVEDEV*	        wwo;
-    snd_pcm_t *                 pcm = NULL;
-    snd_hctl_t *                hctl = NULL;
-    snd_pcm_hw_params_t *       hw_params;
-    snd_pcm_sw_params_t *       sw_params;
-    snd_pcm_access_t            access;
-    snd_pcm_format_t            format = -1;
-    unsigned int                rate;
-    unsigned int                buffer_time = 120000;
-    unsigned int                period_time = 22000;
-    snd_pcm_uframes_t           buffer_size;
-    snd_pcm_uframes_t           period_size;
-    int                         flags;
-    int                         err=0;
-    int                         dir=0;
-    DWORD                       retcode = 0;
-
-    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
-    if (lpDesc == NULL) {
-	WARN("Invalid Parameter !\n");
-	return MMSYSERR_INVALPARAM;
-    }
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    /* only PCM format is supported so far... */
-    if (!ALSA_supportedFormat(lpDesc->lpFormat)) {
-	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return WAVERR_BADFORMAT;
-    }
-
-    if (dwFlags & WAVE_FORMAT_QUERY) {
-	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return MMSYSERR_NOERROR;
-    }
-
-    wwo = &WOutDev[wDevID];
-
-    if (wwo->pcm != NULL) {
-        WARN("%d already allocated\n", wDevID);
-        return MMSYSERR_ALLOCATED;
-    }
-
-    if (dwFlags & WAVE_DIRECTSOUND)
-        FIXME("Why are we called with DirectSound flag? It doesn't use MMSYSTEM any more\n");
-        /* not supported, ignore it */
-    dwFlags &= ~WAVE_DIRECTSOUND;
-
-    flags = SND_PCM_NONBLOCK;
-
-    if ( (err = snd_pcm_open(&pcm, wwo->pcmname, SND_PCM_STREAM_PLAYBACK, flags)) < 0)
-    {
-        ERR("Error open: %s\n", snd_strerror(err));
-	return MMSYSERR_NOTENABLED;
-    }
-
-    if (wwo->ctlname)
-    {
-        err = snd_hctl_open(&hctl, wwo->ctlname, 0);
-        if (err >= 0)
-        {
-            snd_hctl_load(hctl);
-        }
-        else
-        {
-            WARN("Could not open hctl for [%s]: %s\n", wwo->ctlname, snd_strerror(err));
-            hctl = NULL;
-        }
-    }
-
-    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-
-    wwo->waveDesc = *lpDesc;
-    ALSA_copyFormat(lpDesc->lpFormat, &wwo->format);
-
-    TRACE("Requested this format: %dx%dx%d %s\n",
-          wwo->format.Format.nSamplesPerSec,
-          wwo->format.Format.wBitsPerSample,
-          wwo->format.Format.nChannels,
-          ALSA_getFormat(wwo->format.Format.wFormatTag));
-
-    if (wwo->format.Format.wBitsPerSample == 0) {
-	WARN("Resetting zeroed wBitsPerSample\n");
-	wwo->format.Format.wBitsPerSample = 8 *
-	    (wwo->format.Format.nAvgBytesPerSec /
-	     wwo->format.Format.nSamplesPerSec) /
-	    wwo->format.Format.nChannels;
-    }
-
-#define EXIT_ON_ERROR(f,e,txt) do \
-{ \
-    int err; \
-    if ( (err = (f) ) < 0) \
-    { \
-	WARN(txt ": %s\n", snd_strerror(err)); \
-	retcode=e; \
-	goto errexit; \
-    } \
-} while(0)
-
-    sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() );
-    hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() );
-    if (!hw_params || !sw_params)
-    {
-        retcode = MMSYSERR_NOMEM;
-        goto errexit;
-    }
-    snd_pcm_hw_params_any(pcm, hw_params);
-
-    access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-    if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) {
-        WARN("mmap not available. switching to standard write.\n");
-        access = SND_PCM_ACCESS_RW_INTERLEAVED;
-	EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback");
-	wwo->write = snd_pcm_writei;
-    }
-    else
-	wwo->write = snd_pcm_mmap_writei;
-
-    if ((err = snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels)) < 0) {
-        WARN("unable to set required channels: %d\n", wwo->format.Format.nChannels);
-        EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels ), WAVERR_BADFORMAT, "unable to set required channels" );
-    }
-
-    if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
-        ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
-        IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) {
-        format = (wwo->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 :
-                 (wwo->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE :
-                 (wwo->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE :
-                 (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1;
-    } else if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
-        IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){
-        format = (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1;
-    } else {
-        ERR("invalid format: %0x04x\n", wwo->format.Format.wFormatTag);
-        retcode = WAVERR_BADFORMAT;
-        goto errexit;
-    }
-
-    if ((err = snd_pcm_hw_params_set_format(pcm, hw_params, format)) < 0) {
-        WARN("unable to set required format: %s\n", snd_pcm_format_name(format));
-        EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format" );
-    }
-
-    rate = wwo->format.Format.nSamplesPerSec;
-    dir=0;
-    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir);
-    if (err < 0) {
-	WARN("Rate %d Hz not available for playback: %s\n", wwo->format.Format.nSamplesPerSec, snd_strerror(rate));
-        retcode = WAVERR_BADFORMAT;
-        goto errexit;
-    }
-    if (!ALSA_NearMatch(rate, wwo->format.Format.nSamplesPerSec)) {
-        WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate);
-        retcode = WAVERR_BADFORMAT;
-        goto errexit;
-    }
-
-    TRACE("Got this format: %dx%dx%d %s\n",
-          wwo->format.Format.nSamplesPerSec,
-          wwo->format.Format.wBitsPerSample,
-          wwo->format.Format.nChannels,
-          ALSA_getFormat(wwo->format.Format.wFormatTag));
-
-    dir=0;
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time");
-    dir=0;
-    EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time");
-
-    EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback");
-
-    err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
-    err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
-
-    snd_pcm_sw_params_current(pcm, sw_params);
-
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min");
-    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold");
-    EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
-#undef EXIT_ON_ERROR
-
-    snd_pcm_prepare(pcm);
-
-    if (TRACE_ON(wave))
-	ALSA_TraceParameters(hw_params, sw_params, FALSE);
-
-    /* now, we can save all required data for later use... */
-
-    wwo->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size);
-    wwo->lpQueuePtr = wwo->lpPlayPtr = wwo->lpLoopPtr = NULL;
-    wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
-    wwo->dwPartialOffset = 0;
-
-    ALSA_InitRingMessage(&wwo->msgRing);
-
-    wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwo->dwThreadID));
-    if (!wwo->hThread) {
-        ERR("Thread creation for the wodPlayer failed!\n");
-        CloseHandle(wwo->hStartUpEvent);
-        retcode = MMSYSERR_NOMEM;
-        goto errexit;
-    }
-    SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL);
-    WaitForSingleObject(wwo->hStartUpEvent, INFINITE);
-    CloseHandle(wwo->hStartUpEvent);
-    wwo->hStartUpEvent = NULL;
-
-    TRACE("handle=%p\n", pcm);
-    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
-	  wwo->format.Format.wBitsPerSample, wwo->format.Format.nAvgBytesPerSec,
-	  wwo->format.Format.nSamplesPerSec, wwo->format.Format.nChannels,
-	  wwo->format.Format.nBlockAlign);
-
-    HeapFree( GetProcessHeap(), 0, sw_params );
-    wwo->hw_params = hw_params;
-    wwo->hctl = hctl;
-    wwo->pcm = pcm;
-
-    wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
-    return MMSYSERR_NOERROR;
-
-errexit:
-    if (pcm)
-        snd_pcm_close(pcm);
-
-    if (hctl)
-    {
-        snd_hctl_free(hctl);
-        snd_hctl_close(hctl);
-    }
-
-    HeapFree( GetProcessHeap(), 0, hw_params );
-    HeapFree( GetProcessHeap(), 0, sw_params );
-    if (wwo->msgRing.ring_buffer_size > 0)
-        ALSA_DestroyRingMessage(&wwo->msgRing);
-
-    return retcode;
-}
-
-
-/**************************************************************************
- * 				wodClose			[internal]
- */
-static DWORD wodClose(WORD wDevID)
-{
-    WINE_WAVEDEV*	wwo;
-
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    wwo = &WOutDev[wDevID];
-    if (wwo->pcm == NULL) {
-	WARN("Requested to close already closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (wwo->lpQueuePtr) {
-	WARN("buffers still playing !\n");
-	return WAVERR_STILLPLAYING;
-    } else {
-	if (wwo->hThread) {
-	    ALSA_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE);
-	}
-        ALSA_DestroyRingMessage(&wwo->msgRing);
-
-	HeapFree( GetProcessHeap(), 0, wwo->hw_params );
-	wwo->hw_params = NULL;
-
-        if (wwo->hctl)
-        {
-            snd_hctl_free(wwo->hctl);
-            snd_hctl_close(wwo->hctl);
-            wwo->hctl = NULL;
-        }
-
-	snd_pcm_close(wwo->pcm);
-	wwo->pcm = NULL;
-
-	wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-
-/**************************************************************************
- * 				wodWrite			[internal]
- *
- */
-static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to write to closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
-	return WAVERR_UNPREPARED;
-
-    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
-	return WAVERR_STILLPLAYING;
-
-    lpWaveHdr->dwFlags &= ~WHDR_DONE;
-    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
-    lpWaveHdr->lpNext = 0;
-
-    ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD_PTR)lpWaveHdr, FALSE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodPause				[internal]
- */
-static DWORD wodPause(WORD wDevID)
-{
-    TRACE("(%u);!\n", wDevID);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to pause closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodRestart				[internal]
- */
-static DWORD wodRestart(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to restart closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].state == WINE_WS_PAUSED) {
-	ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE);
-    }
-
-    /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
-    /* FIXME: Myst crashes with this ... hmm -MM
-       return wodNotifyClient(wwo, WOM_DONE, 0L, 0L);
-    */
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodReset				[internal]
- */
-static DWORD wodReset(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to reset closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodGetPosition			[internal]
- */
-static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
-{
-    WINE_WAVEDEV*	wwo;
-
-    TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to get position of closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpTime == NULL)	return MMSYSERR_INVALPARAM;
-
-    wwo = &WOutDev[wDevID];
-    return ALSA_bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
-}
-
-/**************************************************************************
- * 				wodBreakLoop			[internal]
- */
-static DWORD wodBreakLoop(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].pcm == NULL) {
-	WARN("Requested to breakloop of closed device %d!\n", wDevID);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodGetVolume			[internal]
- */
-static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
-{
-    WORD	       wleft, wright;
-    WINE_WAVEDEV*      wwo;
-    int                min, max;
-    int                left, right;
-    DWORD              rc;
-
-    TRACE("(%u, %p);\n", wDevID, lpdwVol);
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpdwVol == NULL)
-	return MMSYSERR_NOTENABLED;
-
-    wwo = &WOutDev[wDevID];
-
-    rc = ALSA_CheckSetVolume(wwo->hctl, &left, &right, &min, &max, NULL, NULL, NULL);
-    if (rc == MMSYSERR_NOERROR)
-    {
-#define VOLUME_ALSA_TO_WIN(x) (  ( (((x)-min) * 65535) + (max-min)/2 ) /(max-min))
-        wleft = VOLUME_ALSA_TO_WIN(left);
-        wright = VOLUME_ALSA_TO_WIN(right);
-#undef VOLUME_ALSA_TO_WIN
-        TRACE("left=%d,right=%d,converted to windows left %d, right %d\n", left, right, wleft, wright);
-        *lpdwVol = MAKELONG( wleft, wright );
-    }
-    else
-        TRACE("CheckSetVolume failed; rc %d\n", rc);
-
-    return rc;
-}
-
-/**************************************************************************
- * 				wodSetVolume			[internal]
- */
-static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
-{
-    WORD	       wleft, wright;
-    WINE_WAVEDEV*      wwo;
-    int                min, max;
-    int                left, right;
-    DWORD              rc;
-
-    TRACE("(%u, %08X);\n", wDevID, dwParam);
-    if (wDevID >= ALSA_WodNumDevs) {
-	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    wwo = &WOutDev[wDevID];
-
-    rc = ALSA_CheckSetVolume(wwo->hctl, NULL, NULL, &min, &max, NULL, NULL, NULL);
-    if (rc == MMSYSERR_NOERROR)
-    {
-        wleft  = LOWORD(dwParam);
-        wright = HIWORD(dwParam);
-#define VOLUME_WIN_TO_ALSA(x) ( (  ( ((x) * (max-min)) + 32767) / 65535) + min )
-        left = VOLUME_WIN_TO_ALSA(wleft);
-        right = VOLUME_WIN_TO_ALSA(wright);
-#undef VOLUME_WIN_TO_ALSA
-        rc = ALSA_CheckSetVolume(wwo->hctl, NULL, NULL, NULL, NULL, NULL, &left, &right);
-        if (rc == MMSYSERR_NOERROR)
-            TRACE("set volume:  wleft=%d, wright=%d, converted to alsa left %d, right %d\n", wleft, wright, left, right);
-        else
-            TRACE("SetVolume failed; rc %d\n", rc);
-    }
-
-    return rc;
-}
-
-/**************************************************************************
- * 				wodGetNumDevs			[internal]
- */
-static	DWORD	wodGetNumDevs(void)
-{
-    return ALSA_WodNumDevs;
-}
-
-/**************************************************************************
- * 				wodDevInterfaceSize		[internal]
- */
-static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
-{
-    TRACE("(%u, %p)\n", wDevID, dwParam1);
-
-    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].interface_name, -1,
-                                    NULL, 0 ) * sizeof(WCHAR);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodDevInterface			[internal]
- */
-static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
-{
-    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].interface_name, -1,
-                                        NULL, 0 ) * sizeof(WCHAR))
-    {
-        MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].interface_name, -1,
-                            dwParam1, dwParam2 / sizeof(WCHAR));
-	return MMSYSERR_NOERROR;
-    }
-    return MMSYSERR_INVALPARAM;
-}
-
-/**************************************************************************
- * 				wodMessage (WINEALSA.@)
- */
-DWORD WINAPI ALSA_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
-                             DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("(%u, %s, %08lX, %08lX, %08lX);\n",
-	  wDevID, ALSA_getMessage(wMsg), dwUser, dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case DRVM_INIT:
-        ALSA_WaveInit();
-    case DRVM_EXIT:
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
-    case WODM_OPEN:	 	return wodOpen		(wDevID, (LPWAVEOPENDESC)dwParam1,	dwParam2);
-    case WODM_CLOSE:	 	return wodClose		(wDevID);
-    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (LPWAVEOUTCAPSW)dwParam1,	dwParam2);
-    case WODM_GETNUMDEVS:	return wodGetNumDevs	();
-    case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
-    case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
-    case WODM_WRITE:	 	return wodWrite		(wDevID, (LPWAVEHDR)dwParam1,		dwParam2);
-    case WODM_PAUSE:	 	return wodPause		(wDevID);
-    case WODM_GETPOS:	 	return wodGetPosition	(wDevID, (LPMMTIME)dwParam1, 		dwParam2);
-    case WODM_BREAKLOOP: 	return wodBreakLoop     (wDevID);
-    case WODM_PREPARE:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_UNPREPARE: 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (LPDWORD)dwParam1);
-    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, dwParam1);
-    case WODM_RESTART:		return wodRestart	(wDevID);
-    case WODM_RESET:		return wodReset		(wDevID);
-    case DRV_QUERYDEVICEINTERFACESIZE: return wodDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
-    case DRV_QUERYDEVICEINTERFACE:     return wodDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
-    case DRV_QUERYDSOUNDIFACE:	return wodDsCreate	(wDevID, (PIDSDRIVER*)dwParam1);
-    case DRV_QUERYDSOUNDDESC:	return wodDsDesc	(wDevID, (PDSDRIVERDESC)dwParam1);
-
-    default:
-	FIXME("unknown message %d!\n", wMsg);
-    }
-    return MMSYSERR_NOTSUPPORTED;
-}
diff --git a/dlls/winealsa.drv/winealsa.drv.spec b/dlls/winealsa.drv/winealsa.drv.spec
index c87ec17..cf3053b 100644
--- a/dlls/winealsa.drv/winealsa.drv.spec
+++ b/dlls/winealsa.drv/winealsa.drv.spec
@@ -2,9 +2,6 @@
 @ stdcall -private DriverProc(long long long long long) ALSA_DriverProc
 @ stdcall -private midMessage(long long long long long) ALSA_midMessage
 @ stdcall -private modMessage(long long long long long) ALSA_modMessage
-@ stdcall -private mxdMessage(long long long long long) ALSA_mxdMessage
-@ stdcall -private widMessage(long long long long long) ALSA_widMessage
-@ stdcall -private wodMessage(long long long long long) ALSA_wodMessage
 
 # MMDevAPI driver functions
 @ stdcall -private GetPriority() AUDDRV_GetPriority

From: Andrew Eikum <aeikum at codeweavers.com>
Subject: [PATCH 2/9] wineoss.drv: Remove wave, mixer, and dsound driver code
Message-Id: <20110923200359.GD6146 at foghorn.codeweavers.com>
Date: Fri, 23 Sep 2011 15:03:59 -0500

---
 dlls/wineoss.drv/Makefile.in      |    6 +-
 dlls/wineoss.drv/audio.c          | 3189 -------------------------------------
 dlls/wineoss.drv/audio.h          |  183 ---
 dlls/wineoss.drv/dscapture.c      | 1330 ----------------
 dlls/wineoss.drv/dsrender.c       |  966 -----------
 dlls/wineoss.drv/midi.c           |   27 +-
 dlls/wineoss.drv/mixer.c          | 1553 ------------------
 dlls/wineoss.drv/mmdevdrv.c       |    2 +-
 dlls/wineoss.drv/wineoss.drv.spec |    3 -
 9 files changed, 28 insertions(+), 7231 deletions(-)
 delete mode 100644 dlls/wineoss.drv/audio.c
 delete mode 100644 dlls/wineoss.drv/audio.h
 delete mode 100644 dlls/wineoss.drv/dscapture.c
 delete mode 100644 dlls/wineoss.drv/dsrender.c
 delete mode 100644 dlls/wineoss.drv/mixer.c

diff --git a/dlls/wineoss.drv/Makefile.in b/dlls/wineoss.drv/Makefile.in
index 3696a7a..61b466b 100644
--- a/dlls/wineoss.drv/Makefile.in
+++ b/dlls/wineoss.drv/Makefile.in
@@ -1,14 +1,10 @@
 MODULE    = wineoss.drv
-IMPORTS   = dxguid uuid winmm ole32 user32
+IMPORTS   = uuid winmm ole32 user32
 EXTRAINCL = @OSS4INCL@
 
 C_SRCS = \
-	audio.c \
-	dscapture.c \
-	dsrender.c \
 	midi.c \
 	midipatch.c \
-	mixer.c \
 	mmaux.c \
 	mmdevdrv.c
 
diff --git a/dlls/wineoss.drv/audio.c b/dlls/wineoss.drv/audio.c
deleted file mode 100644
index fcf5923..0000000
--- a/dlls/wineoss.drv/audio.c
+++ /dev/null
@@ -1,3189 +0,0 @@
-/*
- * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
- *
- * Copyright 1994 Martin Ayotte
- *           1999 Eric Pouech (async playing in waveOut/waveIn)
- *	     2000 Eric Pouech (loops in waveOut)
- *           2002 Eric Pouech (full duplex)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-/*
- * FIXME:
- *	pause in waveOut does not work correctly in loop mode
- *	Direct Sound Capture driver does not work (not complete yet)
- */
-
-/* an exact wodGetPosition is usually not worth the extra context switches,
- * as we're going to have near fragment accuracy anyway */
-#define EXACT_WODPOSITION
-#define EXACT_WIDPOSITION
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <sys/soundcard.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "winerror.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "ks.h"
-#include "wine/debug.h"
-
-#include "initguid.h"
-#include "ksmedia.h"
-#include "dsdriver.h"
-
-#include "audio.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wave);
-
-/* Allow 1% deviation for sample rates (some ES137x cards) */
-#define NEAR_MATCH(rate1,rate2) (((100*((int)(rate1)-(int)(rate2)))/(rate1))==0)
-
-WINE_WAVEOUT    WOutDev[MAX_WAVEDRV];
-WINE_WAVEIN     WInDev[MAX_WAVEDRV];
-unsigned        numOutDev;
-unsigned        numInDev;
-
-/* state diagram for waveOut writing:
- *
- * +---------+-------------+---------------+---------------------------------+
- * |  state  |  function   |     event     |            new state	     |
- * +---------+-------------+---------------+---------------------------------+
- * |	     | open()	   |		   | STOPPED		       	     |
- * | PAUSED  | write()	   | 		   | PAUSED		       	     |
- * | STOPPED | write()	   | <thrd create> | PLAYING		  	     |
- * | PLAYING | write()	   | HEADER        | PLAYING		  	     |
- * | (other) | write()	   | <error>       |		       		     |
- * | (any)   | pause()	   | PAUSING	   | PAUSED		       	     |
- * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
- * | (any)   | reset()	   | RESETTING     | STOPPED		      	     |
- * | (any)   | close()	   | CLOSING	   | CLOSED		      	     |
- * +---------+-------------+---------------+---------------------------------+
- */
-
-/* These strings used only for tracing */
-static const char * getCmdString(enum win_wm_message msg)
-{
-#define MSG_TO_STR(x) case x: return #x
-    switch(msg) {
-    MSG_TO_STR(WINE_WM_PAUSING);
-    MSG_TO_STR(WINE_WM_RESTARTING);
-    MSG_TO_STR(WINE_WM_RESETTING);
-    MSG_TO_STR(WINE_WM_HEADER);
-    MSG_TO_STR(WINE_WM_UPDATE);
-    MSG_TO_STR(WINE_WM_BREAKLOOP);
-    MSG_TO_STR(WINE_WM_CLOSING);
-    MSG_TO_STR(WINE_WM_STARTING);
-    MSG_TO_STR(WINE_WM_STOPPING);
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(0x%08x)", msg);
-}
-
-int getEnables(OSS_DEVICE *ossdev)
-{
-    return ( (ossdev->bOutputEnabled ? PCM_ENABLE_OUTPUT : 0) |
-             (ossdev->bInputEnabled  ? PCM_ENABLE_INPUT  : 0) );
-}
-
-static const char * getMessage(UINT msg)
-{
-#define MSG_TO_STR(x) case x: return #x
-    switch(msg) {
-    MSG_TO_STR(DRVM_INIT);
-    MSG_TO_STR(DRVM_EXIT);
-    MSG_TO_STR(DRVM_ENABLE);
-    MSG_TO_STR(DRVM_DISABLE);
-    MSG_TO_STR(WIDM_OPEN);
-    MSG_TO_STR(WIDM_CLOSE);
-    MSG_TO_STR(WIDM_ADDBUFFER);
-    MSG_TO_STR(WIDM_PREPARE);
-    MSG_TO_STR(WIDM_UNPREPARE);
-    MSG_TO_STR(WIDM_GETDEVCAPS);
-    MSG_TO_STR(WIDM_GETNUMDEVS);
-    MSG_TO_STR(WIDM_GETPOS);
-    MSG_TO_STR(WIDM_RESET);
-    MSG_TO_STR(WIDM_START);
-    MSG_TO_STR(WIDM_STOP);
-    MSG_TO_STR(WODM_OPEN);
-    MSG_TO_STR(WODM_CLOSE);
-    MSG_TO_STR(WODM_WRITE);
-    MSG_TO_STR(WODM_PAUSE);
-    MSG_TO_STR(WODM_GETPOS);
-    MSG_TO_STR(WODM_BREAKLOOP);
-    MSG_TO_STR(WODM_PREPARE);
-    MSG_TO_STR(WODM_UNPREPARE);
-    MSG_TO_STR(WODM_GETDEVCAPS);
-    MSG_TO_STR(WODM_GETNUMDEVS);
-    MSG_TO_STR(WODM_GETPITCH);
-    MSG_TO_STR(WODM_SETPITCH);
-    MSG_TO_STR(WODM_GETPLAYBACKRATE);
-    MSG_TO_STR(WODM_SETPLAYBACKRATE);
-    MSG_TO_STR(WODM_GETVOLUME);
-    MSG_TO_STR(WODM_SETVOLUME);
-    MSG_TO_STR(WODM_RESTART);
-    MSG_TO_STR(WODM_RESET);
-    MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
-    MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
-    MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
-    MSG_TO_STR(DRV_QUERYDSOUNDDESC);
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(0x%04x)", msg);
-}
-
-static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
-{
-    TRACE("(%u, %p)\n", wDevID, dwParam1);
-
-    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
-                                    NULL, 0 ) * sizeof(WCHAR);
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
-{
-    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
-                                        NULL, 0 ) * sizeof(WCHAR))
-    {
-        MultiByteToWideChar(CP_UNIXCP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
-                            dwParam1, dwParam2 / sizeof(WCHAR));
-	return MMSYSERR_NOERROR;
-    }
-
-    return MMSYSERR_INVALPARAM;
-}
-
-static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
-{
-    TRACE("(%u, %p)\n", wDevID, dwParam1);
-
-    *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].ossdev.interface_name, -1,
-                                    NULL, 0 ) * sizeof(WCHAR);
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
-{
-    if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].ossdev.interface_name, -1,
-                                        NULL, 0 ) * sizeof(WCHAR))
-    {
-        MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].ossdev.interface_name, -1,
-                            dwParam1, dwParam2 / sizeof(WCHAR));
-	return MMSYSERR_NOERROR;
-    }
-
-    return MMSYSERR_INVALPARAM;
-}
-
-static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
-                             WAVEFORMATPCMEX* format)
-{
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
-          lpTime->wType, format->Format.wBitsPerSample, format->Format.nSamplesPerSec,
-          format->Format.nChannels, format->Format.nAvgBytesPerSec);
-    TRACE("Position in bytes=%u\n", position);
-
-    switch (lpTime->wType) {
-    case TIME_SAMPLES:
-        lpTime->u.sample = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
-        TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
-        break;
-    case TIME_MS:
-        lpTime->u.ms = 1000.0 * position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels * format->Format.nSamplesPerSec);
-        TRACE("TIME_MS=%u\n", lpTime->u.ms);
-        break;
-    case TIME_SMPTE:
-        lpTime->u.smpte.fps = 30;
-        position = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
-        position += (format->Format.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
-        lpTime->u.smpte.sec = position / format->Format.nSamplesPerSec;
-        position -= lpTime->u.smpte.sec * format->Format.nSamplesPerSec;
-        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
-        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
-        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
-        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
-        lpTime->u.smpte.fps = 30;
-        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->Format.nSamplesPerSec;
-        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-              lpTime->u.smpte.hour, lpTime->u.smpte.min,
-              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-        break;
-    default:
-        WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
-        lpTime->wType = TIME_BYTES;
-        /* fall through */
-    case TIME_BYTES:
-        lpTime->u.cb = position;
-        TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
-        break;
-    }
-    return MMSYSERR_NOERROR;
-}
-
-static BOOL supportedFormat(LPWAVEFORMATEX wf)
-{
-    TRACE("(%p)\n",wf);
-
-    if (wf->nSamplesPerSec<DSBFREQUENCY_MIN||wf->nSamplesPerSec>DSBFREQUENCY_MAX)
-        return FALSE;
-
-    if (wf->wFormatTag == WAVE_FORMAT_PCM) {
-        if (wf->nChannels >= 1 && wf->nChannels <= MAX_CHANNELS) {
-            if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
-                return TRUE;
-        }
-    } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
-        WAVEFORMATEXTENSIBLE * wfex = (WAVEFORMATEXTENSIBLE *)wf;
-
-        if (wf->cbSize == 22 && IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
-            if (wf->nChannels >=1 && wf->nChannels <= MAX_CHANNELS) {
-                if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
-                    if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
-                        return TRUE;
-                } else
-                    WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
-            }
-        } else
-            WARN("only KSDATAFORMAT_SUBTYPE_PCM supported\n");
-    } else
-        WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
-
-    return FALSE;
-}
-
-void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
-{
-    ZeroMemory(wf2, sizeof(*wf2));
-    if (wf1->wFormatTag == WAVE_FORMAT_PCM)
-        memcpy(wf2, wf1, sizeof(PCMWAVEFORMAT));
-    else if (wf1->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-        memcpy(wf2, wf1, sizeof(WAVEFORMATPCMEX));
-    else
-        memcpy(wf2, wf1, sizeof(WAVEFORMATEX) + wf1->cbSize);
-}
-
-/*======================================================================*
- *                  Low level WAVE implementation			*
- *======================================================================*/
-
-/******************************************************************
- *		OSS_RawOpenDevice
- *
- * Low level device opening (from values stored in ossdev)
- */
-static DWORD      OSS_RawOpenDevice(OSS_DEVICE* ossdev, int strict_format)
-{
-    int fd, val, rc;
-    TRACE("(%p,%d)\n",ossdev,strict_format);
-
-    TRACE("open_access=%s\n",
-        ossdev->open_access == O_RDONLY ? "O_RDONLY" :
-        ossdev->open_access == O_WRONLY ? "O_WRONLY" :
-        ossdev->open_access == O_RDWR ? "O_RDWR" : "Unknown");
-
-    if ((fd = open(ossdev->dev_name, ossdev->open_access|O_NDELAY, 0)) == -1)
-    {
-        WARN("Couldn't open %s (%s)\n", ossdev->dev_name, strerror(errno));
-        return (errno == EBUSY) ? MMSYSERR_ALLOCATED : MMSYSERR_ERROR;
-    }
-    fcntl(fd, F_SETFD, 1); /* set close on exec flag */
-    /* turn full duplex on if it has been requested */
-    if (ossdev->open_access == O_RDWR && ossdev->full_duplex) {
-        rc = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
-        /* on *BSD, as full duplex is always enabled by default, this ioctl
-         * will fail with EINVAL
-         * so, we don't consider EINVAL an error here
-         */
-        if (rc != 0 && errno != EINVAL) {
-            WARN("ioctl(%s, SNDCTL_DSP_SETDUPLEX) failed (%s)\n", ossdev->dev_name, strerror(errno));
-            goto error2;
-	}
-    }
-
-    if (ossdev->audio_fragment) {
-        rc = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossdev->audio_fragment);
-        if (rc != 0) {
-	    ERR("ioctl(%s, SNDCTL_DSP_SETFRAGMENT) failed (%s)\n", ossdev->dev_name, strerror(errno));
-            goto error2;
-	}
-    }
-
-    /* First size and channels then samplerate */
-    if (ossdev->format>=0)
-    {
-        val = ossdev->format;
-        rc = ioctl(fd, SNDCTL_DSP_SETFMT, &ossdev->format);
-        if (rc != 0 || val != ossdev->format) {
-            TRACE("Can't set format to %d (returned %d)\n", val, ossdev->format);
-            if (strict_format)
-                goto error;
-        }
-    }
-    if (ossdev->channels>=0)
-    {
-        val = ossdev->channels;
-        rc = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossdev->channels);
-        if (rc != 0 || val != ossdev->channels) {
-            TRACE("Can't set channels to %u (returned %d)\n", val, ossdev->channels);
-            if (strict_format)
-                goto error;
-        }
-    }
-    if (ossdev->sample_rate>=0)
-    {
-        val = ossdev->sample_rate;
-        rc = ioctl(fd, SNDCTL_DSP_SPEED, &ossdev->sample_rate);
-        if (rc != 0 || !NEAR_MATCH(val, ossdev->sample_rate)) {
-            TRACE("Can't set sample_rate to %u (returned %d)\n", val, ossdev->sample_rate);
-            if (strict_format)
-                goto error;
-        }
-    }
-    ossdev->fd = fd;
-
-    ossdev->bOutputEnabled = TRUE;	/* OSS enables by default */
-    ossdev->bInputEnabled  = TRUE;	/* OSS enables by default */
-    if (ossdev->open_access == O_RDONLY)
-        ossdev->bOutputEnabled = FALSE;
-    if (ossdev->open_access == O_WRONLY)
-        ossdev->bInputEnabled = FALSE;
-
-    if (ossdev->bTriggerSupport) {
-	int trigger;
-        trigger = getEnables(ossdev);
-        /* If we do not have full duplex, but they opened RDWR 
-        ** (as you have to in order for an mmap to succeed)
-        ** then we start out with input off
-        */
-        if (ossdev->open_access == O_RDWR && !ossdev->full_duplex && 
-            ossdev->bInputEnabled && ossdev->bOutputEnabled) {
-    	    ossdev->bInputEnabled  = FALSE;
-            trigger &= ~PCM_ENABLE_INPUT;
-	    ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trigger);
-        }
-    }
-
-    return MMSYSERR_NOERROR;
-
-error:
-    close(fd);
-    return WAVERR_BADFORMAT;
-error2:
-    close(fd);
-    return MMSYSERR_ERROR;
-}
-
-/******************************************************************
- *		OSS_OpenDevice
- *
- * since OSS has poor capabilities in full duplex, we try here to let a program
- * open the device for both waveout and wavein streams...
- * this is hackish, but it's the way OSS interface is done...
- */
-DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
-                            int* frag, int strict_format,
-                            int sample_rate, int channels, int fmt)
-{
-    DWORD       ret;
-    DWORD open_access;
-    TRACE("(%p,%u,%p,%d,%d,%d,%x)\n",ossdev,req_access,frag,strict_format,sample_rate,channels,fmt);
-
-    if (ossdev->full_duplex && (req_access == O_RDONLY || req_access == O_WRONLY))
-    {
-        TRACE("Opening RDWR because full_duplex=%d and req_access=%d\n",
-              ossdev->full_duplex,req_access);
-        open_access = O_RDWR;
-    }
-    else
-    {
-        open_access=req_access;
-    }
-
-    /* FIXME: this should be protected, and it also contains a race with OSS_CloseDevice */
-    if (ossdev->open_count == 0)
-    {
-	if (access(ossdev->dev_name, 0) != 0) return MMSYSERR_NODRIVER;
-
-        ossdev->audio_fragment = (frag) ? *frag : 0;
-        ossdev->sample_rate = sample_rate;
-        ossdev->channels = channels;
-        ossdev->format = fmt;
-        ossdev->open_access = open_access;
-        ossdev->owner_tid = GetCurrentThreadId();
-
-        if ((ret = OSS_RawOpenDevice(ossdev,strict_format)) != MMSYSERR_NOERROR) return ret;
-        if (ossdev->full_duplex && ossdev->bTriggerSupport &&
-            (req_access == O_RDONLY || req_access == O_WRONLY))
-        {
-            int enable;
-            if (req_access == O_WRONLY)
-                ossdev->bInputEnabled=0;
-            else
-                ossdev->bOutputEnabled=0;
-            enable = getEnables(ossdev);
-            TRACE("Calling SNDCTL_DSP_SETTRIGGER with %x\n",enable);
-            if (ioctl(ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
-                ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER, %d) failed (%s)\n",ossdev->dev_name, enable, strerror(errno));
-        }
-    }
-    else
-    {
-        /* check we really open with the same parameters */
-        if (ossdev->open_access != open_access)
-        {
-            ERR("FullDuplex: Mismatch in access. Your sound device is not full duplex capable.\n");
-            return WAVERR_BADFORMAT;
-        }
-
-	/* check if the audio parameters are the same */
-        if (ossdev->sample_rate != sample_rate ||
-            ossdev->channels != channels ||
-            ossdev->format != fmt)
-        {
-	    /* This is not a fatal error because MSACM might do the remapping */
-            WARN("FullDuplex: mismatch in PCM parameters for input and output\n"
-                 "OSS doesn't allow us different parameters\n"
-                 "audio_frag(%x/%x) sample_rate(%d/%d) channels(%d/%d) fmt(%d/%d)\n",
-                 ossdev->audio_fragment, frag ? *frag : 0,
-                 ossdev->sample_rate, sample_rate,
-                 ossdev->channels, channels,
-                 ossdev->format, fmt);
-            return WAVERR_BADFORMAT;
-        }
-	/* check if the fragment sizes are the same */
-        if (ossdev->audio_fragment != (frag ? *frag : 0) )
-        {
-	    ERR("FullDuplex: Playback and Capture hardware acceleration levels are different.\n"
-	        "Please run winecfg, open \"Audio\" page and set\n"
-                "\"Hardware Acceleration\" to \"Emulation\".\n");
-	    return WAVERR_BADFORMAT;
-	}
-        if (GetCurrentThreadId() != ossdev->owner_tid)
-        {
-            WARN("Another thread is trying to access audio...\n");
-            return MMSYSERR_ERROR;
-        }
-        if (ossdev->full_duplex && ossdev->bTriggerSupport &&
-            (req_access == O_RDONLY || req_access == O_WRONLY))
-        {
-            int enable;
-            if (req_access == O_WRONLY)
-                ossdev->bOutputEnabled=1;
-            else
-                ossdev->bInputEnabled=1;
-            enable = getEnables(ossdev);
-            TRACE("Calling SNDCTL_DSP_SETTRIGGER with %x\n",enable);
-            if (ioctl(ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
-                ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER, %d) failed (%s)\n",ossdev->dev_name, enable, strerror(errno));
-        }
-    }
-
-    ossdev->open_count++;
-
-    return MMSYSERR_NOERROR;
-}
-
-/******************************************************************
- *		OSS_CloseDevice
- *
- *
- */
-void	OSS_CloseDevice(OSS_DEVICE* ossdev)
-{
-    TRACE("(%p)\n",ossdev);
-    if (ossdev->open_count>0) {
-        ossdev->open_count--;
-    } else {
-        WARN("OSS_CloseDevice called too many times\n");
-    }
-    if (ossdev->open_count == 0)
-    {
-        fcntl(ossdev->fd, F_SETFL, fcntl(ossdev->fd, F_GETFL) & ~O_NDELAY);
-        /* reset the device before we close it in case it is in a bad state */
-        ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
-        if (close(ossdev->fd) != 0) FIXME("Cannot close %d: %s\n", ossdev->fd, strerror(errno));
-    }
-}
-
-/******************************************************************
- *		OSS_ResetDevice
- *
- * Resets the device. OSS Commercial requires the device to be closed
- * after a SNDCTL_DSP_RESET ioctl call... this function implements
- * this behavior...
- * FIXME: This causes problems when doing full duplex so we really
- * only reset when not doing full duplex. We need to do this better
- * someday.
- */
-static DWORD     OSS_ResetDevice(OSS_DEVICE* ossdev)
-{
-    DWORD       ret = MMSYSERR_NOERROR;
-    int         old_fd = ossdev->fd;
-    TRACE("(%p)\n", ossdev);
-
-    if (ossdev->open_count == 1) {
-	if (ioctl(ossdev->fd, SNDCTL_DSP_RESET, NULL) == -1)
-	{
-	    perror("ioctl SNDCTL_DSP_RESET");
-            return -1;
-	}
-	close(ossdev->fd);
-	ret = OSS_RawOpenDevice(ossdev, 1);
-	TRACE("Changing fd from %d to %d\n", old_fd, ossdev->fd);
-    } else
-	WARN("Not resetting device because it is in full duplex mode!\n");
-
-    return ret;
-}
-
-static const int win_std_oss_fmts[2]={AFMT_U8,AFMT_S16_LE};
-static const int win_std_rates[5]={96000,48000,44100,22050,11025};
-static const int win_std_formats[2][2][5]=
-    {{{WAVE_FORMAT_96M08, WAVE_FORMAT_48M08, WAVE_FORMAT_4M08,
-       WAVE_FORMAT_2M08,  WAVE_FORMAT_1M08},
-      {WAVE_FORMAT_96S08, WAVE_FORMAT_48S08, WAVE_FORMAT_4S08,
-       WAVE_FORMAT_2S08,  WAVE_FORMAT_1S08}},
-     {{WAVE_FORMAT_96M16, WAVE_FORMAT_48M16, WAVE_FORMAT_4M16,
-       WAVE_FORMAT_2M16,  WAVE_FORMAT_1M16},
-      {WAVE_FORMAT_96S16, WAVE_FORMAT_48S16, WAVE_FORMAT_4S16,
-       WAVE_FORMAT_2S16,  WAVE_FORMAT_1S16}},
-    };
-
-static void OSS_Info(int fd)
-{
-    /* Note that this only reports the formats supported by the hardware.
-     * The driver may support other formats and do the conversions in
-     * software which is why we don't use this value
-     */
-    int oss_mask, oss_caps;
-    if (ioctl(fd, SNDCTL_DSP_GETFMTS, &oss_mask) >= 0) {
-        TRACE("Formats=%08x ( ", oss_mask);
-        if (oss_mask & AFMT_MU_LAW) TRACE("AFMT_MU_LAW ");
-        if (oss_mask & AFMT_A_LAW) TRACE("AFMT_A_LAW ");
-        if (oss_mask & AFMT_IMA_ADPCM) TRACE("AFMT_IMA_ADPCM ");
-        if (oss_mask & AFMT_U8) TRACE("AFMT_U8 ");
-        if (oss_mask & AFMT_S16_LE) TRACE("AFMT_S16_LE ");
-        if (oss_mask & AFMT_S16_BE) TRACE("AFMT_S16_BE ");
-        if (oss_mask & AFMT_S8) TRACE("AFMT_S8 ");
-        if (oss_mask & AFMT_U16_LE) TRACE("AFMT_U16_LE ");
-        if (oss_mask & AFMT_U16_BE) TRACE("AFMT_U16_BE ");
-        if (oss_mask & AFMT_MPEG) TRACE("AFMT_MPEG ");
-#ifdef AFMT_AC3
-        if (oss_mask & AFMT_AC3) TRACE("AFMT_AC3 ");
-#endif
-#ifdef AFMT_VORBIS
-        if (oss_mask & AFMT_VORBIS) TRACE("AFMT_VORBIS ");
-#endif
-#ifdef AFMT_S32_LE
-        if (oss_mask & AFMT_S32_LE) TRACE("AFMT_S32_LE ");
-#endif
-#ifdef AFMT_S32_BE
-        if (oss_mask & AFMT_S32_BE) TRACE("AFMT_S32_BE ");
-#endif
-#ifdef AFMT_FLOAT
-        if (oss_mask & AFMT_FLOAT) TRACE("AFMT_FLOAT ");
-#endif
-#ifdef AFMT_S24_LE
-        if (oss_mask & AFMT_S24_LE) TRACE("AFMT_S24_LE ");
-#endif
-#ifdef AFMT_S24_BE
-        if (oss_mask & AFMT_S24_BE) TRACE("AFMT_S24_BE ");
-#endif
-#ifdef AFMT_SPDIF_RAW
-        if (oss_mask & AFMT_SPDIF_RAW) TRACE("AFMT_SPDIF_RAW ");
-#endif
-        TRACE(")\n");
-    }
-    if (ioctl(fd, SNDCTL_DSP_GETCAPS, &oss_caps) >= 0) {
-        TRACE("Caps=%08x\n",oss_caps);
-        TRACE("\tRevision: %d\n", oss_caps&DSP_CAP_REVISION);
-        TRACE("\tDuplex: %s\n", oss_caps & DSP_CAP_DUPLEX ? "true" : "false");
-        TRACE("\tRealtime: %s\n", oss_caps & DSP_CAP_REALTIME ? "true" : "false");
-        TRACE("\tBatch: %s\n", oss_caps & DSP_CAP_BATCH ? "true" : "false");
-        TRACE("\tCoproc: %s\n", oss_caps & DSP_CAP_COPROC ? "true" : "false");
-        TRACE("\tTrigger: %s\n", oss_caps & DSP_CAP_TRIGGER ? "true" : "false");
-        TRACE("\tMmap: %s\n", oss_caps & DSP_CAP_MMAP ? "true" : "false");
-#ifdef DSP_CAP_MULTI
-        TRACE("\tMulti: %s\n", oss_caps & DSP_CAP_MULTI ? "true" : "false");
-#endif
-#ifdef DSP_CAP_BIND
-        TRACE("\tBind: %s\n", oss_caps & DSP_CAP_BIND ? "true" : "false");
-#endif
-#ifdef DSP_CAP_INPUT
-        TRACE("\tInput: %s\n", oss_caps & DSP_CAP_INPUT ? "true" : "false");
-#endif
-#ifdef DSP_CAP_OUTPUT
-        TRACE("\tOutput: %s\n", oss_caps & DSP_CAP_OUTPUT ? "true" : "false");
-#endif
-#ifdef DSP_CAP_VIRTUAL
-        TRACE("\tVirtual: %s\n", oss_caps & DSP_CAP_VIRTUAL ? "true" : "false");
-#endif
-#ifdef DSP_CAP_ANALOGOUT
-        TRACE("\tAnalog Out: %s\n", oss_caps & DSP_CAP_ANALOGOUT ? "true" : "false");
-#endif
-#ifdef DSP_CAP_ANALOGIN
-        TRACE("\tAnalog In: %s\n", oss_caps & DSP_CAP_ANALOGIN ? "true" : "false");
-#endif
-#ifdef DSP_CAP_DIGITALOUT
-        TRACE("\tDigital Out: %s\n", oss_caps & DSP_CAP_DIGITALOUT ? "true" : "false");
-#endif
-#ifdef DSP_CAP_DIGITALIN
-        TRACE("\tDigital In: %s\n", oss_caps & DSP_CAP_DIGITALIN ? "true" : "false");
-#endif
-#ifdef DSP_CAP_ADMASK
-        TRACE("\tA/D Mask: %s\n", oss_caps & DSP_CAP_ADMASK ? "true" : "false");
-#endif
-#ifdef DSP_CAP_SHADOW
-        TRACE("\tShadow: %s\n", oss_caps & DSP_CAP_SHADOW ? "true" : "false");
-#endif
-#ifdef DSP_CH_MASK
-        TRACE("\tChannel Mask: %x\n", oss_caps & DSP_CH_MASK);
-#endif
-#ifdef DSP_CAP_SLAVE
-        TRACE("\tSlave: %s\n", oss_caps & DSP_CAP_SLAVE ? "true" : "false");
-#endif
-    }
-}
-
-/******************************************************************
- *		OSS_WaveOutInit
- *
- *
- */
-static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev)
-{
-    int rc,arg;
-    int f,c;
-    unsigned int r;
-    BOOL has_mixer = FALSE;
-    TRACE("(%p) %s\n", ossdev, ossdev->dev_name);
-
-    if (OSS_OpenDevice(ossdev, O_WRONLY, NULL, 0,-1,-1,-1) != 0)
-        return FALSE;
-
-    ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
-
-#if defined(SNDCTL_MIXERINFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
-            oss_mixerinfo info;
-            info.dev = 0;
-            if (ioctl(mixer, SNDCTL_MIXERINFO, &info) >= 0) {
-                lstrcpynA(ossdev->ds_desc.szDesc, info.name, sizeof(info.name));
-                strcpy(ossdev->ds_desc.szDrvname, "wineoss.drv");
-                MultiByteToWideChar(CP_UNIXCP, 0, info.name, sizeof(info.name),
-                                    ossdev->out_caps.szPname,
-                                    sizeof(ossdev->out_caps.szPname) / sizeof(WCHAR));
-                TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
-                has_mixer = TRUE;
-            } else {
-                WARN("%s: cannot read SNDCTL_MIXERINFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
-        }
-    }
-#elif defined(SOUND_MIXER_INFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
-            mixer_info info;
-            if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) {
-                lstrcpynA(ossdev->ds_desc.szDesc, info.name, sizeof(info.name));
-                strcpy(ossdev->ds_desc.szDrvname, "wineoss.drv");
-                MultiByteToWideChar(CP_UNIXCP, 0, info.name, sizeof(info.name),
-                                    ossdev->out_caps.szPname, 
-                                    sizeof(ossdev->out_caps.szPname) / sizeof(WCHAR));
-                TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
-                has_mixer = TRUE;
-            } else {
-                /* FreeBSD up to at least 5.2 provides this ioctl, but does not
-                 * implement it properly, and there are probably similar issues
-                 * on other platforms, so we warn but try to go ahead.
-                 */
-                WARN("%s: cannot read SOUND_MIXER_INFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
-        }
-    }
-#endif /* SOUND_MIXER_INFO */
-
-    if (WINE_TRACE_ON(wave))
-        OSS_Info(ossdev->fd);
-
-    ossdev->out_caps.wMid = 0x00FF; /* Manufac ID */
-    ossdev->out_caps.wPid = 0x0001; /* Product ID */
-
-    ossdev->out_caps.vDriverVersion = 0x0100;
-    ossdev->out_caps.wChannels = 1;
-    ossdev->out_caps.dwFormats = 0x00000000;
-    ossdev->out_caps.wReserved1 = 0;
-    ossdev->out_caps.dwSupport = has_mixer ? WAVECAPS_VOLUME : 0;
-
-    /* direct sound caps */
-    ossdev->ds_caps.dwFlags = DSCAPS_CERTIFIED;
-    ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARY8BIT;
-    ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARY16BIT;
-    ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARYMONO;
-    ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARYSTEREO;
-    ossdev->ds_caps.dwFlags |= DSCAPS_CONTINUOUSRATE;
-
-    ossdev->ds_caps.dwPrimaryBuffers = 1;
-    ossdev->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
-    ossdev->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
-
-    /* We must first set the format and the stereo mode as some sound cards
-     * may support 44kHz mono but not 44kHz stereo. Also we must
-     * systematically check the return value of these ioctls as they will
-     * always succeed (see OSS Linux) but will modify the parameter to match
-     * whatever they support. The OSS specs also say we must first set the
-     * sample size, then the stereo and then the sample rate.
-     */
-    for (f=0;f<2;f++) {
-        arg=win_std_oss_fmts[f];
-        rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg);
-        if (rc!=0 || arg!=win_std_oss_fmts[f]) {
-            TRACE("DSP_SAMPLESIZE: rc=%d returned %d for %d\n",
-                  rc,arg,win_std_oss_fmts[f]);
-            continue;
-        }
-	if (f == 0)
-	    ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY8BIT;
-	else if (f == 1)
-	    ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY16BIT;
-
-        for (c = 1; c <= MAX_CHANNELS; c++) {
-            arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
-            if( rc == -1) break;
-            if (rc!=0 || arg!=c) {
-                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
-                continue;
-            }
-	    if (c == 1) {
-		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO;
-	    } else if (c == 2) {
-                ossdev->out_caps.wChannels = 2;
-                if (has_mixer)
-                    ossdev->out_caps.dwSupport|=WAVECAPS_LRVOLUME;
-		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-            } else
-                ossdev->out_caps.wChannels = c;
-
-            for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) {
-                arg=win_std_rates[r];
-                rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg);
-                TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",
-                      rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
-                if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
-                    ossdev->out_caps.dwFormats|=win_std_formats[f][c-1][r];
-            }
-        }
-    }
-
-    if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) {
-        if (arg & DSP_CAP_TRIGGER)
-            ossdev->bTriggerSupport = TRUE;
-        if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) {
-            ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
-        }
-        /* well, might as well use the DirectSound cap flag for something */
-        if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) &&
-            !(arg & DSP_CAP_BATCH)) {
-            ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND;
-	} else {
-	    ossdev->ds_caps.dwFlags |= DSCAPS_EMULDRIVER;
-	}
-#ifdef DSP_CAP_MULTI    /* not every oss has this */
-        /* check for hardware secondary buffer support (multi open) */
-        if ((arg & DSP_CAP_MULTI) &&
-            (ossdev->out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
-            TRACE("hardware secondary buffer support available\n");
-
-            ossdev->ds_caps.dwMaxHwMixingAllBuffers = 16;
-            ossdev->ds_caps.dwMaxHwMixingStaticBuffers = 0;
-            ossdev->ds_caps.dwMaxHwMixingStreamingBuffers = 16;
-
-            ossdev->ds_caps.dwFreeHwMixingAllBuffers = 16;
-            ossdev->ds_caps.dwFreeHwMixingStaticBuffers = 0;
-            ossdev->ds_caps.dwFreeHwMixingStreamingBuffers = 16;
-        }
-#endif
-    }
-    OSS_CloseDevice(ossdev);
-    TRACE("out wChannels = %d, dwFormats = %08X, dwSupport = %08X\n",
-          ossdev->out_caps.wChannels, ossdev->out_caps.dwFormats,
-          ossdev->out_caps.dwSupport);
-    return TRUE;
-}
-
-/******************************************************************
- *		OSS_WaveInInit
- *
- *
- */
-static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev)
-{
-    int rc,arg;
-    int f,c;
-    unsigned int r;
-    TRACE("(%p) %s\n", ossdev, ossdev->dev_name);
-
-    if (OSS_OpenDevice(ossdev, O_RDONLY, NULL, 0,-1,-1,-1) != 0)
-        return FALSE;
-
-    ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
-
-#if defined(SNDCTL_MIXERINFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
-            oss_mixerinfo info;
-            info.dev = 0;
-            if (ioctl(mixer, SNDCTL_MIXERINFO, &info) >= 0) {
-                MultiByteToWideChar(CP_UNIXCP, 0, info.name, -1,
-                                    ossdev->in_caps.szPname,
-                                    sizeof(ossdev->in_caps.szPname) / sizeof(WCHAR));
-                TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
-            } else {
-                WARN("%s: cannot read SNDCTL_MIXERINFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name, strerror(errno));
-        }
-    }
-#elif defined(SOUND_MIXER_INFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
-            mixer_info info;
-            if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) {
-                MultiByteToWideChar(CP_UNIXCP, 0, info.name, -1,
-                                    ossdev->in_caps.szPname, 
-                                    sizeof(ossdev->in_caps.szPname) / sizeof(WCHAR));
-                TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
-            } else {
-                /* FreeBSD up to at least 5.2 provides this ioctl, but does not
-                 * implement it properly, and there are probably similar issues
-                 * on other platforms, so we warn but try to go ahead.
-                 */
-                WARN("%s: cannot read SOUND_MIXER_INFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name, strerror(errno));
-        }
-    }
-#endif /* SOUND_MIXER_INFO */
-
-    if (WINE_TRACE_ON(wave))
-        OSS_Info(ossdev->fd);
-
-    ossdev->in_caps.wMid = 0x00FF; /* Manufac ID */
-    ossdev->in_caps.wPid = 0x0001; /* Product ID */
-
-    ossdev->in_caps.dwFormats = 0x00000000;
-    ossdev->in_caps.wChannels = 1;
-    ossdev->in_caps.wReserved1 = 0;
-
-    /* direct sound caps */
-    ossdev->dsc_caps.dwSize = sizeof(ossdev->dsc_caps);
-    ossdev->dsc_caps.dwFlags = 0;
-    ossdev->dsc_caps.dwFormats = 0x00000000;
-    ossdev->dsc_caps.dwChannels = 1;
-
-    /* See the comment in OSS_WaveOutInit for the loop order */
-    for (f=0;f<2;f++) {
-        arg=win_std_oss_fmts[f];
-        rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg);
-        if (rc!=0 || arg!=win_std_oss_fmts[f]) {
-            TRACE("DSP_SAMPLESIZE: rc=%d returned 0x%x for 0x%x\n",
-                  rc,arg,win_std_oss_fmts[f]);
-            continue;
-        }
-
-        for (c = 1; c <= MAX_CHANNELS; c++) {
-            arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
-            if( rc == -1) break;
-            if (rc!=0 || arg!=c) {
-                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
-                continue;
-            }
-            if (c > 1) {
-                ossdev->in_caps.wChannels = c;
-    		ossdev->dsc_caps.dwChannels = c;
-            }
-
-            for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) {
-                arg=win_std_rates[r];
-                rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg);
-                TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
-                if (rc==0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
-                    ossdev->in_caps.dwFormats|=win_std_formats[f][c-1][r];
-		    ossdev->dsc_caps.dwFormats|=win_std_formats[f][c-1][r];
-            }
-        }
-    }
-
-    if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) {
-        if (arg & DSP_CAP_TRIGGER)
-            ossdev->bTriggerSupport = TRUE;
-        if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) &&
-            !(arg & DSP_CAP_BATCH)) {
-	    /* FIXME: enable the next statement if you want to work on the driver */
-#if 0
-            ossdev->in_caps_support |= WAVECAPS_DIRECTSOUND;
-#endif
-	}
-	if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH))
-	    ossdev->in_caps_support |= WAVECAPS_SAMPLEACCURATE;
-    }
-    OSS_CloseDevice(ossdev);
-    TRACE("in wChannels = %d, dwFormats = %08X, in_caps_support = %08X\n",
-        ossdev->in_caps.wChannels, ossdev->in_caps.dwFormats, ossdev->in_caps_support);
-    return TRUE;
-}
-
-/******************************************************************
- *		OSS_WaveFullDuplexInit
- *
- *
- */
-static void OSS_WaveFullDuplexInit(OSS_DEVICE* ossdev)
-{
-    int rc,arg;
-    int f,c;
-    unsigned int r;
-    int caps;
-    BOOL has_mixer = FALSE;
-    TRACE("(%p) %s\n", ossdev, ossdev->dev_name);
-
-    /* The OSS documentation says we must call SNDCTL_SETDUPLEX
-     * *before* checking for SNDCTL_DSP_GETCAPS otherwise we may
-     * get the wrong result. This ioctl must even be done before
-     * setting the fragment size so that only OSS_RawOpenDevice is
-     * in a position to do it. So we set full_duplex speculatively
-     * and adjust right after.
-     */
-    ossdev->full_duplex=1;
-    rc=OSS_OpenDevice(ossdev, O_RDWR, NULL, 0,-1,-1,-1);
-    ossdev->full_duplex=0;
-    if (rc != 0)
-        return;
-
-    ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
-
-#if defined(SNDCTL_MIXERINFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDWR|O_NDELAY)) >= 0) {
-            oss_mixerinfo info;
-            info.dev = 0;
-            if (ioctl(mixer, SNDCTL_MIXERINFO, &info) >= 0) {
-                has_mixer = TRUE;
-            } else {
-                WARN("%s: cannot read SNDCTL_MIXERINFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
-        }
-    }
-#elif defined(SOUND_MIXER_INFO)
-    {
-        int mixer;
-        if ((mixer = open(ossdev->mixer_name, O_RDWR|O_NDELAY)) >= 0) {
-            mixer_info info;
-            if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) {
-                has_mixer = TRUE;
-            } else {
-                /* FreeBSD up to at least 5.2 provides this ioctl, but does not
-                 * implement it properly, and there are probably similar issues
-                 * on other platforms, so we warn but try to go ahead.
-                 */
-                WARN("%s: cannot read SOUND_MIXER_INFO!\n", ossdev->mixer_name);
-            }
-            close(mixer);
-        } else {
-            WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
-        }
-    }
-#endif /* SOUND_MIXER_INFO */
-
-    TRACE("%s\n", ossdev->ds_desc.szDesc);
-
-    if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &caps) == 0)
-        ossdev->full_duplex = (caps & DSP_CAP_DUPLEX);
-
-    ossdev->duplex_out_caps = ossdev->out_caps;
-
-    ossdev->duplex_out_caps.wChannels = 1;
-    ossdev->duplex_out_caps.dwFormats = 0x00000000;
-    ossdev->duplex_out_caps.dwSupport = has_mixer ? WAVECAPS_VOLUME : 0;
-
-    if (WINE_TRACE_ON(wave))
-        OSS_Info(ossdev->fd);
-
-    /* See the comment in OSS_WaveOutInit for the loop order */
-    for (f=0;f<2;f++) {
-        arg=win_std_oss_fmts[f];
-        rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg);
-        if (rc!=0 || arg!=win_std_oss_fmts[f]) {
-            TRACE("DSP_SAMPLESIZE: rc=%d returned 0x%x for 0x%x\n",
-                  rc,arg,win_std_oss_fmts[f]);
-            continue;
-        }
-
-        for (c = 1; c <= MAX_CHANNELS; c++) {
-            arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
-            if( rc == -1) break;
-            if (rc!=0 || arg!=c) {
-                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
-                continue;
-            }
-	    if (c == 1) {
-		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO;
-	    } else if (c == 2) {
-                ossdev->duplex_out_caps.wChannels = 2;
-                if (has_mixer)
-                    ossdev->duplex_out_caps.dwSupport|=WAVECAPS_LRVOLUME;
-		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-            } else
-                ossdev->duplex_out_caps.wChannels = c;
-
-            for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) {
-                arg=win_std_rates[r];
-                rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg);
-                TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",
-                      rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
-                if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
-                    ossdev->duplex_out_caps.dwFormats|=win_std_formats[f][c-1][r];
-            }
-        }
-    }
-
-    if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) {
-        if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) {
-            ossdev->duplex_out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
-        }
-        /* well, might as well use the DirectSound cap flag for something */
-        if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) &&
-            !(arg & DSP_CAP_BATCH)) {
-            ossdev->duplex_out_caps.dwSupport |= WAVECAPS_DIRECTSOUND;
-	}
-    }
-    OSS_CloseDevice(ossdev);
-    TRACE("duplex wChannels = %d, dwFormats = %08X, dwSupport = %08X\n",
-          ossdev->duplex_out_caps.wChannels,
-          ossdev->duplex_out_caps.dwFormats,
-          ossdev->duplex_out_caps.dwSupport);
-}
-
-static char* StrDup(const char* str, const char* def)
-{
-    char* dst;
-    if (str==NULL)
-        str=def;
-    dst=HeapAlloc(GetProcessHeap(),0,strlen(str)+1);
-    strcpy(dst, str);
-    return dst;
-}
-
-static int WAVE_loadcount;
-
-/******************************************************************
- *		OSS_WaveInit
- *
- * Initialize internal structures from OSS information
- */
-static LRESULT OSS_WaveInit(void)
-{
-    char* str;
-    unsigned int i;
-
-    /* FIXME: Remove unneeded members of WOutDev and WInDev */
-    TRACE("(%i)\n", WAVE_loadcount);
-    if (WAVE_loadcount++)
-        return 1;
-
-    str=getenv("AUDIODEV");
-    if (str!=NULL)
-    {
-        WOutDev[0].ossdev.dev_name = WInDev[0].ossdev.dev_name = StrDup(str,"");
-        WOutDev[0].ossdev.mixer_name = WInDev[0].ossdev.mixer_name = StrDup(getenv("MIXERDEV"),"/dev/mixer");
-        for (i = 1; i < MAX_WAVEDRV; ++i)
-        {
-            WOutDev[i].ossdev.dev_name = WInDev[i].ossdev.dev_name = StrDup("",NULL);
-            WOutDev[i].ossdev.mixer_name = WInDev[i].ossdev.mixer_name = StrDup("",NULL);
-        }
-    }
-    else
-    {
-        WOutDev[0].ossdev.dev_name = WInDev[0].ossdev.dev_name = StrDup("/dev/dsp",NULL);
-        WOutDev[0].ossdev.mixer_name = WInDev[0].ossdev.mixer_name = StrDup("/dev/mixer",NULL);
-        for (i = 1; i < MAX_WAVEDRV; ++i)
-        {
-            WOutDev[i].ossdev.dev_name = WInDev[i].ossdev.dev_name = HeapAlloc(GetProcessHeap(),0,11);
-            sprintf(WOutDev[i].ossdev.dev_name, "/dev/dsp%u", i);
-            WOutDev[i].ossdev.mixer_name = WInDev[i].ossdev.mixer_name = HeapAlloc(GetProcessHeap(),0,13);
-            sprintf(WOutDev[i].ossdev.mixer_name, "/dev/mixer%u", i);
-        }
-    }
-
-    for (i = 0; i < MAX_WAVEDRV; ++i)
-    {
-        WOutDev[i].ossdev.interface_name = WInDev[i].ossdev.interface_name =
-            HeapAlloc(GetProcessHeap(),0,9+strlen(WOutDev[i].ossdev.dev_name)+1);
-        sprintf(WOutDev[i].ossdev.interface_name, "wineoss: %s", WOutDev[i].ossdev.dev_name);
-    }
-
-    /* start with output devices */
-    for (i = 0; i < MAX_WAVEDRV; ++i)
-    {
-        if (*WOutDev[i].ossdev.dev_name == '\0' || OSS_WaveOutInit(&WOutDev[i].ossdev))
-        {
-            WOutDev[numOutDev].state = WINE_WS_CLOSED;
-            WOutDev[numOutDev].volume = 0xffffffff;
-            numOutDev++;
-        }
-    }
-
-    /* then do input devices */
-    for (i = 0; i < MAX_WAVEDRV; ++i)
-    {
-        if (*WInDev[i].ossdev.dev_name=='\0' || OSS_WaveInInit(&WInDev[i].ossdev))
-        {
-            WInDev[numInDev].state = WINE_WS_CLOSED;
-            numInDev++;
-        }
-    }
-
-    /* finish with the full duplex bits */
-    for (i = 0; i < MAX_WAVEDRV; i++)
-        if (*WOutDev[i].ossdev.dev_name!='\0')
-            OSS_WaveFullDuplexInit(&WOutDev[i].ossdev);
-
-    TRACE("%d wave out devices\n", numOutDev);
-    for (i = 0; i < numOutDev; i++) {
-        TRACE("%u: %s, %s, %s\n", i, WOutDev[i].ossdev.dev_name,
-              WOutDev[i].ossdev.mixer_name, WOutDev[i].ossdev.interface_name);
-    }
-
-    TRACE("%d wave in devices\n", numInDev);
-    for (i = 0; i < numInDev; i++) {
-        TRACE("%u: %s, %s, %s\n", i, WInDev[i].ossdev.dev_name,
-              WInDev[i].ossdev.mixer_name, WInDev[i].ossdev.interface_name);
-    }
-
-    return 0;
-}
-
-/******************************************************************
- *		OSS_WaveExit
- *
- * Delete/clear internal structures of OSS information
- */
-static LRESULT OSS_WaveExit(void)
-{
-    int i;
-    TRACE("(%i)\n", WAVE_loadcount);
-    if (--WAVE_loadcount)
-        return 1;
-
-    for (i = 0; i < MAX_WAVEDRV; ++i)
-    {
-        HeapFree(GetProcessHeap(), 0, WOutDev[i].ossdev.dev_name);
-        HeapFree(GetProcessHeap(), 0, WOutDev[i].ossdev.mixer_name);
-        HeapFree(GetProcessHeap(), 0, WOutDev[i].ossdev.interface_name);
-    }
-
-    ZeroMemory(WOutDev, sizeof(WOutDev));
-    ZeroMemory(WInDev, sizeof(WInDev));
-
-    numOutDev = 0;
-    numInDev = 0;
-
-    return 0;
-}
-
-/******************************************************************
- *		OSS_InitRingMessage
- *
- * Initialize the ring of messages for passing between driver's caller and playback/record
- * thread
- */
-static int OSS_InitRingMessage(OSS_MSG_RING* omr)
-{
-    omr->msg_toget = 0;
-    omr->msg_tosave = 0;
-#ifdef USE_PIPE_SYNC
-    if (pipe(omr->msg_pipe) < 0) {
-	omr->msg_pipe[0] = -1;
-	omr->msg_pipe[1] = -1;
-	ERR("could not create pipe, error=%s\n", strerror(errno));
-    }
-#else
-    omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL);
-#endif
-    omr->ring_buffer_size = OSS_RING_BUFFER_INCREMENT;
-    omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(OSS_MSG));
-    InitializeCriticalSection(&omr->msg_crst);
-    omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": OSS_MSG_RING.msg_crst");
-    return 0;
-}
-
-/******************************************************************
- *		OSS_DestroyRingMessage
- *
- */
-static int OSS_DestroyRingMessage(OSS_MSG_RING* omr)
-{
-#ifdef USE_PIPE_SYNC
-    close(omr->msg_pipe[0]);
-    close(omr->msg_pipe[1]);
-#else
-    CloseHandle(omr->msg_event);
-#endif
-    HeapFree(GetProcessHeap(),0,omr->messages);
-    omr->msg_crst.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&omr->msg_crst);
-    return 0;
-}
-
-/******************************************************************
- *		OSS_AddRingMessage
- *
- * Inserts a new message into the ring (should be called from DriverProc derived routines)
- */
-static int OSS_AddRingMessage(OSS_MSG_RING* omr, enum win_wm_message msg, DWORD param, BOOL wait)
-{
-    HANDLE	hEvent = INVALID_HANDLE_VALUE;
-
-    EnterCriticalSection(&omr->msg_crst);
-    if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
-    {
-	int old_ring_buffer_size = omr->ring_buffer_size;
-	omr->ring_buffer_size += OSS_RING_BUFFER_INCREMENT;
-	TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
-	omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(OSS_MSG));
-	/* Now we need to rearrange the ring buffer so that the new
-	   buffers just allocated are in between omr->msg_tosave and
-	   omr->msg_toget.
-	*/
-	if (omr->msg_tosave < omr->msg_toget)
-	{
-	    memmove(&(omr->messages[omr->msg_toget + OSS_RING_BUFFER_INCREMENT]),
-		    &(omr->messages[omr->msg_toget]),
-		    sizeof(OSS_MSG)*(old_ring_buffer_size - omr->msg_toget)
-		    );
-	    omr->msg_toget += OSS_RING_BUFFER_INCREMENT;
-	}
-    }
-    if (wait)
-    {
-        hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-        if (hEvent == INVALID_HANDLE_VALUE)
-        {
-            ERR("can't create event !?\n");
-            LeaveCriticalSection(&omr->msg_crst);
-            return 0;
-        }
-        if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->msg_toget].msg != WINE_WM_HEADER)
-            FIXME("two fast messages in the queue!!!! toget = %d(%s), tosave=%d(%s)\n",
-            omr->msg_toget,getCmdString(omr->messages[omr->msg_toget].msg),
-            omr->msg_tosave,getCmdString(omr->messages[omr->msg_tosave].msg));
-
-        /* fast messages have to be added at the start of the queue */
-        omr->msg_toget = (omr->msg_toget + omr->ring_buffer_size - 1) % omr->ring_buffer_size;
-        omr->messages[omr->msg_toget].msg = msg;
-        omr->messages[omr->msg_toget].param = param;
-        omr->messages[omr->msg_toget].hEvent = hEvent;
-    }
-    else
-    {
-        omr->messages[omr->msg_tosave].msg = msg;
-        omr->messages[omr->msg_tosave].param = param;
-        omr->messages[omr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;
-        omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
-    }
-    LeaveCriticalSection(&omr->msg_crst);
-    /* signal a new message */
-    SIGNAL_OMR(omr);
-    if (wait)
-    {
-        /* wait for playback/record thread to have processed the message */
-        WaitForSingleObject(hEvent, INFINITE);
-        CloseHandle(hEvent);
-    }
-    return 1;
-}
-
-/******************************************************************
- *		OSS_RetrieveRingMessage
- *
- * Get a message from the ring. Should be called by the playback/record thread.
- */
-static int OSS_RetrieveRingMessage(OSS_MSG_RING* omr,
-                                   enum win_wm_message *msg, DWORD_PTR *param, HANDLE *hEvent)
-{
-    EnterCriticalSection(&omr->msg_crst);
-
-    if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
-    {
-        LeaveCriticalSection(&omr->msg_crst);
-	return 0;
-    }
-
-    *msg = omr->messages[omr->msg_toget].msg;
-    omr->messages[omr->msg_toget].msg = 0;
-    *param = omr->messages[omr->msg_toget].param;
-    *hEvent = omr->messages[omr->msg_toget].hEvent;
-    omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
-    CLEAR_OMR(omr);
-    LeaveCriticalSection(&omr->msg_crst);
-    return 1;
-}
-
-/******************************************************************
- *              OSS_PeekRingMessage
- *
- * Peek at a message from the ring but do not remove it.
- * Should be called by the playback/record thread.
- */
-static int OSS_PeekRingMessage(OSS_MSG_RING* omr,
-                               enum win_wm_message *msg,
-                               DWORD_PTR *param, HANDLE *hEvent)
-{
-    EnterCriticalSection(&omr->msg_crst);
-
-    if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
-    {
-	LeaveCriticalSection(&omr->msg_crst);
-	return 0;
-    }
-
-    *msg = omr->messages[omr->msg_toget].msg;
-    *param = omr->messages[omr->msg_toget].param;
-    *hEvent = omr->messages[omr->msg_toget].hEvent;
-    LeaveCriticalSection(&omr->msg_crst);
-    return 1;
-}
-
-/*======================================================================*
- *                  Low level WAVE OUT implementation			*
- *======================================================================*/
-
-/**************************************************************************
- * 			wodNotifyClient			[internal]
- */
-static void wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("wMsg = 0x%04x (%s) dwParm1 = %04lx dwParam2 = %04lx\n", wMsg,
-        wMsg == WOM_OPEN ? "WOM_OPEN" : wMsg == WOM_CLOSE ? "WOM_CLOSE" :
-        wMsg == WOM_DONE ? "WOM_DONE" : "Unknown", dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case WOM_OPEN:
-    case WOM_CLOSE:
-    case WOM_DONE:
-        DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
-                       (HDRVR)wwo->waveDesc.hWave, wMsg,
-                       wwo->waveDesc.dwInstance, dwParam1, dwParam2);
-	break;
-    default:
-	FIXME("Unknown callback message %u\n", wMsg);
-    }
-}
-
-/**************************************************************************
- * 				wodUpdatePlayedTotal	[internal]
- *
- */
-static BOOL wodUpdatePlayedTotal(WINE_WAVEOUT* wwo, audio_buf_info* info)
-{
-    audio_buf_info dspspace;
-    DWORD notplayed;
-    if (!info) info = &dspspace;
-
-    if (ioctl(wwo->ossdev.fd, SNDCTL_DSP_GETOSPACE, info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n", wwo->ossdev.dev_name, strerror(errno));
-        return FALSE;
-    }
-
-    /* GETOSPACE is not always accurate when we're down to the last fragment or two;
-    **   we try to accommodate that here by assuming that the dsp is empty by looking
-    **   at the clock rather than the result of GETOSPACE */
-    notplayed = wwo->dwBufferSize - info->bytes;
-    if (notplayed > 0 && notplayed < (info->fragsize * 2))
-    {
-        if (wwo->dwProjectedFinishTime && GetTickCount() >= wwo->dwProjectedFinishTime)
-        {
-            TRACE("Adjusting for a presumed OSS bug and assuming all data has been played.\n");
-            wwo->dwPlayedTotal = wwo->dwWrittenTotal;
-            return TRUE;
-        }
-        else
-            /* Some OSS drivers will clean up nicely if given a POST, so give 'em the chance... */
-            ioctl(wwo->ossdev.fd, SNDCTL_DSP_POST, 0);
-    }
-
-    wwo->dwPlayedTotal = wwo->dwWrittenTotal - notplayed;
-    return TRUE;
-}
-
-/**************************************************************************
- * 				wodPlayer_BeginWaveHdr          [internal]
- *
- * Makes the specified lpWaveHdr the currently playing wave header.
- * If the specified wave header is a begin loop and we're not already in
- * a loop, setup the loop.
- */
-static void wodPlayer_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
-{
-    wwo->lpPlayPtr = lpWaveHdr;
-
-    if (!lpWaveHdr) return;
-
-    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP) {
-	if (wwo->lpLoopPtr) {
-	    WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
-	} else {
-            TRACE("Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
-	    wwo->lpLoopPtr = lpWaveHdr;
-	    /* Windows does not touch WAVEHDR.dwLoops,
-	     * so we need to make an internal copy */
-	    wwo->dwLoops = lpWaveHdr->dwLoops;
-	}
-    }
-    wwo->dwPartialOffset = 0;
-}
-
-/**************************************************************************
- * 				wodPlayer_PlayPtrNext	        [internal]
- *
- * Advance the play pointer to the next waveheader, looping if required.
- */
-static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEOUT* wwo)
-{
-    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
-
-    wwo->dwPartialOffset = 0;
-    if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {
-	/* We're at the end of a loop, loop if required */
-	if (--wwo->dwLoops > 0) {
-	    wwo->lpPlayPtr = wwo->lpLoopPtr;
-	} else {
-	    /* Handle overlapping loops correctly */
-	    if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
-		FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
-		/* shall we consider the END flag for the closing loop or for
-		 * the opening one or for both ???
-		 * code assumes for closing loop only
-		 */
-	    } else {
-                lpWaveHdr = lpWaveHdr->lpNext;
-            }
-            wwo->lpLoopPtr = NULL;
-            wodPlayer_BeginWaveHdr(wwo, lpWaveHdr);
-	}
-    } else {
-	/* We're not in a loop.  Advance to the next wave header */
-	wodPlayer_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
-    }
-
-    return lpWaveHdr;
-}
-
-/**************************************************************************
- * 			     wodPlayer_TicksTillEmpty		[internal]
- * Returns the number of ticks until we think the DSP should be empty
- */
-static DWORD wodPlayer_TicksTillEmpty(const WINE_WAVEOUT *wwo)
-{
-    return ((wwo->dwWrittenTotal - wwo->dwPlayedTotal) * 1000)
-        / wwo->waveFormat.Format.nAvgBytesPerSec;
-}
-
-/**************************************************************************
- * 			     wodPlayer_DSPWait			[internal]
- * Returns the number of milliseconds to wait for the DSP buffer to write
- * one fragment.
- */
-static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo)
-{
-    /* time for one fragment to be played */
-    return wwo->dwFragmentSize * 1000 / wwo->waveFormat.Format.nAvgBytesPerSec;
-}
-
-/**************************************************************************
- * 			     wodPlayer_NotifyWait               [internal]
- * Returns the number of milliseconds to wait before attempting to notify
- * completion of the specified wavehdr.
- * This is based on the number of bytes remaining to be written in the
- * wave.
- */
-static DWORD wodPlayer_NotifyWait(const WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
-{
-    DWORD dwMillis;
-
-    if (lpWaveHdr->reserved < wwo->dwPlayedTotal) {
-	dwMillis = 1;
-    } else {
-	dwMillis = (lpWaveHdr->reserved - wwo->dwPlayedTotal) * 1000 / wwo->waveFormat.Format.nAvgBytesPerSec;
-	if (!dwMillis) dwMillis = 1;
-    }
-
-    return dwMillis;
-}
-
-
-/**************************************************************************
- * 			     wodPlayer_WriteMaxFrags            [internal]
- * Writes the maximum number of bytes possible to the DSP and returns
- * TRUE iff the current playPtr has been fully played
- */
-static BOOL wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes)
-{
-    DWORD       dwLength = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
-    DWORD       toWrite = min(dwLength, *bytes);
-    int         written;
-    BOOL        ret = FALSE;
-
-    TRACE("Writing wavehdr %p.%u[%u]/%u\n",
-          wwo->lpPlayPtr, wwo->dwPartialOffset, wwo->lpPlayPtr->dwBufferLength, toWrite);
-
-    if (toWrite > 0)
-    {
-        written = write(wwo->ossdev.fd, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toWrite);
-        if (written <= 0) {
-            TRACE("write(%s, %p, %d) failed (%s) returned %d\n", wwo->ossdev.dev_name,
-                wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toWrite, strerror(errno), written);
-            return FALSE;
-        }
-    }
-    else
-        written = 0;
-
-    if (written >= dwLength) {
-        /* If we wrote all current wavehdr, skip to the next one */
-        wodPlayer_PlayPtrNext(wwo);
-        ret = TRUE;
-    } else {
-        /* Remove the amount written */
-        wwo->dwPartialOffset += written;
-    }
-    *bytes -= written;
-    wwo->dwWrittenTotal += written;
-    TRACE("dwWrittenTotal=%u\n", wwo->dwWrittenTotal);
-    return ret;
-}
-
-
-/**************************************************************************
- * 				wodPlayer_NotifyCompletions	[internal]
- *
- * Notifies and remove from queue all wavehdrs which have been played to
- * the speaker (ie. they have cleared the OSS buffer).  If force is true,
- * we notify all wavehdrs and remove them all from the queue even if they
- * are unplayed or part of a loop.
- */
-static DWORD wodPlayer_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
-{
-    LPWAVEHDR		lpWaveHdr;
-
-    /* Start from lpQueuePtr and keep notifying until:
-     * - we hit an unwritten wavehdr
-     * - we hit the beginning of a running loop
-     * - we hit a wavehdr which hasn't finished playing
-     */
-#if 0
-    while ((lpWaveHdr = wwo->lpQueuePtr) && 
-           (force || 
-            (lpWaveHdr != wwo->lpPlayPtr &&
-             lpWaveHdr != wwo->lpLoopPtr &&
-             lpWaveHdr->reserved <= wwo->dwPlayedTotal))) {
-
-	wwo->lpQueuePtr = lpWaveHdr->lpNext;
-
-	lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-	lpWaveHdr->dwFlags |= WHDR_DONE;
-
-	wodNotifyClient(wwo, WOM_DONE, (DWORD_PTR)lpWaveHdr, 0);
-    }
-#else
-    for (;;)
-    {
-        lpWaveHdr = wwo->lpQueuePtr;
-        if (!lpWaveHdr) {TRACE("Empty queue\n"); break;}
-        if (!force)
-        {
-            if (lpWaveHdr == wwo->lpPlayPtr) {TRACE("play %p\n", lpWaveHdr); break;}
-            if (lpWaveHdr == wwo->lpLoopPtr) {TRACE("loop %p\n", lpWaveHdr); break;}
-            if (lpWaveHdr->reserved > wwo->dwPlayedTotal) {TRACE("still playing %p (%lu/%u)\n", lpWaveHdr, lpWaveHdr->reserved, wwo->dwPlayedTotal);break;}
-        }
-	wwo->lpQueuePtr = lpWaveHdr->lpNext;
-
-	lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-	lpWaveHdr->dwFlags |= WHDR_DONE;
-
-	wodNotifyClient(wwo, WOM_DONE, (DWORD_PTR)lpWaveHdr, 0);
-    }
-#endif
-    return  (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != wwo->lpLoopPtr) ? 
-        wodPlayer_NotifyWait(wwo, lpWaveHdr) : INFINITE;
-}
-
-/**************************************************************************
- * 				wodPlayer_Reset			[internal]
- *
- * wodPlayer helper. Resets current output stream.
- */
-static	void	wodPlayer_Reset(WINE_WAVEOUT* wwo, BOOL reset)
-{
-    wodUpdatePlayedTotal(wwo, NULL);
-    /* updates current notify list */
-    wodPlayer_NotifyCompletions(wwo, FALSE);
-
-    /* flush all possible output */
-    if (OSS_ResetDevice(&wwo->ossdev) != MMSYSERR_NOERROR)
-    {
-	wwo->hThread = 0;
-	wwo->state = WINE_WS_STOPPED;
-	ExitThread(-1);
-    }
-
-    if (reset) {
-        enum win_wm_message	msg;
-        DWORD_PTR	        param;
-        HANDLE		        ev;
-
-	/* remove any buffer */
-	wodPlayer_NotifyCompletions(wwo, TRUE);
-
-	wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
-	wwo->state = WINE_WS_STOPPED;
-	wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
-        /* Clear partial wavehdr */
-        wwo->dwPartialOffset = 0;
-
-        /* remove any existing message in the ring */
-        EnterCriticalSection(&wwo->msgRing.msg_crst);
-        /* return all pending headers in queue */
-        while (OSS_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
-        {
-            if (msg != WINE_WM_HEADER)
-            {
-                FIXME("shouldn't have headers left\n");
-                SetEvent(ev);
-                continue;
-            }
-            ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
-            ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
-
-            wodNotifyClient(wwo, WOM_DONE, param, 0);
-        }
-        RESET_OMR(&wwo->msgRing);
-        LeaveCriticalSection(&wwo->msgRing.msg_crst);
-    } else {
-        if (wwo->lpLoopPtr) {
-            /* complicated case, not handled yet (could imply modifying the loop counter */
-            FIXME("Pausing while in loop isn't correctly handled yet, expect strange results\n");
-            wwo->lpPlayPtr = wwo->lpLoopPtr;
-            wwo->dwPartialOffset = 0;
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
-        } else {
-            LPWAVEHDR   ptr;
-            DWORD       sz = wwo->dwPartialOffset;
-
-            /* reset all the data as if we had written only up to lpPlayedTotal bytes */
-            /* compute the max size playable from lpQueuePtr */
-            for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext) {
-                sz += ptr->dwBufferLength;
-            }
-            /* because the reset lpPlayPtr will be lpQueuePtr */
-            if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("grin\n");
-            wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal;
-            wwo->lpPlayPtr = wwo->lpQueuePtr;
-        }
-	wwo->state = WINE_WS_PAUSED;
-    }
-}
-
-/**************************************************************************
- * 		      wodPlayer_ProcessMessages			[internal]
- */
-static void wodPlayer_ProcessMessages(WINE_WAVEOUT* wwo)
-{
-    LPWAVEHDR           lpWaveHdr;
-    enum win_wm_message	msg;
-    DWORD_PTR		param;
-    HANDLE		ev;
-
-    while (OSS_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev)) {
-	TRACE("Received %s %lx\n", getCmdString(msg), param);
-	switch (msg) {
-	case WINE_WM_PAUSING:
-	    wodPlayer_Reset(wwo, FALSE);
-	    SetEvent(ev);
-	    break;
-	case WINE_WM_RESTARTING:
-            if (wwo->state == WINE_WS_PAUSED)
-            {
-                wwo->state = WINE_WS_PLAYING;
-            }
-	    SetEvent(ev);
-	    break;
-	case WINE_WM_HEADER:
-	    lpWaveHdr = (LPWAVEHDR)param;
-
-	    /* insert buffer at the end of queue */
-	    {
-		LPWAVEHDR*	wh;
-		for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-		*wh = lpWaveHdr;
-	    }
-            if (!wwo->lpPlayPtr)
-                wodPlayer_BeginWaveHdr(wwo,lpWaveHdr);
-	    if (wwo->state == WINE_WS_STOPPED)
-		wwo->state = WINE_WS_PLAYING;
-	    break;
-	case WINE_WM_RESETTING:
-	    wodPlayer_Reset(wwo, TRUE);
-	    SetEvent(ev);
-	    break;
-        case WINE_WM_UPDATE:
-            wodUpdatePlayedTotal(wwo, NULL);
-	    SetEvent(ev);
-            break;
-        case WINE_WM_BREAKLOOP:
-            if (wwo->state == WINE_WS_PLAYING && wwo->lpLoopPtr != NULL) {
-                /* ensure exit at end of current loop */
-                wwo->dwLoops = 1;
-            }
-	    SetEvent(ev);
-            break;
-	case WINE_WM_CLOSING:
-	    /* sanity check: this should not happen since the device must have been reset before */
-	    if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
-	    wwo->hThread = 0;
-	    wwo->state = WINE_WS_CLOSED;
-	    SetEvent(ev);
-	    ExitThread(0);
-	    /* shouldn't go here */
-	default:
-	    FIXME("unknown message %d\n", msg);
-	    break;
-	}
-    }
-}
-
-/**************************************************************************
- * 			     wodPlayer_FeedDSP			[internal]
- * Feed as much sound data as we can into the DSP and return the number of
- * milliseconds before it will be necessary to feed the DSP again.
- */
-static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo)
-{
-    audio_buf_info dspspace;
-    DWORD       availInQ;
-
-    if (!wodUpdatePlayedTotal(wwo, &dspspace)) return INFINITE;
-    availInQ = dspspace.bytes;
-    TRACE("fragments=%d/%d, fragsize=%d, bytes=%d\n",
-	  dspspace.fragments, dspspace.fragstotal, dspspace.fragsize, dspspace.bytes);
-
-    /* no more room... no need to try to feed */
-    if (dspspace.fragments != 0) {
-        /* Feed from partial wavehdr */
-        if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) {
-            wodPlayer_WriteMaxFrags(wwo, &availInQ);
-        }
-
-        /* Feed wavehdrs until we run out of wavehdrs or DSP space */
-        if (wwo->dwPartialOffset == 0 && wwo->lpPlayPtr) {
-            do {
-                TRACE("Setting time to elapse for %p to %u\n",
-                      wwo->lpPlayPtr, wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength);
-                /* note the value that dwPlayedTotal will return when this wave finishes playing */
-                wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength;
-            } while (wodPlayer_WriteMaxFrags(wwo, &availInQ) && wwo->lpPlayPtr && availInQ > 0);
-        }
-
-        if (wwo->bNeedPost) {
-            /* OSS doesn't start before it gets either 2 fragments or a SNDCTL_DSP_POST;
-             * if it didn't get one, we give it the other */
-            if (wwo->dwBufferSize < availInQ + 2 * wwo->dwFragmentSize)
-                ioctl(wwo->ossdev.fd, SNDCTL_DSP_POST, 0);
-            wwo->bNeedPost = FALSE;
-        }
-    }
-
-    return wodPlayer_DSPWait(wwo);
-}
-
-
-/**************************************************************************
- * 				wodPlayer			[internal]
- */
-static	DWORD	CALLBACK	wodPlayer(LPVOID pmt)
-{
-    WORD	  uDevID = (DWORD_PTR)pmt;
-    WINE_WAVEOUT* wwo = &WOutDev[uDevID];
-    DWORD         dwNextFeedTime = INFINITE;   /* Time before DSP needs feeding */
-    DWORD         dwNextNotifyTime = INFINITE; /* Time before next wave completion */
-    DWORD         dwSleepTime;
-
-    wwo->state = WINE_WS_STOPPED;
-    SetEvent(wwo->hStartUpEvent);
-
-    for (;;) {
-        /** Wait for the shortest time before an action is required.  If there
-         *  are no pending actions, wait forever for a command.
-         */
-        dwSleepTime = min(dwNextFeedTime, dwNextNotifyTime);
-        TRACE("waiting %ums (%u,%u)\n", dwSleepTime, dwNextFeedTime, dwNextNotifyTime);
-	WAIT_OMR(&wwo->msgRing, dwSleepTime);
-	wodPlayer_ProcessMessages(wwo);
-	if (wwo->state == WINE_WS_PLAYING) {
-	    dwNextFeedTime = wodPlayer_FeedDSP(wwo);
-            if (dwNextFeedTime != INFINITE)
-                wwo->dwProjectedFinishTime = GetTickCount() + wodPlayer_TicksTillEmpty(wwo);
-            else
-                wwo->dwProjectedFinishTime = 0;
-
-	    dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE);
-	    if (dwNextFeedTime == INFINITE) {
-		/* FeedDSP ran out of data, but before flushing, */
-		/* check that a notification didn't give us more */
-		wodPlayer_ProcessMessages(wwo);
-		if (!wwo->lpPlayPtr) {
-		    TRACE("flushing\n");
-		    ioctl(wwo->ossdev.fd, SNDCTL_DSP_SYNC, 0);
-		    wwo->dwPlayedTotal = wwo->dwWrittenTotal;
-                    dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE);
-		} else {
-		    TRACE("recovering\n");
-		    dwNextFeedTime = wodPlayer_FeedDSP(wwo);
-		}
-	    }
-	} else {
-	    dwNextFeedTime = dwNextNotifyTime = INFINITE;
-	}
-    }
-
-    return 0;
-}
-
-/**************************************************************************
- * 			wodGetDevCaps				[internal]
- */
-static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
-{
-    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) {
-        WARN("not enabled\n");
-        return MMSYSERR_NOTENABLED;
-    }
-
-    if (wDevID >= numOutDev) {
-	WARN("numOutDev reached !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (WOutDev[wDevID].ossdev.open_access == O_RDWR)
-        memcpy(lpCaps, &WOutDev[wDevID].ossdev.duplex_out_caps, min(dwSize, sizeof(*lpCaps)));
-    else
-        memcpy(lpCaps, &WOutDev[wDevID].ossdev.out_caps, min(dwSize, sizeof(*lpCaps)));
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodOpen				[internal]
- */
-static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
-{
-    int			audio_fragment;
-    WINE_WAVEOUT*	wwo;
-    audio_buf_info      info;
-    DWORD               ret;
-
-    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
-    if (lpDesc == NULL) {
-	WARN("Invalid Parameter !\n");
-	return MMSYSERR_INVALPARAM;
-    }
-    if (wDevID >= numOutDev) {
-	TRACE("MAX_WAVOUTDRV reached !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    /* only PCM format is supported so far... */
-    if (!supportedFormat(lpDesc->lpFormat)) {
-	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return WAVERR_BADFORMAT;
-    }
-
-    if (dwFlags & WAVE_FORMAT_QUERY) {
-	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return MMSYSERR_NOERROR;
-    }
-
-    /* nBlockAlign and nAvgBytesPerSec are output variables for dsound */
-    if (lpDesc->lpFormat->nBlockAlign != lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8) {
-        lpDesc->lpFormat->nBlockAlign  = lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
-        WARN("Fixing nBlockAlign\n");
-    }
-    if (lpDesc->lpFormat->nAvgBytesPerSec!= lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign) {
-        lpDesc->lpFormat->nAvgBytesPerSec = lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
-        WARN("Fixing nAvgBytesPerSec\n");
-    }
-
-    TRACE("OSS_OpenDevice requested this format: %dx%dx%d %s\n",
-          lpDesc->lpFormat->nSamplesPerSec,
-          lpDesc->lpFormat->wBitsPerSample,
-          lpDesc->lpFormat->nChannels,
-          lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM ? "WAVE_FORMAT_PCM" :
-          lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? "WAVE_FORMAT_EXTENSIBLE" :
-          "UNSUPPORTED");
-
-    wwo = &WOutDev[wDevID];
-
-    if ((dwFlags & WAVE_DIRECTSOUND) &&
-        !(wwo->ossdev.duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND))
-	/* not supported, ignore it */
-	dwFlags &= ~WAVE_DIRECTSOUND;
-
-    if (dwFlags & WAVE_DIRECTSOUND) {
-        if (wwo->ossdev.duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
-	    /* we have realtime DirectSound, fragments just waste our time,
-	     * but a large buffer is good, so choose 64KB (32 * 2^11) */
-	    audio_fragment = 0x0020000B;
-	else
-	    /* to approximate realtime, we must use small fragments,
-	     * let's try to fragment the above 64KB (256 * 2^8) */
-	    audio_fragment = 0x01000008;
-    } else {
-	/* A wave device must have a worst case latency of 10 ms so calculate
-	 * the largest fragment size less than 10 ms long.
-	 */
-	int	fsize = lpDesc->lpFormat->nAvgBytesPerSec / 100;	/* 10 ms chunk */
-	int	shift = 0;
-	while ((1 << shift) <= fsize)
-	    shift++;
-	shift--;
-	audio_fragment = 0x00100000 + shift;	/* 16 fragments of 2^shift */
-    }
-
-    TRACE("requesting %d %d byte fragments (%d ms/fragment)\n",
-        audio_fragment >> 16, 1 << (audio_fragment & 0xffff),
-	((1 << (audio_fragment & 0xffff)) * 1000) / lpDesc->lpFormat->nAvgBytesPerSec);
-
-    if (wwo->state != WINE_WS_CLOSED) {
-        WARN("already allocated\n");
-        return MMSYSERR_ALLOCATED;
-    }
-
-    /* we want to be able to mmap() the device, which means it must be opened readable,
-     * otherwise mmap() will fail (at least under Linux) */
-    ret = OSS_OpenDevice(&wwo->ossdev,
-                         (dwFlags & WAVE_DIRECTSOUND) ? O_RDWR : O_WRONLY,
-                         &audio_fragment,
-                         (dwFlags & WAVE_DIRECTSOUND) ? 0 : 1,
-                         lpDesc->lpFormat->nSamplesPerSec,
-                         lpDesc->lpFormat->nChannels,
-                         (lpDesc->lpFormat->wBitsPerSample == 16)
-                             ? AFMT_S16_LE : AFMT_U8);
-    if ((ret==MMSYSERR_NOERROR) && (dwFlags & WAVE_DIRECTSOUND)) {
-        lpDesc->lpFormat->nSamplesPerSec=wwo->ossdev.sample_rate;
-        lpDesc->lpFormat->nChannels=wwo->ossdev.channels;
-        lpDesc->lpFormat->wBitsPerSample=(wwo->ossdev.format == AFMT_U8 ? 8 : 16);
-        lpDesc->lpFormat->nBlockAlign=lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
-        lpDesc->lpFormat->nAvgBytesPerSec=lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
-        TRACE("OSS_OpenDevice returned this format: %dx%dx%d\n",
-              lpDesc->lpFormat->nSamplesPerSec,
-              lpDesc->lpFormat->wBitsPerSample,
-              lpDesc->lpFormat->nChannels);
-    }
-    if (ret != 0) return ret;
-    wwo->state = WINE_WS_STOPPED;
-
-    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-
-    wwo->waveDesc = *lpDesc;
-    copy_format(lpDesc->lpFormat, &wwo->waveFormat);
-
-    /* Read output space info for future reference */
-    if (ioctl(wwo->ossdev.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n", wwo->ossdev.dev_name, strerror(errno));
-        OSS_CloseDevice(&wwo->ossdev);
-	wwo->state = WINE_WS_CLOSED;
-	return MMSYSERR_NOTENABLED;
-    }
-
-    TRACE("got %d %d byte fragments (%d ms/fragment)\n", info.fragstotal,
-        info.fragsize, (info.fragsize * 1000) / (wwo->ossdev.sample_rate *
-        wwo->ossdev.channels * (wwo->ossdev.format == AFMT_U8 ? 1 : 2)));
-
-    /* Check that fragsize is correct per our settings above */
-    if ((info.fragsize > 1024) && (LOWORD(audio_fragment) <= 10)) {
-        /* we've tried to set 1K fragments or less, but it didn't work */
-        WARN("fragment size set failed, size is now %d\n", info.fragsize);
-    }
-
-    /* Remember fragsize and total buffer size for future use */
-    wwo->dwFragmentSize = info.fragsize;
-    wwo->dwBufferSize = info.fragstotal * info.fragsize;
-    wwo->dwPlayedTotal = 0;
-    wwo->dwWrittenTotal = 0;
-    wwo->bNeedPost = TRUE;
-
-    TRACE("fd=%d fragstotal=%d fragsize=%d BufferSize=%d\n",
-          wwo->ossdev.fd, info.fragstotal, info.fragsize, wwo->dwBufferSize);
-    if (wwo->dwFragmentSize % wwo->waveFormat.Format.nBlockAlign) {
-        ERR("Fragment doesn't contain an integral number of data blocks fragsize=%d BlockAlign=%d\n",wwo->dwFragmentSize,wwo->waveFormat.Format.nBlockAlign);
-        /* Some SoundBlaster 16 cards return an incorrect (odd) fragment
-         * size for 16 bit sound. This will cause a system crash when we try
-         * to write just the specified odd number of bytes. So if we
-         * detect something is wrong we'd better fix it.
-         */
-        wwo->dwFragmentSize-=wwo->dwFragmentSize % wwo->waveFormat.Format.nBlockAlign;
-    }
-
-    OSS_InitRingMessage(&wwo->msgRing);
-
-    wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwo->dwThreadID));
-    if (wwo->hThread)
-        SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL);
-    WaitForSingleObject(wwo->hStartUpEvent, INFINITE);
-    CloseHandle(wwo->hStartUpEvent);
-    wwo->hStartUpEvent = INVALID_HANDLE_VALUE;
-
-    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
-	  wwo->waveFormat.Format.wBitsPerSample, wwo->waveFormat.Format.nAvgBytesPerSec,
-	  wwo->waveFormat.Format.nSamplesPerSec, wwo->waveFormat.Format.nChannels,
-	  wwo->waveFormat.Format.nBlockAlign);
-
-    wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodClose			[internal]
- */
-static DWORD wodClose(WORD wDevID)
-{
-    WINE_WAVEOUT*	wwo;
-
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    wwo = &WOutDev[wDevID];
-    if (wwo->lpQueuePtr) {
-	WARN("buffers still playing !\n");
-	return WAVERR_STILLPLAYING;
-    } else {
-	if (wwo->hThread != INVALID_HANDLE_VALUE) {
-	    OSS_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE);
-	}
-
-        OSS_DestroyRingMessage(&wwo->msgRing);
-
-        OSS_CloseDevice(&wwo->ossdev);
-	wwo->state = WINE_WS_CLOSED;
-	wwo->dwFragmentSize = 0;
-	wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
-    }
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodWrite			[internal]
- *
- */
-static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    WORD delta;
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    /* first, do the sanity checks... */
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-        WARN("bad dev ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
-	return WAVERR_UNPREPARED;
-
-    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
-	return WAVERR_STILLPLAYING;
-
-    lpWaveHdr->dwFlags &= ~WHDR_DONE;
-    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
-    lpWaveHdr->lpNext = 0;
-
-    delta = lpWaveHdr->dwBufferLength % WOutDev[wDevID].waveFormat.Format.nBlockAlign;
-    if (delta != 0)
-    {
-        WARN("WaveHdr length isn't a multiple of the PCM block size: %d %% %d\n",lpWaveHdr->dwBufferLength,WOutDev[wDevID].waveFormat.Format.nBlockAlign);
-        lpWaveHdr->dwBufferLength -= delta;
-    }
-
-    OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD_PTR)lpWaveHdr, FALSE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodPause				[internal]
- */
-static DWORD wodPause(WORD wDevID)
-{
-    TRACE("(%u);!\n", wDevID);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodRestart				[internal]
- */
-static DWORD wodRestart(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE);
-
-    /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
-    /* FIXME: Myst crashes with this ... hmm -MM
-       return wodNotifyClient(wwo, WOM_DONE, 0L, 0L);
-    */
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			wodReset				[internal]
- */
-static DWORD wodReset(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodGetPosition			[internal]
- */
-static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
-{
-    WINE_WAVEOUT*	wwo;
-
-    TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    if (lpTime == NULL) {
-	WARN("invalid parameter: lpTime == NULL\n");
-	return MMSYSERR_INVALPARAM;
-    }
-
-    wwo = &WOutDev[wDevID];
-#ifdef EXACT_WODPOSITION
-    if (wwo->ossdev.open_access == O_RDWR) {
-        if (wwo->ossdev.duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
-	    OSS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
-    } else {
-        if (wwo->ossdev.out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
-	    OSS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
-    }
-#endif
-
-    return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->waveFormat);
-}
-
-/**************************************************************************
- * 				wodBreakLoop			[internal]
- */
-static DWORD wodBreakLoop(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-
-    if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("bad device ID !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-    OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodGetVolume			[internal]
- */
-static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
-{
-    int		mixer;
-    int		volume;
-    DWORD	left, right;
-    DWORD	last_left, last_right;
-
-    TRACE("(%u, %p);\n", wDevID, lpdwVol);
-
-    if (lpdwVol == NULL) {
-        WARN("not enabled\n");
-        return MMSYSERR_NOTENABLED;
-    }
-    if (wDevID >= numOutDev) {
-        WARN("invalid parameter\n");
-        return MMSYSERR_INVALPARAM;
-    }
-    if (WOutDev[wDevID].ossdev.open_access == O_RDWR) {
-        if (!(WOutDev[wDevID].ossdev.duplex_out_caps.dwSupport & WAVECAPS_VOLUME)) {
-            TRACE("Volume not supported\n");
-            return MMSYSERR_NOTSUPPORTED;
-        }
-    } else {
-        if (!(WOutDev[wDevID].ossdev.out_caps.dwSupport & WAVECAPS_VOLUME)) {
-            TRACE("Volume not supported\n");
-            return MMSYSERR_NOTSUPPORTED;
-        }
-    }
-
-    if ((mixer = open(WOutDev[wDevID].ossdev.mixer_name, O_RDONLY|O_NDELAY)) < 0) {
-        WARN("mixer device not available !\n");
-        return MMSYSERR_NOTENABLED;
-    }
-    if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
-        close(mixer);
-        WARN("ioctl(%s, SOUND_MIXER_READ_PCM) failed (%s)\n",
-             WOutDev[wDevID].ossdev.mixer_name, strerror(errno));
-        return MMSYSERR_NOTENABLED;
-    }
-    close(mixer);
-
-    left = LOBYTE(volume);
-    right = HIBYTE(volume);
-    TRACE("left=%d right=%d !\n", left, right);
-    last_left  = (LOWORD(WOutDev[wDevID].volume) * 100) / 0xFFFFl;
-    last_right = (HIWORD(WOutDev[wDevID].volume) * 100) / 0xFFFFl;
-    TRACE("last_left=%d last_right=%d !\n", last_left, last_right);
-    if (last_left == left && last_right == right)
-	*lpdwVol = WOutDev[wDevID].volume;
-    else
-	*lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) << 16);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodSetVolume			[internal]
- */
-DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
-{
-    int		mixer;
-    int		volume;
-    DWORD	left, right;
-
-    TRACE("(%u, %08X);\n", wDevID, dwParam);
-
-    left  = (LOWORD(dwParam) * 100) / 0xFFFFl;
-    right = (HIWORD(dwParam) * 100) / 0xFFFFl;
-    volume = left + (right << 8);
-
-    if (wDevID >= numOutDev) {
-        WARN("invalid parameter: wDevID > %d\n", numOutDev);
-        return MMSYSERR_INVALPARAM;
-    }
-    if (WOutDev[wDevID].ossdev.open_access == O_RDWR) {
-        if (!(WOutDev[wDevID].ossdev.duplex_out_caps.dwSupport & WAVECAPS_VOLUME)) {
-            TRACE("Volume not supported\n");
-            return MMSYSERR_NOTSUPPORTED;
-        }
-    } else {
-        if (!(WOutDev[wDevID].ossdev.out_caps.dwSupport & WAVECAPS_VOLUME)) {
-            TRACE("Volume not supported\n");
-            return MMSYSERR_NOTSUPPORTED;
-        }
-    }
-    if ((mixer = open(WOutDev[wDevID].ossdev.mixer_name, O_WRONLY|O_NDELAY)) < 0) {
-        WARN("open(%s) failed (%s)\n", WOutDev[wDevID].ossdev.mixer_name, strerror(errno));
-        return MMSYSERR_NOTENABLED;
-    }
-    if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
-        close(mixer);
-        WARN("ioctl(%s, SOUND_MIXER_WRITE_PCM) failed (%s)\n",
-            WOutDev[wDevID].ossdev.mixer_name, strerror(errno));
-        return MMSYSERR_NOTENABLED;
-    }
-    TRACE("volume=%04x\n", (unsigned)volume);
-    close(mixer);
-
-    /* save requested volume */
-    WOutDev[wDevID].volume = dwParam;
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				wodMessage (WINEOSS.7)
- */
-DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
-			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("(%u, %s, %08lX, %08lX, %08lX);\n",
-	  wDevID, getMessage(wMsg), dwUser, dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case DRVM_INIT:
-    case DRVM_EXIT:
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
-    case WODM_OPEN:	 	return wodOpen		(wDevID, (LPWAVEOPENDESC)dwParam1,	dwParam2);
-    case WODM_CLOSE:	 	return wodClose		(wDevID);
-    case WODM_WRITE:	 	return wodWrite		(wDevID, (LPWAVEHDR)dwParam1,		dwParam2);
-    case WODM_PAUSE:	 	return wodPause		(wDevID);
-    case WODM_GETPOS:	 	return wodGetPosition	(wDevID, (LPMMTIME)dwParam1, 		dwParam2);
-    case WODM_BREAKLOOP: 	return wodBreakLoop     (wDevID);
-    case WODM_PREPARE:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_UNPREPARE: 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (LPWAVEOUTCAPSW)dwParam1,	dwParam2);
-    case WODM_GETNUMDEVS:	return numOutDev;
-    case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
-    case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
-    case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
-    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (LPDWORD)dwParam1);
-    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, dwParam1);
-    case WODM_RESTART:		return wodRestart	(wDevID);
-    case WODM_RESET:		return wodReset		(wDevID);
-
-    case DRV_QUERYDEVICEINTERFACESIZE: return wodDevInterfaceSize      (wDevID, (LPDWORD)dwParam1);
-    case DRV_QUERYDEVICEINTERFACE:     return wodDevInterface          (wDevID, (PWCHAR)dwParam1, dwParam2);
-    case DRV_QUERYDSOUNDIFACE:	return wodDsCreate	(wDevID, (PIDSDRIVER*)dwParam1);
-    case DRV_QUERYDSOUNDDESC:	return wodDsDesc	(wDevID, (PDSDRIVERDESC)dwParam1);
-    default:
-	FIXME("unknown message %d!\n", wMsg);
-    }
-    return MMSYSERR_NOTSUPPORTED;
-}
-
-/*======================================================================*
- *                  Low level WAVE IN implementation			*
- *======================================================================*/
-
-/**************************************************************************
- * 			widNotifyClient			[internal]
- */
-static void widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("wMsg = 0x%04x (%s) dwParm1 = %04lx dwParam2 = %04lx\n", wMsg,
-        wMsg == WIM_OPEN ? "WIM_OPEN" : wMsg == WIM_CLOSE ? "WIM_CLOSE" :
-        wMsg == WIM_DATA ? "WIM_DATA" : "Unknown", dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case WIM_OPEN:
-    case WIM_CLOSE:
-    case WIM_DATA:
-        DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
-                       (HDRVR)wwi->waveDesc.hWave, wMsg,
-                       wwi->waveDesc.dwInstance, dwParam1, dwParam2);
-	break;
-    default:
-	FIXME("Unknown callback message %u\n", wMsg);
-    }
-}
-
-/**************************************************************************
- * 			widGetDevCaps				[internal]
- */
-static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
-{
-    TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
-
-    if (wDevID >= numInDev) {
-	TRACE("numOutDev reached !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    memcpy(lpCaps, &WInDev[wDevID].ossdev.in_caps, min(dwSize, sizeof(*lpCaps)));
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widRecorder_ReadHeaders		[internal]
- */
-static void widRecorder_ReadHeaders(WINE_WAVEIN * wwi)
-{
-    enum win_wm_message tmp_msg;
-    DWORD_PTR		tmp_param;
-    HANDLE		tmp_ev;
-    WAVEHDR*		lpWaveHdr;
-
-    while (OSS_RetrieveRingMessage(&wwi->msgRing, &tmp_msg, &tmp_param, &tmp_ev)) {
-        if (tmp_msg == WINE_WM_HEADER) {
-	    LPWAVEHDR*	wh;
-	    lpWaveHdr = (LPWAVEHDR)tmp_param;
-	    lpWaveHdr->lpNext = 0;
-
-	    if (wwi->lpQueuePtr == 0)
-		wwi->lpQueuePtr = lpWaveHdr;
-	    else {
-	        for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-	        *wh = lpWaveHdr;
-	    }
-	} else {
-            ERR("should only have headers left\n");
-        }
-    }
-}
-
-/**************************************************************************
- * 				widRecorder			[internal]
- */
-static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
-{
-    WORD		uDevID = (DWORD_PTR)pmt;
-    WINE_WAVEIN*	wwi = &WInDev[uDevID];
-    WAVEHDR*		lpWaveHdr;
-    DWORD		dwSleepTime;
-    DWORD		bytesRead;
-    LPVOID		buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wwi->dwFragmentSize);
-    char               *pOffset = buffer;
-    audio_buf_info 	info;
-    int 		xs;
-    enum win_wm_message msg;
-    DWORD_PTR		param;
-    HANDLE		ev;
-    int                 enable;
-
-    wwi->state = WINE_WS_STOPPED;
-    wwi->dwTotalRecorded = 0;
-    wwi->dwTotalRead = 0;
-    wwi->lpQueuePtr = NULL;
-
-    SetEvent(wwi->hStartUpEvent);
-
-    /* disable input so capture will begin when triggered */
-    wwi->ossdev.bInputEnabled = FALSE;
-    enable = getEnables(&wwi->ossdev);
-    if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev.dev_name, strerror(errno));
-
-    /* the soundblaster live needs a micro wake to get its recording started
-     * (or GETISPACE will have 0 frags all the time)
-     */
-    read(wwi->ossdev.fd, &xs, 4);
-
-    /* make sleep time to be # of ms to output a fragment */
-    dwSleepTime = (wwi->dwFragmentSize * 1000) / wwi->waveFormat.Format.nAvgBytesPerSec;
-    TRACE("sleeptime=%d ms\n", dwSleepTime);
-
-    for (;;) {
-	/* wait for dwSleepTime or an event in thread's queue */
-	/* FIXME: could improve wait time depending on queue state,
-	 * ie, number of queued fragments
-	 */
-
-	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
-        {
-            lpWaveHdr = wwi->lpQueuePtr;
-
-	    ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info);
-            TRACE("info={frag=%d fsize=%d ftotal=%d bytes=%d}\n", info.fragments, info.fragsize, info.fragstotal, info.bytes);
-
-            /* read all the fragments accumulated so far */
-            while ((info.fragments > 0) && (wwi->lpQueuePtr))
-            {
-                info.fragments --;
-
-                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded >= wwi->dwFragmentSize)
-                {
-                    /* directly read fragment in wavehdr */
-                    bytesRead = read(wwi->ossdev.fd,
-		      		     lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                                     wwi->dwFragmentSize);
-
-                    TRACE("bytesRead=%d (direct)\n", bytesRead);
-                    if (bytesRead != (DWORD) -1)
-		    {
-			/* update number of bytes recorded in current buffer and by this device */
-                        lpWaveHdr->dwBytesRecorded += bytesRead;
-			wwi->dwTotalRead           += bytesRead;
-			wwi->dwTotalRecorded = wwi->dwTotalRead;
-
-			/* buffer is full. notify client */
-			if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
-			{
-			    /* must copy the value of next waveHdr, because we have no idea of what
-			     * will be done with the content of lpWaveHdr in callback
-			     */
-			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-
-			    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-			    lpWaveHdr->dwFlags |=  WHDR_DONE;
-
-			    wwi->lpQueuePtr = lpNext;
-			    widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-			    lpWaveHdr = lpNext;
-			}
-                    } else {
-                        TRACE("read(%s, %p, %d) failed (%s)\n", wwi->ossdev.dev_name,
-                            lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                            wwi->dwFragmentSize, strerror(errno));
-                    }
-                }
-                else
-		{
-                    /* read the fragment in a local buffer */
-                    bytesRead = read(wwi->ossdev.fd, buffer, wwi->dwFragmentSize);
-                    pOffset = buffer;
-
-                    TRACE("bytesRead=%d (local)\n", bytesRead);
-
-                    if (bytesRead == (DWORD) -1) {
-                        TRACE("read(%s, %p, %d) failed (%s)\n", wwi->ossdev.dev_name,
-                            buffer, wwi->dwFragmentSize, strerror(errno));
-                        continue;
-                    }
-
-                    /* copy data in client buffers */
-                    while (bytesRead != (DWORD) -1 && bytesRead > 0)
-                    {
-                        DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
-
-                        memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                               pOffset,
-                               dwToCopy);
-
-                        /* update number of bytes recorded in current buffer and by this device */
-                        lpWaveHdr->dwBytesRecorded += dwToCopy;
-                        wwi->dwTotalRead           += dwToCopy;
-			wwi->dwTotalRecorded = wwi->dwTotalRead;
-                        bytesRead -= dwToCopy;
-                        pOffset   += dwToCopy;
-
-                        /* client buffer is full. notify client */
-                        if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
-                        {
-			    /* must copy the value of next waveHdr, because we have no idea of what
-			     * will be done with the content of lpWaveHdr in callback
-			     */
-			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-			    TRACE("lpNext=%p\n", lpNext);
-
-                            lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-                            lpWaveHdr->dwFlags |=  WHDR_DONE;
-
-			    wwi->lpQueuePtr = lpNext;
-                            widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-
-			    lpWaveHdr = lpNext;
-			    if (!lpNext && bytesRead) {
-				/* before we give up, check for more header messages */
-				while (OSS_PeekRingMessage(&wwi->msgRing, &msg, &param, &ev))
-				{
-				    if (msg == WINE_WM_HEADER) {
-					LPWAVEHDR hdr;
-					OSS_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev);
-					hdr = ((LPWAVEHDR)param);
-					TRACE("msg = %s, hdr = %p, ev = %p\n", getCmdString(msg), hdr, ev);
-					hdr->lpNext = 0;
-					if (lpWaveHdr == 0) {
-					    /* new head of queue */
-					    wwi->lpQueuePtr = lpWaveHdr = hdr;
-					} else {
-					    /* insert buffer at the end of queue */
-					    LPWAVEHDR*  wh;
-					    for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-					    *wh = hdr;
-					}
-				    } else
-					break;
-				}
-
-				if (lpWaveHdr == 0) {
-                                    /* no more buffer to copy data to, but we did read more.
-                                     * what hasn't been copied will be dropped
-                                     */
-                                    WARN("buffer under run! %u bytes dropped.\n", bytesRead);
-                                    wwi->lpQueuePtr = NULL;
-                                    break;
-				}
-                            }
-                        }
-                    }
-                }
-            }
-	}
-
-	WAIT_OMR(&wwi->msgRing, dwSleepTime);
-
-	while (OSS_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev))
-	{
-            TRACE("msg=%s param=0x%lx\n", getCmdString(msg), param);
-	    switch (msg) {
-	    case WINE_WM_PAUSING:
-		wwi->state = WINE_WS_PAUSED;
-                /*FIXME("Device should stop recording\n");*/
-		SetEvent(ev);
-		break;
-	    case WINE_WM_STARTING:
-		wwi->state = WINE_WS_PLAYING;
-
-                if (wwi->ossdev.bTriggerSupport)
-                {
-                    /* start the recording */
-		    wwi->ossdev.bInputEnabled = TRUE;
-                    enable = getEnables(&wwi->ossdev);
-                    if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-		        wwi->ossdev.bInputEnabled = FALSE;
-                        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev.dev_name, strerror(errno));
-		    }
-                }
-                else
-                {
-                    unsigned char data[4];
-                    /* read 4 bytes to start the recording */
-                    read(wwi->ossdev.fd, data, 4);
-                }
-
-		SetEvent(ev);
-		break;
-	    case WINE_WM_HEADER:
-		lpWaveHdr = (LPWAVEHDR)param;
-		lpWaveHdr->lpNext = 0;
-
-		/* insert buffer at the end of queue */
-		{
-		    LPWAVEHDR*	wh;
-		    for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-		    *wh = lpWaveHdr;
-		}
-		break;
-	    case WINE_WM_STOPPING:
-		if (wwi->state != WINE_WS_STOPPED)
-		{
-                    if (wwi->ossdev.bTriggerSupport)
-                    {
-                        /* stop the recording */
-		        wwi->ossdev.bInputEnabled = FALSE;
-                        enable = getEnables(&wwi->ossdev);
-                        if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-		            wwi->ossdev.bInputEnabled = FALSE;
-                            ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev.dev_name, strerror(errno));
-		        }
-                    }
-
-		    /* read any headers in queue */
-		    widRecorder_ReadHeaders(wwi);
-
-		    /* return current buffer to app */
-		    lpWaveHdr = wwi->lpQueuePtr;
-		    if (lpWaveHdr)
-		    {
-		        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-		        TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
-		        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-		        lpWaveHdr->dwFlags |= WHDR_DONE;
-		        wwi->lpQueuePtr = lpNext;
-		        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-		    }
-		}
-		wwi->state = WINE_WS_STOPPED;
-		SetEvent(ev);
-		break;
-	    case WINE_WM_RESETTING:
-		if (wwi->state != WINE_WS_STOPPED)
-		{
-                    if (wwi->ossdev.bTriggerSupport)
-                    {
-                        /* stop the recording */
-		        wwi->ossdev.bInputEnabled = FALSE;
-                        enable = getEnables(&wwi->ossdev);
-                        if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-		            wwi->ossdev.bInputEnabled = FALSE;
-                            ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev.dev_name, strerror(errno));
-		        }
-                    }
-		}
-		wwi->state = WINE_WS_STOPPED;
-    		wwi->dwTotalRecorded = 0;
-		wwi->dwTotalRead = 0;
-
-		/* read any headers in queue */
-		widRecorder_ReadHeaders(wwi);
-
-		/* return all buffers to the app */
-		while (wwi->lpQueuePtr) {
-		    lpWaveHdr = wwi->lpQueuePtr;
-		    TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
-		    wwi->lpQueuePtr = lpWaveHdr->lpNext;
-		    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-		    lpWaveHdr->dwFlags |= WHDR_DONE;
-		    widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
-		}
-
-		SetEvent(ev);
-		break;
-	    case WINE_WM_UPDATE:
-		if (wwi->state == WINE_WS_PLAYING) {
-		    audio_buf_info tmp_info;
-		    if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &tmp_info) < 0)
-			ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n", wwi->ossdev.dev_name, strerror(errno));
-		    else
-			wwi->dwTotalRecorded = wwi->dwTotalRead + tmp_info.bytes;
-		}
-		SetEvent(ev);
-		break;
-	    case WINE_WM_CLOSING:
-		wwi->hThread = 0;
-		wwi->state = WINE_WS_CLOSED;
-		SetEvent(ev);
-		HeapFree(GetProcessHeap(), 0, buffer);
-		ExitThread(0);
-		/* shouldn't go here */
-	    default:
-		FIXME("unknown message %d\n", msg);
-		break;
-	    }
-	}
-    }
-    ExitThread(0);
-    /* just for not generating compilation warnings... should never be executed */
-    return 0;
-}
-
-
-/**************************************************************************
- * 				widOpen				[internal]
- */
-static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
-{
-    WINE_WAVEIN*	wwi;
-    audio_buf_info      info;
-    int                 audio_fragment;
-    DWORD               ret;
-
-    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
-    if (lpDesc == NULL) {
-	WARN("Invalid Parameter !\n");
-	return MMSYSERR_INVALPARAM;
-    }
-    if (wDevID >= numInDev) {
-        WARN("bad device id: %d >= %d\n", wDevID, numInDev);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    /* only PCM format is supported so far... */
-    if (!supportedFormat(lpDesc->lpFormat)) {
-	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return WAVERR_BADFORMAT;
-    }
-
-    if (dwFlags & WAVE_FORMAT_QUERY) {
-	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
-	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
-	     lpDesc->lpFormat->nSamplesPerSec);
-	return MMSYSERR_NOERROR;
-    }
-
-    /* nBlockAlign and nAvgBytesPerSec are output variables for dsound */
-    if (lpDesc->lpFormat->nBlockAlign != lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8) {
-        lpDesc->lpFormat->nBlockAlign  = lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
-        WARN("Fixing nBlockAlign\n");
-    }
-    if (lpDesc->lpFormat->nAvgBytesPerSec!= lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign) {
-        lpDesc->lpFormat->nAvgBytesPerSec = lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
-        WARN("Fixing nAvgBytesPerSec\n");
-    }
-
-    TRACE("OSS_OpenDevice requested this format: %dx%dx%d %s\n",
-          lpDesc->lpFormat->nSamplesPerSec,
-          lpDesc->lpFormat->wBitsPerSample,
-          lpDesc->lpFormat->nChannels,
-          lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM ? "WAVE_FORMAT_PCM" :
-          lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? "WAVE_FORMAT_EXTENSIBLE" :
-          "UNSUPPORTED");
-
-    wwi = &WInDev[wDevID];
-
-    if (wwi->state != WINE_WS_CLOSED) return MMSYSERR_ALLOCATED;
-
-    if ((dwFlags & WAVE_DIRECTSOUND) &&
-        !(wwi->ossdev.in_caps_support & WAVECAPS_DIRECTSOUND))
-	/* not supported, ignore it */
-	dwFlags &= ~WAVE_DIRECTSOUND;
-
-    if (dwFlags & WAVE_DIRECTSOUND) {
-	TRACE("has DirectSoundCapture driver\n");
-        if (wwi->ossdev.in_caps_support & WAVECAPS_SAMPLEACCURATE)
-	    /* we have realtime DirectSound, fragments just waste our time,
-	     * but a large buffer is good, so choose 64KB (32 * 2^11) */
-	    audio_fragment = 0x0020000B;
-	else
-	    /* to approximate realtime, we must use small fragments,
-	     * let's try to fragment the above 64KB (256 * 2^8) */
-	    audio_fragment = 0x01000008;
-    } else {
-	TRACE("doesn't have DirectSoundCapture driver\n");
-	if (wwi->ossdev.open_count > 0) {
-	    TRACE("Using output device audio_fragment\n");
-	    /* FIXME: This may not be optimal for capture but it allows us
-	     * to do hardware playback without hardware capture. */
-	    audio_fragment = wwi->ossdev.audio_fragment;
-	} else {
-	    /* A wave device must have a worst case latency of 10 ms so calculate
-	     * the largest fragment size less than 10 ms long.
-	     */
-	    int	fsize = lpDesc->lpFormat->nAvgBytesPerSec / 100;	/* 10 ms chunk */
-	    int	shift = 0;
-	    while ((1 << shift) <= fsize)
-		shift++;
-	    shift--;
-	    audio_fragment = 0x00100000 + shift;	/* 16 fragments of 2^shift */
-	}
-    }
-
-    TRACE("requesting %d %d byte fragments (%d ms)\n", audio_fragment >> 16,
-	1 << (audio_fragment & 0xffff),
-	((1 << (audio_fragment & 0xffff)) * 1000) / lpDesc->lpFormat->nAvgBytesPerSec);
-
-    ret = OSS_OpenDevice(&wwi->ossdev, O_RDONLY, &audio_fragment,
-                         1,
-                         lpDesc->lpFormat->nSamplesPerSec,
-                         lpDesc->lpFormat->nChannels,
-                         (lpDesc->lpFormat->wBitsPerSample == 16)
-                         ? AFMT_S16_LE : AFMT_U8);
-    if (ret != 0) return ret;
-    wwi->state = WINE_WS_STOPPED;
-
-    if (wwi->lpQueuePtr) {
-	WARN("Should have an empty queue (%p)\n", wwi->lpQueuePtr);
-	wwi->lpQueuePtr = NULL;
-    }
-    wwi->dwTotalRecorded = 0;
-    wwi->dwTotalRead = 0;
-    wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-
-    wwi->waveDesc = *lpDesc;
-    copy_format(lpDesc->lpFormat, &wwi->waveFormat);
-
-    if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
-            wwi->ossdev.dev_name, strerror(errno));
-        OSS_CloseDevice(&wwi->ossdev);
-	wwi->state = WINE_WS_CLOSED;
-	return MMSYSERR_NOTENABLED;
-    }
-
-    TRACE("got %d %d byte fragments (%d ms/fragment)\n", info.fragstotal,
-        info.fragsize, (info.fragsize * 1000) / (wwi->ossdev.sample_rate *
-        wwi->ossdev.channels * (wwi->ossdev.format == AFMT_U8 ? 1 : 2)));
-
-    wwi->dwFragmentSize = info.fragsize;
-
-    TRACE("dwFragmentSize=%u\n", wwi->dwFragmentSize);
-    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
-	  wwi->waveFormat.Format.wBitsPerSample, wwi->waveFormat.Format.nAvgBytesPerSec,
-	  wwi->waveFormat.Format.nSamplesPerSec, wwi->waveFormat.Format.nChannels,
-	  wwi->waveFormat.Format.nBlockAlign);
-
-    OSS_InitRingMessage(&wwi->msgRing);
-
-    wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwi->dwThreadID));
-    if (wwi->hThread)
-        SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL);
-    WaitForSingleObject(wwi->hStartUpEvent, INFINITE);
-    CloseHandle(wwi->hStartUpEvent);
-    wwi->hStartUpEvent = INVALID_HANDLE_VALUE;
-
-    widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widClose			[internal]
- */
-static DWORD widClose(WORD wDevID)
-{
-    WINE_WAVEIN*	wwi;
-
-    TRACE("(%u);\n", wDevID);
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't close !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-
-    wwi = &WInDev[wDevID];
-
-    if (wwi->lpQueuePtr != NULL) {
-	WARN("still buffers open !\n");
-	return WAVERR_STILLPLAYING;
-    }
-
-    OSS_AddRingMessage(&wwi->msgRing, WINE_WM_CLOSING, 0, TRUE);
-    OSS_CloseDevice(&wwi->ossdev);
-    wwi->state = WINE_WS_CLOSED;
-    wwi->dwFragmentSize = 0;
-    OSS_DestroyRingMessage(&wwi->msgRing);
-    widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widAddBuffer		[internal]
- */
-static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
-{
-    TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
-
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't do it !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-    if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
-	TRACE("never been prepared !\n");
-	return WAVERR_UNPREPARED;
-    }
-    if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
-	TRACE("header already in use !\n");
-	return WAVERR_STILLPLAYING;
-    }
-
-    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
-    lpWaveHdr->dwFlags &= ~WHDR_DONE;
-    lpWaveHdr->dwBytesRecorded = 0;
-    lpWaveHdr->lpNext = NULL;
-
-    OSS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD_PTR)lpWaveHdr, FALSE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			widStart				[internal]
- */
-static DWORD widStart(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't start recording !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-
-    OSS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STARTING, 0, TRUE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			widStop					[internal]
- */
-static DWORD widStop(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't stop !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-
-    OSS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STOPPING, 0, TRUE);
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			widReset				[internal]
- */
-static DWORD widReset(WORD wDevID)
-{
-    TRACE("(%u);\n", wDevID);
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't reset !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-    OSS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widGetPosition			[internal]
- */
-static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
-{
-    WINE_WAVEIN*	wwi;
-
-    TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
-
-    if (wDevID >= numInDev || WInDev[wDevID].state == WINE_WS_CLOSED) {
-	WARN("can't get pos !\n");
-	return MMSYSERR_INVALHANDLE;
-    }
-
-    if (lpTime == NULL) {
-	WARN("invalid parameter: lpTime == NULL\n");
-	return MMSYSERR_INVALPARAM;
-    }
-
-    wwi = &WInDev[wDevID];
-#ifdef EXACT_WIDPOSITION
-    if (wwi->ossdev.in_caps_support & WAVECAPS_SAMPLEACCURATE)
-        OSS_AddRingMessage(&(wwi->msgRing), WINE_WM_UPDATE, 0, TRUE);
-#endif
-
-    return bytes_to_mmtime(lpTime, wwi->dwTotalRecorded, &wwi->waveFormat);
-}
-
-/**************************************************************************
- * 				widMessage (WINEOSS.6)
- */
-DWORD WINAPI OSS_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser,
-			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("(%u, %s, %08lX, %08lX, %08lX);\n",
-	  wDevID, getMessage(wMsg), dwUser, dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case DRVM_INIT:
-        return OSS_WaveInit();
-    case DRVM_EXIT:
-        return OSS_WaveExit();
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
-    case WIDM_OPEN:		return widOpen       (wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
-    case WIDM_CLOSE:		return widClose      (wDevID);
-    case WIDM_ADDBUFFER:	return widAddBuffer  (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
-    case WIDM_PREPARE:		return MMSYSERR_NOTSUPPORTED;
-    case WIDM_UNPREPARE:	return MMSYSERR_NOTSUPPORTED;
-    case WIDM_GETDEVCAPS:	return widGetDevCaps (wDevID, (LPWAVEINCAPSW)dwParam1, dwParam2);
-    case WIDM_GETNUMDEVS:	return numInDev;
-    case WIDM_GETPOS:		return widGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2);
-    case WIDM_RESET:		return widReset      (wDevID);
-    case WIDM_START:		return widStart      (wDevID);
-    case WIDM_STOP:		return widStop       (wDevID);
-    case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize      (wDevID, (LPDWORD)dwParam1);
-    case DRV_QUERYDEVICEINTERFACE:     return widDevInterface          (wDevID, (PWCHAR)dwParam1, dwParam2);
-    case DRV_QUERYDSOUNDIFACE:	return widDsCreate   (wDevID, (PIDSCDRIVER*)dwParam1);
-    case DRV_QUERYDSOUNDDESC:	return widDsDesc     (wDevID, (PDSDRIVERDESC)dwParam1);
-    default:
-	FIXME("unknown message %u!\n", wMsg);
-    }
-    return MMSYSERR_NOTSUPPORTED;
-}
-
-/**************************************************************************
- * 				DriverProc (WINEOSS.1)
- */
-LRESULT CALLBACK OSS_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
-                                LPARAM dwParam1, LPARAM dwParam2)
-{
-     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
-           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
-
-    switch(wMsg) {
-    case DRV_LOAD:
-    case DRV_FREE:
-    case DRV_OPEN:
-    case DRV_CLOSE:
-    case DRV_ENABLE:
-    case DRV_DISABLE:
-    case DRV_QUERYCONFIGURE:
-        return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "OSS MultiMedia Driver !", "OSS Driver", MB_OK);	return 1;
-    case DRV_INSTALL:
-    case DRV_REMOVE:
-        return DRV_SUCCESS;
-    default:
-	return 0;
-    }
-}
diff --git a/dlls/wineoss.drv/audio.h b/dlls/wineoss.drv/audio.h
deleted file mode 100644
index c917196..0000000
--- a/dlls/wineoss.drv/audio.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
- *
- * Copyright 1994 Martin Ayotte
- *           1999 Eric Pouech (async playing in waveOut/waveIn)
- *	     2000 Eric Pouech (loops in waveOut)
- *           2002 Eric Pouech (full duplex)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __WINE_CONFIG_H
-# error You must include config.h to use this header
-#endif
-
-/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
-#define USE_PIPE_SYNC
-
-#define MAX_WAVEDRV 	(6)
-#define MAX_CHANNELS	6
-
-/* states of the playing device */
-#define	WINE_WS_PLAYING		0
-#define	WINE_WS_PAUSED		1
-#define	WINE_WS_STOPPED		2
-#define WINE_WS_CLOSED		3
-
-/* events to be send to device */
-enum win_wm_message {
-    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
-    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
-};
-
-#ifdef USE_PIPE_SYNC
-#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
-#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
-#define RESET_OMR(omr) do { } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
-       pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
-#else
-#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
-#define CLEAR_OMR(omr) do { } while (0)
-#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
-#endif
-
-typedef struct {
-    enum win_wm_message 	msg;	/* message identifier */
-    DWORD_PTR                   param;  /* parameter for this message */
-    HANDLE	                hEvent;	/* if message is synchronous, handle of event for synchro */
-} OSS_MSG;
-
-/* implement an in-process message ring for better performance
- * (compared to passing thru the server)
- * this ring will be used by the input (resp output) record (resp playback) routine
- */
-#define OSS_RING_BUFFER_INCREMENT	64
-typedef struct {
-    int                         ring_buffer_size;
-    OSS_MSG			* messages;
-    int				msg_tosave;
-    int				msg_toget;
-#ifdef USE_PIPE_SYNC
-    int				msg_pipe[2];
-#else
-    HANDLE			msg_event;
-#endif
-    CRITICAL_SECTION		msg_crst;
-} OSS_MSG_RING;
-
-typedef struct tagOSS_DEVICE {
-    char*                       dev_name;
-    char*                       mixer_name;
-    char*                       interface_name;
-    unsigned                    open_count;
-    WAVEOUTCAPSW                out_caps;
-    WAVEOUTCAPSW                duplex_out_caps;
-    WAVEINCAPSW                 in_caps;
-    DWORD                       in_caps_support;
-    unsigned                    open_access;
-    int                         fd;
-    DWORD                       owner_tid;
-    int                         sample_rate;
-    int                         channels;
-    int                         format;
-    unsigned                    audio_fragment;
-    BOOL                        full_duplex;
-    BOOL                        bTriggerSupport;
-    BOOL                        bOutputEnabled;
-    BOOL                        bInputEnabled;
-    DSDRIVERDESC                ds_desc;
-    DSDRIVERCAPS                ds_caps;
-    DSCDRIVERCAPS               dsc_caps;
-} OSS_DEVICE;
-
-typedef struct {
-    OSS_DEVICE ossdev;
-    volatile int		state;			/* one of the WINE_WS_ manifest constants */
-    WAVEOPENDESC		waveDesc;
-    WORD			wFlags;
-    WAVEFORMATPCMEX             waveFormat;
-    DWORD			volume;
-
-    /* OSS information */
-    DWORD			dwFragmentSize;		/* size of OSS buffer fragment */
-    DWORD                       dwBufferSize;           /* size of whole OSS buffer in bytes */
-    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
-    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
-    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
-
-    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
-    DWORD			dwLoops;		/* private copy of loop counter */
-
-    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */
-    DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
-    BOOL                        bNeedPost;              /* whether audio still needs to be physically started */
-
-    /* synchronization stuff */
-    HANDLE			hStartUpEvent;
-    HANDLE			hThread;
-    DWORD			dwThreadID;
-    OSS_MSG_RING		msgRing;
-
-    /* make accommodation for the inaccuracy of OSS when reporting buffer size remaining by using the clock instead of GETOSPACE */
-    DWORD                       dwProjectedFinishTime;
-
-} WINE_WAVEOUT;
-
-typedef struct {
-    OSS_DEVICE ossdev;
-    volatile int		state;
-    DWORD			dwFragmentSize;		/* OpenSound '/dev/dsp' give us that size */
-    WAVEOPENDESC		waveDesc;
-    WORD			wFlags;
-    WAVEFORMATPCMEX             waveFormat;
-    LPWAVEHDR			lpQueuePtr;
-    DWORD			dwTotalRecorded;
-    DWORD			dwTotalRead;
-
-    /* synchronization stuff */
-    HANDLE			hThread;
-    DWORD			dwThreadID;
-    HANDLE			hStartUpEvent;
-    OSS_MSG_RING		msgRing;
-} WINE_WAVEIN;
-
-extern WINE_WAVEOUT	WOutDev[MAX_WAVEDRV] DECLSPEC_HIDDEN;
-extern WINE_WAVEIN	WInDev[MAX_WAVEDRV] DECLSPEC_HIDDEN;
-extern unsigned         numOutDev DECLSPEC_HIDDEN;
-extern unsigned         numInDev DECLSPEC_HIDDEN;
-
-extern int getEnables(OSS_DEVICE *ossdev) DECLSPEC_HIDDEN;
-extern void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2) DECLSPEC_HIDDEN;
-
-extern DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
-                            int* frag, int strict_format,
-                            int sample_rate, int stereo, int fmt) DECLSPEC_HIDDEN;
-
-extern void OSS_CloseDevice(OSS_DEVICE* ossdev) DECLSPEC_HIDDEN;
-
-extern DWORD wodSetVolume(WORD wDevID, DWORD dwParam) DECLSPEC_HIDDEN;
-
-/* dscapture.c */
-extern DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv) DECLSPEC_HIDDEN;
-extern DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc) DECLSPEC_HIDDEN;
-
-/* dsrender.c */
-extern DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv) DECLSPEC_HIDDEN;
-extern DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc) DECLSPEC_HIDDEN;
diff --git a/dlls/wineoss.drv/dscapture.c b/dlls/wineoss.drv/dscapture.c
deleted file mode 100644
index ca1f337..0000000
--- a/dlls/wineoss.drv/dscapture.c
+++ /dev/null
@@ -1,1330 +0,0 @@
-/*
- * Direct Sound Capture driver
- *
- * Copyright 2004 Robert Reif
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <sys/soundcard.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winerror.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "wine/debug.h"
-
-#include "audio.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(dscapture);
-
-/*======================================================================*
- *           Low level DSOUND capture definitions                       *
- *======================================================================*/
-
-typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
-typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
-typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
-typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
-
-struct IDsCaptureDriverPropertySetImpl
-{
-    /* IUnknown fields */
-    IDsDriverPropertySet                IDsDriverPropertySet_iface;
-    LONG                                ref;
-
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverNotifyImpl
-{
-    /* IUnknown fields */
-    IDsDriverNotify                     IDsDriverNotify_iface;
-    LONG                                ref;
-
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverImpl
-{
-    /* IUnknown fields */
-    IDsCaptureDriver                    IDsCaptureDriver_iface;
-    LONG                                ref;
-
-    /* IDsCaptureDriverImpl fields */
-    UINT                                wDevID;
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverBufferImpl
-{
-    /* IUnknown fields */
-    IDsCaptureDriverBuffer              IDsCaptureDriverBuffer_iface;
-    LONG                                ref;
-
-    /* IDsCaptureDriverBufferImpl fields */
-    IDsCaptureDriverImpl*               drv;
-    LPBYTE                              buffer;         /* user buffer */
-    DWORD                               buflen;         /* user buffer length */
-    LPBYTE                              mapping;        /* DMA buffer */
-    DWORD                               maplen;         /* DMA buffer length */
-    BOOL                                is_direct_map;  /* DMA == user ? */
-    DWORD                               fragsize;
-    DWORD                               map_writepos;   /* DMA write offset */
-    DWORD                               map_readpos;    /* DMA read offset */
-    DWORD                               writeptr;       /* user write offset */
-    DWORD                               readptr;        /* user read offset */
-
-    /* IDsDriverNotifyImpl fields */
-    IDsCaptureDriverNotifyImpl*         notify;
-    int                                 notify_index;
-    LPDSBPOSITIONNOTIFY                 notifies;
-    int                                 nrofnotifies;
-
-    /* IDsDriverPropertySetImpl fields */
-    IDsCaptureDriverPropertySetImpl*    property_set;
-
-    BOOL                                is_capturing;
-    BOOL                                is_looping;
-    WAVEFORMATEX                        wfx;
-    HANDLE                              hThread;
-    DWORD                               dwThreadID;
-    HANDLE                              hStartUpEvent;
-    HANDLE                              hExitEvent;
-    int                                 pipe_fd[2];
-    int                                 fd;
-};
-
-static inline IDsCaptureDriverPropertySetImpl *impl_from_IDsDriverPropertySet(IDsDriverPropertySet *iface)
-{
-    return CONTAINING_RECORD(iface, IDsCaptureDriverPropertySetImpl, IDsDriverPropertySet_iface);
-}
-
-static inline IDsCaptureDriverNotifyImpl *impl_from_IDsDriverNotify(IDsDriverNotify *iface)
-{
-    return CONTAINING_RECORD(iface, IDsCaptureDriverNotifyImpl, IDsDriverNotify_iface);
-}
-
-static inline IDsCaptureDriverImpl *impl_from_IDsCaptureDriver(IDsCaptureDriver *iface)
-{
-    return CONTAINING_RECORD(iface, IDsCaptureDriverImpl, IDsCaptureDriver_iface);
-}
-
-static inline IDsCaptureDriverBufferImpl *impl_from_IDsCaptureDriverBuffer(IDsCaptureDriverBuffer *iface)
-{
-    return CONTAINING_RECORD(iface, IDsCaptureDriverBufferImpl, IDsCaptureDriverBuffer_iface);
-}
-
-static HRESULT IDsCaptureDriverPropertySetImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverPropertySetImpl **pdscdps);
-
-static HRESULT IDsCaptureDriverNotifyImpl_Create(
-    IDsCaptureDriverBufferImpl * dsdcb,
-    IDsCaptureDriverNotifyImpl **pdscdn);
-
-/*======================================================================*
- *           Low level DSOUND capture property set implementation       *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
-    PIDSDRIVERPROPERTYSET iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
-        IDsDriverPropertySet_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
-    PIDSDRIVERPROPERTYSET iface)
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
-    PIDSDRIVERPROPERTYSET iface)
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
-        This->capture_buffer->property_set = NULL;
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData,
-    PULONG pcbReturnedData )
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,
-          cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData )
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,
-          cbPropertyParams,pPropertyData,cbPropertyData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
-    PIDSDRIVERPROPERTYSET iface,
-    REFGUID PropertySetId,
-    ULONG PropertyId,
-    PULONG pSupport )
-{
-    IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
-    FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
-          pSupport);
-    return DSERR_UNSUPPORTED;
-}
-
-static const IDsDriverPropertySetVtbl dscdpsvt =
-{
-    IDsCaptureDriverPropertySetImpl_QueryInterface,
-    IDsCaptureDriverPropertySetImpl_AddRef,
-    IDsCaptureDriverPropertySetImpl_Release,
-    IDsCaptureDriverPropertySetImpl_Get,
-    IDsCaptureDriverPropertySetImpl_Set,
-    IDsCaptureDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- *                  Low level DSOUND capture notify implementation      *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
-    PIDSDRIVERNOTIFY iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
-        IDsDriverNotify_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
-    PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
-    PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
-        This->capture_buffer->notify = NULL;
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
-    PIDSDRIVERNOTIFY iface,
-    DWORD howmuch,
-    LPCDSBPOSITIONNOTIFY notify)
-{
-    IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
-    TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
-
-    if (!notify) {
-        WARN("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (TRACE_ON(dscapture)) {
-        DWORD i;
-        for (i=0;i<howmuch;i++)
-            TRACE("notify at %d to 0x%08lx\n",
-                notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
-    }
-
-    /* Make an internal copy of the caller-supplied array.
-     * Replace the existing copy if one is already present. */
-    if (This->capture_buffer->notifies)
-        This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
-            HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
-            howmuch * sizeof(DSBPOSITIONNOTIFY));
-    else
-        This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
-            HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
-
-    memcpy(This->capture_buffer->notifies, notify,
-           howmuch * sizeof(DSBPOSITIONNOTIFY));
-    This->capture_buffer->nrofnotifies = howmuch;
-
-    return S_OK;
-}
-
-static const IDsDriverNotifyVtbl dscdnvt =
-{
-    IDsCaptureDriverNotifyImpl_QueryInterface,
-    IDsCaptureDriverNotifyImpl_AddRef,
-    IDsCaptureDriverNotifyImpl_Release,
-    IDsCaptureDriverNotifyImpl_SetNotificationPositions,
-};
-
-/*======================================================================*
- *                  Low level DSOUND capture implementation             *
- *======================================================================*/
-
-static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
-    if (!dscdb->mapping) {
-        dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
-                              WInDev[dscdb->drv->wDevID].ossdev.fd, 0);
-        if (dscdb->mapping == (LPBYTE)-1) {
-            TRACE("(%p): Could not map sound device for direct access (%s)\n",
-                  dscdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        TRACE("(%p): sound device has been mapped for direct access at %p, "
-              "size=%d\n", dscdb, dscdb->mapping, dscdb->maplen);
-    }
-    return DS_OK;
-}
-
-static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
-    if (dscdb->mapping) {
-        if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
-            ERR("(%p): Could not unmap sound device (%s)\n",
-                dscdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        dscdb->mapping = NULL;
-        TRACE("(%p): sound device unmapped\n", dscdb);
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
-    PIDSCDRIVERBUFFER iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    *ppobj = 0;
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
-        IDsCaptureDriverBuffer_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
-        if (!This->notify)
-            IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
-        if (This->notify) {
-            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-            *ppobj = This->notify;
-            return DS_OK;
-        }
-        return E_FAIL;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
-        if (!This->property_set)
-            IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
-        if (This->property_set) {
-            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
-            *ppobj = This->property_set;
-            return DS_OK;
-        }
-        return E_FAIL;
-    }
-
-    FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        WINE_WAVEIN*        wwi;
-
-        wwi = &WInDev[This->drv->wDevID];
-
-        if (This->hThread) {
-            int x = 0;
-
-            /* request thread termination */
-            write(This->pipe_fd[1], &x, sizeof(x));
-
-            /* wait for reply */
-            WaitForSingleObject(This->hExitEvent, INFINITE);
-            CloseHandle(This->hExitEvent);
-        }
-
-        close(This->pipe_fd[0]);
-        close(This->pipe_fd[1]);
-
-        DSCDB_UnmapBuffer(This);
-
-        OSS_CloseDevice(&wwi->ossdev);
-        wwi->state = WINE_WS_CLOSED;
-        wwi->dwFragmentSize = 0;
-        This->drv->capture_buffer = NULL;
-
-        HeapFree(GetProcessHeap(), 0, This->notifies);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
-    PIDSCDRIVERBUFFER iface,
-    LPVOID* ppvAudio1,
-    LPDWORD pdwLen1,
-    LPVOID* ppvAudio2,
-    LPDWORD pdwLen2,
-    DWORD dwWritePosition,
-    DWORD dwWriteLen,
-    DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n",This,ppvAudio1,pdwLen1,
-          ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
-
-    if (This->is_direct_map) {
-        if (ppvAudio1)
-            *ppvAudio1 = This->mapping + dwWritePosition;
-
-        if (dwWritePosition + dwWriteLen < This->maplen) {
-            if (pdwLen1)
-                *pdwLen1 = dwWriteLen;
-            if (ppvAudio2)
-                *ppvAudio2 = 0;
-            if (pdwLen2)
-                *pdwLen2 = 0;
-        } else {
-            if (pdwLen1)
-                *pdwLen1 = This->maplen - dwWritePosition;
-            if (ppvAudio2)
-                *ppvAudio2 = 0;
-            if (pdwLen2)
-                *pdwLen2 = dwWriteLen - (This->maplen - dwWritePosition);
-        }
-    } else {
-        if (ppvAudio1)
-            *ppvAudio1 = This->buffer + dwWritePosition;
-
-        if (dwWritePosition + dwWriteLen < This->buflen) {
-            if (pdwLen1)
-                *pdwLen1 = dwWriteLen;
-            if (ppvAudio2)
-                *ppvAudio2 = 0;
-            if (pdwLen2)
-                *pdwLen2 = 0;
-        } else {
-            if (pdwLen1)
-                *pdwLen1 = This->buflen - dwWritePosition;
-            if (ppvAudio2)
-                *ppvAudio2 = 0;
-            if (pdwLen2)
-                *pdwLen2 = dwWriteLen - (This->buflen - dwWritePosition);
-        }
-    }
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
-    PIDSCDRIVERBUFFER iface,
-    LPVOID pvAudio1,
-    DWORD dwLen1,
-    LPVOID pvAudio2,
-    DWORD dwLen2)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
-
-    if (This->is_direct_map)
-        This->map_readpos = (This->map_readpos + dwLen1 + dwLen2) % This->maplen;
-    else
-        This->readptr = (This->readptr + dwLen1 + dwLen2) % This->buflen;
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
-    PIDSCDRIVERBUFFER iface,
-    LPDWORD lpdwCapture,
-    LPDWORD lpdwRead)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
-
-    if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
-        ERR("device not open, but accessing?\n");
-        return DSERR_UNINITIALIZED;
-    }
-
-    if (!This->is_capturing) {
-        if (lpdwCapture)
-            *lpdwCapture = 0;
-        if (lpdwRead)
-            *lpdwRead = 0;
-    }
-
-    if (This->is_direct_map) {
-        if (lpdwCapture)
-            *lpdwCapture = This->map_writepos;
-        if (lpdwRead) {
-            *lpdwRead = This->map_readpos;
-        }
-    } else {
-        if (lpdwCapture)
-            *lpdwCapture = This->writeptr;
-        if (lpdwRead)
-            *lpdwRead = This->readptr;
-    }
-
-    TRACE("capturepos=%d, readpos=%d\n", lpdwCapture?*lpdwCapture:0,
-          lpdwRead?*lpdwRead:0);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
-    PIDSCDRIVERBUFFER iface,
-    LPDWORD lpdwStatus)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    TRACE("(%p,%p)\n",This,lpdwStatus);
-
-    if (This->is_capturing) {
-        if (This->is_looping)
-            *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
-        else
-            *lpdwStatus = DSCBSTATUS_CAPTURING;
-    } else
-        *lpdwStatus = 0;
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
-    PIDSCDRIVERBUFFER iface,
-    DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    int enable;
-    TRACE("(%p,%x)\n",This,dwFlags);
-
-    if (This->is_capturing)
-        return DS_OK;
-
-    if (dwFlags & DSCBSTART_LOOPING)
-        This->is_looping = TRUE;
-
-    WInDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
-    enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
-    if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        if (errno == EINVAL) {
-            /* Don't give up yet. OSS trigger support is inconsistent. */
-            if (WInDev[This->drv->wDevID].ossdev.open_count == 1) {
-                /* try the opposite output enable */
-                if (WInDev[This->drv->wDevID].ossdev.bOutputEnabled == FALSE)
-                    WInDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
-                else
-                    WInDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
-                /* try it again */
-                enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
-                if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
-                    This->is_capturing = TRUE;
-                    return DS_OK;
-                }
-            }
-        }
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-        WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
-        return DSERR_GENERIC;
-    }
-
-    This->is_capturing = TRUE;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    int enable;
-    TRACE("(%p)\n",This);
-
-    if (!This->is_capturing)
-        return DS_OK;
-
-    /* no more capturing */
-    WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
-    enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
-    if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WInDev[This->drv->wDevID].ossdev.dev_name,  strerror(errno));
-        return DSERR_GENERIC;
-    }
-
-    /* send a final event if necessary */
-    if (This->nrofnotifies > 0) {
-        if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
-            SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
-    }
-
-    This->is_capturing = FALSE;
-    This->is_looping = FALSE;
-
-    if (This->hThread) {
-        int x = 0;
-        write(This->pipe_fd[1], &x, sizeof(x));
-        WaitForSingleObject(This->hExitEvent, INFINITE);
-        CloseHandle(This->hExitEvent);
-        This->hExitEvent = INVALID_HANDLE_VALUE;
-        This->hThread = 0;
-    }
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
-    PIDSCDRIVERBUFFER iface,
-    LPWAVEFORMATEX pwfx)
-{
-    IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
-    FIXME("(%p): stub!\n",This);
-    return DSERR_UNSUPPORTED;
-}
-
-static const IDsCaptureDriverBufferVtbl dscdbvt =
-{
-    IDsCaptureDriverBufferImpl_QueryInterface,
-    IDsCaptureDriverBufferImpl_AddRef,
-    IDsCaptureDriverBufferImpl_Release,
-    IDsCaptureDriverBufferImpl_Lock,
-    IDsCaptureDriverBufferImpl_Unlock,
-    IDsCaptureDriverBufferImpl_SetFormat,
-    IDsCaptureDriverBufferImpl_GetPosition,
-    IDsCaptureDriverBufferImpl_GetStatus,
-    IDsCaptureDriverBufferImpl_Start,
-    IDsCaptureDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
-    PIDSCDRIVER iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
-        IDsCaptureDriver_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
-    PIDSCDRIVER iface,
-    PDSDRIVERDESC pDesc)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    TRACE("(%p,%p)\n",This,pDesc);
-
-    if (!pDesc) {
-        TRACE("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    /* copy version from driver */
-    *pDesc = WInDev[This->wDevID].ossdev.ds_desc;
-
-    pDesc->dnDevNode            = WInDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId               = 0;
-    pDesc->wReserved            = 0;
-    pDesc->ulDeviceNum          = This->wDevID;
-    pDesc->dwHeapType           = DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap     = NULL;
-    pDesc->dwMemStartAddress    = 0;
-    pDesc->dwMemEndAddress      = 0;
-    pDesc->dwMemAllocExtra      = 0;
-    pDesc->pvReserved1          = NULL;
-    pDesc->pvReserved2          = NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    TRACE("(%p)\n",This);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    TRACE("(%p)\n",This);
-    if (This->capture_buffer) {
-        ERR("problem with DirectSound: capture buffer not released\n");
-        return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
-    PIDSCDRIVER iface,
-    PDSCDRIVERCAPS pCaps)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    TRACE("(%p,%p)\n",This,pCaps);
-    *pCaps = WInDev[This->wDevID].ossdev.dsc_caps;
-    return DS_OK;
-}
-
-static void DSCDB_CheckEvent(
-    IDsCaptureDriverBufferImpl *dscb,
-    DWORD writepos,
-    DWORD len,
-    DWORD buflen)
-{
-    LPDSBPOSITIONNOTIFY event = dscb->notifies + dscb->notify_index;
-    DWORD offset = event->dwOffset;
-    TRACE("(%p,%d,%d,%d)\n", dscb, writepos, len, buflen);
-
-    TRACE("(%p) buflen = %d, writeptr = %d\n",
-        dscb, dscb->buflen, dscb->writeptr);
-    TRACE("checking %d, position %d, event = %p\n",
-        dscb->notify_index, offset, event->hEventNotify);
-
-    if ((writepos + len) > offset) {
-         TRACE("signalled event %p (%d) %d\n",
-               event->hEventNotify, dscb->notify_index, offset);
-         SetEvent(event->hEventNotify);
-         dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
-         return;
-    } else if ((writepos + len) > buflen) {
-        writepos = writepos + len - buflen;
-        if ((writepos + len) > offset) {
-             TRACE("signalled event %p (%d) %d\n",
-                   event->hEventNotify, dscb->notify_index, offset);
-             SetEvent(event->hEventNotify);
-             dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
-             return;
-        }
-    }
-
-    return;
-}
-
-/* FIXME: using memcpy can cause strange crashes so use this fake one */
-static void * my_memcpy(void * dst, const void * src, int length)
-{
-    int i;
-    for (i = 0; i < length; i++)
-        ((char *)dst)[i] = ((const char *)src)[i];
-    return dst;
-}
-
-static DWORD CALLBACK DSCDB_Thread(LPVOID lpParameter)
-{
-    IDsCaptureDriverBufferImpl *This = lpParameter;
-    struct pollfd poll_list[2];
-    int retval;
-    DWORD offset = 0;
-    DWORD map_offset = 0;
-    TRACE("(%p)\n", lpParameter);
-
-    poll_list[0].fd = This->fd;                /* data available */
-    poll_list[1].fd = This->pipe_fd[0];        /* message from parent process */
-    poll_list[0].events = POLLIN;
-    poll_list[1].events = POLLIN;
-
-    /* let other process know we are running */
-    SetEvent(This->hStartUpEvent);
-
-    while (1) {
-        /* wait for something to happen */
-        retval = poll(poll_list,(unsigned long)2,-1);
-        /* Retval will always be greater than 0 or -1 in this case.
-         * Since we're doing it while blocking
-         */
-        if (retval < 0) {
-            ERR("Error while polling: %s\n",strerror(errno));
-            continue;
-        }
-
-        /* check for exit command */
-        if ((poll_list[1].revents & POLLIN) == POLLIN) {
-            TRACE("(%p) done\n", lpParameter);
-            /* acknowledge command and exit */
-            SetEvent(This->hExitEvent);
-            ExitThread(0);
-            return 0;
-        }
-
-        /* check for data */
-        if ((poll_list[0].revents & POLLIN) == POLLIN) {
-            count_info info;
-            int fragsize, first, second;
-
-            /* get the current DMA position */
-            if (ioctl(This->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
-                ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
-                    WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-                return DSERR_GENERIC;
-            }
-
-            if (This->is_direct_map) {
-                offset = This->map_writepos;
-                This->map_writepos = info.ptr;
-
-                if (info.ptr < offset)
-                    fragsize = info.ptr + This->maplen - offset;
-                else
-                    fragsize = info.ptr - offset;
-
-                DSCDB_CheckEvent(This, offset, fragsize, This->maplen);
-            } else {
-                map_offset = This->map_writepos;
-                offset = This->writeptr;
-
-                /* test for mmap buffer wrap */
-                if (info.ptr < map_offset) {
-                    /* mmap buffer wrapped */
-                    fragsize = info.ptr + This->maplen - map_offset;
-
-                    /* check for user buffer wrap */
-                    if ((offset + fragsize) > This->buflen) {
-                        /* both buffers wrapped
-                         * figure out which wrapped first
-                         */
-                        if ((This->maplen - map_offset) > (This->buflen - offset)) {
-                            /* user buffer wrapped first */
-                            first = This->buflen - offset;
-                            second = (This->maplen - map_offset) - first;
-                            my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
-                            my_memcpy(This->buffer, This->mapping + map_offset + first, second);
-                            my_memcpy(This->buffer + second, This->mapping, fragsize - (first + second));
-                        } else {
-                            /* mmap buffer wrapped first */
-                            first = This->maplen - map_offset;
-                            second = (This->buflen - offset) - first;
-                            my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
-                            my_memcpy(This->buffer + offset + first, This->mapping, second);
-                            my_memcpy(This->buffer, This->mapping + second, fragsize - (first + second));
-                        }
-                    } else {
-                        /* only mmap buffer wrapped */
-                        first = This->maplen - map_offset;
-                        my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
-                        my_memcpy(This->buffer + offset + first, This->mapping, fragsize - first);
-                    }
-                } else {
-                    /* mmap buffer didn't wrap */
-                    fragsize = info.ptr - map_offset;
-
-                    /* check for user buffer wrap */
-                    if ((offset + fragsize) > This->buflen) {
-                        first = This->buflen - offset;
-                        my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
-                        my_memcpy(This->buffer, This->mapping + map_offset + first, fragsize - first);
-                    } else
-                        my_memcpy(This->buffer + offset, This->mapping + map_offset, fragsize);
-                }
-
-                This->map_writepos = info.ptr;
-                This->writeptr = (This->writeptr + fragsize) % This->buflen;
-                DSCDB_CheckEvent(This, offset, fragsize, This->buflen);
-            }
-        }
-    }
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
-    PIDSCDRIVER iface,
-    LPWAVEFORMATEX pwfx,
-    DWORD dwFlags,
-    DWORD dwCardAddress,
-    LPDWORD pdwcbBufferSize,
-    LPBYTE *ppbBuffer,
-    LPVOID *ppvObj)
-{
-    IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
-    IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
-    HRESULT err;
-    audio_buf_info info;
-    int audio_fragment, fsize, shift, ret;
-    BOOL bNewBuffer = FALSE;
-    WINE_WAVEIN* wwi;
-    TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
-          pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (This->capture_buffer) {
-        TRACE("already allocated\n");
-        return DSERR_ALLOCATED;
-    }
-
-    /* must be given a buffer size */
-    if (pdwcbBufferSize == NULL || *pdwcbBufferSize == 0) {
-       TRACE("invalid parameter: pdwcbBufferSize\n");
-       return DSERR_INVALIDPARAM;
-    }
-
-    /* must be given a buffer pointer */
-    if (ppbBuffer == NULL) {
-       TRACE("invalid parameter: ppbBuffer\n");
-       return DSERR_INVALIDPARAM;
-    }
-
-    /* may or may not be given a buffer */
-    if (*ppbBuffer == NULL) {
-        TRACE("creating buffer\n");
-        bNewBuffer = TRUE;     /* not given a buffer so create one */
-    } else
-        TRACE("using supplied buffer\n");
-
-    *ippdscdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
-    if (*ippdscdb == NULL) {
-        TRACE("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    (*ippdscdb)->IDsCaptureDriverBuffer_iface.lpVtbl = &dscdbvt;
-    (*ippdscdb)->ref          = 1;
-    (*ippdscdb)->drv          = This;
-    (*ippdscdb)->notify       = NULL;
-    (*ippdscdb)->notify_index = 0;
-    (*ippdscdb)->notifies     = NULL;
-    (*ippdscdb)->nrofnotifies = 0;
-    (*ippdscdb)->property_set = NULL;
-    (*ippdscdb)->is_capturing = FALSE;
-    (*ippdscdb)->is_looping   = FALSE;
-    (*ippdscdb)->wfx          = *pwfx;
-    (*ippdscdb)->buflen       = *pdwcbBufferSize;
-
-    if (bNewBuffer)
-        (*ippdscdb)->buffer = NULL;
-    else
-        (*ippdscdb)->buffer = *ppbBuffer;
-
-    wwi = &WInDev[This->wDevID];
-
-    if (wwi->state == WINE_WS_CLOSED) {
-        unsigned int frag_size;
-
-        if (wwi->ossdev.open_count > 0) {
-            /* opened already so use existing fragment size */
-            audio_fragment = wwi->ossdev.audio_fragment;
-        } else {
-            /* calculate a fragment size */
-            unsigned int mask = 0xffffffff;
-
-            /* calculate largest fragment size less than 10 ms. */
-            fsize = pwfx->nAvgBytesPerSec / 100;        /* 10 ms chunk */
-            shift = 0;
-            while ((1 << shift) <= fsize)
-                shift++;
-            shift--;
-            fsize = 1 << shift;
-            TRACE("shift = %d, fragment size = %d\n", shift, fsize);
-            TRACE("BufferSize=%d(%08x)\n", *pdwcbBufferSize, *pdwcbBufferSize);
-
-            /* See if we can directly map the buffer first.
-             * (buffer length is multiple of a power of 2)
-             */
-            mask = (mask >> (32 - shift));
-            TRACE("mask=%08x\n", mask);
-            if (*pdwcbBufferSize & mask) {
-                /* no so try a smaller fragment size greater than 1 ms */
-                int new_shift = shift - 1;
-                int min_shift = 0;
-                int min_fsize = pwfx->nAvgBytesPerSec / 1000;
-                BOOL found_one = FALSE;
-                while ((1 << min_shift) <= min_fsize)
-                    min_shift++;
-                min_shift--;
-                while (new_shift > min_shift) {
-                    if (*pdwcbBufferSize & (-1 >> (32 - new_shift))) {
-                        new_shift--;
-                        continue;
-                    } else {
-                        found_one = TRUE;
-                        break;
-                    }
-                }
-                if (found_one) {
-                    /* found a smaller one that will work */
-                    audio_fragment = ((*pdwcbBufferSize >> new_shift) << 16) | new_shift;
-                    (*ippdscdb)->is_direct_map = TRUE;
-                    TRACE("new shift = %d, fragment size = %d\n",
-                          new_shift, 1 << (audio_fragment & 0xffff));
-                } else {
-                    /* buffer can't be direct mapped */
-                    audio_fragment = 0x00100000 + shift;        /* 16 fragments of 2^shift */
-                    (*ippdscdb)->is_direct_map = FALSE;
-                }
-            } else {
-                /* good fragment size */
-                audio_fragment = ((*pdwcbBufferSize >> shift) << 16) | shift;
-                (*ippdscdb)->is_direct_map = TRUE;
-            }
-        }
-        frag_size = 1 << (audio_fragment & 0xffff);
-        TRACE("is_direct_map = %s\n", (*ippdscdb)->is_direct_map ? "TRUE" : "FALSE");
-        TRACE("requesting %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
-              audio_fragment >> 16, frag_size, frag_size * (audio_fragment >> 16),
-              (frag_size * 1000) / pwfx->nAvgBytesPerSec);
-
-        ret = OSS_OpenDevice(&wwi->ossdev, O_RDWR, &audio_fragment, 1,
-                             pwfx->nSamplesPerSec,
-                             (pwfx->nChannels > 1) ? 1 : 0,
-                             (pwfx->wBitsPerSample == 16)
-                             ? AFMT_S16_LE : AFMT_U8);
-
-        if (ret != 0) {
-            WARN("OSS_OpenDevice failed\n");
-            HeapFree(GetProcessHeap(),0,*ippdscdb);
-            *ippdscdb = NULL;
-            return DSERR_GENERIC;
-        }
-
-        wwi->state = WINE_WS_STOPPED;
-
-        /* find out what fragment and buffer sizes OSS gave us */
-        if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
-             ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
-                 wwi->ossdev.dev_name, strerror(errno));
-             OSS_CloseDevice(&wwi->ossdev);
-             wwi->state = WINE_WS_CLOSED;
-             HeapFree(GetProcessHeap(),0,*ippdscdb);
-             *ippdscdb = NULL;
-             return DSERR_GENERIC;
-        }
-
-        TRACE("got %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
-              info.fragstotal, info.fragsize, info.fragstotal * info.fragsize,
-              info.fragsize * 1000 / pwfx->nAvgBytesPerSec);
-
-        wwi->dwTotalRecorded = 0;
-        memcpy(&wwi->waveFormat, pwfx, sizeof(PCMWAVEFORMAT));
-        wwi->dwFragmentSize = info.fragsize;
-
-        /* make sure we got what we asked for */
-        if ((*ippdscdb)->buflen != info.fragstotal * info.fragsize) {
-            TRACE("Couldn't create requested buffer\n");
-            if ((*ippdscdb)->is_direct_map) {
-                (*ippdscdb)->is_direct_map = FALSE;
-                TRACE("is_direct_map = FALSE\n");
-            }
-        } else if (info.fragsize != frag_size) {
-            TRACE("same buffer length but different fragment size\n");
-        }
-    }
-    (*ippdscdb)->fd = WInDev[This->wDevID].ossdev.fd;
-
-    if (pipe((*ippdscdb)->pipe_fd) < 0) {
-        TRACE("pipe() failed (%s)\n", strerror(errno));
-        OSS_CloseDevice(&wwi->ossdev);
-        wwi->state = WINE_WS_CLOSED;
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return DSERR_GENERIC;
-    }
-
-    /* check how big the DMA buffer is now */
-    if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
-            wwi->ossdev.dev_name, strerror(errno));
-        OSS_CloseDevice(&wwi->ossdev);
-        wwi->state = WINE_WS_CLOSED;
-        close((*ippdscdb)->pipe_fd[0]);
-        close((*ippdscdb)->pipe_fd[1]);
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return DSERR_GENERIC;
-    }
-
-    (*ippdscdb)->maplen = info.fragstotal * info.fragsize;
-    (*ippdscdb)->fragsize = info.fragsize;
-    (*ippdscdb)->map_writepos = 0;
-    (*ippdscdb)->map_readpos = 0;
-
-    /* map the DMA buffer */
-    err = DSCDB_MapBuffer(*ippdscdb);
-    if (err != DS_OK) {
-        OSS_CloseDevice(&wwi->ossdev);
-        wwi->state = WINE_WS_CLOSED;
-        close((*ippdscdb)->pipe_fd[0]);
-        close((*ippdscdb)->pipe_fd[1]);
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return err;
-    }
-
-    /* create the buffer if necessary */
-    if (!(*ippdscdb)->buffer)
-        (*ippdscdb)->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(*ippdscdb)->buflen);
-
-    if ((*ippdscdb)->buffer == NULL) {
-        OSS_CloseDevice(&wwi->ossdev);
-        wwi->state = WINE_WS_CLOSED;
-        close((*ippdscdb)->pipe_fd[0]);
-        close((*ippdscdb)->pipe_fd[1]);
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return DSERR_OUTOFMEMORY;
-    }
-
-    This->capture_buffer = *ippdscdb;
-
-    (*ippdscdb)->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    (*ippdscdb)->hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-
-    (*ippdscdb)->hThread = CreateThread(NULL, 0,  DSCDB_Thread, *ippdscdb, 0, &((*ippdscdb)->dwThreadID));
-    WaitForSingleObject((*ippdscdb)->hStartUpEvent, INFINITE);
-    CloseHandle((*ippdscdb)->hStartUpEvent);
-    (*ippdscdb)->hStartUpEvent = INVALID_HANDLE_VALUE;
-
-    return DS_OK;
-}
-
-static const IDsCaptureDriverVtbl dscdvt =
-{
-    IDsCaptureDriverImpl_QueryInterface,
-    IDsCaptureDriverImpl_AddRef,
-    IDsCaptureDriverImpl_Release,
-    IDsCaptureDriverImpl_GetDriverDesc,
-    IDsCaptureDriverImpl_Open,
-    IDsCaptureDriverImpl_Close,
-    IDsCaptureDriverImpl_GetCaps,
-    IDsCaptureDriverImpl_CreateCaptureBuffer
-};
-
-static HRESULT IDsCaptureDriverPropertySetImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverPropertySetImpl **pdscdps)
-{
-    IDsCaptureDriverPropertySetImpl * dscdps;
-    TRACE("(%p,%p)\n",dscdb,pdscdps);
-
-    dscdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdps));
-    if (dscdps == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dscdps->ref = 0;
-    dscdps->IDsDriverPropertySet_iface.lpVtbl = &dscdpsvt;
-    dscdps->capture_buffer = dscdb;
-    dscdb->property_set = dscdps;
-    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
-    *pdscdps = dscdps;
-    return DS_OK;
-}
-
-static HRESULT IDsCaptureDriverNotifyImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverNotifyImpl **pdscdn)
-{
-    IDsCaptureDriverNotifyImpl * dscdn;
-    TRACE("(%p,%p)\n",dscdb,pdscdn);
-
-    dscdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdn));
-    if (dscdn == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dscdn->ref = 0;
-    dscdn->IDsDriverNotify_iface.lpVtbl = &dscdnvt;
-    dscdn->capture_buffer = dscdb;
-    dscdb->notify = dscdn;
-    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
-    *pdscdn = dscdn;
-    return DS_OK;
-}
-
-DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
-{
-    IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
-    TRACE("(%d,%p)\n",wDevID,drv);
-
-    /* the HAL isn't much better than the HEL if we can't do mmap() */
-    if (!(WInDev[wDevID].ossdev.in_caps_support & WAVECAPS_DIRECTSOUND)) {
-        ERR("DirectSoundCapture flag not set\n");
-        MESSAGE("This sound card's driver does not support direct access\n");
-        MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
-        return MMSYSERR_NOTSUPPORTED;
-    }
-
-    *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
-    if (!*idrv)
-        return MMSYSERR_NOMEM;
-    (*idrv)->IDsCaptureDriver_iface.lpVtbl = &dscdvt;
-    (*idrv)->ref	= 1;
-
-    (*idrv)->wDevID	= wDevID;
-    (*idrv)->capture_buffer = NULL;
-    return MMSYSERR_NOERROR;
-}
-
-DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    memcpy(desc, &(WInDev[wDevID].ossdev.ds_desc), sizeof(DSDRIVERDESC));
-    return MMSYSERR_NOERROR;
-}
diff --git a/dlls/wineoss.drv/dsrender.c b/dlls/wineoss.drv/dsrender.c
deleted file mode 100644
index afcc1df..0000000
--- a/dlls/wineoss.drv/dsrender.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/*
- * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
- *
- * Copyright 1994 Martin Ayotte
- *           1999 Eric Pouech (async playing in waveOut/waveIn)
- *	     2000 Eric Pouech (loops in waveOut)
- *           2002 Eric Pouech (full duplex)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <sys/soundcard.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winerror.h"
-#include "mmddk.h"
-#include "mmreg.h"
-#include "dsound.h"
-#include "dsdriver.h"
-#include "wine/debug.h"
-
-#include "audio.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wave);
-
-/*======================================================================*
- *                  Low level DSOUND definitions                        *
- *======================================================================*/
-
-typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl;
-typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl;
-typedef struct IDsDriverImpl IDsDriverImpl;
-typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
-
-struct IDsDriverPropertySetImpl
-{
-    /* IUnknown fields */
-    const IDsDriverPropertySetVtbl *lpVtbl;
-    LONG                        ref;
-
-    IDsDriverBufferImpl*        buffer;
-};
-
-struct IDsDriverNotifyImpl
-{
-    /* IUnknown fields */
-    const IDsDriverNotifyVtbl  *lpVtbl;
-    LONG                        ref;
-
-    /* IDsDriverNotifyImpl fields */
-    LPDSBPOSITIONNOTIFY         notifies;
-    int                         nrofnotifies;
-
-    IDsDriverBufferImpl*        buffer;
-};
-
-struct IDsDriverImpl
-{
-    /* IUnknown fields */
-    const IDsDriverVtbl        *lpVtbl;
-    LONG                        ref;
-
-    /* IDsDriverImpl fields */
-    UINT                        wDevID;
-    IDsDriverBufferImpl*        primary;
-
-    int                         nrofsecondaries;
-    IDsDriverBufferImpl**       secondaries;
-};
-
-struct IDsDriverBufferImpl
-{
-    /* IUnknown fields */
-    const IDsDriverBufferVtbl  *lpVtbl;
-    LONG                        ref;
-
-    /* IDsDriverBufferImpl fields */
-    IDsDriverImpl*              drv;
-    DWORD                       buflen;
-    WAVEFORMATPCMEX             wfex;
-    LPBYTE                      mapping;
-    DWORD                       maplen;
-    int                         fd;
-    DWORD                       dwFlags;
-
-    /* IDsDriverNotifyImpl fields */
-    IDsDriverNotifyImpl*        notify;
-    int                         notify_index;
-
-    /* IDsDriverPropertySetImpl fields */
-    IDsDriverPropertySetImpl*   property_set;
-};
-
-static HRESULT IDsDriverPropertySetImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverPropertySetImpl **pdsdps);
-
-static HRESULT IDsDriverNotifyImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverNotifyImpl **pdsdn);
-
-/*======================================================================*
- *                  Low level DSOUND property set implementation        *
- *======================================================================*/
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_QueryInterface(
-    PIDSDRIVERPROPERTYSET iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
-        IDsDriverPropertySet_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface)
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface)
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Get(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData,
-    PULONG pcbReturnedData )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Set(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_QuerySupport(
-    PIDSDRIVERPROPERTYSET iface,
-    REFGUID PropertySetId,
-    ULONG PropertyId,
-    PULONG pSupport )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,pSupport);
-    return DSERR_UNSUPPORTED;
-}
-
-static const IDsDriverPropertySetVtbl dsdpsvt =
-{
-    IDsDriverPropertySetImpl_QueryInterface,
-    IDsDriverPropertySetImpl_AddRef,
-    IDsDriverPropertySetImpl_Release,
-    IDsDriverPropertySetImpl_Get,
-    IDsDriverPropertySetImpl_Set,
-    IDsDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- *                  Low level DSOUND notify implementation              *
- *======================================================================*/
-
-static HRESULT WINAPI IDsDriverNotifyImpl_QueryInterface(
-    PIDSDRIVERNOTIFY iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
-        IDsDriverNotify_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
-        HeapFree(GetProcessHeap(), 0, This->notifies);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsDriverNotifyImpl_SetNotificationPositions(
-    PIDSDRIVERNOTIFY iface,
-    DWORD howmuch,
-    LPCDSBPOSITIONNOTIFY notify)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
-
-    if (!notify) {
-        WARN("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (TRACE_ON(wave)) {
-        DWORD i;
-        for (i=0;i<howmuch;i++)
-            TRACE("notify at %d to 0x%08lx\n",
-                notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
-    }
-
-    /* Make an internal copy of the caller-supplied array.
-     * Replace the existing copy if one is already present. */
-    if (This->notifies)
-        This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-        This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
-    else
-        This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-        howmuch * sizeof(DSBPOSITIONNOTIFY));
-
-    memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
-    This->nrofnotifies = howmuch;
-
-    return S_OK;
-}
-
-static const IDsDriverNotifyVtbl dsdnvt =
-{
-    IDsDriverNotifyImpl_QueryInterface,
-    IDsDriverNotifyImpl_AddRef,
-    IDsDriverNotifyImpl_Release,
-    IDsDriverNotifyImpl_SetNotificationPositions,
-};
-
-/*======================================================================*
- *                  Low level DSOUND implementation                     *
- *======================================================================*/
-
-static HRESULT DSDB_MapBuffer(IDsDriverBufferImpl *dsdb)
-{
-    TRACE("(%p), format=%dx%dx%d\n", dsdb, dsdb->wfex.Format.nSamplesPerSec,
-          dsdb->wfex.Format.wBitsPerSample, dsdb->wfex.Format.nChannels);
-    if (!dsdb->mapping) {
-        dsdb->mapping = mmap(NULL, dsdb->maplen, PROT_WRITE, MAP_SHARED,
-                             dsdb->fd, 0);
-        if (dsdb->mapping == (LPBYTE)-1) {
-            WARN("Could not map sound device for direct access (%s)\n", strerror(errno));
-            return DSERR_GENERIC;
-        }
-        TRACE("The sound device has been mapped for direct access at %p, size=%d\n", dsdb->mapping, dsdb->maplen);
-
-	/* for some reason, es1371 and sblive! sometimes have junk in here.
-	 * clear it, or we get junk noise */
-	/* some libc implementations are buggy: their memset reads from the buffer...
-	 * to work around it, we have to zero the block by hand. We don't do the expected:
-	 * memset(dsdb->mapping,0, dsdb->maplen);
-	 */
-	{
-            unsigned char*      p1 = dsdb->mapping;
-            unsigned            len = dsdb->maplen;
-	    unsigned char	silence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 128 : 0;
-	    unsigned long	ulsilence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 0x80808080 : 0;
-
-	    if (len >= 16) /* so we can have at least a 4 long area to store... */
-	    {
-		/* the mmap:ed value is (at least) dword aligned
-		 * so, start filling the complete unsigned long:s
-		 */
-		int		b = len >> 2;
-		unsigned long*	p4 = (unsigned long*)p1;
-
-		while (b--) *p4++ = ulsilence;
-		/* prepare for filling the rest */
-		len &= 3;
-		p1 = (unsigned char*)p4;
-	    }
-	    /* in all cases, fill the remaining bytes */
-	    while (len-- != 0) *p1++ = silence;
-	}
-    }
-    return DS_OK;
-}
-
-static HRESULT DSDB_UnmapBuffer(IDsDriverBufferImpl *dsdb)
-{
-    TRACE("(%p)\n",dsdb);
-    if (dsdb->mapping) {
-        if (munmap(dsdb->mapping, dsdb->maplen) < 0) {
-            ERR("(%p): Could not unmap sound device (%s)\n", dsdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        dsdb->mapping = NULL;
-        TRACE("(%p): sound device unmapped\n", dsdb);
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),*ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverBuffer) ) {
-	IDsDriverBuffer_AddRef(iface);
-        *ppobj = This;
-	return DS_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
-        if (!This->notify)
-            IDsDriverNotifyImpl_Create(This, &(This->notify));
-        if (This->notify) {
-            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-            *ppobj = This->notify;
-            return DS_OK;
-        }
-        *ppobj = 0;
-        return E_FAIL;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
-        if (!This->property_set)
-            IDsDriverPropertySetImpl_Create(This, &(This->property_set));
-        if (This->property_set) {
-            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
-            *ppobj = This->property_set;
-            return DS_OK;
-        }
-	*ppobj = 0;
-	return E_FAIL;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (refCount)
-        return refCount;
-
-    if (This == This->drv->primary)
-	This->drv->primary = NULL;
-    else {
-        int i;
-        for (i = 0; i < This->drv->nrofsecondaries; i++)
-            if (This->drv->secondaries[i] == This)
-                break;
-        if (i < This->drv->nrofsecondaries) {
-            /* Put the last buffer of the list in the (now empty) position */
-            This->drv->secondaries[i] = This->drv->secondaries[This->drv->nrofsecondaries - 1];
-            This->drv->nrofsecondaries--;
-            This->drv->secondaries = HeapReAlloc(GetProcessHeap(),0,
-                This->drv->secondaries,
-                sizeof(PIDSDRIVERBUFFER)*This->drv->nrofsecondaries);
-            TRACE("(%p) buffer count is now %d\n", This, This->drv->nrofsecondaries);
-        }
-
-        WOutDev[This->drv->wDevID].ossdev.ds_caps.dwFreeHwMixingAllBuffers++;
-        WOutDev[This->drv->wDevID].ossdev.ds_caps.dwFreeHwMixingStreamingBuffers++;
-    }
-
-    DSDB_UnmapBuffer(This);
-    HeapFree(GetProcessHeap(),0,This);
-    TRACE("(%p) released\n",This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
-					       LPVOID*ppvAudio1,LPDWORD pdwLen1,
-					       LPVOID*ppvAudio2,LPDWORD pdwLen2,
-					       DWORD dwWritePosition,DWORD dwWriteLen,
-					       DWORD dwFlags)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
-     * and that we don't support secondary buffers, this method will never be called */
-    TRACE("(%p): stub\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
-						 LPVOID pvAudio1,DWORD dwLen1,
-						 LPVOID pvAudio2,DWORD dwLen2)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    TRACE("(%p): stub\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
-						    LPWAVEFORMATEX pwfx)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-
-    TRACE("(%p,%p)\n",iface,pwfx);
-    /* On our request (GetDriverDesc flags), DirectSound has by now used
-     * waveOutClose/waveOutOpen to set the format...
-     * unfortunately, this means our mmap() is now gone...
-     * so we need to somehow signal to our DirectSound implementation
-     * that it should completely recreate this HW buffer...
-     * this unexpected error code should do the trick... */
-    return DSERR_BUFFERLOST;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    TRACE("(%p,%d): stub\n",iface,dwFreq);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
-{
-    DWORD vol;
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    TRACE("(%p,%p)\n",This,pVolPan);
-
-    vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
-
-    if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
-	WARN("wodSetVolume failed\n");
-	return DSERR_INVALIDPARAM;
-    }
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
-{
-    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
-    TRACE("(%p,%d): stub\n",iface,dwNewPos);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
-						      LPDWORD lpdwPlay, LPDWORD lpdwWrite)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    count_info info;
-    DWORD ptr;
-
-    TRACE("(%p)\n",iface);
-    if (WOutDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
-	ERR("device not open, but accessing?\n");
-	return DSERR_UNINITIALIZED;
-    }
-    if (ioctl(This->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
-            WOutDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-    ptr = info.ptr & ~3; /* align the pointer, just in case */
-    if (lpdwPlay) *lpdwPlay = ptr;
-    if (lpdwWrite) {
-	/* add some safety margin (not strictly necessary, but...) */
-	if (WOutDev[This->drv->wDevID].ossdev.duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
-	    *lpdwWrite = ptr + 32;
-	else
-	    *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
-	while (*lpdwWrite >= This->buflen)
-	    *lpdwWrite -= This->buflen;
-    }
-    TRACE("playpos=%d, writepos=%d\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p,%x,%x,%x)\n",iface,dwRes1,dwRes2,dwFlags);
-    WOutDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
-    enable = getEnables(&WOutDev[This->drv->wDevID].ossdev);
-    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	if (errno == EINVAL) {
-	    /* Don't give up yet. OSS trigger support is inconsistent. */
-	    if (WOutDev[This->drv->wDevID].ossdev.open_count == 1) {
-		/* try the opposite input enable */
-		if (WOutDev[This->drv->wDevID].ossdev.bInputEnabled == FALSE)
-		    WOutDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
-		else
-		    WOutDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
-		/* try it again */
-		enable = getEnables(&WOutDev[This->drv->wDevID].ossdev);
-                if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0)
-		    return DS_OK;
-	    }
-	}
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WOutDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-	WOutDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p)\n",iface);
-    /* no more playing */
-    WOutDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
-    enable = getEnables(&WOutDev[This->drv->wDevID].ossdev);
-    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-#if 0
-    /* the play position must be reset to the beginning of the buffer */
-    if (ioctl(This->fd, SNDCTL_DSP_RESET, 0) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-#endif
-    /* Most OSS drivers just can't stop the playback without closing the device...
-     * so we need to somehow signal to our DirectSound implementation
-     * that it should completely recreate this HW buffer...
-     * this unexpected error code should do the trick... */
-    /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
-    if (WOutDev[This->drv->wDevID].ossdev.open_count == 1)
-	return DSERR_BUFFERLOST;
-
-    return DS_OK;
-}
-
-static const IDsDriverBufferVtbl dsdbvt =
-{
-    IDsDriverBufferImpl_QueryInterface,
-    IDsDriverBufferImpl_AddRef,
-    IDsDriverBufferImpl_Release,
-    IDsDriverBufferImpl_Lock,
-    IDsDriverBufferImpl_Unlock,
-    IDsDriverBufferImpl_SetFormat,
-    IDsDriverBufferImpl_SetFrequency,
-    IDsDriverBufferImpl_SetVolumePan,
-    IDsDriverBufferImpl_SetPosition,
-    IDsDriverBufferImpl_GetPosition,
-    IDsDriverBufferImpl_Play,
-    IDsDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriver) ) {
-	IDsDriver_AddRef(iface);
-        *ppobj = This;
-	return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, refCount + 1);
-
-    if (!refCount) {
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface,
-                                                  PDSDRIVERDESC pDesc)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%p)\n",iface,pDesc);
-
-    /* copy version from driver */
-    *pDesc = WOutDev[This->wDevID].ossdev.ds_desc;
-
-    pDesc->dwFlags |= DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
-        DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK |
-        DSDDESC_DONTNEEDSECONDARYLOCK;
-    pDesc->dnDevNode		= WOutDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId		= 0;
-    pDesc->wReserved		= 0;
-    pDesc->ulDeviceNum		= This->wDevID;
-    pDesc->dwHeapType		= DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap	= NULL;
-    pDesc->dwMemStartAddress	= 0;
-    pDesc->dwMemEndAddress	= 0;
-    pDesc->dwMemAllocExtra	= 0;
-    pDesc->pvReserved1		= NULL;
-    pDesc->pvReserved2		= NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    int enable;
-    TRACE("(%p)\n",iface);
-
-    /* make sure the card doesn't start playing before we want it to */
-    WOutDev[This->wDevID].ossdev.bOutputEnabled = FALSE;
-    WOutDev[This->wDevID].ossdev.bInputEnabled = FALSE;
-    enable = getEnables(&WOutDev[This->wDevID].ossdev);
-    if (ioctl(WOutDev[This->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev[This->wDevID].ossdev.dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p)\n",iface);
-    if (This->primary) {
-	ERR("problem with DirectSound: primary not released\n");
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%p)\n",iface,pCaps);
-    *pCaps = WOutDev[This->wDevID].ossdev.ds_caps;
-    return DS_OK;
-}
-
-static HRESULT DSD_CreatePrimaryBuffer(PIDSDRIVER iface,
-                                       LPWAVEFORMATEX pwfx,
-                                       DWORD dwFlags,
-                                       DWORD dwCardAddress,
-                                       LPDWORD pdwcbBufferSize,
-                                       LPBYTE *ppbBuffer,
-                                       LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
-    HRESULT err;
-    audio_buf_info info;
-    int enable = 0;
-    TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (This->primary)
-	return DSERR_ALLOCATED;
-    if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
-	return DSERR_CONTROLUNAVAIL;
-
-    *ippdsdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverBufferImpl));
-    if (*ippdsdb == NULL)
-	return DSERR_OUTOFMEMORY;
-    (*ippdsdb)->lpVtbl  = &dsdbvt;
-    (*ippdsdb)->ref	= 1;
-    (*ippdsdb)->drv	= This;
-    copy_format(pwfx, &(*ippdsdb)->wfex);
-    (*ippdsdb)->fd      = WOutDev[This->wDevID].ossdev.fd;
-    (*ippdsdb)->dwFlags = dwFlags;
-
-    /* check how big the DMA buffer is now */
-    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
-            WOutDev[This->wDevID].ossdev.dev_name, strerror(errno));
-	HeapFree(GetProcessHeap(),0,*ippdsdb);
-	*ippdsdb = NULL;
-	return DSERR_GENERIC;
-    }
-    (*ippdsdb)->maplen = (*ippdsdb)->buflen = info.fragstotal * info.fragsize;
-
-    /* map the DMA buffer */
-    err = DSDB_MapBuffer(*ippdsdb);
-    if (err != DS_OK) {
-	HeapFree(GetProcessHeap(),0,*ippdsdb);
-	*ippdsdb = NULL;
-	return err;
-    }
-
-    /* primary buffer is ready to go */
-    *pdwcbBufferSize    = (*ippdsdb)->maplen;
-    *ppbBuffer          = (*ippdsdb)->mapping;
-
-    /* some drivers need some extra nudging after mapping */
-    WOutDev[This->wDevID].ossdev.bInputEnabled = FALSE;
-    WOutDev[This->wDevID].ossdev.bOutputEnabled = FALSE;
-    enable = getEnables(&WOutDev[This->wDevID].ossdev);
-    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WOutDev[This->wDevID].ossdev.dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-
-    This->primary = *ippdsdb;
-
-    return DS_OK;
-}
-
-static HRESULT DSD_CreateSecondaryBuffer(PIDSDRIVER iface,
-                                         LPWAVEFORMATEX pwfx,
-                                         DWORD dwFlags,
-                                         DWORD dwCardAddress,
-                                         LPDWORD pdwcbBufferSize,
-                                         LPBYTE *ppbBuffer,
-                                         LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
-    FIXME("(%p,%p,%x,%x,%p,%p,%p): stub\n",This,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    *ippdsdb = 0;
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
-                                                      LPWAVEFORMATEX pwfx,
-                                                      DWORD dwFlags,
-                                                      DWORD dwCardAddress,
-                                                      LPDWORD pdwcbBufferSize,
-                                                      LPBYTE *ppbBuffer,
-                                                      LPVOID *ppvObj)
-{
-    TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (dwFlags & DSBCAPS_PRIMARYBUFFER)
-        return DSD_CreatePrimaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    return DSD_CreateSecondaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-}
-
-static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
-							 PIDSDRIVERBUFFER pBuffer,
-							 LPVOID *ppvObj)
-{
-    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
-    TRACE("(%p,%p): stub\n",iface,pBuffer);
-    return DSERR_INVALIDCALL;
-}
-
-static const IDsDriverVtbl dsdvt =
-{
-    IDsDriverImpl_QueryInterface,
-    IDsDriverImpl_AddRef,
-    IDsDriverImpl_Release,
-    IDsDriverImpl_GetDriverDesc,
-    IDsDriverImpl_Open,
-    IDsDriverImpl_Close,
-    IDsDriverImpl_GetCaps,
-    IDsDriverImpl_CreateSoundBuffer,
-    IDsDriverImpl_DuplicateSoundBuffer
-};
-
-static HRESULT IDsDriverPropertySetImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverPropertySetImpl **pdsdps)
-{
-    IDsDriverPropertySetImpl * dsdps;
-    TRACE("(%p,%p)\n",dsdb,pdsdps);
-
-    dsdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsdps));
-    if (dsdps == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dsdps->ref = 0;
-    dsdps->lpVtbl = &dsdpsvt;
-    dsdps->buffer = dsdb;
-    dsdb->property_set = dsdps;
-    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
-    *pdsdps = dsdps;
-    return DS_OK;
-}
-
-static HRESULT IDsDriverNotifyImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverNotifyImpl **pdsdn)
-{
-    IDsDriverNotifyImpl * dsdn;
-    TRACE("(%p,%p)\n",dsdb,pdsdn);
-
-    dsdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsdn));
-
-    if (dsdn == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dsdn->ref = 0;
-    dsdn->lpVtbl = &dsdnvt;
-    dsdn->buffer = dsdb;
-    dsdb->notify = dsdn;
-    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
-    *pdsdn = dsdn;
-    return DS_OK;
-}
-
-DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
-{
-    IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
-    TRACE("(%d,%p)\n",wDevID,drv);
-
-    /* the HAL isn't much better than the HEL if we can't do mmap() */
-    if (!(WOutDev[wDevID].ossdev.duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
-        WARN("Warn DirectSound flag not set, falling back to HEL layer\n");
-        return MMSYSERR_NOTSUPPORTED;
-    }
-
-    *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverImpl));
-    if (!*idrv)
-	return MMSYSERR_NOMEM;
-    (*idrv)->lpVtbl          = &dsdvt;
-    (*idrv)->ref             = 1;
-    (*idrv)->wDevID          = wDevID;
-    (*idrv)->primary         = NULL;
-    (*idrv)->nrofsecondaries = 0;
-    (*idrv)->secondaries     = NULL;
-
-    return MMSYSERR_NOERROR;
-}
-
-DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    TRACE("(%d,%p)\n",wDevID,desc);
-    *desc = WOutDev[wDevID].ossdev.ds_desc;
-    return MMSYSERR_NOERROR;
-}
diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c
index 7ca4cff..72ceb1a 100644
--- a/dlls/wineoss.drv/midi.c
+++ b/dlls/wineoss.drv/midi.c
@@ -1775,4 +1775,29 @@ DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
     return MMSYSERR_NOTSUPPORTED;
 }
 
-/*-----------------------------------------------------------------------*/
+/**************************************************************************
+ * 				DriverProc (WINEOSS.1)
+ */
+LRESULT CALLBACK OSS_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
+                                LPARAM dwParam1, LPARAM dwParam2)
+{
+     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
+           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+
+    switch(wMsg) {
+    case DRV_LOAD:
+    case DRV_FREE:
+    case DRV_OPEN:
+    case DRV_CLOSE:
+    case DRV_ENABLE:
+    case DRV_DISABLE:
+    case DRV_QUERYCONFIGURE:
+    case DRV_CONFIGURE:
+        return 1;
+    case DRV_INSTALL:
+    case DRV_REMOVE:
+        return DRV_SUCCESS;
+    default:
+	return 0;
+    }
+}
diff --git a/dlls/wineoss.drv/mixer.c b/dlls/wineoss.drv/mixer.c
deleted file mode 100644
index 5256cb8..0000000
--- a/dlls/wineoss.drv/mixer.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/* -*- tab-width: 8; c-basic-offset: 4 -*- */
-
-/*
- * Sample MIXER Wine Driver for Linux
- *
- * Copyright 	1997 Marcus Meissner
- * 		1999,2001 Eric Pouech
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* TODO:
- * + implement notification mechanism when state of mixer's controls
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <fcntl.h>
-#include <errno.h>
-#include <assert.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <sys/soundcard.h>
-
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#include "windef.h"
-#include "winbase.h"
-#include "winnls.h"
-#include "mmddk.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(mixer);
-
-#define MAX_MIXERDRV     (6)
-
-#define	WINE_MIXER_MANUF_ID		0xAA
-#define	WINE_MIXER_PRODUCT_ID		0x55
-#define	WINE_MIXER_VERSION		0x0100
-#define	WINE_MIXER_NAME			"WINE OSS Mixer"
-
-#define WINE_CHN_MASK(_x)		(1L << (_x))
-#define WINE_CHN_SUPPORTS(_c, _x)	((_c) & WINE_CHN_MASK(_x))
-/* Bass and Treble are no longer in the mask as Windows does not handle them */
-#define WINE_MIXER_MASK_SPEAKER		(WINE_CHN_MASK(SOUND_MIXER_SYNTH)  | \
-                                         WINE_CHN_MASK(SOUND_MIXER_PCM)    | \
-                                         WINE_CHN_MASK(SOUND_MIXER_LINE)   | \
-                                         WINE_CHN_MASK(SOUND_MIXER_MIC)    | \
-                                         WINE_CHN_MASK(SOUND_MIXER_CD)     )
-
-#define WINE_MIXER_MASK_RECORD		(WINE_CHN_MASK(SOUND_MIXER_SYNTH)  | \
-                                         WINE_CHN_MASK(SOUND_MIXER_LINE)   | \
-                                         WINE_CHN_MASK(SOUND_MIXER_MIC)    | \
-                                         WINE_CHN_MASK(SOUND_MIXER_IMIX)   )
-
-/* FIXME: the two following string arrays should be moved to a resource file in a string table */
-/* if it's done, better use a struct to hold labels, name, and muted channel volume cache */
-static const char * const MIX_Labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
-static const char * const MIX_Names [SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
-
-struct mixerCtrl
-{
-    DWORD		dwLineID;
-    MIXERCONTROLW	ctrl;
-};
-
-struct mixer
-{
-    char*		name;
-    char*		dev_name;
-    int			volume[SOUND_MIXER_NRDEVICES];
-    int			devMask;
-    int			stereoMask;
-    int			recMask;
-    BOOL		singleRecChannel;
-    struct mixerCtrl*	ctrl;
-    int			numCtrl;
-};
-
-#define LINEID_DST	0xFFFF
-#define LINEID_SPEAKER	0x0000
-#define LINEID_RECORD	0x0001
-
-static int		MIX_NumMixers;
-static struct mixer	MIX_Mixers[MAX_MIXERDRV];
-
-/**************************************************************************
- */
-
-static const char * getMessage(UINT uMsg)
-{
-#define MSG_TO_STR(x) case x: return #x;
-    switch (uMsg) {
-    MSG_TO_STR(DRVM_INIT);
-    MSG_TO_STR(DRVM_EXIT);
-    MSG_TO_STR(DRVM_ENABLE);
-    MSG_TO_STR(DRVM_DISABLE);
-    MSG_TO_STR(MXDM_GETDEVCAPS);
-    MSG_TO_STR(MXDM_GETLINEINFO);
-    MSG_TO_STR(MXDM_GETNUMDEVS);
-    MSG_TO_STR(MXDM_OPEN);
-    MSG_TO_STR(MXDM_CLOSE);
-    MSG_TO_STR(MXDM_GETLINECONTROLS);
-    MSG_TO_STR(MXDM_GETCONTROLDETAILS);
-    MSG_TO_STR(MXDM_SETCONTROLDETAILS);
-    }
-#undef MSG_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", uMsg);
-}
-
-static const char * getIoctlCommand(int command)
-{
-#define IOCTL_TO_STR(x) case x: return #x;
-    switch (command) {
-    IOCTL_TO_STR(SOUND_MIXER_VOLUME);
-    IOCTL_TO_STR(SOUND_MIXER_BASS);
-    IOCTL_TO_STR(SOUND_MIXER_TREBLE);
-    IOCTL_TO_STR(SOUND_MIXER_SYNTH);
-    IOCTL_TO_STR(SOUND_MIXER_PCM);
-    IOCTL_TO_STR(SOUND_MIXER_SPEAKER);
-    IOCTL_TO_STR(SOUND_MIXER_LINE);
-    IOCTL_TO_STR(SOUND_MIXER_MIC);
-    IOCTL_TO_STR(SOUND_MIXER_CD);
-    IOCTL_TO_STR(SOUND_MIXER_IMIX);
-    IOCTL_TO_STR(SOUND_MIXER_ALTPCM);
-    IOCTL_TO_STR(SOUND_MIXER_RECLEV);
-    IOCTL_TO_STR(SOUND_MIXER_IGAIN);
-    IOCTL_TO_STR(SOUND_MIXER_OGAIN);
-    IOCTL_TO_STR(SOUND_MIXER_LINE1);
-    IOCTL_TO_STR(SOUND_MIXER_LINE2);
-    IOCTL_TO_STR(SOUND_MIXER_LINE3);
-    IOCTL_TO_STR(SOUND_MIXER_DIGITAL1);
-    IOCTL_TO_STR(SOUND_MIXER_DIGITAL2);
-    IOCTL_TO_STR(SOUND_MIXER_DIGITAL3);
-#ifdef SOUND_MIXER_PHONEIN
-    IOCTL_TO_STR(SOUND_MIXER_PHONEIN);
-#endif
-#ifdef SOUND_MIXER_PHONEOUT
-    IOCTL_TO_STR(SOUND_MIXER_PHONEOUT);
-#endif
-    IOCTL_TO_STR(SOUND_MIXER_VIDEO);
-    IOCTL_TO_STR(SOUND_MIXER_RADIO);
-#ifdef SOUND_MIXER_MONITOR
-    IOCTL_TO_STR(SOUND_MIXER_MONITOR);
-#endif
-    }
-#undef IOCTL_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", command);
-}
-
-static const char * getControlType(DWORD dwControlType)
-{
-#define TYPE_TO_STR(x) case x: return #x
-    switch (dwControlType) {
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME);
-    TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME);
-    }
-#undef TYPE_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", dwControlType);
-}
-
-static const char * getComponentType(DWORD dwComponentType)
-{
-#define TYPE_TO_STR(x) case x: return #x;
-    switch (dwComponentType) {
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_UNDEFINED);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_DIGITAL);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_LINE);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_MONITOR);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_HEADPHONES);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_TELEPHONE);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_VOICEIN);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_DIGITAL);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_LINE);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY);
-    TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_ANALOG);
-    }
-#undef TYPE_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", dwComponentType);
-}
-
-static const char * getTargetType(DWORD dwType)
-{
-#define TYPE_TO_STR(x) case x: return #x;
-    switch (dwType) {
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_UNDEFINED);
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEOUT);
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEIN);
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIOUT);
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIIN);
-    TYPE_TO_STR(MIXERLINE_TARGETTYPE_AUX);
-    }
-#undef TYPE_TO_STR
-    return wine_dbg_sprintf("UNKNOWN(%08x)", dwType);
-}
-
-static const WCHAR sz_short_volume [] = {'V','o','l',0};
-static const WCHAR sz_long_volume  [] = {'V','o','l','u','m','e',0};
-static const WCHAR sz_shrtlng_mute [] = {'M','u','t','e',0};
-static const WCHAR sz_shrtlng_mixer[] = {'M','i','x','e','r',0};
-
-/**************************************************************************
- * 				MIX_FillLineControls		[internal]
- */
-static void MIX_FillLineControls(struct mixer* mix, int c, DWORD lineID,
-                                 DWORD dwControlType)
-{
-    struct mixerCtrl* 	mc = &mix->ctrl[c];
-    int			j;
-
-    TRACE("(%p, %d, %08x, %s)\n", mix, c, lineID,
-          getControlType(dwControlType));
-
-    mc->dwLineID = lineID;
-    mc->ctrl.cbStruct = sizeof(MIXERCONTROLW);
-    mc->ctrl.dwControlID = c + 1;
-    mc->ctrl.dwControlType = dwControlType;
-
-    switch (dwControlType)
-    {
-    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-	mc->ctrl.fdwControl = 0;
-	mc->ctrl.cMultipleItems = 0;
-	strcpyW(mc->ctrl.szShortName, sz_short_volume);
-	strcpyW(mc->ctrl.szName, sz_long_volume);
-	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));
-	/* CONTROLTYPE_VOLUME uses the MIXER_CONTROLDETAILS_UNSIGNED struct,
-	 * [0, 100] is the range supported by OSS
-	 * whatever the min and max values are they must match
-	 * conversions done in (Get|Set)ControlDetails to stay in [0, 100] range
-	 */
-	mc->ctrl.Bounds.s1.dwMinimum = 0;
-	mc->ctrl.Bounds.s1.dwMaximum = 65535;
-	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));
-        mc->ctrl.Metrics.cSteps = 656;
-	break;
-    case MIXERCONTROL_CONTROLTYPE_MUTE:
-    case MIXERCONTROL_CONTROLTYPE_ONOFF:
-	mc->ctrl.fdwControl = 0;
-	mc->ctrl.cMultipleItems = 0;
-	strcpyW(mc->ctrl.szShortName, sz_shrtlng_mute);
-	strcpyW(mc->ctrl.szName, sz_shrtlng_mute);
-	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));
-	mc->ctrl.Bounds.s1.dwMinimum = 0;
-	mc->ctrl.Bounds.s1.dwMaximum = 1;
-	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));
-	break;
-    case MIXERCONTROL_CONTROLTYPE_MUX:
-    case MIXERCONTROL_CONTROLTYPE_MIXER:
-	mc->ctrl.fdwControl = MIXERCONTROL_CONTROLF_MULTIPLE;
-	mc->ctrl.cMultipleItems = 0;
-	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-	    if (WINE_CHN_SUPPORTS(mix->recMask, j))
-		mc->ctrl.cMultipleItems++;
-	strcpyW(mc->ctrl.szShortName, sz_shrtlng_mixer);
-	strcpyW(mc->ctrl.szName, sz_shrtlng_mixer);
-	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));
-        mc->ctrl.Bounds.s1.dwMaximum = mc->ctrl.cMultipleItems - 1;
-	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));
-        mc->ctrl.Metrics.cSteps = mc->ctrl.cMultipleItems;
-	break;
-
-    default:
-	FIXME("Internal error: unknown type: %08x\n", dwControlType);
-    }
-    TRACE("ctrl[%2d]: typ=%08x lin=%08x\n", c + 1, dwControlType, lineID);
-}
-
-/******************************************************************
- *		MIX_GetMixer
- *
- *
- */
-static struct mixer*	MIX_Get(WORD wDevID)
-{
-    TRACE("(%04x)\n", wDevID);
-
-    if (wDevID >= MIX_NumMixers || MIX_Mixers[wDevID].dev_name == NULL)
-        return NULL;
-
-    return &MIX_Mixers[wDevID];
-}
-
-/**************************************************************************
- * 				MIX_Open			[internal]
- */
-static DWORD MIX_Open(WORD wDevID, LPMIXEROPENDESC lpMod, DWORD flags)
-{
-    int			mixer, i, j;
-    unsigned 		caps;
-    struct mixer*	mix;
-    DWORD		ret = MMSYSERR_NOERROR;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpMod, flags);
-
-    /* as we partly init the mixer with MIX_Open, we can allow null open decs
-     * EPP     if (lpMod == NULL) return MMSYSERR_INVALPARAM;
-     * anyway, it seems that WINMM/MMSYSTEM doesn't always open the mixer
-     * device before sending messages to it... it seems to be linked to all
-     * the equivalent of mixer identification
-     * (with a reference to a wave, midi.. handle
-     */
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    if ((mixer = open(mix->dev_name, O_RDWR)) < 0)
-    {
-	ERR("open(%s, O_RDWR) failed (%s)\n",
-            mix->dev_name, strerror(errno));
-
-	if (errno == ENODEV || errno == ENXIO)
-	{
-	    /* no driver present */
-            WARN("no driver\n");
-	    return MMSYSERR_NODRIVER;
-	}
-	return MMSYSERR_ERROR;
-    }
-
-    if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &mix->devMask) == -1)
-    {
-	ERR("ioctl(%s, SOUND_MIXER_DEVMASK) failed (%s)\n",
-            mix->dev_name, strerror(errno));
-	ret = MMSYSERR_ERROR;
-	goto error;
-    }
-
-    mix->devMask &= WINE_MIXER_MASK_SPEAKER;
-    if (mix->devMask == 0)
-    {
-        WARN("no driver\n");
-	ret = MMSYSERR_NODRIVER;
-	goto error;
-    }
-
-    if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &mix->stereoMask) == -1)
-    {
-	ERR("ioctl(%s, SOUND_MIXER_STEREODEVS) failed (%s)\n",
-            mix->dev_name, strerror(errno));
-	ret = MMSYSERR_ERROR;
-	goto error;
-    }
-    mix->stereoMask &= WINE_MIXER_MASK_SPEAKER;
-
-    if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &mix->recMask) == -1)
-    {
-	ERR("ioctl(%s, SOUND_MIXER_RECMASK) failed (%s)\n",
-            mix->dev_name, strerror(errno));
-	ret = MMSYSERR_ERROR;
-	goto error;
-    }
-    mix->recMask &= WINE_MIXER_MASK_RECORD;
-    /* FIXME: we may need to support both rec lev & igain */
-    if (!WINE_CHN_SUPPORTS(mix->recMask, SOUND_MIXER_RECLEV))
-    {
-	WARN("The sound card doesn't support rec level\n");
-	if (WINE_CHN_SUPPORTS(mix->recMask, SOUND_MIXER_IGAIN))
-	    WARN("but it does support IGain, please report\n");
-    }
-    if (ioctl(mixer, SOUND_MIXER_READ_CAPS, &caps) == -1)
-    {
-	ERR("ioctl(%s, SOUND_MIXER_READ_CAPS) failed (%s)\n",
-            mix->dev_name, strerror(errno));
-	ret = MMSYSERR_ERROR;
-	goto error;
-    }
-    mix->singleRecChannel = caps & SOUND_CAP_EXCL_INPUT;
-    TRACE("dev=%04x rec=%04x stereo=%04x %s\n",
-	  mix->devMask, mix->recMask, mix->stereoMask,
-	  mix->singleRecChannel ? "single" : "multiple");
-    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-    {
-	mix->volume[i] = -1;
-    }
-    mix->numCtrl = 4; /* dst lines... vol&mute on speakers, vol&onoff on rec */
-    /* FIXME: do we always have RECLEV on all cards ??? */
-    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-    {
-	if (WINE_CHN_SUPPORTS(mix->devMask, i))
-	    mix->numCtrl += 2; /* volume & mute */
-	if (WINE_CHN_SUPPORTS(mix->recMask, i))
-	    mix->numCtrl += 2; /* volume & onoff */
-
-    }
-    if (!(mix->ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                sizeof(mix->ctrl[0]) * mix->numCtrl)))
-    {
-	ret = MMSYSERR_NOMEM;
-	goto error;
-    }
-
-    j = 0;
-    MIX_FillLineControls(mix, j++, MAKELONG(0, LINEID_DST),
-                         MIXERCONTROL_CONTROLTYPE_VOLUME);
-    MIX_FillLineControls(mix, j++, MAKELONG(0, LINEID_DST),
-                         MIXERCONTROL_CONTROLTYPE_MUTE);
-    MIX_FillLineControls(mix, j++, MAKELONG(1, LINEID_DST),
-			 mix->singleRecChannel ?
-			     MIXERCONTROL_CONTROLTYPE_MUX :
-                             MIXERCONTROL_CONTROLTYPE_MIXER);
-    MIX_FillLineControls(mix, j++, MAKELONG(1, LINEID_DST),
-                         MIXERCONTROL_CONTROLTYPE_MUTE/*EPP*/);
-    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-    {
-	if (WINE_CHN_SUPPORTS(mix->devMask, i))
-	{
-	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_SPEAKER, i),
-				 MIXERCONTROL_CONTROLTYPE_VOLUME);
-	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_SPEAKER, i),
-				 MIXERCONTROL_CONTROLTYPE_MUTE);
-	}
-    }
-    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-    {
-	if (WINE_CHN_SUPPORTS(mix->recMask, i))
-	{
-	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_RECORD, i),
-				 MIXERCONTROL_CONTROLTYPE_VOLUME);
-	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_RECORD, i),
-				 MIXERCONTROL_CONTROLTYPE_MUTE/*EPP*/);
-	}
-    }
-    assert(j == mix->numCtrl);
- error:
-    close(mixer);
-    return ret;
-}
-
-/**************************************************************************
- * 				MIX_GetVal			[internal]
- */
-static	BOOL	MIX_GetVal(struct mixer* mix, int chn, int* val)
-{
-    int		mixer;
-    BOOL	ret = FALSE;
-
-    TRACE("(%p, %s, %p\n", mix, getIoctlCommand(chn), val);
-
-    if ((mixer = open(mix->dev_name, O_RDWR)) < 0) {
-	/* FIXME: ENXIO => no mixer installed */
-	WARN("mixer device not available !\n");
-    } else {
-	if (ioctl(mixer, MIXER_READ(chn), val) >= 0) {
-	    TRACE("Reading %04x for %s\n", *val, getIoctlCommand(chn));
-	    ret = TRUE;
-	} else {
-            ERR("ioctl(%s, MIXER_READ(%s)) failed (%s)\n",
-                mix->dev_name, getIoctlCommand(chn), strerror(errno));
-        }
-	close(mixer);
-    }
-    return ret;
-}
-
-/**************************************************************************
- * 				MIX_SetVal			[internal]
- */
-static	BOOL	MIX_SetVal(struct mixer* mix, int chn, int val)
-{
-    int		mixer;
-    BOOL	ret = FALSE;
-
-    TRACE("(%p, %s, %x)\n", mix, getIoctlCommand(chn), val);
-
-    if ((mixer = open(mix->dev_name, O_RDWR)) < 0) {
-	/* FIXME: ENXIO => no mixer installed */
-	WARN("mixer device not available !\n");
-    } else {
-	if (ioctl(mixer, MIXER_WRITE(chn), &val) >= 0) {
-	    TRACE("Set %s to %04x\n", getIoctlCommand(chn), val);
-	    ret = TRUE;
-	} else {
-            ERR("ioctl(%s, MIXER_WRITE(%s)) failed (%s)\n",
-                mix->dev_name, getIoctlCommand(chn), strerror(errno));
-        }
-	close(mixer);
-    }
-    return ret;
-}
-
-/******************************************************************
- *		MIX_GetRecSrc
- *
- *
- */
-static BOOL	MIX_GetRecSrc(struct mixer* mix, unsigned* mask)
-{
-    int		mixer;
-    BOOL	ret = FALSE;
-
-    TRACE("(%p, %p)\n", mix, mask);
-
-    if ((mixer = open(mix->dev_name, O_RDWR)) >= 0) {
-	if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &mask) >= 0) {
-            ret = TRUE;
-	} else {
-            ERR("ioctl(%s, SOUND_MIXER_READ_RECSRC) failed (%s)\n",
-                mix->dev_name, strerror(errno));
-        }
-	close(mixer);
-    }
-    return ret;
-}
-
-/******************************************************************
- *		MIX_SetRecSrc
- *
- *
- */
-static BOOL	MIX_SetRecSrc(struct mixer* mix, unsigned mask)
-{
-    int		mixer;
-    BOOL	ret = FALSE;
-
-    TRACE("(%p, %08x)\n", mix, mask);
-
-    if ((mixer = open(mix->dev_name, O_RDWR)) >= 0) {
-	if (ioctl(mixer, SOUND_MIXER_WRITE_RECSRC, &mask) >= 0) {
-	    ret = TRUE;
-	} else {
-            ERR("ioctl(%s, SOUND_MIXER_WRITE_RECSRC) failed (%s)\n",
-                mix->dev_name, strerror(errno));
-        }
-	close(mixer);
-    }
-    return ret;
-}
-
-/**************************************************************************
- * 				MIX_GetDevCaps			[internal]
- */
-static DWORD MIX_GetDevCaps(WORD wDevID, LPMIXERCAPSW lpCaps, DWORD dwSize)
-{
-    struct mixer*	mix;
-    MIXERCAPSW		capsW;
-    const char*         name;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) {
-        WARN("invalid parameter: lpCaps == NULL\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    capsW.wMid = WINE_MIXER_MANUF_ID;
-    capsW.wPid = WINE_MIXER_PRODUCT_ID;
-    capsW.vDriverVersion = WINE_MIXER_VERSION;
-    if (!(name = mix->name)) name = WINE_MIXER_NAME;
-    MultiByteToWideChar(CP_UNIXCP, 0, name, -1, capsW.szPname, sizeof(capsW.szPname) / sizeof(WCHAR));
-    capsW.cDestinations = 2; /* speakers & record */
-    capsW.fdwSupport = 0; /* No bits defined yet */
-
-    memcpy(lpCaps, &capsW, min(dwSize, sizeof(capsW)));
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				MIX_GetLineInfoDst	[internal]
- */
-static	DWORD	MIX_GetLineInfoDst(struct mixer* mix, LPMIXERLINEW lpMl,
-                                   DWORD dst)
-{
-    unsigned mask;
-    int	j;
-
-    TRACE("(%p, %p, %08x)\n", mix, lpMl, dst);
-
-    lpMl->dwDestination = dst;
-    switch (dst)
-    {
-    case LINEID_SPEAKER:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
-	mask = mix->devMask;
-	j = SOUND_MIXER_VOLUME;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
-	break;
-    case LINEID_RECORD:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
-	mask = mix->recMask;
-	j = SOUND_MIXER_RECLEV;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
-	break;
-    default:
-	FIXME("shouldn't happen\n");
-	return MMSYSERR_ERROR;
-    }
-    lpMl->dwSource = 0xFFFFFFFF;
-    MultiByteToWideChar(CP_UNIXCP, 0, MIX_Labels[j], -1, lpMl->szShortName, sizeof(lpMl->szShortName) / sizeof(WCHAR));
-    MultiByteToWideChar(CP_UNIXCP, 0, MIX_Names[j],  -1, lpMl->szName,      sizeof(lpMl->szName) / sizeof(WCHAR));
-
-    /* we have all connections found in the MIX_DevMask */
-    lpMl->cConnections = 0;
-    for (j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-	if (WINE_CHN_SUPPORTS(mask, j))
-	    lpMl->cConnections++;
-    lpMl->cChannels = 1;
-    if (WINE_CHN_SUPPORTS(mix->stereoMask, lpMl->dwLineID))
-	lpMl->cChannels++;
-    lpMl->dwLineID = MAKELONG(dst, LINEID_DST);
-    lpMl->cControls = 0;
-    for (j = 0; j < mix->numCtrl; j++)
-	if (mix->ctrl[j].dwLineID == lpMl->dwLineID)
-	    lpMl->cControls++;
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				MIX_GetLineInfoSrc	[internal]
- */
-static	DWORD	MIX_GetLineInfoSrc(struct mixer* mix, LPMIXERLINEW lpMl,
-                                   DWORD idx, DWORD dst)
-{
-    int		i, j;
-    unsigned	mask = (dst) ? mix->recMask : mix->devMask;
-
-    TRACE("(%p, %p, %d, %08x)\n", mix, lpMl, idx, dst);
-
-    MultiByteToWideChar(CP_UNIXCP, 0, MIX_Labels[idx], -1, lpMl->szShortName, sizeof(lpMl->szShortName) / sizeof(WCHAR));
-    MultiByteToWideChar(CP_UNIXCP, 0, MIX_Names[idx],  -1, lpMl->szName,      sizeof(lpMl->szName) / sizeof(WCHAR));
-    lpMl->dwLineID = MAKELONG(dst, idx);
-    lpMl->dwDestination = dst;
-    lpMl->cConnections = 1;
-    lpMl->cControls = 0;
-    for (i = 0; i < mix->numCtrl; i++)
-	if (mix->ctrl[i].dwLineID == lpMl->dwLineID)
-	    lpMl->cControls++;
-
-    switch (idx)
-    {
-    case SOUND_MIXER_SYNTH:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT;
-	break;
-    case SOUND_MIXER_CD:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
-	break;
-    case SOUND_MIXER_LINE:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
-	break;
-    case SOUND_MIXER_MIC:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
-	break;
-    case SOUND_MIXER_PCM:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
-	break;
-    case SOUND_MIXER_IMIX:
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
-	lpMl->fdwLine	 |= MIXERLINE_LINEF_SOURCE;
-        lpMl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
-	break;
-    default:
-	WARN("Index %d not handled.\n", idx);
-	return MIXERR_INVALLINE;
-    }
-    lpMl->cChannels = 1;
-    if (dst == 0 && WINE_CHN_SUPPORTS(mix->stereoMask, idx))
-	lpMl->cChannels++;
-    for (i = j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-    {
-	if (WINE_CHN_SUPPORTS(mask, j))
-	{
-	    if (j == idx) break;
-	    i++;
-	}
-    }
-    lpMl->dwSource = i;
-    return MMSYSERR_NOERROR;
-}
-
-/******************************************************************
- *		MIX_CheckLine
- */
-static BOOL MIX_CheckLine(DWORD lineID)
-{
-    TRACE("(%08x)\n",lineID);
-
-    return ((HIWORD(lineID) < SOUND_MIXER_NRDEVICES && LOWORD(lineID) < 2) ||
-	    (HIWORD(lineID) == LINEID_DST &&
-             LOWORD(lineID) < SOUND_MIXER_NRDEVICES));
-}
-
-/**************************************************************************
- * 				MIX_GetLineInfo			[internal]
- */
-static DWORD MIX_GetLineInfo(WORD wDevID, LPMIXERLINEW lpMl, DWORD fdwInfo)
-{
-    int 		i, j;
-    DWORD		ret = MMSYSERR_NOERROR;
-    unsigned		mask;
-    struct mixer*	mix;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpMl, fdwInfo);
-
-    if (lpMl == NULL) {
-        WARN("invalid parameter: lpMl = NULL\n");
-	return MMSYSERR_INVALPARAM;
-    }
-
-    if (lpMl->cbStruct != sizeof(*lpMl)) {
-        WARN("invalid parameter: lpMl->cbStruct = %d\n",
-             lpMl->cbStruct);
-	return MMSYSERR_INVALPARAM;
-    }
-
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    /* FIXME: set all the variables correctly... the lines below
-     * are very wrong...
-     */
-    lpMl->fdwLine	= MIXERLINE_LINEF_ACTIVE;
-    lpMl->dwUser	= 0;
-
-    switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK)
-    {
-    case MIXER_GETLINEINFOF_DESTINATION:
-	TRACE("MIXER_GETLINEINFOF_DESTINATION (%08x)\n", lpMl->dwDestination);
-	if (lpMl->dwDestination >= 2) {
-            WARN("invalid parameter: lpMl->dwDestination = %d >= 2\n",
-                 lpMl->dwDestination);
-	    return MMSYSERR_INVALPARAM;
-        }
-	ret = MIX_GetLineInfoDst(mix, lpMl, lpMl->dwDestination);
-	if (ret != MMSYSERR_NOERROR) {
-            WARN("error\n");
-	    return ret;
-        }
-	break;
-    case MIXER_GETLINEINFOF_SOURCE:
-	TRACE("MIXER_GETLINEINFOF_SOURCE (%08x), dst=%08x\n", lpMl->dwSource,
-              lpMl->dwDestination);
-	switch (lpMl->dwDestination)
-	{
-	case LINEID_SPEAKER: mask = mix->devMask; break;
-	case LINEID_RECORD: mask = mix->recMask; break;
-	default:
-            WARN("invalid parameter\n");
-            return MMSYSERR_INVALPARAM;
-	}
-	i = lpMl->dwSource;
-	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-	{
-	    if (WINE_CHN_SUPPORTS(mask, j) && (i-- == 0))
-		break;
-	}
-	if (j >= SOUND_MIXER_NRDEVICES) {
-            WARN("invalid line\n");
-	    return MIXERR_INVALLINE;
-        }
-	ret = MIX_GetLineInfoSrc(mix, lpMl, j, lpMl->dwDestination);
-	if (ret != MMSYSERR_NOERROR) {
-            WARN("error\n");
-	    return ret;
-        }
-	break;
-    case MIXER_GETLINEINFOF_LINEID:
-	TRACE("MIXER_GETLINEINFOF_LINEID (%08x)\n", lpMl->dwLineID);
-
-	if (!MIX_CheckLine(lpMl->dwLineID)) {
-            WARN("invalid line\n");
-	    return MIXERR_INVALLINE;
-        }
-	if (HIWORD(lpMl->dwLineID) == LINEID_DST)
-	    ret = MIX_GetLineInfoDst(mix, lpMl, LOWORD(lpMl->dwLineID));
-	else
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, HIWORD(lpMl->dwLineID),
-                                     LOWORD(lpMl->dwLineID));
-	if (ret != MMSYSERR_NOERROR) {
-            WARN("error\n");
-	    return ret;
-        }
-	break;
-    case MIXER_GETLINEINFOF_COMPONENTTYPE:
-	TRACE("MIXER_GETLINEINFOF_COMPONENTTYPE (%s)\n",
-              getComponentType(lpMl->dwComponentType));
-	switch (lpMl->dwComponentType)
-	{
-	case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES:
-	case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
-	    ret = MIX_GetLineInfoDst(mix, lpMl, LINEID_SPEAKER);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_DST_LINE:
-	case MIXERLINE_COMPONENTTYPE_DST_VOICEIN:
-	case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
-	    ret = MIX_GetLineInfoDst(mix, lpMl, LINEID_RECORD);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_SYNTH, 0);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_CD, 0);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_LINE:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_LINE, 0);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_MIC, 1);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_PCM, 0);
-	    break;
-	case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED:
-	    ret = MIX_GetLineInfoSrc(mix, lpMl, SOUND_MIXER_IMIX, 1);
-	    break;
-	default:
-	    FIXME("Unhandled component type (%s)\n",
-                  getComponentType(lpMl->dwComponentType));
-	    return MMSYSERR_INVALPARAM;
-	}
-	break;
-    case MIXER_GETLINEINFOF_TARGETTYPE:
-	FIXME("MIXER_GETLINEINFOF_TARGETTYPE not implemented yet.\n");
-        TRACE("MIXER_GETLINEINFOF_TARGETTYPE (%s)\n",
-              getTargetType(lpMl->Target.dwType));
-        switch (lpMl->Target.dwType) {
-        case MIXERLINE_TARGETTYPE_UNDEFINED:
-        case MIXERLINE_TARGETTYPE_WAVEOUT:
-        case MIXERLINE_TARGETTYPE_WAVEIN:
-        case MIXERLINE_TARGETTYPE_MIDIOUT:
-        case MIXERLINE_TARGETTYPE_MIDIIN:
-        case MIXERLINE_TARGETTYPE_AUX:
-	default:
-	    FIXME("Unhandled target type (%s)\n",
-                  getTargetType(lpMl->Target.dwType));
-	    return MMSYSERR_INVALPARAM;
-        }
-	break;
-    default:
-	WARN("Unknown flag (%08lx)\n", fdwInfo & MIXER_GETLINEINFOF_QUERYMASK);
-	break;
-    }
-
-    if ((fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) != MIXER_GETLINEINFOF_TARGETTYPE) {
-        const char* name;
-        lpMl->Target.dwDeviceID = 0xFFFFFFFF;
-        lpMl->Target.wMid = WINE_MIXER_MANUF_ID;
-        lpMl->Target.wPid = WINE_MIXER_PRODUCT_ID;
-        lpMl->Target.vDriverVersion = WINE_MIXER_VERSION;
-        if (!(name = mix->name)) name = WINE_MIXER_NAME;
-        MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpMl->Target.szPname, sizeof(lpMl->Target.szPname) / sizeof(WCHAR));
-    }
-
-    return ret;
-}
-
-/******************************************************************
- *		MIX_CheckControl
- *
- */
-static BOOL	MIX_CheckControl(struct mixer* mix, DWORD ctrlID)
-{
-    TRACE("(%p, %08x)\n", mix, ctrlID);
-
-    return (ctrlID >= 1 && ctrlID <= mix->numCtrl);
-}
-
-/**************************************************************************
- * 				MIX_GetLineControls		[internal]
- */
-static	DWORD	MIX_GetLineControls(WORD wDevID, LPMIXERLINECONTROLSW lpMlc,
-                                    DWORD flags)
-{
-    DWORD		dwRet = MMSYSERR_NOERROR;
-    struct mixer*	mix;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpMlc, flags);
-
-    if (lpMlc == NULL) {
-        WARN("invalid parameter: lpMlc == NULL\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if (lpMlc->cbStruct < sizeof(*lpMlc)) {
-        WARN("invalid parameter: lpMlc->cbStruct = %d\n",
-             lpMlc->cbStruct);
-	return MMSYSERR_INVALPARAM;
-    }
-
-    if (lpMlc->cbmxctrl < sizeof(MIXERCONTROLW)) {
-        WARN("invalid parameter: lpMlc->cbmxctrl = %d\n",
-             lpMlc->cbmxctrl);
-	return MMSYSERR_INVALPARAM;
-    }
-
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    switch (flags & MIXER_GETLINECONTROLSF_QUERYMASK)
-    {
-    case MIXER_GETLINECONTROLSF_ALL:
-        {
-	    int		i, j;
-
-            TRACE("line=%08x MIXER_GETLINECONTROLSF_ALL (%d)\n",
-                  lpMlc->dwLineID, lpMlc->cControls);
-
-	    for (i = j = 0; i < mix->numCtrl; i++)
-	    {
-		if (mix->ctrl[i].dwLineID == lpMlc->dwLineID)
-		    j++;
-	    }
-
-	    if (!j || lpMlc->cControls != j) {
-                WARN("invalid parameter\n");
-                dwRet = MMSYSERR_INVALPARAM;
-	    } else if (!MIX_CheckLine(lpMlc->dwLineID)) {
-                WARN("invalid line\n");
-                dwRet = MIXERR_INVALLINE;
-	    } else {
-		for (i = j = 0; i < mix->numCtrl; i++)
-		{
-		    if (mix->ctrl[i].dwLineID == lpMlc->dwLineID)
-		    {
-			TRACE("[%d] => [%2d]: typ=%08x\n", j, i + 1,
-                              mix->ctrl[i].ctrl.dwControlType);
-			lpMlc->pamxctrl[j++] = mix->ctrl[i].ctrl;
-                    }
-		}
-	    }
-	}
-	break;
-    case MIXER_GETLINECONTROLSF_ONEBYID:
-	TRACE("line=%08x MIXER_GETLINECONTROLSF_ONEBYID (%x)\n",
-              lpMlc->dwLineID, lpMlc->u.dwControlID);
-
-	if (!MIX_CheckControl(mix, lpMlc->u.dwControlID) ||
-	    mix->ctrl[lpMlc->u.dwControlID - 1].dwLineID != lpMlc->dwLineID) {
-            WARN("invalid parameter\n");
-	    dwRet = MMSYSERR_INVALPARAM;
-	} else
-	    lpMlc->pamxctrl[0] = mix->ctrl[lpMlc->u.dwControlID - 1].ctrl;
-	break;
-    case MIXER_GETLINECONTROLSF_ONEBYTYPE:
-	TRACE("line=%08x MIXER_GETLINECONTROLSF_ONEBYTYPE (%s)\n",
-              lpMlc->dwLineID, getControlType(lpMlc->u.dwControlType));
-	if (!MIX_CheckLine(lpMlc->dwLineID)) {
-            WARN("invalid line\n");
-            dwRet = MIXERR_INVALLINE;
-	} else {
-	    int	  i;
-	    DWORD ct = lpMlc->u.dwControlType & MIXERCONTROL_CT_CLASS_MASK;
-	    for (i = 0; i < mix->numCtrl; i++) {
-		if (mix->ctrl[i].dwLineID == lpMlc->dwLineID &&
-		    ct == (mix->ctrl[i].ctrl.dwControlType &
-                    MIXERCONTROL_CT_CLASS_MASK)) {
-		    lpMlc->pamxctrl[0] = mix->ctrl[i].ctrl;
-		    break;
-		}
-	    }
-
-	    if (i == mix->numCtrl) {
-                WARN("invalid parameter: control not found\n");
-                dwRet = MMSYSERR_INVALPARAM;
-            }
-	}
-	break;
-    default:
-	ERR("Unknown flag %08lx\n", flags & MIXER_GETLINECONTROLSF_QUERYMASK);
-	dwRet = MMSYSERR_INVALPARAM;
-    }
-
-    return dwRet;
-}
-
-/**************************************************************************
- * 				MIX_GetControlDetails		[internal]
- */
-static	DWORD	MIX_GetControlDetails(WORD wDevID, LPMIXERCONTROLDETAILS lpmcd,
-                                      DWORD fdwDetails)
-{
-    DWORD		ret = MMSYSERR_NOTSUPPORTED;
-    DWORD		chnl;
-    struct mixer*	mix;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpmcd, fdwDetails);
-
-    if (lpmcd == NULL) {
-        WARN("invalid parameter: lpmcd == NULL\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK)
-    {
-    case MIXER_GETCONTROLDETAILSF_VALUE:
-	TRACE("MIXER_GETCONTROLDETAILSF_VALUE (%08x)\n", lpmcd->dwControlID);
-	if (MIX_CheckControl(mix, lpmcd->dwControlID))
-	{
-	    DWORD c = lpmcd->dwControlID - 1;
-	    chnl = HIWORD(mix->ctrl[c].dwLineID);
-	    if (chnl == LINEID_DST)
-		chnl = LOWORD(mix->ctrl[c].dwLineID) ? SOUND_MIXER_RECLEV :
-                    SOUND_MIXER_VOLUME;
-	    switch (mix->ctrl[c].ctrl.dwControlType)
-	    {
-	    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-		{
-		    LPMIXERCONTROLDETAILS_UNSIGNED	mcdu;
-		    int					val;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_UNSIGNED)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_UNSIGNED[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-                    mcdu = lpmcd->paDetails;
-
-		    /* return value is 00RL (4 bytes)... */
-		    if ((val = mix->volume[chnl]) == -1 &&
-                        !MIX_GetVal(mix, chnl, &val)) {
-                        WARN("invalid parameter\n");
-			return MMSYSERR_INVALPARAM;
-                    }
-
-		    switch (lpmcd->cChannels)
-		    {
-		    case 1:
-			/* mono... so R = L */
-			mcdu->dwValue = ((LOBYTE(LOWORD(val)) * 65536.0) / 100.0) + 0.5;
-			TRACE("Reading RL = %d\n", mcdu->dwValue);
-			break;
-		    case 2:
-			/* stereo, left is paDetails[0] */
-			mcdu->dwValue = ((LOBYTE(LOWORD(val)) * 65536.0) / 100.0) + 0.5;
-			TRACE("Reading L = %d\n", mcdu->dwValue);
-                        mcdu++;
-			mcdu->dwValue = ((HIBYTE(LOWORD(val)) * 65536.0) / 100.0) + 0.5;
-			TRACE("Reading R = %d\n", mcdu->dwValue);
-			break;
-		    default:
-			WARN("Unsupported cChannels (%d)\n", lpmcd->cChannels);
-			return MMSYSERR_INVALPARAM;
-		    }
-                    TRACE("=> %08x\n", mcdu->dwValue);
-		}
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MUTE:
-	    case MIXERCONTROL_CONTROLTYPE_ONOFF:
-		{
-		    LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_BOOLEAN)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-		    /* we mute both channels at the same time */
-                    mcdb = lpmcd->paDetails;
-		    mcdb->fValue = (mix->volume[chnl] != -1);
-		    TRACE("=> %s\n", mcdb->fValue ? "on" : "off");
-		}
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MIXER:
-	    case MIXERCONTROL_CONTROLTYPE_MUX:
-		{
-		    unsigned				mask;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_BOOLEAN)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-		    if (!MIX_GetRecSrc(mix, &mask))
-		    {
-			/* FIXME: ENXIO => no mixer installed */
-			WARN("mixer device not available !\n");
-			ret = MMSYSERR_ERROR;
-		    }
-		    else
-		    {
-			LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-			int				i, j;
-
-			/* we mute both channels at the same time */
-			mcdb = lpmcd->paDetails;
-
-			for (i = j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-			{
-			    if (WINE_CHN_SUPPORTS(mix->recMask, j))
-			    {
-				if (i >= lpmcd->u.cMultipleItems)
-				    return MMSYSERR_INVALPARAM;
-				mcdb[i++].fValue = WINE_CHN_SUPPORTS(mask, j);
-			    }
-			}
-		    }
-		}
-		break;
-	    default:
-		WARN("%s Unsupported\n",
-                     getControlType(mix->ctrl[c].ctrl.dwControlType));
-	    }
-	    ret = MMSYSERR_NOERROR;
-	}
-	else
-	{
-            WARN("invalid parameter\n");
-	    ret = MMSYSERR_INVALPARAM;
-	}
-	break;
-    case MIXER_GETCONTROLDETAILSF_LISTTEXT:
-	TRACE("MIXER_GETCONTROLDETAILSF_LISTTEXT (%08x)\n",
-              lpmcd->dwControlID);
-
-	ret = MMSYSERR_INVALPARAM;
-	if (MIX_CheckControl(mix, lpmcd->dwControlID))
-	{
-	    DWORD c = lpmcd->dwControlID - 1;
-
-	    if (mix->ctrl[c].ctrl.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ||
-		mix->ctrl[c].ctrl.dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
-	    {
-		LPMIXERCONTROLDETAILS_LISTTEXTW	mcdlt;
-		int i, j;
-
-		mcdlt = lpmcd->paDetails;
-		for (i = j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-		{
-		    if (WINE_CHN_SUPPORTS(mix->recMask, j))
-		    {
-			mcdlt[i].dwParam1 = MAKELONG(LINEID_RECORD, j);
-			mcdlt[i].dwParam2 = 0;
-			MultiByteToWideChar(CP_UNIXCP, 0, MIX_Names[j], -1,
-                                            mcdlt[i].szName, sizeof(mcdlt[i]) / sizeof(WCHAR));
-			i++;
-		    }
-		}
-		if (i != lpmcd->u.cMultipleItems) FIXME("bad count\n");
-		ret = MMSYSERR_NOERROR;
-	    }
-	}
-	break;
-    default:
-	WARN("Unknown flag (%08lx)\n",
-             fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK);
-    }
-    return ret;
-}
-
-/**************************************************************************
- * 				MIX_SetControlDetails		[internal]
- */
-static	DWORD	MIX_SetControlDetails(WORD wDevID, LPMIXERCONTROLDETAILS lpmcd,
-                                      DWORD fdwDetails)
-{
-    DWORD		ret = MMSYSERR_NOTSUPPORTED;
-    DWORD		c, chnl;
-    int			val;
-    struct mixer*	mix;
-
-    TRACE("(%04X, %p, %u);\n", wDevID, lpmcd, fdwDetails);
-
-    if (lpmcd == NULL) {
-        TRACE("invalid parameter: lpmcd == NULL\n");
-        return MMSYSERR_INVALPARAM;
-    }
-
-    if ((mix = MIX_Get(wDevID)) == NULL) {
-        WARN("bad device ID: %04X\n", wDevID);
-        return MMSYSERR_BADDEVICEID;
-    }
-
-    switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK)
-    {
-    case MIXER_GETCONTROLDETAILSF_VALUE:
-	TRACE("MIXER_GETCONTROLDETAILSF_VALUE (%08x)\n", lpmcd->dwControlID);
-	if (MIX_CheckControl(mix, lpmcd->dwControlID))
-	{
-	    c = lpmcd->dwControlID - 1;
-
-            TRACE("dwLineID=%08x\n",mix->ctrl[c].dwLineID);
-
-	    chnl = HIWORD(mix->ctrl[c].dwLineID);
-	    if (chnl == LINEID_DST)
-		chnl = LOWORD(mix->ctrl[c].dwLineID) ?
-                    SOUND_MIXER_RECLEV : SOUND_MIXER_VOLUME;
-
-	    switch (mix->ctrl[c].ctrl.dwControlType)
-	    {
-	    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-		{
-		    LPMIXERCONTROLDETAILS_UNSIGNED	mcdu;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_UNSIGNED)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_UNSIGNED[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-                    mcdu = lpmcd->paDetails;
-		    /* val should contain 00RL */
-		    switch (lpmcd->cChannels)
-		    {
-		    case 1:
-			/* mono... so R = L */
-			TRACE("Setting RL to %d\n", mcdu->dwValue);
-			val = 0x101 * ((mcdu->dwValue * 100) >> 16);
-			break;
-		    case 2:
-			/* stereo, left is paDetails[0] */
-			TRACE("Setting L to %d\n", mcdu->dwValue);
-			val = ((mcdu->dwValue * 100.0) / 65536.0) + 0.5;
-                        mcdu++;
-			TRACE("Setting R to %d\n", mcdu->dwValue);
-			val += (int)(((mcdu->dwValue * 100) / 65536.0) + 0.5) << 8;
-			break;
-		    default:
-			WARN("Unsupported cChannels (%d)\n", lpmcd->cChannels);
-			return MMSYSERR_INVALPARAM;
-		    }
-
-		    if (mix->volume[chnl] == -1)
-		    {
-			if (!MIX_SetVal(mix, chnl, val)) {
-                            WARN("invalid parameter\n");
-			    return MMSYSERR_INVALPARAM;
-                        }
-		    }
-		    else
-		    {
-			mix->volume[chnl] = val;
-		    }
-		}
-		ret = MMSYSERR_NOERROR;
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MUTE:
-	    case MIXERCONTROL_CONTROLTYPE_ONOFF:
-		{
-		    LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_BOOLEAN)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-                    mcdb = lpmcd->paDetails;
-		    if (mcdb->fValue)
-		    {
-                        /* save the volume and then set it to 0 */
-			if (!MIX_GetVal(mix, chnl, &mix->volume[chnl]) ||
-                            !MIX_SetVal(mix, chnl, 0)) {
-                            WARN("invalid parameter\n");
-			    return MMSYSERR_INVALPARAM;
-                        }
-		    }
-		    else
-		    {
-			if (mix->volume[chnl] == -1)
-			{
-			    ret = MMSYSERR_NOERROR;
-			    break;
-			}
-			if (!MIX_SetVal(mix, chnl, mix->volume[chnl])) {
-                            WARN("invalid parameter\n");
-			    return MMSYSERR_INVALPARAM;
-                        }
-			mix->volume[chnl] = -1;
-		    }
-		}
-		ret = MMSYSERR_NOERROR;
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MIXER:
-	    case MIXERCONTROL_CONTROLTYPE_MUX:
-		{
-		    LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-		    unsigned				mask;
-		    int					i, j;
-
-                    if (lpmcd->cbDetails !=
-                        sizeof(MIXERCONTROLDETAILS_BOOLEAN)) {
-                        WARN("invalid parameter: cbDetails = %d\n",
-                             lpmcd->cbDetails);
-                        return MMSYSERR_INVALPARAM;
-                    }
-
-                    TRACE("%s MIXERCONTROLDETAILS_BOOLEAN[%u]\n",
-                          getControlType(mix->ctrl[c].ctrl.dwControlType),
-                          lpmcd->cChannels);
-
-		    /* we mute both channels at the same time */
-                    mcdb = lpmcd->paDetails;
-		    mask = 0;
-		    for (i = j = 0; j < SOUND_MIXER_NRDEVICES; j++)
-		    {
-			if (WINE_CHN_SUPPORTS(mix->recMask, j) &&
-                            mcdb[i++].fValue)
-			{
-			    /* a mux can only select one line at a time... */
-			    if (mix->singleRecChannel && mask != 0)
-			    {
-				FIXME("!!!\n");
-				return MMSYSERR_INVALPARAM;
-			    }
-			    mask |= WINE_CHN_MASK(j);
-			}
-		    }
-		    if (i != lpmcd->u.cMultipleItems)
-                        FIXME("bad count\n");
-		    TRACE("writing %04x as rec src\n", mask);
-		    if (!MIX_SetRecSrc(mix, mask))
-			ERR("Can't write new mixer settings\n");
-		    else
-			ret = MMSYSERR_NOERROR;
-		}
-		break;
-	    }
-	}
-	break;
-    default:
-	WARN("Unknown SetControlDetails flag (%08lx)\n",
-             fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK);
-    }
-    return ret;
-}
-
-/**************************************************************************
- * 				MIX_Init			[internal]
- */
-static LRESULT OSS_MixerInit(void)
-{
-    int	i, mixer;
-
-    TRACE("()\n");
-
-    MIX_NumMixers = 0;
-
-    for (i = 0; i < MAX_MIXERDRV; i++) {
-        char name[32];
-
-        if (i == 0)
-            sprintf(name, "/dev/mixer");
-        else
-            sprintf(name, "/dev/mixer%d", i);
-
-        if ((mixer = open(name, O_RDWR)) >= 0) {
-#ifdef SOUND_MIXER_INFO
-            mixer_info info;
-            if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) {
-                MIX_Mixers[MIX_NumMixers].name = HeapAlloc(GetProcessHeap(),0,strlen(info.name) + 1);
-                strcpy(MIX_Mixers[MIX_NumMixers].name, info.name);
-            } else {
-                /* FreeBSD up to at least 5.2 provides this ioctl, but does not
-                 * implement it properly, and there are probably similar issues
-                 * on other platforms, so we warn but try to go ahead.
-                 */
-                WARN("%s: cannot read SOUND_MIXER_INFO!\n", name);
-            }
-#endif
-            close(mixer);
-
-            MIX_Mixers[MIX_NumMixers].dev_name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
-            strcpy(MIX_Mixers[MIX_NumMixers].dev_name, name);
-            MIX_NumMixers++;
-            MIX_Open(MIX_NumMixers - 1, NULL, 0); /* FIXME */
-        } else {
-            WARN("couldn't open %s\n", name);
-        }
-    }
-
-    if (MIX_NumMixers == 0) {
-        WARN("no driver\n");
-        return MMSYSERR_NODRIVER;
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				MIX_Exit			[internal]
- */
-static LRESULT OSS_MixerExit(void)
-{
-    int	i;
-
-    TRACE("()\n");
-
-    for (i = 0; i < MIX_NumMixers; i++) {
-        HeapFree(GetProcessHeap(),0,MIX_Mixers[i].name);
-        HeapFree(GetProcessHeap(),0,MIX_Mixers[i].dev_name);
-    }
-
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				MIX_GetNumDevs			[internal]
- */
-static	DWORD	MIX_GetNumDevs(void)
-{
-    TRACE("()\n");
-
-    return MIX_NumMixers;
-}
-
-/**************************************************************************
- * 				mxdMessage (WINEOSS.3)
- */
-DWORD WINAPI OSS_mxdMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
-			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
-    TRACE("(%04X, %s, %08lX, %08lX, %08lX);\n", wDevID, getMessage(wMsg),
-          dwUser, dwParam1, dwParam2);
-
-    switch (wMsg)
-    {
-    case DRVM_INIT:
-        return OSS_MixerInit();
-    case DRVM_EXIT:
-        return OSS_MixerExit();
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
-    case MXDM_GETDEVCAPS:
-        return MIX_GetDevCaps(wDevID, (LPMIXERCAPSW)dwParam1, dwParam2);
-    case MXDM_GETLINEINFO:
-	return MIX_GetLineInfo(wDevID, (LPMIXERLINEW)dwParam1, dwParam2);
-    case MXDM_GETNUMDEVS:
-	return MIX_GetNumDevs();
-    case MXDM_OPEN:
-	return MMSYSERR_NOERROR;
-	/* MIX_Open(wDevID, (LPMIXEROPENDESC)dwParam1, dwParam2); */
-    case MXDM_CLOSE:
-	return MMSYSERR_NOERROR;
-    case MXDM_GETLINECONTROLS:
-	return MIX_GetLineControls(wDevID, (LPMIXERLINECONTROLSW)dwParam1, dwParam2);
-    case MXDM_GETCONTROLDETAILS:
-	return MIX_GetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2);
-    case MXDM_SETCONTROLDETAILS:
-	return MIX_SetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2);
-    default:
-	WARN("unknown message %d!\n", wMsg);
-	return MMSYSERR_NOTSUPPORTED;
-    }
-}
diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c
index b7e3bbf..01a8fe7 100644
--- a/dlls/wineoss.drv/mmdevdrv.c
+++ b/dlls/wineoss.drv/mmdevdrv.c
@@ -47,9 +47,9 @@
 #include "devpkey.h"
 #include "dshow.h"
 #include "dsound.h"
-#include "endpointvolume.h"
 
 #include "initguid.h"
+#include "endpointvolume.h"
 #include "audiopolicy.h"
 #include "audioclient.h"
 
diff --git a/dlls/wineoss.drv/wineoss.drv.spec b/dlls/wineoss.drv/wineoss.drv.spec
index 4b12196..13723e6 100644
--- a/dlls/wineoss.drv/wineoss.drv.spec
+++ b/dlls/wineoss.drv/wineoss.drv.spec
@@ -1,11 +1,8 @@
 # WinMM driver functions
 @ stdcall -private DriverProc(long long long long long) OSS_DriverProc
 @ stdcall -private auxMessage(long long long long long) OSS_auxMessage
-@ stdcall -private mxdMessage(long long long long long) OSS_mxdMessage
 @ stdcall -private midMessage(long long long long long) OSS_midMessage
 @ stdcall -private modMessage(long long long long long) OSS_modMessage
-@ stdcall -private widMessage(long long long long long) OSS_widMessage
-@ stdcall -private wodMessage(long long long long long) OSS_wodMessage
 
 # MMDevAPI driver functions
 @ stdcall -private GetPriority() AUDDRV_GetPriority



More information about the wine-tests-results mailing list