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)
21 #include <sys/ioctl.h>
32 #ifdef HAVE_MACHINE_SOUNDCARD_H
33 # include <machine/soundcard.h>
35 #ifdef HAVE_SYS_SOUNDCARD_H
36 # include <sys/soundcard.h>
39 #define SOUND_DEV "/dev/dsp"
40 #define MIXER_DEV "/dev/mixer"
43 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
45 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
48 #define MAX_WAVEOUTDRV (1)
49 #define MAX_WAVEINDRV (1)
55 WAVEOPENDESC waveDesc
;
65 DWORD bufsize
; /* OpenSound '/dev/dsp' give us that size */
66 WAVEOPENDESC waveDesc
;
70 DWORD dwTotalRecorded
;
73 static WINE_WAVEOUT WOutDev
[MAX_WAVEOUTDRV
];
74 static WINE_WAVEIN WInDev
[MAX_WAVEOUTDRV
];
76 /*======================================================================*
77 * Low level WAVE implemantation *
78 *======================================================================*/
80 /**************************************************************************
81 * WAVE_NotifyClient [internal]
83 static DWORD
WAVE_NotifyClient(UINT16 wDevID
, WORD wMsg
,
84 DWORD dwParam1
, DWORD dwParam2
)
86 TRACE(wave
,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID
, wMsg
, dwParam1
, dwParam2
);
92 if (wDevID
> MAX_WAVEOUTDRV
) return MCIERR_INTERNAL
;
94 if (WOutDev
[wDevID
].wFlags
!= DCB_NULL
&&
96 WOutDev
[wDevID
].waveDesc
.dwCallBack
,
97 WOutDev
[wDevID
].wFlags
,
98 WOutDev
[wDevID
].waveDesc
.hWave
,
100 WOutDev
[wDevID
].waveDesc
.dwInstance
,
103 WARN(wave
, "can't notify client !\n");
104 return MMSYSERR_NOERROR
;
111 if (wDevID
> MAX_WAVEINDRV
) return MCIERR_INTERNAL
;
113 if (WInDev
[wDevID
].wFlags
!= DCB_NULL
&&
115 WInDev
[wDevID
].waveDesc
.dwCallBack
,
116 WInDev
[wDevID
].wFlags
,
117 WInDev
[wDevID
].waveDesc
.hWave
,
119 WInDev
[wDevID
].waveDesc
.dwInstance
,
122 WARN(wave
, "can't notify client !\n");
123 return MMSYSERR_NOERROR
;
130 /**************************************************************************
131 * wodGetDevCaps [internal]
133 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPS16 lpCaps
, DWORD dwSize
)
141 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
142 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
143 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
144 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
145 if (audio
== -1) return MMSYSERR_ALLOCATED
;
147 lpCaps
->wMid
= 0x0002;
148 lpCaps
->wPid
= 0x0104;
149 strcpy(lpCaps
->szPname
, "SB16 Wave Out");
151 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
152 lpCaps
->wPid
= 0x0001; /* Product ID */
153 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVOUT Driver");
155 lpCaps
->vDriverVersion
= 0x0100;
156 lpCaps
->dwFormats
= 0x00000000;
157 lpCaps
->dwSupport
= WAVECAPS_VOLUME
;
159 /* First bytespersampl, then stereo */
160 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
162 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
163 if (lpCaps
->wChannels
> 1) lpCaps
->dwSupport
|= WAVECAPS_LRVOLUME
;
166 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
167 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
168 if (lpCaps
->wChannels
> 1)
169 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
170 if (bytespersmpl
> 1) {
171 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
172 if (lpCaps
->wChannels
> 1)
173 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
177 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
178 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
179 if (lpCaps
->wChannels
> 1)
180 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
181 if (bytespersmpl
> 1) {
182 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
183 if (lpCaps
->wChannels
> 1)
184 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
188 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
189 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
190 if (lpCaps
->wChannels
> 1)
191 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
192 if (bytespersmpl
> 1) {
193 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
194 if (lpCaps
->wChannels
> 1)
195 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
199 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
200 return MMSYSERR_NOERROR
;
204 /**************************************************************************
207 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
209 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
210 LPWAVEFORMAT lpFormat
;
212 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
213 if (lpDesc
== NULL
) {
214 WARN(wave
, "Invalid Parameter !\n");
215 return MMSYSERR_INVALPARAM
;
217 if (wDevID
>= MAX_WAVEOUTDRV
) {
218 TRACE(wave
,"MAX_WAVOUTDRV reached !\n");
219 return MMSYSERR_ALLOCATED
;
221 WOutDev
[wDevID
].unixdev
= 0;
222 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
223 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
225 WARN(wave
, "can't open !\n");
226 return MMSYSERR_ALLOCATED
;
228 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
229 if (abuf_size
< 1024 || abuf_size
> 65536) {
231 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
233 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
234 return MMSYSERR_NOTENABLED
;
236 WOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
237 switch(WOutDev
[wDevID
].wFlags
) {
239 TRACE(wave
, "CALLBACK_NULL !\n");
242 TRACE(wave
, "CALLBACK_WINDOW !\n");
245 TRACE(wave
, "CALLBACK_TASK !\n");
248 TRACE(wave
, "CALLBACK_FUNCTION !\n");
251 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
252 WOutDev
[wDevID
].unixdev
= audio
;
253 WOutDev
[wDevID
].dwTotalPlayed
= 0;
254 WOutDev
[wDevID
].bufsize
= abuf_size
;
255 /* FIXME: copy lpFormat too? */
256 memcpy(&WOutDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
257 TRACE(wave
,"lpDesc->lpFormat = %p\n",lpDesc
->lpFormat
);
258 lpFormat
= lpDesc
->lpFormat
;
259 TRACE(wave
,"lpFormat = %p\n",lpFormat
);
260 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
261 WARN(wave
,"Bad format %04X !\n", lpFormat
->wFormatTag
);
262 WARN(wave
,"Bad nChannels %d !\n", lpFormat
->nChannels
);
263 WARN(wave
,"Bad nSamplesPerSec %ld !\n", lpFormat
->nSamplesPerSec
);
264 return WAVERR_BADFORMAT
;
266 memcpy(&WOutDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
267 if (WOutDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
268 if (WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
269 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
270 if (WOutDev
[wDevID
].Format
.wBitsPerSample
== 0) {
271 WOutDev
[wDevID
].Format
.wBitsPerSample
= 8 *
272 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
273 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
274 WOutDev
[wDevID
].Format
.wf
.nChannels
;
276 samplesize
= WOutDev
[wDevID
].Format
.wBitsPerSample
;
277 smplrate
= WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
278 dsp_stereo
= (WOutDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
280 /* First size and stereo then samplerate */
281 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
282 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
283 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
285 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
286 TRACE(wave
,"nAvgBytesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
287 TRACE(wave
,"nSamplesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
288 TRACE(wave
,"nChannels=%u !\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
289 if (WAVE_NotifyClient(wDevID
, WOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
290 WARN(wave
, "can't notify client !\n");
291 return MMSYSERR_INVALPARAM
;
293 return MMSYSERR_NOERROR
;
296 /**************************************************************************
297 * wodClose [internal]
299 static DWORD
wodClose(WORD wDevID
)
301 TRACE(wave
,"(%u);\n", wDevID
);
303 if (wDevID
> MAX_WAVEOUTDRV
) return MMSYSERR_INVALPARAM
;
304 if (WOutDev
[wDevID
].unixdev
== 0) {
305 WARN(wave
, "can't close !\n");
306 return MMSYSERR_NOTENABLED
;
308 if (WOutDev
[wDevID
].lpQueueHdr
!= NULL
) {
309 WARN(wave
, "still buffers open !\n");
310 /* Don't care. Who needs those buffers anyway */
311 /*return WAVERR_STILLPLAYING; */
313 close(WOutDev
[wDevID
].unixdev
);
314 WOutDev
[wDevID
].unixdev
= 0;
315 WOutDev
[wDevID
].bufsize
= 0;
316 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
317 if (WAVE_NotifyClient(wDevID
, WOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
318 WARN(wave
, "can't notify client !\n");
319 return MMSYSERR_INVALPARAM
;
321 return MMSYSERR_NOERROR
;
324 /**************************************************************************
325 * wodWrite [internal]
326 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
327 * device, and initiate async playing.
329 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
335 TRACE(wave
,"(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
336 if (WOutDev
[wDevID
].unixdev
== 0) {
337 WARN(wave
, "can't play !\n");
338 return MMSYSERR_NOTENABLED
;
340 if (lpWaveHdr
->lpData
== NULL
) return WAVERR_UNPREPARED
;
341 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) return WAVERR_UNPREPARED
;
342 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) return WAVERR_STILLPLAYING
;
343 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
344 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
345 TRACE(wave
, "dwBufferLength %lu !\n", lpWaveHdr
->dwBufferLength
);
346 TRACE(wave
, "WOutDev[%u].unixdev %u !\n", wDevID
, WOutDev
[wDevID
].unixdev
);
347 lpData
= lpWaveHdr
->lpData
;
348 count
= write (WOutDev
[wDevID
].unixdev
, lpData
, lpWaveHdr
->dwBufferLength
);
349 TRACE(wave
,"write returned count %u !\n",count
);
350 if (count
!= lpWaveHdr
->dwBufferLength
) {
351 WARN(wave
, " error writting !\n");
352 return MMSYSERR_NOTENABLED
;
354 WOutDev
[wDevID
].dwTotalPlayed
+= count
;
355 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
356 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
357 if ((DWORD
)lpWaveHdr
->lpData
!=lpWaveHdr
->reserved
) {
358 /* FIXME: what if it expects it's OWN lpwavehdr back? */
359 xwavehdr
= SEGPTR_NEW(WAVEHDR
);
360 memcpy(xwavehdr
,lpWaveHdr
,sizeof(WAVEHDR
));
361 xwavehdr
->lpData
= (LPBYTE
)xwavehdr
->reserved
;
362 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)SEGPTR_GET(xwavehdr
), count
) != MMSYSERR_NOERROR
) {
363 WARN(wave
, "can't notify client !\n");
364 SEGPTR_FREE(xwavehdr
);
365 return MMSYSERR_INVALPARAM
;
367 SEGPTR_FREE(xwavehdr
);
369 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)lpWaveHdr
, count
) != MMSYSERR_NOERROR
) {
370 WARN(wave
, "can't notify client !\n");
371 return MMSYSERR_INVALPARAM
;
374 return MMSYSERR_NOERROR
;
377 /**************************************************************************
378 * wodPrepare [internal]
380 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
382 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
383 if (WOutDev
[wDevID
].unixdev
== 0) {
384 WARN(wave
, "can't prepare !\n");
385 return MMSYSERR_NOTENABLED
;
387 /* don't append to queue, wodWrite does that */
388 WOutDev
[wDevID
].dwTotalPlayed
= 0;
389 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
390 return WAVERR_STILLPLAYING
;
391 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
392 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
393 return MMSYSERR_NOERROR
;
396 /**************************************************************************
397 * wodUnprepare [internal]
399 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
401 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
402 if (WOutDev
[wDevID
].unixdev
== 0) {
403 WARN(wave
, "can't unprepare !\n");
404 return MMSYSERR_NOTENABLED
;
406 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
407 return WAVERR_STILLPLAYING
;
409 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
410 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
411 TRACE(wave
, "all headers unprepared !\n");
412 return MMSYSERR_NOERROR
;
415 /**************************************************************************
416 * wodRestart [internal]
418 static DWORD
wodRestart(WORD wDevID
)
420 TRACE(wave
,"(%u);\n", wDevID
);
421 if (WOutDev
[wDevID
].unixdev
== 0) {
422 WARN(wave
, "can't restart !\n");
423 return MMSYSERR_NOTENABLED
;
425 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
426 /* FIXME: Myst crashes with this ... hmm -MM
427 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
428 WARN(wave, "can't notify client !\n");
429 return MMSYSERR_INVALPARAM;
433 return MMSYSERR_NOERROR
;
436 /**************************************************************************
437 * wodReset [internal]
439 static DWORD
wodReset(WORD wDevID
)
441 TRACE(wave
,"(%u);\n", wDevID
);
442 if (WOutDev
[wDevID
].unixdev
== 0) {
443 WARN(wave
, "can't reset !\n");
444 return MMSYSERR_NOTENABLED
;
446 return MMSYSERR_NOERROR
;
450 /**************************************************************************
451 * wodGetPosition [internal]
453 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
456 TRACE(wave
,"(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
457 if (WOutDev
[wDevID
].unixdev
== 0) {
458 WARN(wave
, "can't get pos !\n");
459 return MMSYSERR_NOTENABLED
;
461 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
462 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
463 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
464 TRACE(wave
,"nSamplesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
465 TRACE(wave
,"nChannels=%u\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
466 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
467 switch(lpTime
->wType
) {
469 lpTime
->u
.cb
= WOutDev
[wDevID
].dwTotalPlayed
;
470 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
473 TRACE(wave
,"dwTotalPlayed=%lu\n", WOutDev
[wDevID
].dwTotalPlayed
);
474 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
475 lpTime
->u
.sample
= WOutDev
[wDevID
].dwTotalPlayed
* 8 /
476 WOutDev
[wDevID
].Format
.wBitsPerSample
;
477 TRACE(wave
,"TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
480 time
= WOutDev
[wDevID
].dwTotalPlayed
/
481 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
482 lpTime
->u
.smpte
.hour
= time
/ 108000;
483 time
-= lpTime
->u
.smpte
.hour
* 108000;
484 lpTime
->u
.smpte
.min
= time
/ 1800;
485 time
-= lpTime
->u
.smpte
.min
* 1800;
486 lpTime
->u
.smpte
.sec
= time
/ 30;
487 time
-= lpTime
->u
.smpte
.sec
* 30;
488 lpTime
->u
.smpte
.frame
= time
;
489 lpTime
->u
.smpte
.fps
= 30;
490 TRACE(wave
, "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
491 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
492 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
495 FIXME(wave
, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime
->wType
);
496 lpTime
->wType
= TIME_MS
;
498 lpTime
->u
.ms
= WOutDev
[wDevID
].dwTotalPlayed
/
499 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
500 TRACE(wave
,"wodGetPosition // TIME_MS=%lu\n", lpTime
->u
.ms
);
503 return MMSYSERR_NOERROR
;
506 /**************************************************************************
507 * wodGetVolume [internal]
509 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
512 int volume
, left
, right
;
513 TRACE(wave
,"(%u, %p);\n", wDevID
, lpdwVol
);
514 if (lpdwVol
== NULL
) return MMSYSERR_NOTENABLED
;
515 if ((mixer
= open(MIXER_DEV
, O_RDONLY
)) < 0) {
516 WARN(wave
, "mixer device not available !\n");
517 return MMSYSERR_NOTENABLED
;
519 if (ioctl(mixer
, SOUND_MIXER_READ_PCM
, &volume
) == -1) {
520 WARN(wave
, "unable read mixer !\n");
521 return MMSYSERR_NOTENABLED
;
524 left
= volume
& 0x7F;
525 right
= (volume
>> 8) & 0x7F;
526 TRACE(wave
,"left=%d right=%d !\n", left
, right
);
527 *lpdwVol
= MAKELONG(left
<< 9, right
<< 9);
528 return MMSYSERR_NOERROR
;
532 /**************************************************************************
533 * wodSetVolume [internal]
535 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
539 TRACE(wave
,"(%u, %08lX);\n", wDevID
, dwParam
);
540 volume
= (LOWORD(dwParam
) >> 9 & 0x7F) +
541 ((HIWORD(dwParam
) >> 9 & 0x7F) << 8);
542 if ((mixer
= open(MIXER_DEV
, O_WRONLY
)) < 0) {
543 WARN(wave
, "mixer device not available !\n");
544 return MMSYSERR_NOTENABLED
;
546 if (ioctl(mixer
, SOUND_MIXER_WRITE_PCM
, &volume
) == -1) {
547 WARN(wave
, "unable set mixer !\n");
548 return MMSYSERR_NOTENABLED
;
551 return MMSYSERR_NOERROR
;
554 /**************************************************************************
555 * wodMessage [sample driver]
557 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
558 DWORD dwParam1
, DWORD dwParam2
)
561 TRACE(wave
,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
562 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
565 return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
567 return wodClose(wDevID
);
569 return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
571 return MMSYSERR_NOTSUPPORTED
;
573 return MMSYSERR_NOTSUPPORTED
;
575 return wodGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
577 return MMSYSERR_NOTSUPPORTED
;
579 return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
581 return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
582 case WODM_GETDEVCAPS
:
583 return wodGetDevCaps(wDevID
,(LPWAVEOUTCAPS16
)dwParam1
,dwParam2
);
584 case WODM_GETNUMDEVS
:
585 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
586 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
597 return MMSYSERR_NOTSUPPORTED
;
599 return MMSYSERR_NOTSUPPORTED
;
600 case WODM_GETPLAYBACKRATE
:
601 return MMSYSERR_NOTSUPPORTED
;
602 case WODM_SETPLAYBACKRATE
:
603 return MMSYSERR_NOTSUPPORTED
;
605 return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
607 return wodSetVolume(wDevID
, dwParam1
);
609 return wodRestart(wDevID
);
611 return wodReset(wDevID
);
613 WARN(wave
,"unknown message !\n");
615 return MMSYSERR_NOTSUPPORTED
;
619 /*-----------------------------------------------------------------------*/
621 /**************************************************************************
622 * widGetDevCaps [internal]
624 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPS16 lpCaps
, DWORD dwSize
)
626 int audio
,smplrate
,samplesize
=16,dsp_stereo
=1,bytespersmpl
;
628 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
629 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
630 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
631 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
632 if (audio
== -1) return MMSYSERR_ALLOCATED
;
634 lpCaps
->wMid
= 0x0002;
635 lpCaps
->wPid
= 0x0004;
636 strcpy(lpCaps
->szPname
, "SB16 Wave In");
638 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
639 lpCaps
->wPid
= 0x0001; /* Product ID */
640 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVIN Driver");
642 lpCaps
->dwFormats
= 0x00000000;
643 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
644 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
646 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
647 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
648 if (lpCaps
->wChannels
> 1)
649 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
650 if (bytespersmpl
> 1) {
651 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
652 if (lpCaps
->wChannels
> 1)
653 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
657 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
658 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
659 if (lpCaps
->wChannels
> 1)
660 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
661 if (bytespersmpl
> 1) {
662 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
663 if (lpCaps
->wChannels
> 1)
664 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
668 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
669 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
670 if (lpCaps
->wChannels
> 1)
671 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
672 if (bytespersmpl
> 1) {
673 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
674 if (lpCaps
->wChannels
> 1)
675 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
679 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
680 return MMSYSERR_NOERROR
;
684 /**************************************************************************
687 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
689 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
690 LPWAVEFORMAT lpFormat
;
692 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
693 if (lpDesc
== NULL
) {
694 WARN(wave
, "Invalid Parameter !\n");
695 return MMSYSERR_INVALPARAM
;
697 if (wDevID
>= MAX_WAVEINDRV
) {
698 TRACE(wave
,"MAX_WAVINDRV reached !\n");
699 return MMSYSERR_ALLOCATED
;
701 WInDev
[wDevID
].unixdev
= 0;
702 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
703 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
705 WARN(wave
,"can't open !\n");
706 return MMSYSERR_ALLOCATED
;
708 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
709 if (abuf_size
< 1024 || abuf_size
> 65536) {
711 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
713 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
714 return MMSYSERR_NOTENABLED
;
716 WInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
717 switch(WInDev
[wDevID
].wFlags
) {
719 TRACE(wave
,"CALLBACK_NULL!\n");
722 TRACE(wave
,"CALLBACK_WINDOW!\n");
725 TRACE(wave
,"CALLBACK_TASK!\n");
728 TRACE(wave
,"CALLBACK_FUNCTION!\n");
731 if (WInDev
[wDevID
].lpQueueHdr
) {
732 HeapFree(GetProcessHeap(),0,WInDev
[wDevID
].lpQueueHdr
);
733 WInDev
[wDevID
].lpQueueHdr
= NULL
;
735 WInDev
[wDevID
].unixdev
= audio
;
736 WInDev
[wDevID
].bufsize
= abuf_size
;
737 WInDev
[wDevID
].dwTotalRecorded
= 0;
738 memcpy(&WInDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
739 lpFormat
= (LPWAVEFORMAT
) lpDesc
->lpFormat
;
740 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
741 WARN(wave
, "Bad format %04X !\n",
742 lpFormat
->wFormatTag
);
743 return WAVERR_BADFORMAT
;
745 memcpy(&WInDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
746 WInDev
[wDevID
].Format
.wBitsPerSample
= 8; /* <-------------- */
747 if (WInDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
748 if (WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
749 if (WInDev
[wDevID
].Format
.wBitsPerSample
== 0) {
750 WInDev
[wDevID
].Format
.wBitsPerSample
= 8 *
751 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
752 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
753 WInDev
[wDevID
].Format
.wf
.nChannels
;
755 samplesize
= WInDev
[wDevID
].Format
.wBitsPerSample
;
756 smplrate
= WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
757 dsp_stereo
= (WInDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
758 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
759 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
760 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
761 TRACE(wave
,"wBitsPerSample=%u !\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
762 TRACE(wave
,"nSamplesPerSec=%lu !\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
763 TRACE(wave
,"nChannels=%u !\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
764 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
765 if (WAVE_NotifyClient(wDevID
, WIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
766 WARN(wave
,"can't notify client !\n");
767 return MMSYSERR_INVALPARAM
;
769 return MMSYSERR_NOERROR
;
772 /**************************************************************************
773 * widClose [internal]
775 static DWORD
widClose(WORD wDevID
)
777 TRACE(wave
,"(%u);\n", wDevID
);
778 if (wDevID
> MAX_WAVEINDRV
) return MMSYSERR_INVALPARAM
;
779 if (WInDev
[wDevID
].unixdev
== 0) {
780 WARN(wave
,"can't close !\n");
781 return MMSYSERR_NOTENABLED
;
783 if (WInDev
[wDevID
].lpQueueHdr
!= NULL
) {
784 WARN(wave
, "still buffers open !\n");
785 return WAVERR_STILLPLAYING
;
787 close(WInDev
[wDevID
].unixdev
);
788 WInDev
[wDevID
].unixdev
= 0;
789 WInDev
[wDevID
].bufsize
= 0;
790 if (WAVE_NotifyClient(wDevID
, WIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
791 WARN(wave
,"can't notify client !\n");
792 return MMSYSERR_INVALPARAM
;
794 return MMSYSERR_NOERROR
;
797 /**************************************************************************
798 * widAddBuffer [internal]
800 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
805 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
806 if (WInDev
[wDevID
].unixdev
== 0) {
807 WARN(wave
,"can't do it !\n");
808 return MMSYSERR_NOTENABLED
;
810 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
811 TRACE(wave
, "never been prepared !\n");
812 return WAVERR_UNPREPARED
;
814 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
815 TRACE(wave
, "header already in use !\n");
816 return WAVERR_STILLPLAYING
;
818 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
819 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
820 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
821 lpWaveHdr
->dwBytesRecorded
= 0;
822 if (WInDev
[wDevID
].lpQueueHdr
== NULL
) {
823 WInDev
[wDevID
].lpQueueHdr
= lpWaveHdr
;
825 lpWIHdr
= WInDev
[wDevID
].lpQueueHdr
;
826 while (lpWIHdr
->lpNext
!= NULL
) {
827 lpWIHdr
= lpWIHdr
->lpNext
;
830 lpWIHdr
->lpNext
= lpWaveHdr
;
831 lpWaveHdr
->lpNext
= NULL
;
834 TRACE(wave
, "buffer added ! (now %u in queue)\n", count
);
835 return MMSYSERR_NOERROR
;
838 /**************************************************************************
839 * widPrepare [internal]
841 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
843 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
844 if (WInDev
[wDevID
].unixdev
== 0) {
845 WARN(wave
,"can't prepare !\n");
846 return MMSYSERR_NOTENABLED
;
848 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
849 return WAVERR_STILLPLAYING
;
850 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
851 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
852 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
853 lpWaveHdr
->dwBytesRecorded
= 0;
854 TRACE(wave
,"header prepared !\n");
855 return MMSYSERR_NOERROR
;
858 /**************************************************************************
859 * widUnprepare [internal]
861 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
863 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
864 if (WInDev
[wDevID
].unixdev
== 0) {
865 WARN(wave
,"can't unprepare !\n");
866 return MMSYSERR_NOTENABLED
;
868 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
869 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
870 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
872 TRACE(wave
, "all headers unprepared !\n");
873 return MMSYSERR_NOERROR
;
876 /**************************************************************************
877 * widStart [internal]
879 static DWORD
widStart(WORD wDevID
)
884 LPWAVEHDR
*lpWaveHdr
;
886 TRACE(wave
,"(%u);\n", wDevID
);
887 if (WInDev
[wDevID
].unixdev
== 0) {
888 WARN(wave
, "can't start recording !\n");
889 return MMSYSERR_NOTENABLED
;
892 lpWaveHdr
= &(WInDev
[wDevID
].lpQueueHdr
);
893 TRACE(wave
,"lpWaveHdr = %08lx\n",(DWORD
)lpWaveHdr
);
894 if (!*lpWaveHdr
|| !(*lpWaveHdr
)->lpData
) {
895 TRACE(wave
,"never been prepared !\n");
896 return WAVERR_UNPREPARED
;
899 while(*lpWaveHdr
!= NULL
) {
900 lpWIHdr
= *lpWaveHdr
;
901 TRACE(wave
, "recording buf#%u=%p size=%lu \n",
902 count
, lpWIHdr
->lpData
, lpWIHdr
->dwBufferLength
);
904 bytesRead
= read (WInDev
[wDevID
].unixdev
,
906 lpWIHdr
->dwBufferLength
);
908 perror("read from audio device");
909 TRACE(wave
,"bytesread=%d (%ld)\n", bytesRead
, lpWIHdr
->dwBufferLength
);
910 lpWIHdr
->dwBytesRecorded
= bytesRead
;
911 WInDev
[wDevID
].dwTotalRecorded
+= lpWIHdr
->dwBytesRecorded
;
912 lpWIHdr
->dwFlags
&= ~WHDR_INQUEUE
;
913 lpWIHdr
->dwFlags
|= WHDR_DONE
;
915 /* FIXME: should pass segmented pointer here, do we need that?*/
916 if (WAVE_NotifyClient(wDevID
, WIM_DATA
, (DWORD
)lpWaveHdr
, lpWIHdr
->dwBytesRecorded
) != MMSYSERR_NOERROR
) {
917 WARN(wave
, "can't notify client !\n");
918 return MMSYSERR_INVALPARAM
;
920 /* removes the current block from the queue */
921 *lpWaveHdr
= lpWIHdr
->lpNext
;
924 TRACE(wave
,"end of recording !\n");
926 return MMSYSERR_NOERROR
;
929 /**************************************************************************
932 static DWORD
widStop(WORD wDevID
)
934 TRACE(wave
,"(%u);\n", wDevID
);
935 if (WInDev
[wDevID
].unixdev
== 0) {
936 WARN(wave
,"can't stop !\n");
937 return MMSYSERR_NOTENABLED
;
939 return MMSYSERR_NOERROR
;
942 /**************************************************************************
943 * widReset [internal]
945 static DWORD
widReset(WORD wDevID
)
947 TRACE(wave
,"(%u);\n", wDevID
);
948 if (WInDev
[wDevID
].unixdev
== 0) {
949 WARN(wave
,"can't reset !\n");
950 return MMSYSERR_NOTENABLED
;
952 return MMSYSERR_NOERROR
;
955 /**************************************************************************
956 * widGetPosition [internal]
958 static DWORD
widGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
962 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
963 if (WInDev
[wDevID
].unixdev
== 0) {
964 WARN(wave
,"can't get pos !\n");
965 return MMSYSERR_NOTENABLED
;
967 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
968 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
969 TRACE(wave
,"wBitsPerSample=%u\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
970 TRACE(wave
,"nSamplesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
971 TRACE(wave
,"nChannels=%u\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
972 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
974 switch(lpTime
->wType
) {
976 lpTime
->u
.cb
= WInDev
[wDevID
].dwTotalRecorded
;
977 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
980 lpTime
->u
.sample
= WInDev
[wDevID
].dwTotalRecorded
* 8 /
981 WInDev
[wDevID
].Format
.wBitsPerSample
;
982 TRACE(wave
, "TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
985 time
= WInDev
[wDevID
].dwTotalRecorded
/
986 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
987 lpTime
->u
.smpte
.hour
= time
/ 108000;
988 time
-= lpTime
->u
.smpte
.hour
* 108000;
989 lpTime
->u
.smpte
.min
= time
/ 1800;
990 time
-= lpTime
->u
.smpte
.min
* 1800;
991 lpTime
->u
.smpte
.sec
= time
/ 30;
992 time
-= lpTime
->u
.smpte
.sec
* 30;
993 lpTime
->u
.smpte
.frame
= time
;
994 lpTime
->u
.smpte
.fps
= 30;
995 TRACE(wave
,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
996 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
997 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1000 lpTime
->u
.ms
= WInDev
[wDevID
].dwTotalRecorded
/
1001 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1002 TRACE(wave
, "TIME_MS=%lu\n", lpTime
->u
.ms
);
1005 FIXME(wave
, "format not supported ! use TIME_MS !\n");
1006 lpTime
->wType
= TIME_MS
;
1008 return MMSYSERR_NOERROR
;
1011 /**************************************************************************
1012 * widMessage [sample driver]
1014 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1015 DWORD dwParam1
, DWORD dwParam2
)
1018 TRACE(wave
,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1019 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1022 return widOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1024 return widClose(wDevID
);
1025 case WIDM_ADDBUFFER
:
1026 return widAddBuffer(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1028 return widPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1029 case WIDM_UNPREPARE
:
1030 return widUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1031 case WIDM_GETDEVCAPS
:
1032 return widGetDevCaps(wDevID
, (LPWAVEINCAPS16
)dwParam1
,dwParam2
);
1033 case WIDM_GETNUMDEVS
:
1034 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1035 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1046 return widGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1048 return widReset(wDevID
);
1050 return widStart(wDevID
);
1052 return widStop(wDevID
);
1054 return widStop(wDevID
);
1056 WARN(wave
,"unknown message !\n");
1058 return MMSYSERR_NOTSUPPORTED
;
1062 /**************************************************************************
1063 * WAVE_DriverProc16 [sample driver]
1065 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1066 DWORD dwParam1
, DWORD dwParam2
)
1068 TRACE(wave
,"(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1071 case DRV_LOAD
: return 1;
1072 case DRV_FREE
: return 1;
1073 case DRV_OPEN
: return 1;
1074 case DRV_CLOSE
: return 1;
1075 case DRV_ENABLE
: return 1;
1076 case DRV_DISABLE
: return 1;
1077 case DRV_QUERYCONFIGURE
: return 1;
1078 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1079 case DRV_INSTALL
: return DRVCNF_RESTART
;
1080 case DRV_REMOVE
: return DRVCNF_RESTART
;
1082 FIXME(wave
, "is probably wrong msg=0x%04x\n", wMsg
);
1083 return DefDriverProc16(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1085 return MMSYSERR_NOTENABLED
;
1088 /**************************************************************************
1089 * WAVE_DriverProc32 [sample driver]
1091 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1092 DWORD dwParam1
, DWORD dwParam2
)
1094 TRACE(wave
,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1096 case DRV_LOAD
: return 1;
1097 case DRV_FREE
: return 1;
1098 case DRV_OPEN
: return 1;
1099 case DRV_CLOSE
: return 1;
1100 case DRV_ENABLE
: return 1;
1101 case DRV_DISABLE
: return 1;
1102 case DRV_QUERYCONFIGURE
: return 1;
1103 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1104 case DRV_INSTALL
: return DRVCNF_RESTART
;
1105 case DRV_REMOVE
: return DRVCNF_RESTART
;
1107 FIXME(wave
, "is probably wrong msg=0x%04lx\n", wMsg
);
1108 return DefDriverProc32(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1110 return MMSYSERR_NOTENABLED
;
1113 #else /* !HAVE_OSS */
1115 /**************************************************************************
1116 * wodMessage [sample driver]
1118 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1119 DWORD dwParam1
, DWORD dwParam2
)
1121 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1122 return MMSYSERR_NOTENABLED
;
1125 /**************************************************************************
1126 * widMessage [sample driver]
1128 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1129 DWORD dwParam1
, DWORD dwParam2
)
1131 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1132 return MMSYSERR_NOTENABLED
;
1135 /**************************************************************************
1136 * WAVE_DriverProc16 [sample driver]
1138 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1139 DWORD dwParam1
, DWORD dwParam2
)
1141 return MMSYSERR_NOTENABLED
;
1144 /**************************************************************************
1145 * WAVE_DriverProc32 [sample driver]
1147 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1148 DWORD dwParam1
, DWORD dwParam2
)
1150 return MMSYSERR_NOTENABLED
;
1152 #endif /* HAVE_OSS */