comctl32: Validate the day of month when scrolling through years.
[wine] / dlls / wineoss.drv / dscapture.c
1 /*
2  * Direct Sound Capture driver
3  *
4  * Copyright 2004 Robert Reif
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_IOCTL_H
34 # include <sys/ioctl.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
39 #ifdef HAVE_POLL_H
40 #include <poll.h>
41 #endif
42 #ifdef HAVE_SYS_POLL_H
43 # include <sys/poll.h>
44 #endif
45 #if defined(HAVE_SYS_SOUNDCARD_H)
46 # include <sys/soundcard.h>
47 #elif defined(HAVE_MACHINE_SOUNDCARD_H)
48 # include <machine/soundcard.h>
49 #elif defined(HAVE_SOUNDCARD_H)
50 # include <soundcard.h>
51 #endif
52 #ifdef HAVE_SYS_ERRNO_H
53 #include <sys/errno.h>
54 #endif
55
56 #include "windef.h"
57 #include "winbase.h"
58 #include "wingdi.h"
59 #include "winuser.h"
60 #include "winerror.h"
61 #include "mmddk.h"
62 #include "mmreg.h"
63 #include "dsound.h"
64 #include "dsdriver.h"
65 #include "wine/debug.h"
66
67 #include "audio.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(dscapture);
70
71 /*======================================================================*
72  *           Low level DSOUND capture definitions                       *
73  *======================================================================*/
74
75 typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
76 typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
77 typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
78 typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
79
80 struct IDsCaptureDriverPropertySetImpl
81 {
82     /* IUnknown fields */
83     IDsDriverPropertySet                IDsDriverPropertySet_iface;
84     LONG                                ref;
85
86     IDsCaptureDriverBufferImpl*         capture_buffer;
87 };
88
89 struct IDsCaptureDriverNotifyImpl
90 {
91     /* IUnknown fields */
92     IDsDriverNotify                     IDsDriverNotify_iface;
93     LONG                                ref;
94
95     IDsCaptureDriverBufferImpl*         capture_buffer;
96 };
97
98 struct IDsCaptureDriverImpl
99 {
100     /* IUnknown fields */
101     IDsCaptureDriver                    IDsCaptureDriver_iface;
102     LONG                                ref;
103
104     /* IDsCaptureDriverImpl fields */
105     UINT                                wDevID;
106     IDsCaptureDriverBufferImpl*         capture_buffer;
107 };
108
109 struct IDsCaptureDriverBufferImpl
110 {
111     /* IUnknown fields */
112     IDsCaptureDriverBuffer              IDsCaptureDriverBuffer_iface;
113     LONG                                ref;
114
115     /* IDsCaptureDriverBufferImpl fields */
116     IDsCaptureDriverImpl*               drv;
117     LPBYTE                              buffer;         /* user buffer */
118     DWORD                               buflen;         /* user buffer length */
119     LPBYTE                              mapping;        /* DMA buffer */
120     DWORD                               maplen;         /* DMA buffer length */
121     BOOL                                is_direct_map;  /* DMA == user ? */
122     DWORD                               fragsize;
123     DWORD                               map_writepos;   /* DMA write offset */
124     DWORD                               map_readpos;    /* DMA read offset */
125     DWORD                               writeptr;       /* user write offset */
126     DWORD                               readptr;        /* user read offset */
127
128     /* IDsDriverNotifyImpl fields */
129     IDsCaptureDriverNotifyImpl*         notify;
130     int                                 notify_index;
131     LPDSBPOSITIONNOTIFY                 notifies;
132     int                                 nrofnotifies;
133
134     /* IDsDriverPropertySetImpl fields */
135     IDsCaptureDriverPropertySetImpl*    property_set;
136
137     BOOL                                is_capturing;
138     BOOL                                is_looping;
139     WAVEFORMATEX                        wfx;
140     HANDLE                              hThread;
141     DWORD                               dwThreadID;
142     HANDLE                              hStartUpEvent;
143     HANDLE                              hExitEvent;
144     int                                 pipe_fd[2];
145     int                                 fd;
146 };
147
148 static inline IDsCaptureDriverPropertySetImpl *impl_from_IDsDriverPropertySet(IDsDriverPropertySet *iface)
149 {
150     return CONTAINING_RECORD(iface, IDsCaptureDriverPropertySetImpl, IDsDriverPropertySet_iface);
151 }
152
153 static inline IDsCaptureDriverNotifyImpl *impl_from_IDsDriverNotify(IDsDriverNotify *iface)
154 {
155     return CONTAINING_RECORD(iface, IDsCaptureDriverNotifyImpl, IDsDriverNotify_iface);
156 }
157
158 static inline IDsCaptureDriverImpl *impl_from_IDsCaptureDriver(IDsCaptureDriver *iface)
159 {
160     return CONTAINING_RECORD(iface, IDsCaptureDriverImpl, IDsCaptureDriver_iface);
161 }
162
163 static inline IDsCaptureDriverBufferImpl *impl_from_IDsCaptureDriverBuffer(IDsCaptureDriverBuffer *iface)
164 {
165     return CONTAINING_RECORD(iface, IDsCaptureDriverBufferImpl, IDsCaptureDriverBuffer_iface);
166 }
167
168 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
169     IDsCaptureDriverBufferImpl * dscdb,
170     IDsCaptureDriverPropertySetImpl **pdscdps);
171
172 static HRESULT IDsCaptureDriverNotifyImpl_Create(
173     IDsCaptureDriverBufferImpl * dsdcb,
174     IDsCaptureDriverNotifyImpl **pdscdn);
175
176 /*======================================================================*
177  *           Low level DSOUND capture property set implementation       *
178  *======================================================================*/
179
180 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
181     PIDSDRIVERPROPERTYSET iface,
182     REFIID riid,
183     LPVOID *ppobj)
184 {
185     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
186     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
187
188     if ( IsEqualGUID(riid, &IID_IUnknown) ||
189          IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
190         IDsDriverPropertySet_AddRef(iface);
191         *ppobj = This;
192         return DS_OK;
193     }
194
195     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
196
197     *ppobj = 0;
198     return E_NOINTERFACE;
199 }
200
201 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
202     PIDSDRIVERPROPERTYSET iface)
203 {
204     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
205     ULONG refCount = InterlockedIncrement(&This->ref);
206
207     TRACE("(%p) ref was %d\n", This, refCount - 1);
208
209     return refCount;
210 }
211
212 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
213     PIDSDRIVERPROPERTYSET iface)
214 {
215     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
216     ULONG refCount = InterlockedDecrement(&This->ref);
217
218     TRACE("(%p) ref was %d\n", This, refCount + 1);
219
220     if (!refCount) {
221         IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
222         This->capture_buffer->property_set = NULL;
223         HeapFree(GetProcessHeap(),0,This);
224         TRACE("(%p) released\n",This);
225     }
226     return refCount;
227 }
228
229 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
230     PIDSDRIVERPROPERTYSET iface,
231     PDSPROPERTY pDsProperty,
232     LPVOID pPropertyParams,
233     ULONG cbPropertyParams,
234     LPVOID pPropertyData,
235     ULONG cbPropertyData,
236     PULONG pcbReturnedData )
237 {
238     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
239     FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,
240           cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
241     return DSERR_UNSUPPORTED;
242 }
243
244 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
245     PIDSDRIVERPROPERTYSET iface,
246     PDSPROPERTY pDsProperty,
247     LPVOID pPropertyParams,
248     ULONG cbPropertyParams,
249     LPVOID pPropertyData,
250     ULONG cbPropertyData )
251 {
252     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
253     FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,
254           cbPropertyParams,pPropertyData,cbPropertyData);
255     return DSERR_UNSUPPORTED;
256 }
257
258 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
259     PIDSDRIVERPROPERTYSET iface,
260     REFGUID PropertySetId,
261     ULONG PropertyId,
262     PULONG pSupport )
263 {
264     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
265     FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
266           pSupport);
267     return DSERR_UNSUPPORTED;
268 }
269
270 static const IDsDriverPropertySetVtbl dscdpsvt =
271 {
272     IDsCaptureDriverPropertySetImpl_QueryInterface,
273     IDsCaptureDriverPropertySetImpl_AddRef,
274     IDsCaptureDriverPropertySetImpl_Release,
275     IDsCaptureDriverPropertySetImpl_Get,
276     IDsCaptureDriverPropertySetImpl_Set,
277     IDsCaptureDriverPropertySetImpl_QuerySupport,
278 };
279
280 /*======================================================================*
281  *                  Low level DSOUND capture notify implementation      *
282  *======================================================================*/
283
284 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
285     PIDSDRIVERNOTIFY iface,
286     REFIID riid,
287     LPVOID *ppobj)
288 {
289     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
290     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
291
292     if ( IsEqualGUID(riid, &IID_IUnknown) ||
293          IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
294         IDsDriverNotify_AddRef(iface);
295         *ppobj = This;
296         return DS_OK;
297     }
298
299     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
300
301     *ppobj = 0;
302     return E_NOINTERFACE;
303 }
304
305 static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
306     PIDSDRIVERNOTIFY iface)
307 {
308     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
309     ULONG refCount = InterlockedIncrement(&This->ref);
310
311     TRACE("(%p) ref was %d\n", This, refCount - 1);
312
313     return refCount;
314 }
315
316 static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
317     PIDSDRIVERNOTIFY iface)
318 {
319     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
320     ULONG refCount = InterlockedDecrement(&This->ref);
321
322     TRACE("(%p) ref was %d\n", This, refCount + 1);
323
324     if (!refCount) {
325         IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
326         This->capture_buffer->notify = NULL;
327         HeapFree(GetProcessHeap(),0,This);
328         TRACE("(%p) released\n",This);
329     }
330     return refCount;
331 }
332
333 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
334     PIDSDRIVERNOTIFY iface,
335     DWORD howmuch,
336     LPCDSBPOSITIONNOTIFY notify)
337 {
338     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
339     TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
340
341     if (!notify) {
342         WARN("invalid parameter\n");
343         return DSERR_INVALIDPARAM;
344     }
345
346     if (TRACE_ON(dscapture)) {
347         DWORD i;
348         for (i=0;i<howmuch;i++)
349             TRACE("notify at %d to 0x%08lx\n",
350                 notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
351     }
352
353     /* Make an internal copy of the caller-supplied array.
354      * Replace the existing copy if one is already present. */
355     if (This->capture_buffer->notifies)
356         This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
357             HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
358             howmuch * sizeof(DSBPOSITIONNOTIFY));
359     else
360         This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
361             HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
362
363     memcpy(This->capture_buffer->notifies, notify,
364            howmuch * sizeof(DSBPOSITIONNOTIFY));
365     This->capture_buffer->nrofnotifies = howmuch;
366
367     return S_OK;
368 }
369
370 static const IDsDriverNotifyVtbl dscdnvt =
371 {
372     IDsCaptureDriverNotifyImpl_QueryInterface,
373     IDsCaptureDriverNotifyImpl_AddRef,
374     IDsCaptureDriverNotifyImpl_Release,
375     IDsCaptureDriverNotifyImpl_SetNotificationPositions,
376 };
377
378 /*======================================================================*
379  *                  Low level DSOUND capture implementation             *
380  *======================================================================*/
381
382 static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
383 {
384     if (!dscdb->mapping) {
385         dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
386                               WInDev[dscdb->drv->wDevID].ossdev.fd, 0);
387         if (dscdb->mapping == (LPBYTE)-1) {
388             TRACE("(%p): Could not map sound device for direct access (%s)\n",
389                   dscdb, strerror(errno));
390             return DSERR_GENERIC;
391         }
392         TRACE("(%p): sound device has been mapped for direct access at %p, "
393               "size=%d\n", dscdb, dscdb->mapping, dscdb->maplen);
394     }
395     return DS_OK;
396 }
397
398 static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
399 {
400     if (dscdb->mapping) {
401         if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
402             ERR("(%p): Could not unmap sound device (%s)\n",
403                 dscdb, strerror(errno));
404             return DSERR_GENERIC;
405         }
406         dscdb->mapping = NULL;
407         TRACE("(%p): sound device unmapped\n", dscdb);
408     }
409     return DS_OK;
410 }
411
412 static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
413     PIDSCDRIVERBUFFER iface,
414     REFIID riid,
415     LPVOID *ppobj)
416 {
417     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
418     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
419
420     *ppobj = 0;
421
422     if ( IsEqualGUID(riid, &IID_IUnknown) ||
423          IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
424         IDsCaptureDriverBuffer_AddRef(iface);
425         *ppobj = This;
426         return DS_OK;
427     }
428
429     if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
430         if (!This->notify)
431             IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
432         if (This->notify) {
433             IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
434             *ppobj = This->notify;
435             return DS_OK;
436         }
437         return E_FAIL;
438     }
439
440     if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
441         if (!This->property_set)
442             IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
443         if (This->property_set) {
444             IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
445             *ppobj = This->property_set;
446             return DS_OK;
447         }
448         return E_FAIL;
449     }
450
451     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
452     return DSERR_UNSUPPORTED;
453 }
454
455 static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
456 {
457     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
458     ULONG refCount = InterlockedIncrement(&This->ref);
459
460     TRACE("(%p) ref was %d\n", This, refCount - 1);
461
462     return refCount;
463 }
464
465 static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
466 {
467     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
468     ULONG refCount = InterlockedDecrement(&This->ref);
469     TRACE("(%p) ref was %d\n", This, refCount + 1);
470
471     if (!refCount) {
472         WINE_WAVEIN*        wwi;
473
474         wwi = &WInDev[This->drv->wDevID];
475
476         if (This->hThread) {
477             int x = 0;
478
479             /* request thread termination */
480             write(This->pipe_fd[1], &x, sizeof(x));
481
482             /* wait for reply */
483             WaitForSingleObject(This->hExitEvent, INFINITE);
484             CloseHandle(This->hExitEvent);
485         }
486
487         close(This->pipe_fd[0]);
488         close(This->pipe_fd[1]);
489
490         DSCDB_UnmapBuffer(This);
491
492         OSS_CloseDevice(&wwi->ossdev);
493         wwi->state = WINE_WS_CLOSED;
494         wwi->dwFragmentSize = 0;
495         This->drv->capture_buffer = NULL;
496
497         HeapFree(GetProcessHeap(), 0, This->notifies);
498         HeapFree(GetProcessHeap(),0,This);
499         TRACE("(%p) released\n",This);
500     }
501     return refCount;
502 }
503
504 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
505     PIDSCDRIVERBUFFER iface,
506     LPVOID* ppvAudio1,
507     LPDWORD pdwLen1,
508     LPVOID* ppvAudio2,
509     LPDWORD pdwLen2,
510     DWORD dwWritePosition,
511     DWORD dwWriteLen,
512     DWORD dwFlags)
513 {
514     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
515     TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n",This,ppvAudio1,pdwLen1,
516           ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
517
518     if (This->is_direct_map) {
519         if (ppvAudio1)
520             *ppvAudio1 = This->mapping + dwWritePosition;
521
522         if (dwWritePosition + dwWriteLen < This->maplen) {
523             if (pdwLen1)
524                 *pdwLen1 = dwWriteLen;
525             if (ppvAudio2)
526                 *ppvAudio2 = 0;
527             if (pdwLen2)
528                 *pdwLen2 = 0;
529         } else {
530             if (pdwLen1)
531                 *pdwLen1 = This->maplen - dwWritePosition;
532             if (ppvAudio2)
533                 *ppvAudio2 = 0;
534             if (pdwLen2)
535                 *pdwLen2 = dwWriteLen - (This->maplen - dwWritePosition);
536         }
537     } else {
538         if (ppvAudio1)
539             *ppvAudio1 = This->buffer + dwWritePosition;
540
541         if (dwWritePosition + dwWriteLen < This->buflen) {
542             if (pdwLen1)
543                 *pdwLen1 = dwWriteLen;
544             if (ppvAudio2)
545                 *ppvAudio2 = 0;
546             if (pdwLen2)
547                 *pdwLen2 = 0;
548         } else {
549             if (pdwLen1)
550                 *pdwLen1 = This->buflen - dwWritePosition;
551             if (ppvAudio2)
552                 *ppvAudio2 = 0;
553             if (pdwLen2)
554                 *pdwLen2 = dwWriteLen - (This->buflen - dwWritePosition);
555         }
556     }
557
558     return DS_OK;
559 }
560
561 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
562     PIDSCDRIVERBUFFER iface,
563     LPVOID pvAudio1,
564     DWORD dwLen1,
565     LPVOID pvAudio2,
566     DWORD dwLen2)
567 {
568     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
569     TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
570
571     if (This->is_direct_map)
572         This->map_readpos = (This->map_readpos + dwLen1 + dwLen2) % This->maplen;
573     else
574         This->readptr = (This->readptr + dwLen1 + dwLen2) % This->buflen;
575
576     return DS_OK;
577 }
578
579 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
580     PIDSCDRIVERBUFFER iface,
581     LPDWORD lpdwCapture,
582     LPDWORD lpdwRead)
583 {
584     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
585     TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
586
587     if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
588         ERR("device not open, but accessing?\n");
589         return DSERR_UNINITIALIZED;
590     }
591
592     if (!This->is_capturing) {
593         if (lpdwCapture)
594             *lpdwCapture = 0;
595         if (lpdwRead)
596             *lpdwRead = 0;
597     }
598
599     if (This->is_direct_map) {
600         if (lpdwCapture)
601             *lpdwCapture = This->map_writepos;
602         if (lpdwRead) {
603             *lpdwRead = This->map_readpos;
604         }
605     } else {
606         if (lpdwCapture)
607             *lpdwCapture = This->writeptr;
608         if (lpdwRead)
609             *lpdwRead = This->readptr;
610     }
611
612     TRACE("capturepos=%d, readpos=%d\n", lpdwCapture?*lpdwCapture:0,
613           lpdwRead?*lpdwRead:0);
614     return DS_OK;
615 }
616
617 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
618     PIDSCDRIVERBUFFER iface,
619     LPDWORD lpdwStatus)
620 {
621     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
622     TRACE("(%p,%p)\n",This,lpdwStatus);
623
624     if (This->is_capturing) {
625         if (This->is_looping)
626             *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
627         else
628             *lpdwStatus = DSCBSTATUS_CAPTURING;
629     } else
630         *lpdwStatus = 0;
631
632     return DS_OK;
633 }
634
635 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
636     PIDSCDRIVERBUFFER iface,
637     DWORD dwFlags)
638 {
639     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
640     int enable;
641     TRACE("(%p,%x)\n",This,dwFlags);
642
643     if (This->is_capturing)
644         return DS_OK;
645
646     if (dwFlags & DSCBSTART_LOOPING)
647         This->is_looping = TRUE;
648
649     WInDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
650     enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
651     if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
652         if (errno == EINVAL) {
653             /* Don't give up yet. OSS trigger support is inconsistent. */
654             if (WInDev[This->drv->wDevID].ossdev.open_count == 1) {
655                 /* try the opposite output enable */
656                 if (WInDev[This->drv->wDevID].ossdev.bOutputEnabled == FALSE)
657                     WInDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
658                 else
659                     WInDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
660                 /* try it again */
661                 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
662                 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
663                     This->is_capturing = TRUE;
664                     return DS_OK;
665                 }
666             }
667         }
668         ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
669             WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
670         WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
671         return DSERR_GENERIC;
672     }
673
674     This->is_capturing = TRUE;
675     return DS_OK;
676 }
677
678 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
679 {
680     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
681     int enable;
682     TRACE("(%p)\n",This);
683
684     if (!This->is_capturing)
685         return DS_OK;
686
687     /* no more capturing */
688     WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
689     enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
690     if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
691         ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
692             WInDev[This->drv->wDevID].ossdev.dev_name,  strerror(errno));
693         return DSERR_GENERIC;
694     }
695
696     /* send a final event if necessary */
697     if (This->nrofnotifies > 0) {
698         if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
699             SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
700     }
701
702     This->is_capturing = FALSE;
703     This->is_looping = FALSE;
704
705     if (This->hThread) {
706         int x = 0;
707         write(This->pipe_fd[1], &x, sizeof(x));
708         WaitForSingleObject(This->hExitEvent, INFINITE);
709         CloseHandle(This->hExitEvent);
710         This->hExitEvent = INVALID_HANDLE_VALUE;
711         This->hThread = 0;
712     }
713
714     return DS_OK;
715 }
716
717 static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
718     PIDSCDRIVERBUFFER iface,
719     LPWAVEFORMATEX pwfx)
720 {
721     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
722     FIXME("(%p): stub!\n",This);
723     return DSERR_UNSUPPORTED;
724 }
725
726 static const IDsCaptureDriverBufferVtbl dscdbvt =
727 {
728     IDsCaptureDriverBufferImpl_QueryInterface,
729     IDsCaptureDriverBufferImpl_AddRef,
730     IDsCaptureDriverBufferImpl_Release,
731     IDsCaptureDriverBufferImpl_Lock,
732     IDsCaptureDriverBufferImpl_Unlock,
733     IDsCaptureDriverBufferImpl_SetFormat,
734     IDsCaptureDriverBufferImpl_GetPosition,
735     IDsCaptureDriverBufferImpl_GetStatus,
736     IDsCaptureDriverBufferImpl_Start,
737     IDsCaptureDriverBufferImpl_Stop
738 };
739
740 static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
741     PIDSCDRIVER iface,
742     REFIID riid,
743     LPVOID *ppobj)
744 {
745     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
746     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
747
748     if ( IsEqualGUID(riid, &IID_IUnknown) ||
749          IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
750         IDsCaptureDriver_AddRef(iface);
751         *ppobj = This;
752         return DS_OK;
753     }
754
755     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
756
757     *ppobj = 0;
758
759     return E_NOINTERFACE;
760 }
761
762 static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
763 {
764     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
765     ULONG refCount = InterlockedIncrement(&This->ref);
766
767     TRACE("(%p) ref was %d\n", This, refCount - 1);
768
769     return refCount;
770 }
771
772 static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
773 {
774     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
775     ULONG refCount = InterlockedDecrement(&This->ref);
776
777     TRACE("(%p) ref was %d\n", This, refCount + 1);
778
779     if (!refCount) {
780         HeapFree(GetProcessHeap(),0,This);
781         TRACE("(%p) released\n",This);
782     }
783     return refCount;
784 }
785
786 static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
787     PIDSCDRIVER iface,
788     PDSDRIVERDESC pDesc)
789 {
790     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
791     TRACE("(%p,%p)\n",This,pDesc);
792
793     if (!pDesc) {
794         TRACE("invalid parameter\n");
795         return DSERR_INVALIDPARAM;
796     }
797
798     /* copy version from driver */
799     *pDesc = WInDev[This->wDevID].ossdev.ds_desc;
800
801     pDesc->dnDevNode            = WInDev[This->wDevID].waveDesc.dnDevNode;
802     pDesc->wVxdId               = 0;
803     pDesc->wReserved            = 0;
804     pDesc->ulDeviceNum          = This->wDevID;
805     pDesc->dwHeapType           = DSDHEAP_NOHEAP;
806     pDesc->pvDirectDrawHeap     = NULL;
807     pDesc->dwMemStartAddress    = 0;
808     pDesc->dwMemEndAddress      = 0;
809     pDesc->dwMemAllocExtra      = 0;
810     pDesc->pvReserved1          = NULL;
811     pDesc->pvReserved2          = NULL;
812     return DS_OK;
813 }
814
815 static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
816 {
817     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
818     TRACE("(%p)\n",This);
819     return DS_OK;
820 }
821
822 static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
823 {
824     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
825     TRACE("(%p)\n",This);
826     if (This->capture_buffer) {
827         ERR("problem with DirectSound: capture buffer not released\n");
828         return DSERR_GENERIC;
829     }
830     return DS_OK;
831 }
832
833 static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
834     PIDSCDRIVER iface,
835     PDSCDRIVERCAPS pCaps)
836 {
837     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
838     TRACE("(%p,%p)\n",This,pCaps);
839     *pCaps = WInDev[This->wDevID].ossdev.dsc_caps;
840     return DS_OK;
841 }
842
843 static void DSCDB_CheckEvent(
844     IDsCaptureDriverBufferImpl *dscb,
845     DWORD writepos,
846     DWORD len,
847     DWORD buflen)
848 {
849     LPDSBPOSITIONNOTIFY event = dscb->notifies + dscb->notify_index;
850     DWORD offset = event->dwOffset;
851     TRACE("(%p,%d,%d,%d)\n", dscb, writepos, len, buflen);
852
853     TRACE("(%p) buflen = %d, writeptr = %d\n",
854         dscb, dscb->buflen, dscb->writeptr);
855     TRACE("checking %d, position %d, event = %p\n",
856         dscb->notify_index, offset, event->hEventNotify);
857
858     if ((writepos + len) > offset) {
859          TRACE("signalled event %p (%d) %d\n",
860                event->hEventNotify, dscb->notify_index, offset);
861          SetEvent(event->hEventNotify);
862          dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
863          return;
864     } else if ((writepos + len) > buflen) {
865         writepos = writepos + len - buflen;
866         if ((writepos + len) > offset) {
867              TRACE("signalled event %p (%d) %d\n",
868                    event->hEventNotify, dscb->notify_index, offset);
869              SetEvent(event->hEventNotify);
870              dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
871              return;
872         }
873     }
874
875     return;
876 }
877
878 /* FIXME: using memcpy can cause strange crashes so use this fake one */
879 static void * my_memcpy(void * dst, const void * src, int length)
880 {
881     int i;
882     for (i = 0; i < length; i++)
883         ((char *)dst)[i] = ((const char *)src)[i];
884     return dst;
885 }
886
887 static DWORD CALLBACK DSCDB_Thread(LPVOID lpParameter)
888 {
889     IDsCaptureDriverBufferImpl *This = lpParameter;
890     struct pollfd poll_list[2];
891     int retval;
892     DWORD offset = 0;
893     DWORD map_offset = 0;
894     TRACE("(%p)\n", lpParameter);
895
896     poll_list[0].fd = This->fd;                /* data available */
897     poll_list[1].fd = This->pipe_fd[0];        /* message from parent process */
898     poll_list[0].events = POLLIN;
899     poll_list[1].events = POLLIN;
900
901     /* let other process know we are running */
902     SetEvent(This->hStartUpEvent);
903
904     while (1) {
905         /* wait for something to happen */
906         retval = poll(poll_list,(unsigned long)2,-1);
907         /* Retval will always be greater than 0 or -1 in this case.
908          * Since we're doing it while blocking
909          */
910         if (retval < 0) {
911             ERR("Error while polling: %s\n",strerror(errno));
912             continue;
913         }
914
915         /* check for exit command */
916         if ((poll_list[1].revents & POLLIN) == POLLIN) {
917             TRACE("(%p) done\n", lpParameter);
918             /* acknowledge command and exit */
919             SetEvent(This->hExitEvent);
920             ExitThread(0);
921             return 0;
922         }
923
924         /* check for data */
925         if ((poll_list[0].revents & POLLIN) == POLLIN) {
926             count_info info;
927             int fragsize, first, second;
928
929             /* get the current DMA position */
930             if (ioctl(This->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
931                 ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
932                     WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
933                 return DSERR_GENERIC;
934             }
935
936             if (This->is_direct_map) {
937                 offset = This->map_writepos;
938                 This->map_writepos = info.ptr;
939
940                 if (info.ptr < offset)
941                     fragsize = info.ptr + This->maplen - offset;
942                 else
943                     fragsize = info.ptr - offset;
944
945                 DSCDB_CheckEvent(This, offset, fragsize, This->maplen);
946             } else {
947                 map_offset = This->map_writepos;
948                 offset = This->writeptr;
949
950                 /* test for mmap buffer wrap */
951                 if (info.ptr < map_offset) {
952                     /* mmap buffer wrapped */
953                     fragsize = info.ptr + This->maplen - map_offset;
954
955                     /* check for user buffer wrap */
956                     if ((offset + fragsize) > This->buflen) {
957                         /* both buffers wrapped
958                          * figure out which wrapped first
959                          */
960                         if ((This->maplen - map_offset) > (This->buflen - offset)) {
961                             /* user buffer wrapped first */
962                             first = This->buflen - offset;
963                             second = (This->maplen - map_offset) - first;
964                             my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
965                             my_memcpy(This->buffer, This->mapping + map_offset + first, second);
966                             my_memcpy(This->buffer + second, This->mapping, fragsize - (first + second));
967                         } else {
968                             /* mmap buffer wrapped first */
969                             first = This->maplen - map_offset;
970                             second = (This->buflen - offset) - first;
971                             my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
972                             my_memcpy(This->buffer + offset + first, This->mapping, second);
973                             my_memcpy(This->buffer, This->mapping + second, fragsize - (first + second));
974                         }
975                     } else {
976                         /* only mmap buffer wrapped */
977                         first = This->maplen - map_offset;
978                         my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
979                         my_memcpy(This->buffer + offset + first, This->mapping, fragsize - first);
980                     }
981                 } else {
982                     /* mmap buffer didn't wrap */
983                     fragsize = info.ptr - map_offset;
984
985                     /* check for user buffer wrap */
986                     if ((offset + fragsize) > This->buflen) {
987                         first = This->buflen - offset;
988                         my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
989                         my_memcpy(This->buffer, This->mapping + map_offset + first, fragsize - first);
990                     } else
991                         my_memcpy(This->buffer + offset, This->mapping + map_offset, fragsize);
992                 }
993
994                 This->map_writepos = info.ptr;
995                 This->writeptr = (This->writeptr + fragsize) % This->buflen;
996                 DSCDB_CheckEvent(This, offset, fragsize, This->buflen);
997             }
998         }
999     }
1000 }
1001
1002 static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
1003     PIDSCDRIVER iface,
1004     LPWAVEFORMATEX pwfx,
1005     DWORD dwFlags,
1006     DWORD dwCardAddress,
1007     LPDWORD pdwcbBufferSize,
1008     LPBYTE *ppbBuffer,
1009     LPVOID *ppvObj)
1010 {
1011     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
1012     IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
1013     HRESULT err;
1014     audio_buf_info info;
1015     int audio_fragment, fsize, shift, ret;
1016     BOOL bNewBuffer = FALSE;
1017     WINE_WAVEIN* wwi;
1018     TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
1019           pdwcbBufferSize,ppbBuffer,ppvObj);
1020
1021     if (This->capture_buffer) {
1022         TRACE("already allocated\n");
1023         return DSERR_ALLOCATED;
1024     }
1025
1026     /* must be given a buffer size */
1027     if (pdwcbBufferSize == NULL || *pdwcbBufferSize == 0) {
1028        TRACE("invalid parameter: pdwcbBufferSize\n");
1029        return DSERR_INVALIDPARAM;
1030     }
1031
1032     /* must be given a buffer pointer */
1033     if (ppbBuffer == NULL) {
1034        TRACE("invalid parameter: ppbBuffer\n");
1035        return DSERR_INVALIDPARAM;
1036     }
1037
1038     /* may or may not be given a buffer */
1039     if (*ppbBuffer == NULL) {
1040         TRACE("creating buffer\n");
1041         bNewBuffer = TRUE;     /* not given a buffer so create one */
1042     } else
1043         TRACE("using supplied buffer\n");
1044
1045     *ippdscdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
1046     if (*ippdscdb == NULL) {
1047         TRACE("out of memory\n");
1048         return DSERR_OUTOFMEMORY;
1049     }
1050
1051     (*ippdscdb)->IDsCaptureDriverBuffer_iface.lpVtbl = &dscdbvt;
1052     (*ippdscdb)->ref          = 1;
1053     (*ippdscdb)->drv          = This;
1054     (*ippdscdb)->notify       = NULL;
1055     (*ippdscdb)->notify_index = 0;
1056     (*ippdscdb)->notifies     = NULL;
1057     (*ippdscdb)->nrofnotifies = 0;
1058     (*ippdscdb)->property_set = NULL;
1059     (*ippdscdb)->is_capturing = FALSE;
1060     (*ippdscdb)->is_looping   = FALSE;
1061     (*ippdscdb)->wfx          = *pwfx;
1062     (*ippdscdb)->buflen       = *pdwcbBufferSize;
1063
1064     if (bNewBuffer)
1065         (*ippdscdb)->buffer = NULL;
1066     else
1067         (*ippdscdb)->buffer = *ppbBuffer;
1068
1069     wwi = &WInDev[This->wDevID];
1070
1071     if (wwi->state == WINE_WS_CLOSED) {
1072         unsigned int frag_size;
1073
1074         if (wwi->ossdev.open_count > 0) {
1075             /* opened already so use existing fragment size */
1076             audio_fragment = wwi->ossdev.audio_fragment;
1077         } else {
1078             /* calculate a fragment size */
1079             unsigned int mask = 0xffffffff;
1080
1081             /* calculate largest fragment size less than 10 ms. */
1082             fsize = pwfx->nAvgBytesPerSec / 100;        /* 10 ms chunk */
1083             shift = 0;
1084             while ((1 << shift) <= fsize)
1085                 shift++;
1086             shift--;
1087             fsize = 1 << shift;
1088             TRACE("shift = %d, fragment size = %d\n", shift, fsize);
1089             TRACE("BufferSize=%d(%08x)\n", *pdwcbBufferSize, *pdwcbBufferSize);
1090
1091             /* See if we can directly map the buffer first.
1092              * (buffer length is multiple of a power of 2)
1093              */
1094             mask = (mask >> (32 - shift));
1095             TRACE("mask=%08x\n", mask);
1096             if (*pdwcbBufferSize & mask) {
1097                 /* no so try a smaller fragment size greater than 1 ms */
1098                 int new_shift = shift - 1;
1099                 int min_shift = 0;
1100                 int min_fsize = pwfx->nAvgBytesPerSec / 1000;
1101                 BOOL found_one = FALSE;
1102                 while ((1 << min_shift) <= min_fsize)
1103                     min_shift++;
1104                 min_shift--;
1105                 while (new_shift > min_shift) {
1106                     if (*pdwcbBufferSize & (-1 >> (32 - new_shift))) {
1107                         new_shift--;
1108                         continue;
1109                     } else {
1110                         found_one = TRUE;
1111                         break;
1112                     }
1113                 }
1114                 if (found_one) {
1115                     /* found a smaller one that will work */
1116                     audio_fragment = ((*pdwcbBufferSize >> new_shift) << 16) | new_shift;
1117                     (*ippdscdb)->is_direct_map = TRUE;
1118                     TRACE("new shift = %d, fragment size = %d\n",
1119                           new_shift, 1 << (audio_fragment & 0xffff));
1120                 } else {
1121                     /* buffer can't be direct mapped */
1122                     audio_fragment = 0x00100000 + shift;        /* 16 fragments of 2^shift */
1123                     (*ippdscdb)->is_direct_map = FALSE;
1124                 }
1125             } else {
1126                 /* good fragment size */
1127                 audio_fragment = ((*pdwcbBufferSize >> shift) << 16) | shift;
1128                 (*ippdscdb)->is_direct_map = TRUE;
1129             }
1130         }
1131         frag_size = 1 << (audio_fragment & 0xffff);
1132         TRACE("is_direct_map = %s\n", (*ippdscdb)->is_direct_map ? "TRUE" : "FALSE");
1133         TRACE("requesting %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1134               audio_fragment >> 16, frag_size, frag_size * (audio_fragment >> 16),
1135               (frag_size * 1000) / pwfx->nAvgBytesPerSec);
1136
1137         ret = OSS_OpenDevice(&wwi->ossdev, O_RDWR, &audio_fragment, 1,
1138                              pwfx->nSamplesPerSec,
1139                              (pwfx->nChannels > 1) ? 1 : 0,
1140                              (pwfx->wBitsPerSample == 16)
1141                              ? AFMT_S16_LE : AFMT_U8);
1142
1143         if (ret != 0) {
1144             WARN("OSS_OpenDevice failed\n");
1145             HeapFree(GetProcessHeap(),0,*ippdscdb);
1146             *ippdscdb = NULL;
1147             return DSERR_GENERIC;
1148         }
1149
1150         wwi->state = WINE_WS_STOPPED;
1151
1152         /* find out what fragment and buffer sizes OSS gave us */
1153         if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1154              ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1155                  wwi->ossdev.dev_name, strerror(errno));
1156              OSS_CloseDevice(&wwi->ossdev);
1157              wwi->state = WINE_WS_CLOSED;
1158              HeapFree(GetProcessHeap(),0,*ippdscdb);
1159              *ippdscdb = NULL;
1160              return DSERR_GENERIC;
1161         }
1162
1163         TRACE("got %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1164               info.fragstotal, info.fragsize, info.fragstotal * info.fragsize,
1165               info.fragsize * 1000 / pwfx->nAvgBytesPerSec);
1166
1167         wwi->dwTotalRecorded = 0;
1168         memcpy(&wwi->waveFormat, pwfx, sizeof(PCMWAVEFORMAT));
1169         wwi->dwFragmentSize = info.fragsize;
1170
1171         /* make sure we got what we asked for */
1172         if ((*ippdscdb)->buflen != info.fragstotal * info.fragsize) {
1173             TRACE("Couldn't create requested buffer\n");
1174             if ((*ippdscdb)->is_direct_map) {
1175                 (*ippdscdb)->is_direct_map = FALSE;
1176                 TRACE("is_direct_map = FALSE\n");
1177             }
1178         } else if (info.fragsize != frag_size) {
1179             TRACE("same buffer length but different fragment size\n");
1180         }
1181     }
1182     (*ippdscdb)->fd = WInDev[This->wDevID].ossdev.fd;
1183
1184     if (pipe((*ippdscdb)->pipe_fd) < 0) {
1185         TRACE("pipe() failed (%s)\n", strerror(errno));
1186         OSS_CloseDevice(&wwi->ossdev);
1187         wwi->state = WINE_WS_CLOSED;
1188         HeapFree(GetProcessHeap(),0,*ippdscdb);
1189         *ippdscdb = NULL;
1190         return DSERR_GENERIC;
1191     }
1192
1193     /* check how big the DMA buffer is now */
1194     if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1195         ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1196             wwi->ossdev.dev_name, strerror(errno));
1197         OSS_CloseDevice(&wwi->ossdev);
1198         wwi->state = WINE_WS_CLOSED;
1199         close((*ippdscdb)->pipe_fd[0]);
1200         close((*ippdscdb)->pipe_fd[1]);
1201         HeapFree(GetProcessHeap(),0,*ippdscdb);
1202         *ippdscdb = NULL;
1203         return DSERR_GENERIC;
1204     }
1205
1206     (*ippdscdb)->maplen = info.fragstotal * info.fragsize;
1207     (*ippdscdb)->fragsize = info.fragsize;
1208     (*ippdscdb)->map_writepos = 0;
1209     (*ippdscdb)->map_readpos = 0;
1210
1211     /* map the DMA buffer */
1212     err = DSCDB_MapBuffer(*ippdscdb);
1213     if (err != DS_OK) {
1214         OSS_CloseDevice(&wwi->ossdev);
1215         wwi->state = WINE_WS_CLOSED;
1216         close((*ippdscdb)->pipe_fd[0]);
1217         close((*ippdscdb)->pipe_fd[1]);
1218         HeapFree(GetProcessHeap(),0,*ippdscdb);
1219         *ippdscdb = NULL;
1220         return err;
1221     }
1222
1223     /* create the buffer if necessary */
1224     if (!(*ippdscdb)->buffer)
1225         (*ippdscdb)->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(*ippdscdb)->buflen);
1226
1227     if ((*ippdscdb)->buffer == NULL) {
1228         OSS_CloseDevice(&wwi->ossdev);
1229         wwi->state = WINE_WS_CLOSED;
1230         close((*ippdscdb)->pipe_fd[0]);
1231         close((*ippdscdb)->pipe_fd[1]);
1232         HeapFree(GetProcessHeap(),0,*ippdscdb);
1233         *ippdscdb = NULL;
1234         return DSERR_OUTOFMEMORY;
1235     }
1236
1237     This->capture_buffer = *ippdscdb;
1238
1239     (*ippdscdb)->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1240     (*ippdscdb)->hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1241
1242     (*ippdscdb)->hThread = CreateThread(NULL, 0,  DSCDB_Thread, *ippdscdb, 0, &((*ippdscdb)->dwThreadID));
1243     WaitForSingleObject((*ippdscdb)->hStartUpEvent, INFINITE);
1244     CloseHandle((*ippdscdb)->hStartUpEvent);
1245     (*ippdscdb)->hStartUpEvent = INVALID_HANDLE_VALUE;
1246
1247     return DS_OK;
1248 }
1249
1250 static const IDsCaptureDriverVtbl dscdvt =
1251 {
1252     IDsCaptureDriverImpl_QueryInterface,
1253     IDsCaptureDriverImpl_AddRef,
1254     IDsCaptureDriverImpl_Release,
1255     IDsCaptureDriverImpl_GetDriverDesc,
1256     IDsCaptureDriverImpl_Open,
1257     IDsCaptureDriverImpl_Close,
1258     IDsCaptureDriverImpl_GetCaps,
1259     IDsCaptureDriverImpl_CreateCaptureBuffer
1260 };
1261
1262 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
1263     IDsCaptureDriverBufferImpl * dscdb,
1264     IDsCaptureDriverPropertySetImpl **pdscdps)
1265 {
1266     IDsCaptureDriverPropertySetImpl * dscdps;
1267     TRACE("(%p,%p)\n",dscdb,pdscdps);
1268
1269     dscdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdps));
1270     if (dscdps == NULL) {
1271         WARN("out of memory\n");
1272         return DSERR_OUTOFMEMORY;
1273     }
1274
1275     dscdps->ref = 0;
1276     dscdps->IDsDriverPropertySet_iface.lpVtbl = &dscdpsvt;
1277     dscdps->capture_buffer = dscdb;
1278     dscdb->property_set = dscdps;
1279     IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1280
1281     *pdscdps = dscdps;
1282     return DS_OK;
1283 }
1284
1285 static HRESULT IDsCaptureDriverNotifyImpl_Create(
1286     IDsCaptureDriverBufferImpl * dscdb,
1287     IDsCaptureDriverNotifyImpl **pdscdn)
1288 {
1289     IDsCaptureDriverNotifyImpl * dscdn;
1290     TRACE("(%p,%p)\n",dscdb,pdscdn);
1291
1292     dscdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdn));
1293     if (dscdn == NULL) {
1294         WARN("out of memory\n");
1295         return DSERR_OUTOFMEMORY;
1296     }
1297
1298     dscdn->ref = 0;
1299     dscdn->IDsDriverNotify_iface.lpVtbl = &dscdnvt;
1300     dscdn->capture_buffer = dscdb;
1301     dscdb->notify = dscdn;
1302     IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1303
1304     *pdscdn = dscdn;
1305     return DS_OK;
1306 }
1307
1308 DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
1309 {
1310     IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
1311     TRACE("(%d,%p)\n",wDevID,drv);
1312
1313     /* the HAL isn't much better than the HEL if we can't do mmap() */
1314     if (!(WInDev[wDevID].ossdev.in_caps_support & WAVECAPS_DIRECTSOUND)) {
1315         ERR("DirectSoundCapture flag not set\n");
1316         MESSAGE("This sound card's driver does not support direct access\n");
1317         MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1318         return MMSYSERR_NOTSUPPORTED;
1319     }
1320
1321     *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
1322     if (!*idrv)
1323         return MMSYSERR_NOMEM;
1324     (*idrv)->IDsCaptureDriver_iface.lpVtbl = &dscdvt;
1325     (*idrv)->ref        = 1;
1326
1327     (*idrv)->wDevID     = wDevID;
1328     (*idrv)->capture_buffer = NULL;
1329     return MMSYSERR_NOERROR;
1330 }
1331
1332 DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1333 {
1334     memcpy(desc, &(WInDev[wDevID].ossdev.ds_desc), sizeof(DSDRIVERDESC));
1335     return MMSYSERR_NOERROR;
1336 }