Added some support and stubs for VESA to msdos/int10.c.
[wine/testsucceed.git] / multimedia / audio.c
blobe9716a419f45d24f652a8154068368f4ee54c13e
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
6 */
7 /*
8 * FIXME:
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
13 #define EMULATE_SB16
15 #define DEBUG_MCIWAVE
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include "wine/winuser16.h"
24 #include "driver.h"
25 #include "multimedia.h"
26 #include "heap.h"
27 #include "debug.h"
29 #ifdef HAVE_OSS
31 #define SOUND_DEV "/dev/dsp"
32 #define MIXER_DEV "/dev/mixer"
34 #ifdef SOUND_VERSION
35 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
36 #else
37 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
38 #endif
40 #define MAX_WAVEOUTDRV (1)
41 #define MAX_WAVEINDRV (1)
43 typedef struct {
44 int unixdev;
45 int state;
46 DWORD bufsize;
47 WAVEOPENDESC waveDesc;
48 WORD wFlags;
49 PCMWAVEFORMAT Format;
50 LPWAVEHDR lpQueueHdr;
51 DWORD dwTotalPlayed;
52 } WINE_WAVEOUT;
54 typedef struct {
55 int unixdev;
56 int state;
57 DWORD bufsize; /* OpenSound '/dev/dsp' give us that size */
58 WAVEOPENDESC waveDesc;
59 WORD wFlags;
60 PCMWAVEFORMAT Format;
61 LPWAVEHDR lpQueueHdr;
62 DWORD dwTotalRecorded;
63 } WINE_WAVEIN;
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);
80 switch (wMsg) {
81 case WOM_OPEN:
82 case WOM_CLOSE:
83 case WOM_DONE:
84 if (wDevID > MAX_WAVEOUTDRV) return MCIERR_INTERNAL;
86 if (WOutDev[wDevID].wFlags != DCB_NULL &&
87 !DriverCallback16(
88 WOutDev[wDevID].waveDesc.dwCallBack,
89 WOutDev[wDevID].wFlags,
90 WOutDev[wDevID].waveDesc.hWave,
91 wMsg,
92 WOutDev[wDevID].waveDesc.dwInstance,
93 dwParam1,
94 dwParam2)) {
95 WARN(wave, "can't notify client !\n");
96 return MMSYSERR_NOERROR;
98 break;
100 case WIM_OPEN:
101 case WIM_CLOSE:
102 case WIM_DATA:
103 if (wDevID > MAX_WAVEINDRV) return MCIERR_INTERNAL;
105 if (WInDev[wDevID].wFlags != DCB_NULL &&
106 !DriverCallback16(
107 WInDev[wDevID].waveDesc.dwCallBack,
108 WInDev[wDevID].wFlags,
109 WInDev[wDevID].waveDesc.hWave,
110 wMsg,
111 WInDev[wDevID].waveDesc.dwInstance,
112 dwParam1,
113 dwParam2)) {
114 WARN(wave, "can't notify client !\n");
115 return MMSYSERR_NOERROR;
117 break;
119 return 0;
122 /**************************************************************************
123 * wodGetDevCaps [internal]
125 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
127 int audio;
128 int smplrate;
129 int samplesize = 16;
130 int dsp_stereo = 1;
131 int bytespersmpl;
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 ;
138 #ifdef EMULATE_SB16
139 lpCaps->wMid = 0x0002;
140 lpCaps->wPid = 0x0104;
141 strcpy(lpCaps->szPname, "SB16 Wave Out");
142 #else
143 lpCaps->wMid = 0x00FF; /* Manufac ID */
144 lpCaps->wPid = 0x0001; /* Product ID */
145 strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
146 #endif
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;
157 smplrate = 44100;
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;
168 smplrate = 22050;
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;
179 smplrate = 11025;
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;
190 close(audio);
191 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
192 return MMSYSERR_NOERROR;
196 /**************************************************************************
197 * wodOpen [internal]
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);
216 if (audio == -1) {
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) {
222 if (abuf_size == -1)
223 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
224 else
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) {
230 case DCB_NULL:
231 TRACE(wave, "CALLBACK_NULL !\n");
232 break;
233 case DCB_WINDOW:
234 TRACE(wave, "CALLBACK_WINDOW !\n");
235 break;
236 case DCB_TASK:
237 TRACE(wave, "CALLBACK_TASK !\n");
238 break;
239 case DCB_FUNCTION:
240 TRACE(wave, "CALLBACK_FUNCTION !\n");
241 break;
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)
323 int count;
324 LPSTR lpData;
325 LPWAVEHDR xwavehdr;
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);
360 } else {
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)
447 int time;
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) {
460 case TIME_BYTES:
461 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
462 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
463 break;
464 case TIME_SAMPLES:
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);
470 break;
471 case TIME_SMPTE:
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);
485 break;
486 default:
487 FIXME(wave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
488 lpTime->wType = TIME_MS;
489 case 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);
493 break;
495 return MMSYSERR_NOERROR;
498 /**************************************************************************
499 * wodGetVolume [internal]
501 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
503 int mixer;
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;
515 close(mixer);
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)
529 int mixer;
530 int volume;
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;
542 close(mixer);
543 return MMSYSERR_NOERROR;
546 /**************************************************************************
547 * wodMessage [sample driver]
549 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
550 DWORD dwParam1, DWORD dwParam2)
552 int audio;
553 TRACE(wave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
554 wDevID, wMsg, dwUser, dwParam1, dwParam2);
555 switch(wMsg) {
556 case WODM_OPEN:
557 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
558 case WODM_CLOSE:
559 return wodClose(wDevID);
560 case WODM_WRITE:
561 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
562 case WODM_PAUSE:
563 return MMSYSERR_NOTSUPPORTED;
564 case WODM_STOP:
565 return MMSYSERR_NOTSUPPORTED;
566 case WODM_GETPOS:
567 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
568 case WODM_BREAKLOOP:
569 return MMSYSERR_NOTSUPPORTED;
570 case WODM_PREPARE:
571 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
572 case WODM_UNPREPARE:
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);
579 if (audio == -1)
581 if (errno == EBUSY)
582 return 1;
583 else
584 return 0;
586 close (audio);
587 return 1;
588 case WODM_GETPITCH:
589 return MMSYSERR_NOTSUPPORTED;
590 case WODM_SETPITCH:
591 return MMSYSERR_NOTSUPPORTED;
592 case WODM_GETPLAYBACKRATE:
593 return MMSYSERR_NOTSUPPORTED;
594 case WODM_SETPLAYBACKRATE:
595 return MMSYSERR_NOTSUPPORTED;
596 case WODM_GETVOLUME:
597 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
598 case WODM_SETVOLUME:
599 return wodSetVolume(wDevID, dwParam1);
600 case WODM_RESTART:
601 return wodRestart(wDevID);
602 case WODM_RESET:
603 return wodReset(wDevID);
604 default:
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 ;
625 #ifdef EMULATE_SB16
626 lpCaps->wMid = 0x0002;
627 lpCaps->wPid = 0x0004;
628 strcpy(lpCaps->szPname, "SB16 Wave In");
629 #else
630 lpCaps->wMid = 0x00FF; /* Manufac ID */
631 lpCaps->wPid = 0x0001; /* Product ID */
632 strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
633 #endif
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;
637 smplrate = 44100;
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;
648 smplrate = 22050;
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;
659 smplrate = 11025;
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;
670 close(audio);
671 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
672 return MMSYSERR_NOERROR;
676 /**************************************************************************
677 * widOpen [internal]
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);
696 if (audio == -1) {
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) {
702 if (abuf_size == -1)
703 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
704 else
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) {
710 case DCB_NULL:
711 TRACE(wave,"CALLBACK_NULL!\n");
712 break;
713 case DCB_WINDOW:
714 TRACE(wave,"CALLBACK_WINDOW!\n");
715 break;
716 case DCB_TASK:
717 TRACE(wave,"CALLBACK_TASK!\n");
718 break;
719 case DCB_FUNCTION:
720 TRACE(wave,"CALLBACK_FUNCTION!\n");
721 break;
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)
794 int count = 1;
795 LPWAVEHDR lpWIHdr;
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;
816 } else {
817 lpWIHdr = WInDev[wDevID].lpQueueHdr;
818 while (lpWIHdr->lpNext != NULL) {
819 lpWIHdr = lpWIHdr->lpNext;
820 count++;
822 lpWIHdr->lpNext = lpWaveHdr;
823 lpWaveHdr->lpNext = NULL;
824 count++;
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)
873 int count = 1;
874 int bytesRead;
875 LPWAVEHDR lpWIHdr;
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);
895 fflush(stddeb);
896 bytesRead = read (WInDev[wDevID].unixdev,
897 lpWIHdr->lpData,
898 lpWIHdr->dwBufferLength);
899 if (bytesRead==-1)
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;
914 count++;
916 TRACE(wave,"end of recording !\n");
917 fflush(stddeb);
918 return MMSYSERR_NOERROR;
921 /**************************************************************************
922 * widStop [internal]
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)
952 int time;
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);
965 fflush(stddeb);
966 switch(lpTime->wType) {
967 case TIME_BYTES:
968 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
969 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
970 break;
971 case TIME_SAMPLES:
972 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
973 WInDev[wDevID].Format.wBitsPerSample;
974 TRACE(wave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
975 break;
976 case TIME_SMPTE:
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);
990 break;
991 case TIME_MS:
992 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
993 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
994 TRACE(wave, "TIME_MS=%lu\n", lpTime->u.ms);
995 break;
996 default:
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)
1009 int audio;
1010 TRACE(wave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1011 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1012 switch(wMsg) {
1013 case WIDM_OPEN:
1014 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1015 case WIDM_CLOSE:
1016 return widClose(wDevID);
1017 case WIDM_ADDBUFFER:
1018 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1019 case WIDM_PREPARE:
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);
1028 if (audio == -1)
1030 if (errno == EBUSY)
1031 return 1;
1032 else
1033 return 0;
1035 close (audio);
1036 return 1;
1037 case WIDM_GETPOS:
1038 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1039 case WIDM_RESET:
1040 return widReset(wDevID);
1041 case WIDM_START:
1042 return widStart(wDevID);
1043 case WIDM_PAUSE:
1044 return widStop(wDevID);
1045 case WIDM_STOP:
1046 return widStop(wDevID);
1047 default:
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);
1062 switch(wMsg) {
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;
1073 default:
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);
1087 switch(wMsg) {
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;
1098 default:
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 */