1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
22 #include <sys/ioctl.h>
23 #include "wine/winuser16.h"
25 #include "multimedia.h"
31 #define SOUND_DEV "/dev/dsp"
32 #define MIXER_DEV "/dev/mixer"
35 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
37 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
40 #define MAX_WAVEOUTDRV (1)
41 #define MAX_WAVEINDRV (1)
47 WAVEOPENDESC waveDesc
;
57 DWORD bufsize
; /* OpenSound '/dev/dsp' give us that size */
58 WAVEOPENDESC waveDesc
;
62 DWORD dwTotalRecorded
;
65 static WINE_WAVEOUT WOutDev
[MAX_WAVEOUTDRV
];
66 static WINE_WAVEIN WInDev
[MAX_WAVEOUTDRV
];
68 /*======================================================================*
69 * Low level WAVE implemantation *
70 *======================================================================*/
72 /**************************************************************************
73 * WAVE_NotifyClient [internal]
75 static DWORD
WAVE_NotifyClient(UINT16 wDevID
, WORD wMsg
,
76 DWORD dwParam1
, DWORD dwParam2
)
78 TRACE(wave
,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID
, wMsg
, dwParam1
, dwParam2
);
84 if (wDevID
> MAX_WAVEOUTDRV
) return MCIERR_INTERNAL
;
86 if (WOutDev
[wDevID
].wFlags
!= DCB_NULL
&&
88 WOutDev
[wDevID
].waveDesc
.dwCallBack
,
89 WOutDev
[wDevID
].wFlags
,
90 WOutDev
[wDevID
].waveDesc
.hWave
,
92 WOutDev
[wDevID
].waveDesc
.dwInstance
,
95 WARN(wave
, "can't notify client !\n");
96 return MMSYSERR_NOERROR
;
103 if (wDevID
> MAX_WAVEINDRV
) return MCIERR_INTERNAL
;
105 if (WInDev
[wDevID
].wFlags
!= DCB_NULL
&&
107 WInDev
[wDevID
].waveDesc
.dwCallBack
,
108 WInDev
[wDevID
].wFlags
,
109 WInDev
[wDevID
].waveDesc
.hWave
,
111 WInDev
[wDevID
].waveDesc
.dwInstance
,
114 WARN(wave
, "can't notify client !\n");
115 return MMSYSERR_NOERROR
;
122 /**************************************************************************
123 * wodGetDevCaps [internal]
125 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPS16 lpCaps
, DWORD dwSize
)
133 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
134 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
135 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
136 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
137 if (audio
== -1) return MMSYSERR_ALLOCATED
;
139 lpCaps
->wMid
= 0x0002;
140 lpCaps
->wPid
= 0x0104;
141 strcpy(lpCaps
->szPname
, "SB16 Wave Out");
143 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
144 lpCaps
->wPid
= 0x0001; /* Product ID */
145 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVOUT Driver");
147 lpCaps
->vDriverVersion
= 0x0100;
148 lpCaps
->dwFormats
= 0x00000000;
149 lpCaps
->dwSupport
= WAVECAPS_VOLUME
;
151 /* First bytespersampl, then stereo */
152 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
154 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
155 if (lpCaps
->wChannels
> 1) lpCaps
->dwSupport
|= WAVECAPS_LRVOLUME
;
158 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
159 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
160 if (lpCaps
->wChannels
> 1)
161 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
162 if (bytespersmpl
> 1) {
163 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
164 if (lpCaps
->wChannels
> 1)
165 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
169 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
170 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
171 if (lpCaps
->wChannels
> 1)
172 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
173 if (bytespersmpl
> 1) {
174 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
175 if (lpCaps
->wChannels
> 1)
176 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
180 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
181 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
182 if (lpCaps
->wChannels
> 1)
183 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
184 if (bytespersmpl
> 1) {
185 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
186 if (lpCaps
->wChannels
> 1)
187 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
191 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
192 return MMSYSERR_NOERROR
;
196 /**************************************************************************
199 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
201 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
202 LPWAVEFORMAT lpFormat
;
204 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
205 if (lpDesc
== NULL
) {
206 WARN(wave
, "Invalid Parameter !\n");
207 return MMSYSERR_INVALPARAM
;
209 if (wDevID
>= MAX_WAVEOUTDRV
) {
210 TRACE(wave
,"MAX_WAVOUTDRV reached !\n");
211 return MMSYSERR_ALLOCATED
;
213 WOutDev
[wDevID
].unixdev
= 0;
214 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
215 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
217 WARN(wave
, "can't open !\n");
218 return MMSYSERR_ALLOCATED
;
220 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
221 if (abuf_size
< 1024 || abuf_size
> 65536) {
223 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
225 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
226 return MMSYSERR_NOTENABLED
;
228 WOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
229 switch(WOutDev
[wDevID
].wFlags
) {
231 TRACE(wave
, "CALLBACK_NULL !\n");
234 TRACE(wave
, "CALLBACK_WINDOW !\n");
237 TRACE(wave
, "CALLBACK_TASK !\n");
240 TRACE(wave
, "CALLBACK_FUNCTION !\n");
243 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
244 WOutDev
[wDevID
].unixdev
= audio
;
245 WOutDev
[wDevID
].dwTotalPlayed
= 0;
246 WOutDev
[wDevID
].bufsize
= abuf_size
;
247 /* FIXME: copy lpFormat too? */
248 memcpy(&WOutDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
249 TRACE(wave
,"lpDesc->lpFormat = %p\n",lpDesc
->lpFormat
);
250 lpFormat
= lpDesc
->lpFormat
;
251 TRACE(wave
,"lpFormat = %p\n",lpFormat
);
252 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
253 WARN(wave
,"Bad format %04X !\n", lpFormat
->wFormatTag
);
254 WARN(wave
,"Bad nChannels %d !\n", lpFormat
->nChannels
);
255 WARN(wave
,"Bad nSamplesPerSec %ld !\n", lpFormat
->nSamplesPerSec
);
256 return WAVERR_BADFORMAT
;
258 memcpy(&WOutDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
259 if (WOutDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
260 if (WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
261 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
262 if (WOutDev
[wDevID
].Format
.wBitsPerSample
== 0) {
263 WOutDev
[wDevID
].Format
.wBitsPerSample
= 8 *
264 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
265 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
266 WOutDev
[wDevID
].Format
.wf
.nChannels
;
268 samplesize
= WOutDev
[wDevID
].Format
.wBitsPerSample
;
269 smplrate
= WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
270 dsp_stereo
= (WOutDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
272 /* First size and stereo then samplerate */
273 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
274 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
275 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
277 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
278 TRACE(wave
,"nAvgBytesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
279 TRACE(wave
,"nSamplesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
280 TRACE(wave
,"nChannels=%u !\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
281 if (WAVE_NotifyClient(wDevID
, WOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
282 WARN(wave
, "can't notify client !\n");
283 return MMSYSERR_INVALPARAM
;
285 return MMSYSERR_NOERROR
;
288 /**************************************************************************
289 * wodClose [internal]
291 static DWORD
wodClose(WORD wDevID
)
293 TRACE(wave
,"(%u);\n", wDevID
);
295 if (wDevID
> MAX_WAVEOUTDRV
) return MMSYSERR_INVALPARAM
;
296 if (WOutDev
[wDevID
].unixdev
== 0) {
297 WARN(wave
, "can't close !\n");
298 return MMSYSERR_NOTENABLED
;
300 if (WOutDev
[wDevID
].lpQueueHdr
!= NULL
) {
301 WARN(wave
, "still buffers open !\n");
302 /* Don't care. Who needs those buffers anyway */
303 /*return WAVERR_STILLPLAYING; */
305 close(WOutDev
[wDevID
].unixdev
);
306 WOutDev
[wDevID
].unixdev
= 0;
307 WOutDev
[wDevID
].bufsize
= 0;
308 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
309 if (WAVE_NotifyClient(wDevID
, WOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
310 WARN(wave
, "can't notify client !\n");
311 return MMSYSERR_INVALPARAM
;
313 return MMSYSERR_NOERROR
;
316 /**************************************************************************
317 * wodWrite [internal]
318 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
319 * device, and initiate async playing.
321 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
327 TRACE(wave
,"(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
328 if (WOutDev
[wDevID
].unixdev
== 0) {
329 WARN(wave
, "can't play !\n");
330 return MMSYSERR_NOTENABLED
;
332 if (lpWaveHdr
->lpData
== NULL
) return WAVERR_UNPREPARED
;
333 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) return WAVERR_UNPREPARED
;
334 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) return WAVERR_STILLPLAYING
;
335 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
336 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
337 TRACE(wave
, "dwBufferLength %lu !\n", lpWaveHdr
->dwBufferLength
);
338 TRACE(wave
, "WOutDev[%u].unixdev %u !\n", wDevID
, WOutDev
[wDevID
].unixdev
);
339 lpData
= lpWaveHdr
->lpData
;
340 count
= write (WOutDev
[wDevID
].unixdev
, lpData
, lpWaveHdr
->dwBufferLength
);
341 TRACE(wave
,"write returned count %u !\n",count
);
342 if (count
!= lpWaveHdr
->dwBufferLength
) {
343 WARN(wave
, " error writing !\n");
344 return MMSYSERR_NOTENABLED
;
346 WOutDev
[wDevID
].dwTotalPlayed
+= count
;
347 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
348 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
349 if ((DWORD
)lpWaveHdr
->lpData
!=lpWaveHdr
->reserved
) {
350 /* FIXME: what if it expects it's OWN lpwavehdr back? */
351 xwavehdr
= SEGPTR_NEW(WAVEHDR
);
352 memcpy(xwavehdr
,lpWaveHdr
,sizeof(WAVEHDR
));
353 xwavehdr
->lpData
= (LPBYTE
)xwavehdr
->reserved
;
354 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)SEGPTR_GET(xwavehdr
), count
) != MMSYSERR_NOERROR
) {
355 WARN(wave
, "can't notify client !\n");
356 SEGPTR_FREE(xwavehdr
);
357 return MMSYSERR_INVALPARAM
;
359 SEGPTR_FREE(xwavehdr
);
361 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)lpWaveHdr
, count
) != MMSYSERR_NOERROR
) {
362 WARN(wave
, "can't notify client !\n");
363 return MMSYSERR_INVALPARAM
;
366 return MMSYSERR_NOERROR
;
369 /**************************************************************************
370 * wodPrepare [internal]
372 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
374 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
375 if (WOutDev
[wDevID
].unixdev
== 0) {
376 WARN(wave
, "can't prepare !\n");
377 return MMSYSERR_NOTENABLED
;
379 /* don't append to queue, wodWrite does that */
380 WOutDev
[wDevID
].dwTotalPlayed
= 0;
381 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
382 return WAVERR_STILLPLAYING
;
383 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
384 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
385 return MMSYSERR_NOERROR
;
388 /**************************************************************************
389 * wodUnprepare [internal]
391 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
393 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
394 if (WOutDev
[wDevID
].unixdev
== 0) {
395 WARN(wave
, "can't unprepare !\n");
396 return MMSYSERR_NOTENABLED
;
398 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
399 return WAVERR_STILLPLAYING
;
401 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
402 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
403 TRACE(wave
, "all headers unprepared !\n");
404 return MMSYSERR_NOERROR
;
407 /**************************************************************************
408 * wodRestart [internal]
410 static DWORD
wodRestart(WORD wDevID
)
412 TRACE(wave
,"(%u);\n", wDevID
);
413 if (WOutDev
[wDevID
].unixdev
== 0) {
414 WARN(wave
, "can't restart !\n");
415 return MMSYSERR_NOTENABLED
;
417 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
418 /* FIXME: Myst crashes with this ... hmm -MM
419 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
420 WARN(wave, "can't notify client !\n");
421 return MMSYSERR_INVALPARAM;
425 return MMSYSERR_NOERROR
;
428 /**************************************************************************
429 * wodReset [internal]
431 static DWORD
wodReset(WORD wDevID
)
433 TRACE(wave
,"(%u);\n", wDevID
);
434 if (WOutDev
[wDevID
].unixdev
== 0) {
435 WARN(wave
, "can't reset !\n");
436 return MMSYSERR_NOTENABLED
;
438 return MMSYSERR_NOERROR
;
442 /**************************************************************************
443 * wodGetPosition [internal]
445 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
448 TRACE(wave
,"(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
449 if (WOutDev
[wDevID
].unixdev
== 0) {
450 WARN(wave
, "can't get pos !\n");
451 return MMSYSERR_NOTENABLED
;
453 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
454 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
455 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
456 TRACE(wave
,"nSamplesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
457 TRACE(wave
,"nChannels=%u\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
458 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
459 switch(lpTime
->wType
) {
461 lpTime
->u
.cb
= WOutDev
[wDevID
].dwTotalPlayed
;
462 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
465 TRACE(wave
,"dwTotalPlayed=%lu\n", WOutDev
[wDevID
].dwTotalPlayed
);
466 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
467 lpTime
->u
.sample
= WOutDev
[wDevID
].dwTotalPlayed
* 8 /
468 WOutDev
[wDevID
].Format
.wBitsPerSample
;
469 TRACE(wave
,"TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
472 time
= WOutDev
[wDevID
].dwTotalPlayed
/
473 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
474 lpTime
->u
.smpte
.hour
= time
/ 108000;
475 time
-= lpTime
->u
.smpte
.hour
* 108000;
476 lpTime
->u
.smpte
.min
= time
/ 1800;
477 time
-= lpTime
->u
.smpte
.min
* 1800;
478 lpTime
->u
.smpte
.sec
= time
/ 30;
479 time
-= lpTime
->u
.smpte
.sec
* 30;
480 lpTime
->u
.smpte
.frame
= time
;
481 lpTime
->u
.smpte
.fps
= 30;
482 TRACE(wave
, "wodGetPosition , TIME_SMPTE=%02u:%02u:%02u:%02u\n",
483 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
484 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
487 FIXME(wave
, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime
->wType
);
488 lpTime
->wType
= TIME_MS
;
490 lpTime
->u
.ms
= WOutDev
[wDevID
].dwTotalPlayed
/
491 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
492 TRACE(wave
,"wodGetPosition , TIME_MS=%lu\n", lpTime
->u
.ms
);
495 return MMSYSERR_NOERROR
;
498 /**************************************************************************
499 * wodGetVolume [internal]
501 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
504 int volume
, left
, right
;
505 TRACE(wave
,"(%u, %p);\n", wDevID
, lpdwVol
);
506 if (lpdwVol
== NULL
) return MMSYSERR_NOTENABLED
;
507 if ((mixer
= open(MIXER_DEV
, O_RDONLY
)) < 0) {
508 WARN(wave
, "mixer device not available !\n");
509 return MMSYSERR_NOTENABLED
;
511 if (ioctl(mixer
, SOUND_MIXER_READ_PCM
, &volume
) == -1) {
512 WARN(wave
, "unable read mixer !\n");
513 return MMSYSERR_NOTENABLED
;
516 left
= volume
& 0x7F;
517 right
= (volume
>> 8) & 0x7F;
518 TRACE(wave
,"left=%d right=%d !\n", left
, right
);
519 *lpdwVol
= MAKELONG(left
<< 9, right
<< 9);
520 return MMSYSERR_NOERROR
;
524 /**************************************************************************
525 * wodSetVolume [internal]
527 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
531 TRACE(wave
,"(%u, %08lX);\n", wDevID
, dwParam
);
532 volume
= (LOWORD(dwParam
) >> 9 & 0x7F) +
533 ((HIWORD(dwParam
) >> 9 & 0x7F) << 8);
534 if ((mixer
= open(MIXER_DEV
, O_WRONLY
)) < 0) {
535 WARN(wave
, "mixer device not available !\n");
536 return MMSYSERR_NOTENABLED
;
538 if (ioctl(mixer
, SOUND_MIXER_WRITE_PCM
, &volume
) == -1) {
539 WARN(wave
, "unable set mixer !\n");
540 return MMSYSERR_NOTENABLED
;
543 return MMSYSERR_NOERROR
;
546 /**************************************************************************
547 * wodMessage [sample driver]
549 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
550 DWORD dwParam1
, DWORD dwParam2
)
553 TRACE(wave
,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
554 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
557 return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
559 return wodClose(wDevID
);
561 return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
563 return MMSYSERR_NOTSUPPORTED
;
565 return MMSYSERR_NOTSUPPORTED
;
567 return wodGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
569 return MMSYSERR_NOTSUPPORTED
;
571 return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
573 return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
574 case WODM_GETDEVCAPS
:
575 return wodGetDevCaps(wDevID
,(LPWAVEOUTCAPS16
)dwParam1
,dwParam2
);
576 case WODM_GETNUMDEVS
:
577 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
578 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
589 return MMSYSERR_NOTSUPPORTED
;
591 return MMSYSERR_NOTSUPPORTED
;
592 case WODM_GETPLAYBACKRATE
:
593 return MMSYSERR_NOTSUPPORTED
;
594 case WODM_SETPLAYBACKRATE
:
595 return MMSYSERR_NOTSUPPORTED
;
597 return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
599 return wodSetVolume(wDevID
, dwParam1
);
601 return wodRestart(wDevID
);
603 return wodReset(wDevID
);
605 WARN(wave
,"unknown message !\n");
607 return MMSYSERR_NOTSUPPORTED
;
611 /*-----------------------------------------------------------------------*/
613 /**************************************************************************
614 * widGetDevCaps [internal]
616 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPS16 lpCaps
, DWORD dwSize
)
618 int audio
,smplrate
,samplesize
=16,dsp_stereo
=1,bytespersmpl
;
620 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
621 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
622 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
623 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
624 if (audio
== -1) return MMSYSERR_ALLOCATED
;
626 lpCaps
->wMid
= 0x0002;
627 lpCaps
->wPid
= 0x0004;
628 strcpy(lpCaps
->szPname
, "SB16 Wave In");
630 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
631 lpCaps
->wPid
= 0x0001; /* Product ID */
632 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVIN Driver");
634 lpCaps
->dwFormats
= 0x00000000;
635 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
636 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
638 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
639 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
640 if (lpCaps
->wChannels
> 1)
641 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
642 if (bytespersmpl
> 1) {
643 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
644 if (lpCaps
->wChannels
> 1)
645 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
649 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
650 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
651 if (lpCaps
->wChannels
> 1)
652 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
653 if (bytespersmpl
> 1) {
654 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
655 if (lpCaps
->wChannels
> 1)
656 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
660 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
661 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
662 if (lpCaps
->wChannels
> 1)
663 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
664 if (bytespersmpl
> 1) {
665 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
666 if (lpCaps
->wChannels
> 1)
667 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
671 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
672 return MMSYSERR_NOERROR
;
676 /**************************************************************************
679 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
681 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
682 LPWAVEFORMAT lpFormat
;
684 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
685 if (lpDesc
== NULL
) {
686 WARN(wave
, "Invalid Parameter !\n");
687 return MMSYSERR_INVALPARAM
;
689 if (wDevID
>= MAX_WAVEINDRV
) {
690 TRACE(wave
,"MAX_WAVINDRV reached !\n");
691 return MMSYSERR_ALLOCATED
;
693 WInDev
[wDevID
].unixdev
= 0;
694 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
695 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
697 WARN(wave
,"can't open !\n");
698 return MMSYSERR_ALLOCATED
;
700 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
701 if (abuf_size
< 1024 || abuf_size
> 65536) {
703 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
705 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
706 return MMSYSERR_NOTENABLED
;
708 WInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
709 switch(WInDev
[wDevID
].wFlags
) {
711 TRACE(wave
,"CALLBACK_NULL!\n");
714 TRACE(wave
,"CALLBACK_WINDOW!\n");
717 TRACE(wave
,"CALLBACK_TASK!\n");
720 TRACE(wave
,"CALLBACK_FUNCTION!\n");
723 if (WInDev
[wDevID
].lpQueueHdr
) {
724 HeapFree(GetProcessHeap(),0,WInDev
[wDevID
].lpQueueHdr
);
725 WInDev
[wDevID
].lpQueueHdr
= NULL
;
727 WInDev
[wDevID
].unixdev
= audio
;
728 WInDev
[wDevID
].bufsize
= abuf_size
;
729 WInDev
[wDevID
].dwTotalRecorded
= 0;
730 memcpy(&WInDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
731 lpFormat
= (LPWAVEFORMAT
) lpDesc
->lpFormat
;
732 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
733 WARN(wave
, "Bad format %04X !\n",
734 lpFormat
->wFormatTag
);
735 return WAVERR_BADFORMAT
;
737 memcpy(&WInDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
738 WInDev
[wDevID
].Format
.wBitsPerSample
= 8; /* <-------------- */
739 if (WInDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
740 if (WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
741 if (WInDev
[wDevID
].Format
.wBitsPerSample
== 0) {
742 WInDev
[wDevID
].Format
.wBitsPerSample
= 8 *
743 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
744 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
745 WInDev
[wDevID
].Format
.wf
.nChannels
;
747 samplesize
= WInDev
[wDevID
].Format
.wBitsPerSample
;
748 smplrate
= WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
749 dsp_stereo
= (WInDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
750 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
751 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
752 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
753 TRACE(wave
,"wBitsPerSample=%u !\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
754 TRACE(wave
,"nSamplesPerSec=%lu !\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
755 TRACE(wave
,"nChannels=%u !\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
756 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
757 if (WAVE_NotifyClient(wDevID
, WIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
758 WARN(wave
,"can't notify client !\n");
759 return MMSYSERR_INVALPARAM
;
761 return MMSYSERR_NOERROR
;
764 /**************************************************************************
765 * widClose [internal]
767 static DWORD
widClose(WORD wDevID
)
769 TRACE(wave
,"(%u);\n", wDevID
);
770 if (wDevID
> MAX_WAVEINDRV
) return MMSYSERR_INVALPARAM
;
771 if (WInDev
[wDevID
].unixdev
== 0) {
772 WARN(wave
,"can't close !\n");
773 return MMSYSERR_NOTENABLED
;
775 if (WInDev
[wDevID
].lpQueueHdr
!= NULL
) {
776 WARN(wave
, "still buffers open !\n");
777 return WAVERR_STILLPLAYING
;
779 close(WInDev
[wDevID
].unixdev
);
780 WInDev
[wDevID
].unixdev
= 0;
781 WInDev
[wDevID
].bufsize
= 0;
782 if (WAVE_NotifyClient(wDevID
, WIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
783 WARN(wave
,"can't notify client !\n");
784 return MMSYSERR_INVALPARAM
;
786 return MMSYSERR_NOERROR
;
789 /**************************************************************************
790 * widAddBuffer [internal]
792 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
797 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
798 if (WInDev
[wDevID
].unixdev
== 0) {
799 WARN(wave
,"can't do it !\n");
800 return MMSYSERR_NOTENABLED
;
802 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
803 TRACE(wave
, "never been prepared !\n");
804 return WAVERR_UNPREPARED
;
806 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
807 TRACE(wave
, "header already in use !\n");
808 return WAVERR_STILLPLAYING
;
810 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
811 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
812 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
813 lpWaveHdr
->dwBytesRecorded
= 0;
814 if (WInDev
[wDevID
].lpQueueHdr
== NULL
) {
815 WInDev
[wDevID
].lpQueueHdr
= lpWaveHdr
;
817 lpWIHdr
= WInDev
[wDevID
].lpQueueHdr
;
818 while (lpWIHdr
->lpNext
!= NULL
) {
819 lpWIHdr
= lpWIHdr
->lpNext
;
822 lpWIHdr
->lpNext
= lpWaveHdr
;
823 lpWaveHdr
->lpNext
= NULL
;
826 TRACE(wave
, "buffer added ! (now %u in queue)\n", count
);
827 return MMSYSERR_NOERROR
;
830 /**************************************************************************
831 * widPrepare [internal]
833 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
835 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
836 if (WInDev
[wDevID
].unixdev
== 0) {
837 WARN(wave
,"can't prepare !\n");
838 return MMSYSERR_NOTENABLED
;
840 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
841 return WAVERR_STILLPLAYING
;
842 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
843 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
844 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
845 lpWaveHdr
->dwBytesRecorded
= 0;
846 TRACE(wave
,"header prepared !\n");
847 return MMSYSERR_NOERROR
;
850 /**************************************************************************
851 * widUnprepare [internal]
853 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
855 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
856 if (WInDev
[wDevID
].unixdev
== 0) {
857 WARN(wave
,"can't unprepare !\n");
858 return MMSYSERR_NOTENABLED
;
860 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
861 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
862 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
864 TRACE(wave
, "all headers unprepared !\n");
865 return MMSYSERR_NOERROR
;
868 /**************************************************************************
869 * widStart [internal]
871 static DWORD
widStart(WORD wDevID
)
876 LPWAVEHDR
*lpWaveHdr
;
878 TRACE(wave
,"(%u);\n", wDevID
);
879 if (WInDev
[wDevID
].unixdev
== 0) {
880 WARN(wave
, "can't start recording !\n");
881 return MMSYSERR_NOTENABLED
;
884 lpWaveHdr
= &(WInDev
[wDevID
].lpQueueHdr
);
885 TRACE(wave
,"lpWaveHdr = %08lx\n",(DWORD
)lpWaveHdr
);
886 if (!*lpWaveHdr
|| !(*lpWaveHdr
)->lpData
) {
887 TRACE(wave
,"never been prepared !\n");
888 return WAVERR_UNPREPARED
;
891 while(*lpWaveHdr
!= NULL
) {
892 lpWIHdr
= *lpWaveHdr
;
893 TRACE(wave
, "recording buf#%u=%p size=%lu \n",
894 count
, lpWIHdr
->lpData
, lpWIHdr
->dwBufferLength
);
896 bytesRead
= read (WInDev
[wDevID
].unixdev
,
898 lpWIHdr
->dwBufferLength
);
900 perror("read from audio device");
901 TRACE(wave
,"bytesread=%d (%ld)\n", bytesRead
, lpWIHdr
->dwBufferLength
);
902 lpWIHdr
->dwBytesRecorded
= bytesRead
;
903 WInDev
[wDevID
].dwTotalRecorded
+= lpWIHdr
->dwBytesRecorded
;
904 lpWIHdr
->dwFlags
&= ~WHDR_INQUEUE
;
905 lpWIHdr
->dwFlags
|= WHDR_DONE
;
907 /* FIXME: should pass segmented pointer here, do we need that?*/
908 if (WAVE_NotifyClient(wDevID
, WIM_DATA
, (DWORD
)lpWaveHdr
, lpWIHdr
->dwBytesRecorded
) != MMSYSERR_NOERROR
) {
909 WARN(wave
, "can't notify client !\n");
910 return MMSYSERR_INVALPARAM
;
912 /* removes the current block from the queue */
913 *lpWaveHdr
= lpWIHdr
->lpNext
;
916 TRACE(wave
,"end of recording !\n");
918 return MMSYSERR_NOERROR
;
921 /**************************************************************************
924 static DWORD
widStop(WORD wDevID
)
926 TRACE(wave
,"(%u);\n", wDevID
);
927 if (WInDev
[wDevID
].unixdev
== 0) {
928 WARN(wave
,"can't stop !\n");
929 return MMSYSERR_NOTENABLED
;
931 return MMSYSERR_NOERROR
;
934 /**************************************************************************
935 * widReset [internal]
937 static DWORD
widReset(WORD wDevID
)
939 TRACE(wave
,"(%u);\n", wDevID
);
940 if (WInDev
[wDevID
].unixdev
== 0) {
941 WARN(wave
,"can't reset !\n");
942 return MMSYSERR_NOTENABLED
;
944 return MMSYSERR_NOERROR
;
947 /**************************************************************************
948 * widGetPosition [internal]
950 static DWORD
widGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
954 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
955 if (WInDev
[wDevID
].unixdev
== 0) {
956 WARN(wave
,"can't get pos !\n");
957 return MMSYSERR_NOTENABLED
;
959 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
960 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
961 TRACE(wave
,"wBitsPerSample=%u\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
962 TRACE(wave
,"nSamplesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
963 TRACE(wave
,"nChannels=%u\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
964 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
966 switch(lpTime
->wType
) {
968 lpTime
->u
.cb
= WInDev
[wDevID
].dwTotalRecorded
;
969 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
972 lpTime
->u
.sample
= WInDev
[wDevID
].dwTotalRecorded
* 8 /
973 WInDev
[wDevID
].Format
.wBitsPerSample
;
974 TRACE(wave
, "TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
977 time
= WInDev
[wDevID
].dwTotalRecorded
/
978 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
979 lpTime
->u
.smpte
.hour
= time
/ 108000;
980 time
-= lpTime
->u
.smpte
.hour
* 108000;
981 lpTime
->u
.smpte
.min
= time
/ 1800;
982 time
-= lpTime
->u
.smpte
.min
* 1800;
983 lpTime
->u
.smpte
.sec
= time
/ 30;
984 time
-= lpTime
->u
.smpte
.sec
* 30;
985 lpTime
->u
.smpte
.frame
= time
;
986 lpTime
->u
.smpte
.fps
= 30;
987 TRACE(wave
,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
988 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
989 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
992 lpTime
->u
.ms
= WInDev
[wDevID
].dwTotalRecorded
/
993 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
994 TRACE(wave
, "TIME_MS=%lu\n", lpTime
->u
.ms
);
997 FIXME(wave
, "format not supported ! use TIME_MS !\n");
998 lpTime
->wType
= TIME_MS
;
1000 return MMSYSERR_NOERROR
;
1003 /**************************************************************************
1004 * widMessage [sample driver]
1006 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1007 DWORD dwParam1
, DWORD dwParam2
)
1010 TRACE(wave
,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1011 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1014 return widOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1016 return widClose(wDevID
);
1017 case WIDM_ADDBUFFER
:
1018 return widAddBuffer(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1020 return widPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1021 case WIDM_UNPREPARE
:
1022 return widUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1023 case WIDM_GETDEVCAPS
:
1024 return widGetDevCaps(wDevID
, (LPWAVEINCAPS16
)dwParam1
,dwParam2
);
1025 case WIDM_GETNUMDEVS
:
1026 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1027 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1038 return widGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1040 return widReset(wDevID
);
1042 return widStart(wDevID
);
1044 return widStop(wDevID
);
1046 return widStop(wDevID
);
1048 WARN(wave
,"unknown message !\n");
1050 return MMSYSERR_NOTSUPPORTED
;
1054 /**************************************************************************
1055 * WAVE_DriverProc16 [sample driver]
1057 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1058 DWORD dwParam1
, DWORD dwParam2
)
1060 TRACE(wave
,"(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1063 case DRV_LOAD
: return 1;
1064 case DRV_FREE
: return 1;
1065 case DRV_OPEN
: return 1;
1066 case DRV_CLOSE
: return 1;
1067 case DRV_ENABLE
: return 1;
1068 case DRV_DISABLE
: return 1;
1069 case DRV_QUERYCONFIGURE
: return 1;
1070 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1071 case DRV_INSTALL
: return DRVCNF_RESTART
;
1072 case DRV_REMOVE
: return DRVCNF_RESTART
;
1074 FIXME(wave
, "is probably wrong msg=0x%04x\n", wMsg
);
1075 return DefDriverProc16(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1077 return MMSYSERR_NOTENABLED
;
1080 /**************************************************************************
1081 * WAVE_DriverProc32 [sample driver]
1083 LONG
WAVE_DriverProc(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1084 DWORD dwParam1
, DWORD dwParam2
)
1086 TRACE(wave
,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1088 case DRV_LOAD
: return 1;
1089 case DRV_FREE
: return 1;
1090 case DRV_OPEN
: return 1;
1091 case DRV_CLOSE
: return 1;
1092 case DRV_ENABLE
: return 1;
1093 case DRV_DISABLE
: return 1;
1094 case DRV_QUERYCONFIGURE
: return 1;
1095 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1096 case DRV_INSTALL
: return DRVCNF_RESTART
;
1097 case DRV_REMOVE
: return DRVCNF_RESTART
;
1099 FIXME(wave
, "is probably wrong msg=0x%04lx\n", wMsg
);
1100 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1102 return MMSYSERR_NOTENABLED
;
1105 #else /* !HAVE_OSS */
1107 /**************************************************************************
1108 * wodMessage [sample driver]
1110 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1111 DWORD dwParam1
, DWORD dwParam2
)
1113 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1114 return MMSYSERR_NOTENABLED
;
1117 /**************************************************************************
1118 * widMessage [sample driver]
1120 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1121 DWORD dwParam1
, DWORD dwParam2
)
1123 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1124 return MMSYSERR_NOTENABLED
;
1127 /**************************************************************************
1128 * WAVE_DriverProc16 [sample driver]
1130 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1131 DWORD dwParam1
, DWORD dwParam2
)
1133 return MMSYSERR_NOTENABLED
;
1136 /**************************************************************************
1137 * WAVE_DriverProc32 [sample driver]
1139 LONG
WAVE_DriverProc(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1140 DWORD dwParam1
, DWORD dwParam2
)
1142 return MMSYSERR_NOTENABLED
;
1144 #endif /* HAVE_OSS */