Added sysres_Ru.s
[wine/multimedia.git] / multimedia / audio.c
blob7fefd89ee3d794c6ed0144dac23fa21169d50af9
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 #define MAX_WAVEOUTDRV (1)
35 #define MAX_WAVEINDRV (1)
37 typedef struct {
38 int unixdev;
39 int state;
40 DWORD bufsize;
41 WAVEOPENDESC waveDesc;
42 WORD wFlags;
43 PCMWAVEFORMAT Format;
44 LPWAVEHDR lpQueueHdr;
45 DWORD dwTotalPlayed;
46 } WINE_WAVEOUT;
48 typedef struct {
49 int unixdev;
50 int state;
51 DWORD bufsize; /* OpenSound '/dev/dsp' give us that size */
52 WAVEOPENDESC waveDesc;
53 WORD wFlags;
54 PCMWAVEFORMAT Format;
55 LPWAVEHDR lpQueueHdr;
56 DWORD dwTotalRecorded;
57 } WINE_WAVEIN;
59 static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
60 static WINE_WAVEIN WInDev [MAX_WAVEOUTDRV];
62 /*======================================================================*
63 * Low level WAVE implemantation *
64 *======================================================================*/
66 /**************************************************************************
67 * WAVE_NotifyClient [internal]
69 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg,
70 DWORD dwParam1, DWORD dwParam2)
72 TRACE(wave,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
74 switch (wMsg) {
75 case WOM_OPEN:
76 case WOM_CLOSE:
77 case WOM_DONE:
78 if (wDevID > MAX_WAVEOUTDRV) return MCIERR_INTERNAL;
80 if (WOutDev[wDevID].wFlags != DCB_NULL &&
81 !DriverCallback16(
82 WOutDev[wDevID].waveDesc.dwCallBack,
83 WOutDev[wDevID].wFlags,
84 WOutDev[wDevID].waveDesc.hWave,
85 wMsg,
86 WOutDev[wDevID].waveDesc.dwInstance,
87 dwParam1,
88 dwParam2)) {
89 WARN(wave, "can't notify client !\n");
90 return MMSYSERR_NOERROR;
92 break;
94 case WIM_OPEN:
95 case WIM_CLOSE:
96 case WIM_DATA:
97 if (wDevID > MAX_WAVEINDRV) return MCIERR_INTERNAL;
99 if (WInDev[wDevID].wFlags != DCB_NULL &&
100 !DriverCallback16(
101 WInDev[wDevID].waveDesc.dwCallBack,
102 WInDev[wDevID].wFlags,
103 WInDev[wDevID].waveDesc.hWave,
104 wMsg,
105 WInDev[wDevID].waveDesc.dwInstance,
106 dwParam1,
107 dwParam2)) {
108 WARN(wave, "can't notify client !\n");
109 return MMSYSERR_NOERROR;
111 break;
113 return 0;
116 /**************************************************************************
117 * wodGetDevCaps [internal]
119 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
121 int audio;
122 int smplrate;
123 int samplesize = 16;
124 int dsp_stereo = 1;
125 int bytespersmpl;
127 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
128 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
129 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
130 audio = open (SOUND_DEV, O_WRONLY, 0);
131 if (audio == -1) return MMSYSERR_ALLOCATED ;
132 #ifdef EMULATE_SB16
133 lpCaps->wMid = 0x0002;
134 lpCaps->wPid = 0x0104;
135 strcpy(lpCaps->szPname, "SB16 Wave Out");
136 #else
137 lpCaps->wMid = 0x00FF; /* Manufac ID */
138 lpCaps->wPid = 0x0001; /* Product ID */
139 strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
140 #endif
141 lpCaps->vDriverVersion = 0x0100;
142 lpCaps->dwFormats = 0x00000000;
143 lpCaps->dwSupport = WAVECAPS_VOLUME;
145 /* First bytespersampl, then stereo */
146 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
148 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
149 if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
151 smplrate = 44100;
152 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
153 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
154 if (lpCaps->wChannels > 1)
155 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
156 if (bytespersmpl > 1) {
157 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
158 if (lpCaps->wChannels > 1)
159 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
162 smplrate = 22050;
163 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
164 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
165 if (lpCaps->wChannels > 1)
166 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
167 if (bytespersmpl > 1) {
168 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
169 if (lpCaps->wChannels > 1)
170 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
173 smplrate = 11025;
174 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
175 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
176 if (lpCaps->wChannels > 1)
177 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
178 if (bytespersmpl > 1) {
179 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
180 if (lpCaps->wChannels > 1)
181 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
184 close(audio);
185 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
186 return MMSYSERR_NOERROR;
190 /**************************************************************************
191 * wodOpen [internal]
193 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
195 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
196 LPWAVEFORMAT lpFormat;
198 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
199 if (lpDesc == NULL) {
200 WARN(wave, "Invalid Parameter !\n");
201 return MMSYSERR_INVALPARAM;
203 if (wDevID >= MAX_WAVEOUTDRV) {
204 TRACE(wave,"MAX_WAVOUTDRV reached !\n");
205 return MMSYSERR_ALLOCATED;
207 WOutDev[wDevID].unixdev = 0;
208 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
209 audio = open (SOUND_DEV, O_WRONLY, 0);
210 if (audio == -1) {
211 WARN(wave, "can't open !\n");
212 return MMSYSERR_ALLOCATED ;
214 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
215 if (abuf_size < 1024 || abuf_size > 65536) {
216 if (abuf_size == -1)
217 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
218 else
219 WARN(wave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
220 return MMSYSERR_NOTENABLED;
222 WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
223 switch(WOutDev[wDevID].wFlags) {
224 case DCB_NULL:
225 TRACE(wave, "CALLBACK_NULL !\n");
226 break;
227 case DCB_WINDOW:
228 TRACE(wave, "CALLBACK_WINDOW !\n");
229 break;
230 case DCB_TASK:
231 TRACE(wave, "CALLBACK_TASK !\n");
232 break;
233 case DCB_FUNCTION:
234 TRACE(wave, "CALLBACK_FUNCTION !\n");
235 break;
237 WOutDev[wDevID].lpQueueHdr = NULL;
238 WOutDev[wDevID].unixdev = audio;
239 WOutDev[wDevID].dwTotalPlayed = 0;
240 WOutDev[wDevID].bufsize = abuf_size;
241 /* FIXME: copy lpFormat too? */
242 memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
243 TRACE(wave,"lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
244 lpFormat = lpDesc->lpFormat;
245 TRACE(wave,"lpFormat = %p\n",lpFormat);
246 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
247 WARN(wave,"Bad format %04X !\n", lpFormat->wFormatTag);
248 WARN(wave,"Bad nChannels %d !\n", lpFormat->nChannels);
249 WARN(wave,"Bad nSamplesPerSec %ld !\n", lpFormat->nSamplesPerSec);
250 return WAVERR_BADFORMAT;
252 memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
253 if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
254 if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
255 TRACE(wave,"wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample);
256 if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
257 WOutDev[wDevID].Format.wBitsPerSample = 8 *
258 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
259 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
260 WOutDev[wDevID].Format.wf.nChannels;
262 samplesize = WOutDev[wDevID].Format.wBitsPerSample;
263 smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
264 dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
266 /* First size and stereo then samplerate */
267 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
268 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
269 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
271 TRACE(wave,"wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample);
272 TRACE(wave,"nAvgBytesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
273 TRACE(wave,"nSamplesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nSamplesPerSec);
274 TRACE(wave,"nChannels=%u !\n", WOutDev[wDevID].Format.wf.nChannels);
275 if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
276 WARN(wave, "can't notify client !\n");
277 return MMSYSERR_INVALPARAM;
279 return MMSYSERR_NOERROR;
282 /**************************************************************************
283 * wodClose [internal]
285 static DWORD wodClose(WORD wDevID)
287 TRACE(wave,"(%u);\n", wDevID);
289 if (wDevID > MAX_WAVEOUTDRV) return MMSYSERR_INVALPARAM;
290 if (WOutDev[wDevID].unixdev == 0) {
291 WARN(wave, "can't close !\n");
292 return MMSYSERR_NOTENABLED;
294 if (WOutDev[wDevID].lpQueueHdr != NULL) {
295 WARN(wave, "still buffers open !\n");
296 /* Don't care. Who needs those buffers anyway */
297 /*return WAVERR_STILLPLAYING; */
299 close(WOutDev[wDevID].unixdev);
300 WOutDev[wDevID].unixdev = 0;
301 WOutDev[wDevID].bufsize = 0;
302 WOutDev[wDevID].lpQueueHdr = NULL;
303 if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
304 WARN(wave, "can't notify client !\n");
305 return MMSYSERR_INVALPARAM;
307 return MMSYSERR_NOERROR;
310 /**************************************************************************
311 * wodWrite [internal]
312 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
313 * device, and initiate async playing.
315 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
317 int count;
318 LPSTR lpData;
319 LPWAVEHDR xwavehdr;
321 TRACE(wave,"(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
322 if (WOutDev[wDevID].unixdev == 0) {
323 WARN(wave, "can't play !\n");
324 return MMSYSERR_NOTENABLED;
326 if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
327 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
328 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
329 lpWaveHdr->dwFlags &= ~WHDR_DONE;
330 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
331 TRACE(wave, "dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
332 TRACE(wave, "WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
333 lpData = lpWaveHdr->lpData;
334 count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
335 TRACE(wave,"write returned count %u !\n",count);
336 if (count != lpWaveHdr->dwBufferLength) {
337 WARN(wave, " error writing !\n");
338 return MMSYSERR_NOTENABLED;
340 WOutDev[wDevID].dwTotalPlayed += count;
341 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
342 lpWaveHdr->dwFlags |= WHDR_DONE;
343 if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
344 /* FIXME: what if it expects it's OWN lpwavehdr back? */
345 xwavehdr = SEGPTR_NEW(WAVEHDR);
346 memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
347 xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
348 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
349 WARN(wave, "can't notify client !\n");
350 SEGPTR_FREE(xwavehdr);
351 return MMSYSERR_INVALPARAM;
353 SEGPTR_FREE(xwavehdr);
354 } else {
355 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
356 WARN(wave, "can't notify client !\n");
357 return MMSYSERR_INVALPARAM;
360 return MMSYSERR_NOERROR;
363 /**************************************************************************
364 * wodPrepare [internal]
366 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
368 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
369 if (WOutDev[wDevID].unixdev == 0) {
370 WARN(wave, "can't prepare !\n");
371 return MMSYSERR_NOTENABLED;
373 /* don't append to queue, wodWrite does that */
374 WOutDev[wDevID].dwTotalPlayed = 0;
375 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
376 return WAVERR_STILLPLAYING;
377 lpWaveHdr->dwFlags |= WHDR_PREPARED;
378 lpWaveHdr->dwFlags &= ~WHDR_DONE;
379 return MMSYSERR_NOERROR;
382 /**************************************************************************
383 * wodUnprepare [internal]
385 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
387 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
388 if (WOutDev[wDevID].unixdev == 0) {
389 WARN(wave, "can't unprepare !\n");
390 return MMSYSERR_NOTENABLED;
392 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
393 return WAVERR_STILLPLAYING;
395 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
396 lpWaveHdr->dwFlags |= WHDR_DONE;
397 TRACE(wave, "all headers unprepared !\n");
398 return MMSYSERR_NOERROR;
401 /**************************************************************************
402 * wodRestart [internal]
404 static DWORD wodRestart(WORD wDevID)
406 TRACE(wave,"(%u);\n", wDevID);
407 if (WOutDev[wDevID].unixdev == 0) {
408 WARN(wave, "can't restart !\n");
409 return MMSYSERR_NOTENABLED;
411 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
412 /* FIXME: Myst crashes with this ... hmm -MM
413 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
414 WARN(wave, "can't notify client !\n");
415 return MMSYSERR_INVALPARAM;
419 return MMSYSERR_NOERROR;
422 /**************************************************************************
423 * wodReset [internal]
425 static DWORD wodReset(WORD wDevID)
427 TRACE(wave,"(%u);\n", wDevID);
428 if (WOutDev[wDevID].unixdev == 0) {
429 WARN(wave, "can't reset !\n");
430 return MMSYSERR_NOTENABLED;
432 return MMSYSERR_NOERROR;
436 /**************************************************************************
437 * wodGetPosition [internal]
439 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
441 int time;
442 TRACE(wave,"(%u, %p, %lu);\n", wDevID, lpTime, uSize);
443 if (WOutDev[wDevID].unixdev == 0) {
444 WARN(wave, "can't get pos !\n");
445 return MMSYSERR_NOTENABLED;
447 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
448 TRACE(wave,"wType=%04X !\n", lpTime->wType);
449 TRACE(wave,"wBitsPerSample=%u\n", WOutDev[wDevID].Format.wBitsPerSample);
450 TRACE(wave,"nSamplesPerSec=%lu\n", WOutDev[wDevID].Format.wf.nSamplesPerSec);
451 TRACE(wave,"nChannels=%u\n", WOutDev[wDevID].Format.wf.nChannels);
452 TRACE(wave,"nAvgBytesPerSec=%lu\n", WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
453 switch(lpTime->wType) {
454 case TIME_BYTES:
455 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
456 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
457 break;
458 case TIME_SAMPLES:
459 TRACE(wave,"dwTotalPlayed=%lu\n", WOutDev[wDevID].dwTotalPlayed);
460 TRACE(wave,"wBitsPerSample=%u\n", WOutDev[wDevID].Format.wBitsPerSample);
461 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
462 WOutDev[wDevID].Format.wBitsPerSample;
463 TRACE(wave,"TIME_SAMPLES=%lu\n", lpTime->u.sample);
464 break;
465 case TIME_SMPTE:
466 time = WOutDev[wDevID].dwTotalPlayed /
467 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
468 lpTime->u.smpte.hour = time / 108000;
469 time -= lpTime->u.smpte.hour * 108000;
470 lpTime->u.smpte.min = time / 1800;
471 time -= lpTime->u.smpte.min * 1800;
472 lpTime->u.smpte.sec = time / 30;
473 time -= lpTime->u.smpte.sec * 30;
474 lpTime->u.smpte.frame = time;
475 lpTime->u.smpte.fps = 30;
476 TRACE(wave, "wodGetPosition , TIME_SMPTE=%02u:%02u:%02u:%02u\n",
477 lpTime->u.smpte.hour, lpTime->u.smpte.min,
478 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
479 break;
480 default:
481 FIXME(wave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
482 lpTime->wType = TIME_MS;
483 case TIME_MS:
484 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
485 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
486 TRACE(wave,"wodGetPosition , TIME_MS=%lu\n", lpTime->u.ms);
487 break;
489 return MMSYSERR_NOERROR;
492 /**************************************************************************
493 * wodGetVolume [internal]
495 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
497 int mixer;
498 int volume, left, right;
499 TRACE(wave,"(%u, %p);\n", wDevID, lpdwVol);
500 if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
501 if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
502 WARN(wave, "mixer device not available !\n");
503 return MMSYSERR_NOTENABLED;
505 if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
506 WARN(wave, "unable read mixer !\n");
507 return MMSYSERR_NOTENABLED;
509 close(mixer);
510 left = volume & 0x7F;
511 right = (volume >> 8) & 0x7F;
512 TRACE(wave,"left=%d right=%d !\n", left, right);
513 *lpdwVol = MAKELONG(left << 9, right << 9);
514 return MMSYSERR_NOERROR;
518 /**************************************************************************
519 * wodSetVolume [internal]
521 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
523 int mixer;
524 int volume;
525 TRACE(wave,"(%u, %08lX);\n", wDevID, dwParam);
526 volume = (LOWORD(dwParam) >> 9 & 0x7F) +
527 ((HIWORD(dwParam) >> 9 & 0x7F) << 8);
528 if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
529 WARN(wave, "mixer device not available !\n");
530 return MMSYSERR_NOTENABLED;
532 if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
533 WARN(wave, "unable set mixer !\n");
534 return MMSYSERR_NOTENABLED;
536 close(mixer);
537 return MMSYSERR_NOERROR;
540 /**************************************************************************
541 * wodMessage [sample driver]
543 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
544 DWORD dwParam1, DWORD dwParam2)
546 int audio;
547 TRACE(wave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
548 wDevID, wMsg, dwUser, dwParam1, dwParam2);
549 switch(wMsg) {
550 case WODM_OPEN:
551 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
552 case WODM_CLOSE:
553 return wodClose(wDevID);
554 case WODM_WRITE:
555 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
556 case WODM_PAUSE:
557 return MMSYSERR_NOTSUPPORTED;
558 case WODM_STOP:
559 return MMSYSERR_NOTSUPPORTED;
560 case WODM_GETPOS:
561 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
562 case WODM_BREAKLOOP:
563 return MMSYSERR_NOTSUPPORTED;
564 case WODM_PREPARE:
565 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
566 case WODM_UNPREPARE:
567 return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
568 case WODM_GETDEVCAPS:
569 return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
570 case WODM_GETNUMDEVS:
571 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
572 audio = open (SOUND_DEV, O_WRONLY, 0);
573 if (audio == -1)
575 if (errno == EBUSY)
576 return 1;
577 else
578 return 0;
580 close (audio);
581 return 1;
582 case WODM_GETPITCH:
583 return MMSYSERR_NOTSUPPORTED;
584 case WODM_SETPITCH:
585 return MMSYSERR_NOTSUPPORTED;
586 case WODM_GETPLAYBACKRATE:
587 return MMSYSERR_NOTSUPPORTED;
588 case WODM_SETPLAYBACKRATE:
589 return MMSYSERR_NOTSUPPORTED;
590 case WODM_GETVOLUME:
591 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
592 case WODM_SETVOLUME:
593 return wodSetVolume(wDevID, dwParam1);
594 case WODM_RESTART:
595 return wodRestart(wDevID);
596 case WODM_RESET:
597 return wodReset(wDevID);
598 default:
599 WARN(wave,"unknown message !\n");
601 return MMSYSERR_NOTSUPPORTED;
605 /*-----------------------------------------------------------------------*/
607 /**************************************************************************
608 * widGetDevCaps [internal]
610 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
612 int audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
614 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
615 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
616 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
617 audio = open (SOUND_DEV, O_RDONLY, 0);
618 if (audio == -1) return MMSYSERR_ALLOCATED ;
619 #ifdef EMULATE_SB16
620 lpCaps->wMid = 0x0002;
621 lpCaps->wPid = 0x0004;
622 strcpy(lpCaps->szPname, "SB16 Wave In");
623 #else
624 lpCaps->wMid = 0x00FF; /* Manufac ID */
625 lpCaps->wPid = 0x0001; /* Product ID */
626 strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
627 #endif
628 lpCaps->dwFormats = 0x00000000;
629 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
630 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
631 smplrate = 44100;
632 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
633 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
634 if (lpCaps->wChannels > 1)
635 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
636 if (bytespersmpl > 1) {
637 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
638 if (lpCaps->wChannels > 1)
639 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
642 smplrate = 22050;
643 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
644 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
645 if (lpCaps->wChannels > 1)
646 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
647 if (bytespersmpl > 1) {
648 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
649 if (lpCaps->wChannels > 1)
650 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
653 smplrate = 11025;
654 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
655 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
656 if (lpCaps->wChannels > 1)
657 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
658 if (bytespersmpl > 1) {
659 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
660 if (lpCaps->wChannels > 1)
661 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
664 close(audio);
665 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
666 return MMSYSERR_NOERROR;
670 /**************************************************************************
671 * widOpen [internal]
673 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
675 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
676 LPWAVEFORMAT lpFormat;
678 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
679 if (lpDesc == NULL) {
680 WARN(wave, "Invalid Parameter !\n");
681 return MMSYSERR_INVALPARAM;
683 if (wDevID >= MAX_WAVEINDRV) {
684 TRACE(wave,"MAX_WAVINDRV reached !\n");
685 return MMSYSERR_ALLOCATED;
687 WInDev[wDevID].unixdev = 0;
688 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
689 audio = open (SOUND_DEV, O_RDONLY, 0);
690 if (audio == -1) {
691 WARN(wave,"can't open !\n");
692 return MMSYSERR_ALLOCATED;
694 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
695 if (abuf_size < 1024 || abuf_size > 65536) {
696 if (abuf_size == -1)
697 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
698 else
699 WARN(wave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
700 return MMSYSERR_NOTENABLED;
702 WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
703 switch(WInDev[wDevID].wFlags) {
704 case DCB_NULL:
705 TRACE(wave,"CALLBACK_NULL!\n");
706 break;
707 case DCB_WINDOW:
708 TRACE(wave,"CALLBACK_WINDOW!\n");
709 break;
710 case DCB_TASK:
711 TRACE(wave,"CALLBACK_TASK!\n");
712 break;
713 case DCB_FUNCTION:
714 TRACE(wave,"CALLBACK_FUNCTION!\n");
715 break;
717 if (WInDev[wDevID].lpQueueHdr) {
718 HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
719 WInDev[wDevID].lpQueueHdr = NULL;
721 WInDev[wDevID].unixdev = audio;
722 WInDev[wDevID].bufsize = abuf_size;
723 WInDev[wDevID].dwTotalRecorded = 0;
724 memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
725 lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat;
726 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
727 WARN(wave, "Bad format %04X !\n",
728 lpFormat->wFormatTag);
729 return WAVERR_BADFORMAT;
731 memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
732 WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
733 if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
734 if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
735 if (WInDev[wDevID].Format.wBitsPerSample == 0) {
736 WInDev[wDevID].Format.wBitsPerSample = 8 *
737 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
738 WInDev[wDevID].Format.wf.nSamplesPerSec) /
739 WInDev[wDevID].Format.wf.nChannels;
741 samplesize = WInDev[wDevID].Format.wBitsPerSample;
742 smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
743 dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
744 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
745 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
746 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
747 TRACE(wave,"wBitsPerSample=%u !\n", WInDev[wDevID].Format.wBitsPerSample);
748 TRACE(wave,"nSamplesPerSec=%lu !\n", WInDev[wDevID].Format.wf.nSamplesPerSec);
749 TRACE(wave,"nChannels=%u !\n", WInDev[wDevID].Format.wf.nChannels);
750 TRACE(wave,"nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec);
751 if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
752 WARN(wave,"can't notify client !\n");
753 return MMSYSERR_INVALPARAM;
755 return MMSYSERR_NOERROR;
758 /**************************************************************************
759 * widClose [internal]
761 static DWORD widClose(WORD wDevID)
763 TRACE(wave,"(%u);\n", wDevID);
764 if (wDevID > MAX_WAVEINDRV) return MMSYSERR_INVALPARAM;
765 if (WInDev[wDevID].unixdev == 0) {
766 WARN(wave,"can't close !\n");
767 return MMSYSERR_NOTENABLED;
769 if (WInDev[wDevID].lpQueueHdr != NULL) {
770 WARN(wave, "still buffers open !\n");
771 return WAVERR_STILLPLAYING;
773 close(WInDev[wDevID].unixdev);
774 WInDev[wDevID].unixdev = 0;
775 WInDev[wDevID].bufsize = 0;
776 if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
777 WARN(wave,"can't notify client !\n");
778 return MMSYSERR_INVALPARAM;
780 return MMSYSERR_NOERROR;
783 /**************************************************************************
784 * widAddBuffer [internal]
786 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
788 int count = 1;
789 LPWAVEHDR lpWIHdr;
791 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
792 if (WInDev[wDevID].unixdev == 0) {
793 WARN(wave,"can't do it !\n");
794 return MMSYSERR_NOTENABLED;
796 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
797 TRACE(wave, "never been prepared !\n");
798 return WAVERR_UNPREPARED;
800 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
801 TRACE(wave, "header already in use !\n");
802 return WAVERR_STILLPLAYING;
804 lpWaveHdr->dwFlags |= WHDR_PREPARED;
805 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
806 lpWaveHdr->dwFlags &= ~WHDR_DONE;
807 lpWaveHdr->dwBytesRecorded = 0;
808 if (WInDev[wDevID].lpQueueHdr == NULL) {
809 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
810 } else {
811 lpWIHdr = WInDev[wDevID].lpQueueHdr;
812 while (lpWIHdr->lpNext != NULL) {
813 lpWIHdr = lpWIHdr->lpNext;
814 count++;
816 lpWIHdr->lpNext = lpWaveHdr;
817 lpWaveHdr->lpNext = NULL;
818 count++;
820 TRACE(wave, "buffer added ! (now %u in queue)\n", count);
821 return MMSYSERR_NOERROR;
824 /**************************************************************************
825 * widPrepare [internal]
827 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
829 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
830 if (WInDev[wDevID].unixdev == 0) {
831 WARN(wave,"can't prepare !\n");
832 return MMSYSERR_NOTENABLED;
834 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
835 return WAVERR_STILLPLAYING;
836 lpWaveHdr->dwFlags |= WHDR_PREPARED;
837 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
838 lpWaveHdr->dwFlags &= ~WHDR_DONE;
839 lpWaveHdr->dwBytesRecorded = 0;
840 TRACE(wave,"header prepared !\n");
841 return MMSYSERR_NOERROR;
844 /**************************************************************************
845 * widUnprepare [internal]
847 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
849 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
850 if (WInDev[wDevID].unixdev == 0) {
851 WARN(wave,"can't unprepare !\n");
852 return MMSYSERR_NOTENABLED;
854 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
855 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
856 lpWaveHdr->dwFlags |= WHDR_DONE;
858 TRACE(wave, "all headers unprepared !\n");
859 return MMSYSERR_NOERROR;
862 /**************************************************************************
863 * widStart [internal]
865 static DWORD widStart(WORD wDevID)
867 int count = 1;
868 int bytesRead;
869 LPWAVEHDR lpWIHdr;
870 LPWAVEHDR *lpWaveHdr;
872 TRACE(wave,"(%u);\n", wDevID);
873 if (WInDev[wDevID].unixdev == 0) {
874 WARN(wave, "can't start recording !\n");
875 return MMSYSERR_NOTENABLED;
878 lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
879 TRACE(wave,"lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
880 if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
881 TRACE(wave,"never been prepared !\n");
882 return WAVERR_UNPREPARED;
885 while(*lpWaveHdr != NULL) {
886 lpWIHdr = *lpWaveHdr;
887 TRACE(wave, "recording buf#%u=%p size=%lu \n",
888 count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
889 fflush(stddeb);
890 bytesRead = read (WInDev[wDevID].unixdev,
891 lpWIHdr->lpData,
892 lpWIHdr->dwBufferLength);
893 if (bytesRead==-1)
894 perror("read from audio device");
895 TRACE(wave,"bytesread=%d (%ld)\n", bytesRead, lpWIHdr->dwBufferLength);
896 lpWIHdr->dwBytesRecorded = bytesRead;
897 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
898 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
899 lpWIHdr->dwFlags |= WHDR_DONE;
901 /* FIXME: should pass segmented pointer here, do we need that?*/
902 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
903 WARN(wave, "can't notify client !\n");
904 return MMSYSERR_INVALPARAM;
906 /* removes the current block from the queue */
907 *lpWaveHdr = lpWIHdr->lpNext;
908 count++;
910 TRACE(wave,"end of recording !\n");
911 fflush(stddeb);
912 return MMSYSERR_NOERROR;
915 /**************************************************************************
916 * widStop [internal]
918 static DWORD widStop(WORD wDevID)
920 TRACE(wave,"(%u);\n", wDevID);
921 if (WInDev[wDevID].unixdev == 0) {
922 WARN(wave,"can't stop !\n");
923 return MMSYSERR_NOTENABLED;
925 return MMSYSERR_NOERROR;
928 /**************************************************************************
929 * widReset [internal]
931 static DWORD widReset(WORD wDevID)
933 TRACE(wave,"(%u);\n", wDevID);
934 if (WInDev[wDevID].unixdev == 0) {
935 WARN(wave,"can't reset !\n");
936 return MMSYSERR_NOTENABLED;
938 return MMSYSERR_NOERROR;
941 /**************************************************************************
942 * widGetPosition [internal]
944 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
946 int time;
948 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpTime, uSize);
949 if (WInDev[wDevID].unixdev == 0) {
950 WARN(wave,"can't get pos !\n");
951 return MMSYSERR_NOTENABLED;
953 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
954 TRACE(wave,"wType=%04X !\n", lpTime->wType);
955 TRACE(wave,"wBitsPerSample=%u\n", WInDev[wDevID].Format.wBitsPerSample);
956 TRACE(wave,"nSamplesPerSec=%lu\n", WInDev[wDevID].Format.wf.nSamplesPerSec);
957 TRACE(wave,"nChannels=%u\n", WInDev[wDevID].Format.wf.nChannels);
958 TRACE(wave,"nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec);
959 fflush(stddeb);
960 switch(lpTime->wType) {
961 case TIME_BYTES:
962 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
963 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
964 break;
965 case TIME_SAMPLES:
966 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
967 WInDev[wDevID].Format.wBitsPerSample;
968 TRACE(wave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
969 break;
970 case TIME_SMPTE:
971 time = WInDev[wDevID].dwTotalRecorded /
972 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
973 lpTime->u.smpte.hour = time / 108000;
974 time -= lpTime->u.smpte.hour * 108000;
975 lpTime->u.smpte.min = time / 1800;
976 time -= lpTime->u.smpte.min * 1800;
977 lpTime->u.smpte.sec = time / 30;
978 time -= lpTime->u.smpte.sec * 30;
979 lpTime->u.smpte.frame = time;
980 lpTime->u.smpte.fps = 30;
981 TRACE(wave,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
982 lpTime->u.smpte.hour, lpTime->u.smpte.min,
983 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
984 break;
985 case TIME_MS:
986 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
987 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
988 TRACE(wave, "TIME_MS=%lu\n", lpTime->u.ms);
989 break;
990 default:
991 FIXME(wave, "format not supported ! use TIME_MS !\n");
992 lpTime->wType = TIME_MS;
994 return MMSYSERR_NOERROR;
997 /**************************************************************************
998 * widMessage [sample driver]
1000 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1001 DWORD dwParam1, DWORD dwParam2)
1003 int audio;
1004 TRACE(wave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1005 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1006 switch(wMsg) {
1007 case WIDM_OPEN:
1008 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1009 case WIDM_CLOSE:
1010 return widClose(wDevID);
1011 case WIDM_ADDBUFFER:
1012 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1013 case WIDM_PREPARE:
1014 return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1015 case WIDM_UNPREPARE:
1016 return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1017 case WIDM_GETDEVCAPS:
1018 return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1019 case WIDM_GETNUMDEVS:
1020 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1021 audio = open (SOUND_DEV, O_RDONLY, 0);
1022 if (audio == -1)
1024 if (errno == EBUSY)
1025 return 1;
1026 else
1027 return 0;
1029 close (audio);
1030 return 1;
1031 case WIDM_GETPOS:
1032 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1033 case WIDM_RESET:
1034 return widReset(wDevID);
1035 case WIDM_START:
1036 return widStart(wDevID);
1037 case WIDM_PAUSE:
1038 return widStop(wDevID);
1039 case WIDM_STOP:
1040 return widStop(wDevID);
1041 default:
1042 WARN(wave,"unknown message !\n");
1044 return MMSYSERR_NOTSUPPORTED;
1048 /**************************************************************************
1049 * WAVE_DriverProc16 [sample driver]
1051 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1052 DWORD dwParam1, DWORD dwParam2)
1054 TRACE(wave,"(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1056 switch(wMsg) {
1057 case DRV_LOAD: return 1;
1058 case DRV_FREE: return 1;
1059 case DRV_OPEN: return 1;
1060 case DRV_CLOSE: return 1;
1061 case DRV_ENABLE: return 1;
1062 case DRV_DISABLE: return 1;
1063 case DRV_QUERYCONFIGURE: return 1;
1064 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1065 case DRV_INSTALL: return DRVCNF_RESTART;
1066 case DRV_REMOVE: return DRVCNF_RESTART;
1067 default:
1068 FIXME(wave, "is probably wrong msg=0x%04x\n", wMsg);
1069 return DefDriverProc16(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1071 return MMSYSERR_NOTENABLED;
1074 /**************************************************************************
1075 * WAVE_DriverProc32 [sample driver]
1077 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1078 DWORD dwParam1, DWORD dwParam2)
1080 TRACE(wave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1081 switch(wMsg) {
1082 case DRV_LOAD: return 1;
1083 case DRV_FREE: return 1;
1084 case DRV_OPEN: return 1;
1085 case DRV_CLOSE: return 1;
1086 case DRV_ENABLE: return 1;
1087 case DRV_DISABLE: return 1;
1088 case DRV_QUERYCONFIGURE: return 1;
1089 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1090 case DRV_INSTALL: return DRVCNF_RESTART;
1091 case DRV_REMOVE: return DRVCNF_RESTART;
1092 default:
1093 FIXME(wave, "is probably wrong msg=0x%04lx\n", wMsg);
1094 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1096 return MMSYSERR_NOTENABLED;
1099 #else /* !HAVE_OSS */
1101 /**************************************************************************
1102 * wodMessage [sample driver]
1104 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1105 DWORD dwParam1, DWORD dwParam2)
1107 FIXME(wave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1108 return MMSYSERR_NOTENABLED;
1111 /**************************************************************************
1112 * widMessage [sample driver]
1114 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1115 DWORD dwParam1, DWORD dwParam2)
1117 FIXME(wave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1118 return MMSYSERR_NOTENABLED;
1121 /**************************************************************************
1122 * WAVE_DriverProc16 [sample driver]
1124 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1125 DWORD dwParam1, DWORD dwParam2)
1127 return MMSYSERR_NOTENABLED;
1130 /**************************************************************************
1131 * WAVE_DriverProc32 [sample driver]
1133 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1134 DWORD dwParam1, DWORD dwParam2)
1136 return MMSYSERR_NOTENABLED;
1138 #endif /* HAVE_OSS */