Added some error checking ; made use of new 16/32 MCI message
[wine] / multimedia / mcicda.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample MCI CDAUDIO Wine Driver for Linux
4  *
5  * Copyright 1994 Martin Ayotte
6  */
7
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include "windows.h"
15 #include "user.h"
16 #include "driver.h"
17 #include "mmsystem.h"
18 #include "debug.h"
19 #include "multimedia.h"
20
21 #ifdef HAVE_LINUX_CDROM_H
22 # include <linux/cdrom.h>
23 #endif
24 #ifdef HAVE_LINUX_UCDROM_H
25 # include <linux/ucdrom.h>
26 #endif
27 #ifdef HAVE_MACHINE_SOUNDCARD_H
28 # include <machine/soundcard.h>
29 #endif
30 #ifdef HAVE_SYS_CDIO_H
31 # include <sys/cdio.h>
32 #endif
33
34 #ifdef __FreeBSD__
35 # define CDAUDIO_DEV "/dev/rcd0c"
36 #else
37 # define CDAUDIO_DEV "/dev/cdrom"
38 #endif
39
40 #ifdef SOUND_VERSION
41 # define IOCTL(a,b,c)           ioctl(a,b,&c)
42 #else
43 # define IOCTL(a,b,c)           (c = ioctl(a,b,c) )
44 #endif
45
46 #define MAX_CDAUDIODRV          (1)
47 #define MAX_CDAUDIO_TRACKS      256
48
49 #define CDFRAMES_PERSEC         75
50 #define CDFRAMES_PERMIN         4500
51 #define SECONDS_PERMIN          60
52
53 #if defined(linux) || defined(__FreeBSD__)
54 typedef struct {
55     int                 nUseCount;          /* Incremented for each shared open */
56     BOOL16              fShareable;         /* TRUE if first open was shareable */
57     WORD                wNotifyDeviceID;    /* MCI device ID with a pending notification */
58     HANDLE16            hCallback;          /* Callback handle for pending notification */
59     MCI_OPEN_PARMS16    openParms;
60     DWORD               dwTimeFormat;
61     int                 unixdev;
62 #ifdef linux
63     struct cdrom_subchnl        sc;
64 #elif defined(__FreeBSD__)
65     struct cd_sub_channel_info  sc;
66 #endif
67     int                 cdMode;
68     int                 mciMode;
69     UINT16              nCurTrack;
70     DWORD               dwCurFrame;
71     UINT16              nTracks;
72     DWORD               dwTotalLen;
73     LPDWORD             lpdwTrackLen;
74     LPDWORD             lpdwTrackPos;
75     DWORD               dwFirstOffset;
76 } WINE_CDAUDIO;
77
78 static WINE_CDAUDIO     CDADev[MAX_CDAUDIODRV];
79 #endif
80
81 /*-----------------------------------------------------------------------*/
82
83 /**************************************************************************
84  *                              CDAUDIO_mciGetOpenDrv           [internal]      
85  */
86 static WINE_CDAUDIO*  CDAUDIO_mciGetOpenDrv(UINT16 wDevID)
87 {
88     if (wDevID >= MAX_CDAUDIODRV || CDADev[wDevID].nUseCount == 0 || 
89         CDADev[wDevID].unixdev == 0) {
90         WARN(cdaudio, "Invalid wDevID=%u\n", wDevID);
91         return 0;
92     }
93     return &CDADev[wDevID];
94 }
95
96 /**************************************************************************
97  *                              CDAUDIO_GetNumberOfTracks               [internal]
98  */
99 static UINT16 CDAUDIO_GetNumberOfTracks(WINE_CDAUDIO* wcda)
100 {
101 #if defined(linux) || defined(__FreeBSD__)
102 #ifdef linux
103     struct cdrom_tochdr hdr;
104 #elif defined(__FreeBSD__)
105     struct ioc_toc_header       hdr;
106 #endif
107     
108     if (wcda->nTracks == 0) {
109         if (ioctl(wcda->unixdev,
110 #ifdef linux
111                   CDROMREADTOCHDR
112 #elif defined(__FreeBSD__)
113                   CDIOREADTOCHEADER
114 #endif
115                   , &hdr)) {
116             WARN(cdaudio, "(%p) -- Error occured !\n", wcda);
117             return (WORD)-1;
118         }
119 #ifdef linux
120         wcda->nTracks = hdr.cdth_trk1;
121 #elif defined(__FreeBSD__)
122         wcda->nTracks = hdr.ending_track - hdr.starting_track + 1;
123 #endif
124     }
125     return wcda->nTracks;
126 #else
127     return (WORD)-1;
128 #endif
129 }
130
131
132 /**************************************************************************
133  *                              CDAUDIO_GetTracksInfo                   [internal]
134  */
135 static BOOL32 CDAUDIO_GetTracksInfo(WINE_CDAUDIO* wcda)
136 {
137 #if defined(linux) || defined(__FreeBSD__)
138     int         i, length;
139     int         start, last_start = 0;
140     int         total_length = 0;
141 #ifdef linux
142     struct cdrom_tocentry       entry;
143 #elif defined(__FreeBSD__)
144     struct ioc_read_toc_entry   entry;
145     struct cd_toc_entry             toc_buffer;
146 #endif
147     
148     if (wcda->nTracks == 0) {
149         if (CDAUDIO_GetNumberOfTracks(wcda) == (WORD)-1) return FALSE;
150     }
151     TRACE(cdaudio,"nTracks=%u\n", wcda->nTracks);
152
153     if (wcda->lpdwTrackLen != NULL) 
154         free(wcda->lpdwTrackLen);
155     wcda->lpdwTrackLen = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
156     if (wcda->lpdwTrackPos != NULL) 
157         free(wcda->lpdwTrackPos);
158     wcda->lpdwTrackPos = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
159     if (wcda->lpdwTrackLen == NULL || wcda->lpdwTrackPos == NULL) {
160         WARN(cdaudio, "error allocating track table !\n");
161         return FALSE;
162     }
163     memset(wcda->lpdwTrackLen, 0, (wcda->nTracks + 1) * sizeof(DWORD));
164     memset(wcda->lpdwTrackPos, 0, (wcda->nTracks + 1) * sizeof(DWORD));
165     for (i = 0; i <= wcda->nTracks; i++) {
166         if (i == wcda->nTracks)
167 #ifdef linux
168             entry.cdte_track = CDROM_LEADOUT;
169 #elif defined(__FreeBSD__)
170 #define LEADOUT 0xaa
171         entry.starting_track = LEADOUT; /* XXX */
172 #endif
173         else
174 #ifdef linux
175             entry.cdte_track = i + 1;
176 #elif defined(__FreeBSD__)
177         entry.starting_track = i + 1;
178 #endif
179 #ifdef linux
180         entry.cdte_format = CDROM_MSF;
181 #elif defined(__FreeBSD__)
182         bzero((char *)&toc_buffer, sizeof(toc_buffer));
183         entry.address_format = CD_MSF_FORMAT;
184         entry.data_len = sizeof(toc_buffer);
185         entry.data = &toc_buffer;
186 #endif
187         if (ioctl(wcda->unixdev, 
188 #ifdef linux
189                   CDROMREADTOCENTRY
190 #elif defined(__FreeBSD__)
191                   CDIOREADTOCENTRYS
192 #endif
193                   , &entry)) {
194             WARN(cdaudio, "error read entry\n");
195             return FALSE;
196         }
197 #ifdef linux
198         start = CDFRAMES_PERSEC * (SECONDS_PERMIN * 
199                                    entry.cdte_addr.msf.minute + entry.cdte_addr.msf.second) + 
200             entry.cdte_addr.msf.frame;
201 #elif defined(__FreeBSD__)
202         start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
203                                    toc_buffer.addr.msf.minute + toc_buffer.addr.msf.second) +
204             toc_buffer.addr.msf.frame;
205 #endif
206         if (i == 0) {
207             last_start = start;
208             wcda->dwFirstOffset = start;
209             TRACE(cdaudio, "dwFirstOffset=%u\n", start);
210         } else {
211             length = start - last_start;
212             last_start = start;
213             start = last_start - length;
214             total_length += length;
215             wcda->lpdwTrackLen[i - 1] = length;
216             wcda->lpdwTrackPos[i - 1] = start;
217             TRACE(cdaudio, "track #%u start=%u len=%u\n", i, start, length);
218         }
219     }
220     wcda->dwTotalLen = total_length;
221     TRACE(cdaudio,"total_len=%u\n", total_length);
222     return TRUE;
223 #else
224     return FALSE;
225 #endif
226 }
227
228 /**************************************************************************
229  *                              CDAUDIO_mciOpen                 [internal]
230  */
231 static DWORD CDAUDIO_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS32A lpOpenParms)
232 {
233 #if defined(linux) || defined(__FreeBSD__)
234     DWORD       dwDeviceID;
235     WINE_CDAUDIO*       wcda;
236
237     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
238     
239     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
240     if (wDevID > MAX_CDAUDIODRV)        return MCIERR_INVALID_DEVICE_ID;
241
242     dwDeviceID = lpOpenParms->wDeviceID;
243
244     wcda = &CDADev[wDevID];
245
246     if (wcda->nUseCount > 0) {
247         /* The driver already open on this channel */
248         /* If the driver was opened shareable before and this open specifies */
249         /* shareable then increment the use count */
250         if (wcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
251             ++wcda->nUseCount;
252         else
253             return MCIERR_MUST_USE_SHAREABLE;
254     } else {
255         wcda->nUseCount = 1;
256         wcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
257     }
258     if (dwFlags & MCI_OPEN_ELEMENT) {
259         TRACE(cdaudio,"MCI_OPEN_ELEMENT !\n");
260         /*              return MCIERR_NO_ELEMENT_ALLOWED; */
261     }
262
263     wcda->openParms.dwCallback = lpOpenParms->dwCallback;
264     wcda->openParms.wDeviceID  = (WORD)lpOpenParms->wDeviceID;
265     wcda->openParms.wReserved0 = 0; /*????*/
266     wcda->openParms.lpstrDeviceType = lpOpenParms->lpstrDeviceType;
267     wcda->openParms.lpstrElementName = lpOpenParms->lpstrElementName;
268     wcda->openParms.lpstrAlias = lpOpenParms->lpstrAlias;
269
270     wcda->wNotifyDeviceID = dwDeviceID;
271     wcda->unixdev = open (CDAUDIO_DEV, O_RDONLY, 0);
272     if (wcda->unixdev == -1) {
273         WARN(cdaudio,"can't open '%s'!.  errno=%d\n", CDAUDIO_DEV, errno );
274         perror( "can't open\n" );
275         return MCIERR_HARDWARE;
276     }
277     wcda->cdMode = 0;
278     wcda->mciMode = MCI_MODE_STOP;
279     wcda->dwTimeFormat = MCI_FORMAT_TMSF;
280     wcda->nCurTrack = 0;
281     wcda->nTracks = 0;
282     wcda->dwTotalLen = 0;
283     wcda->dwFirstOffset = 0;
284     wcda->lpdwTrackLen = NULL;
285     wcda->lpdwTrackPos = NULL;
286     if (!CDAUDIO_GetTracksInfo(&CDADev[wDevID])) {
287         WARN(cdaudio,"error reading TracksInfo !\n");
288         /*              return MCIERR_INTERNAL; */
289     }
290     
291     /*
292       Moved to mmsystem.c mciOpen routine
293       
294       if (dwFlags & MCI_NOTIFY) {
295       TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
296       lpParms->dwCallback);
297       mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
298       wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
299       }
300     */
301     return 0;
302 #else
303     return MCIERR_HARDWARE;
304 #endif
305 }
306
307 /**************************************************************************
308  *                              CDAUDIO_mciClose                [internal]
309  */
310 static DWORD CDAUDIO_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
311 {
312 #if defined(linux) || defined(__FreeBSD__)
313     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
314
315     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
316
317     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
318     
319     if (--wcda->nUseCount == 0) {
320         if (wcda->lpdwTrackLen != NULL) free(wcda->lpdwTrackLen);
321         if (wcda->lpdwTrackPos != NULL) free(wcda->lpdwTrackPos);
322         close(wcda->unixdev);
323     }
324 #endif
325     return 0;
326 }
327
328 /**************************************************************************
329  *                              CDAUDIO_mciGetDevCaps   [internal]
330  */
331 static DWORD CDAUDIO_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
332                                    LPMCI_GETDEVCAPS_PARMS lpParms)
333 {
334 #if defined(linux) || defined(__FreeBSD__)
335     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
336
337     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
338
339     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
340         TRACE(cdaudio, "MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
341
342         switch(lpParms->dwItem) {
343         case MCI_GETDEVCAPS_CAN_RECORD:
344             lpParms->dwReturn = FALSE;
345             break;
346         case MCI_GETDEVCAPS_HAS_AUDIO:
347             lpParms->dwReturn = TRUE;
348             break;
349         case MCI_GETDEVCAPS_HAS_VIDEO:
350             lpParms->dwReturn = FALSE;
351             break;
352         case MCI_GETDEVCAPS_DEVICE_TYPE:
353             lpParms->dwReturn = MCI_DEVTYPE_CD_AUDIO;
354             break;
355         case MCI_GETDEVCAPS_USES_FILES:
356             lpParms->dwReturn = FALSE;
357             break;
358         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
359             lpParms->dwReturn = FALSE;
360             break;
361         case MCI_GETDEVCAPS_CAN_EJECT:
362             lpParms->dwReturn = TRUE;
363             break;
364         case MCI_GETDEVCAPS_CAN_PLAY:
365             lpParms->dwReturn = TRUE;
366             break;
367         case MCI_GETDEVCAPS_CAN_SAVE:
368             lpParms->dwReturn = FALSE;
369             break;
370         default:
371             return MCIERR_UNRECOGNIZED_COMMAND;
372         }
373     }
374     TRACE(cdaudio, "lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
375     return 0;
376 #else
377     return MCIERR_INTERNAL;
378 #endif
379 }
380
381 /**************************************************************************
382  *                              CDAUDIO_mciInfo                 [internal]
383  */
384 static DWORD CDAUDIO_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
385 {
386 #if defined(linux) || defined(__FreeBSD__)
387     DWORD               ret = 0;
388     LPSTR               str = 0;
389     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
390
391     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
392
393     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
394         ret = MCIERR_NULL_PARAMETER_BLOCK;
395     } else if (wcda == NULL) {
396         ret = MCIERR_INVALID_DEVICE_ID;
397     } else {
398         TRACE(cdaudio, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
399
400     switch(dwFlags) {
401     case MCI_INFO_PRODUCT:
402             str = "Wine's audio CDROM";
403         break;
404     default:
405             WARN(cdaudio, "Don't know this info command (%lu)\n", dwFlags);
406             ret = MCIERR_UNRECOGNIZED_COMMAND;
407     }
408     }
409     if (str) {
410         ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
411     } else {
412         lpParms->lpstrReturn[0] = 0;
413     }
414
415     return ret;
416 #else
417     return MCIERR_INTERNAL;
418 #endif
419 }
420
421
422 /**************************************************************************
423  *                              CDAUDIO_CalcFrame                       [internal]
424  */
425 static DWORD CDAUDIO_CalcFrame(WINE_CDAUDIO* wcda, DWORD dwTime)
426 {
427     DWORD       dwFrame = 0;
428 #if defined(linux) || defined(__FreeBSD__)
429     UINT16      wTrack;
430     
431     TRACE(cdaudio,"(%p, %08lX, %lu);\n", wcda, wcda->dwTimeFormat, dwTime);
432     
433     switch (wcda->dwTimeFormat) {
434     case MCI_FORMAT_MILLISECONDS:
435         dwFrame = dwTime * CDFRAMES_PERSEC / 1000;
436         TRACE(cdaudio, "MILLISECONDS %lu\n", dwFrame);
437         break;
438     case MCI_FORMAT_MSF:
439         TRACE(cdaudio, "MSF %02u:%02u:%02u\n",
440               MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
441         dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
442         dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
443         dwFrame += MCI_MSF_FRAME(dwTime);
444         break;
445     case MCI_FORMAT_TMSF:
446     default:
447         /* unknown format ! force TMSF ! ... */
448         wTrack = MCI_TMSF_TRACK(dwTime);
449         TRACE(cdaudio, "MSF %02u-%02u:%02u:%02u\n",
450               MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime), 
451               MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
452         TRACE(cdaudio, "TMSF trackpos[%u]=%lu\n",
453               wTrack, wcda->lpdwTrackPos[wTrack - 1]);
454         dwFrame = wcda->lpdwTrackPos[wTrack - 1];
455         dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
456         dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
457         dwFrame += MCI_TMSF_FRAME(dwTime);
458         break;
459     }
460 #endif
461     return dwFrame;
462 }
463
464
465 /**************************************************************************
466  *                              CDAUDIO_GetCDStatus                             [internal]
467  */
468 static BOOL32 CDAUDIO_GetCDStatus(WINE_CDAUDIO* wcda)
469 {
470 #if defined(linux) || defined(__FreeBSD__)
471     int         oldmode = wcda->cdMode;
472 #ifdef __FreeBSD__
473     struct ioc_read_subchannel  read_sc;
474     
475     read_sc.address_format = CD_MSF_FORMAT;
476     read_sc.data_format    = CD_CURRENT_POSITION;
477     read_sc.track          = 0;
478     read_sc.data_len       = sizeof(wcda->sc);
479     read_sc.data           = (struct cd_sub_channel_info *)&wcda->sc;
480 #elif linux
481     wcda->sc.cdsc_format = CDROM_MSF;
482 #endif
483     if (ioctl(wcda->unixdev,
484 #ifdef linux
485               CDROMSUBCHNL, &wcda->sc
486 #elif defined(__FreeBSD__)
487               CDIOCREADSUBCHANNEL, &read_sc
488 #endif
489               )) {
490         TRACE(cdaudio,"opened or no_media !\n");
491         wcda->cdMode = MCI_MODE_OPEN; /* was NOT_READY */
492         return TRUE;
493     }
494     switch (
495 #ifdef linux
496             wcda->sc.cdsc_audiostatus
497 #elif defined(__FreeBSD__)
498             wcda->sc.header.audio_status
499 #endif
500             ) {
501 #ifdef linux
502     case CDROM_AUDIO_INVALID:
503 #elif defined(__FreeBSD__)
504     case CD_AS_AUDIO_INVALID:
505 #endif
506         WARN(cdaudio, "device doesn't support status, using MCI status.\n");
507         wcda->cdMode = 0;
508         break;
509 #ifdef linux
510     case CDROM_AUDIO_NO_STATUS: 
511 #elif defined(__FreeBSD__)
512     case CD_AS_NO_STATUS:
513 #endif
514         wcda->cdMode = MCI_MODE_STOP;
515         TRACE(cdaudio,"MCI_MODE_STOP !\n");
516         break;
517 #ifdef linux
518     case CDROM_AUDIO_PLAY: 
519 #elif defined(__FreeBSD__)
520     case CD_AS_PLAY_IN_PROGRESS:
521 #endif
522         wcda->cdMode = MCI_MODE_PLAY;
523         TRACE(cdaudio,"MCI_MODE_PLAY !\n");
524         break;
525 #ifdef linux
526     case CDROM_AUDIO_PAUSED:
527 #elif defined(__FreeBSD__)
528     case CD_AS_PLAY_PAUSED:
529 #endif
530         wcda->cdMode = MCI_MODE_PAUSE;
531         TRACE(cdaudio,"MCI_MODE_PAUSE !\n");
532         break;
533     default:
534 #ifdef linux
535         TRACE(cdaudio,"status=%02X !\n",
536               wcda->sc.cdsc_audiostatus);
537 #elif defined(__FreeBSD__)
538         TRACE(cdaudio,"status=%02X !\n",
539               wcda->sc.header.audio_status);
540 #endif
541     }
542 #ifdef linux
543     wcda->nCurTrack = wcda->sc.cdsc_trk;
544     wcda->dwCurFrame = 
545         CDFRAMES_PERMIN * wcda->sc.cdsc_absaddr.msf.minute +
546         CDFRAMES_PERSEC * wcda->sc.cdsc_absaddr.msf.second +
547         wcda->sc.cdsc_absaddr.msf.frame;
548 #elif defined(__FreeBSD__)
549     wcda->nCurTrack = wcda->sc.what.position.track_number;
550     wcda->dwCurFrame = 
551         CDFRAMES_PERMIN * wcda->sc.what.position.absaddr.msf.minute +
552         CDFRAMES_PERSEC * wcda->sc.what.position.absaddr.msf.second +
553         wcda->sc.what.position.absaddr.msf.frame;
554 #endif
555 #ifdef linux
556     TRACE(cdaudio,"%02u-%02u:%02u:%02u \n",
557           wcda->sc.cdsc_trk,
558           wcda->sc.cdsc_absaddr.msf.minute,
559           wcda->sc.cdsc_absaddr.msf.second,
560           wcda->sc.cdsc_absaddr.msf.frame);
561 #elif defined(__FreeBSD__)
562     TRACE(cdaudio,"%02u-%02u:%02u:%02u \n",
563           wcda->sc.what.position.track_number,
564           wcda->sc.what.position.absaddr.msf.minute,
565           wcda->sc.what.position.absaddr.msf.second,
566           wcda->sc.what.position.absaddr.msf.frame);
567 #endif
568     
569     if (oldmode != wcda->cdMode && oldmode == MCI_MODE_OPEN) {
570         if (!CDAUDIO_GetTracksInfo(wcda)) {
571             WARN(cdaudio, "error updating TracksInfo !\n");
572             return MCIERR_INTERNAL;
573         }
574     }
575     return TRUE;
576 #else
577     return FALSE;
578 #endif
579 }
580
581
582 /**************************************************************************
583  *                              CDAUDIO_CalcTime                        [internal]
584  */
585 static DWORD CDAUDIO_CalcTime(WINE_CDAUDIO* wcda, DWORD dwFrame)
586 {
587     DWORD       dwTime = 0;
588 #if defined(linux) || defined(__FreeBSD__)
589     UINT16      wTrack;
590     UINT16      wMinutes;
591     UINT16      wSeconds;
592     UINT16      wFrames;
593     
594     TRACE(cdaudio,"(%p, %08lX, %lu);\n", wcda, wcda->dwTimeFormat, dwFrame);
595     
596     switch (wcda->dwTimeFormat) {
597     case MCI_FORMAT_MILLISECONDS:
598         dwTime = dwFrame / CDFRAMES_PERSEC * 1000;
599         TRACE(cdaudio, "MILLISECONDS %lu\n", dwTime);
600         break;
601     case MCI_FORMAT_MSF:
602         wMinutes = dwFrame / CDFRAMES_PERMIN;
603         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
604         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
605         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
606         TRACE(cdaudio,"MSF %02u:%02u:%02u -> dwTime=%lu\n",wMinutes, wSeconds, wFrames, dwTime);
607         break;
608     case MCI_FORMAT_TMSF:
609     default:
610         /* unknown format ! force TMSF ! ... */
611         for (wTrack = 0; wTrack < wcda->nTracks; wTrack++) {
612             /*                          dwTime += wcda->lpdwTrackLen[wTrack - 1];
613                                         TRACE(cdaudio, "Adding trk#%u curpos=%u \n", dwTime);
614                                         if (dwTime >= dwFrame) break; */
615             if (wcda->lpdwTrackPos[wTrack - 1] >= dwFrame) break;
616         }
617         wMinutes = dwFrame / CDFRAMES_PERMIN;
618         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
619         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
620         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
621         TRACE(cdaudio, "%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
622         break;
623     }
624 #endif
625     return dwTime;
626 }
627
628
629 /**************************************************************************
630  *                              CDAUDIO_mciStatus               [internal]
631  */
632 static DWORD CDAUDIO_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
633 {
634 #if defined(linux) || defined(__FreeBSD__)
635     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
636     DWORD               ret = 0;
637
638     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
639
640     if (lpParms == NULL) {
641         ret = MCIERR_NULL_PARAMETER_BLOCK;
642     } else if (wcda == NULL) {
643         ret = MCIERR_INVALID_DEVICE_ID;
644     } else {
645     if (dwFlags & MCI_NOTIFY) {
646             TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
647             mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
648                               wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
649     }
650     if (dwFlags & MCI_STATUS_ITEM) {
651         switch(lpParms->dwItem) {
652         case MCI_STATUS_CURRENT_TRACK:
653                 if (!CDAUDIO_GetCDStatus(wcda)) return MCIERR_INTERNAL;
654                 lpParms->dwReturn = wcda->nCurTrack;
655             TRACE(cdaudio,"CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
656             return 0;
657         case MCI_STATUS_LENGTH:
658                 if (wcda->nTracks == 0) {
659                     if (!CDAUDIO_GetTracksInfo(wcda)) {
660                     WARN(cdaudio, "error reading TracksInfo !\n");
661                     return MCIERR_INTERNAL;
662                 }
663             }
664             if (dwFlags & MCI_TRACK) {
665                     TRACE(cdaudio,"MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
666                     if (lpParms->dwTrack > wcda->nTracks)
667                     return MCIERR_OUTOFRANGE;
668                     lpParms->dwReturn = wcda->lpdwTrackLen[lpParms->dwTrack];
669                 } else {
670                     lpParms->dwReturn = wcda->dwTotalLen;
671             }
672                 lpParms->dwReturn = CDAUDIO_CalcTime(wcda, lpParms->dwReturn);
673             TRACE(cdaudio,"LENGTH=%lu !\n", lpParms->dwReturn);
674             return 0;
675         case MCI_STATUS_MODE:
676                 if (!CDAUDIO_GetCDStatus(wcda)) return MCIERR_INTERNAL;
677                 lpParms->dwReturn = wcda->cdMode;
678                 if (!lpParms->dwReturn) lpParms->dwReturn = wcda->mciMode;
679                 TRACE(cdaudio,"MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
680             return 0;
681         case MCI_STATUS_MEDIA_PRESENT:
682                 if (!CDAUDIO_GetCDStatus(wcda)) return MCIERR_INTERNAL;
683                 lpParms->dwReturn = (wcda->nTracks > 0) ? TRUE : FALSE;
684                 TRACE(cdaudio,"MCI_STATUS_MEDIA_PRESENT =%s!\n", lpParms->dwReturn ? "Y" : "N");
685             return 0;
686         case MCI_STATUS_NUMBER_OF_TRACKS:
687                 lpParms->dwReturn = CDAUDIO_GetNumberOfTracks(wcda);
688                 TRACE(cdaudio,"MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
689             if (lpParms->dwReturn == (WORD)-1) return MCIERR_INTERNAL;
690             return 0;
691         case MCI_STATUS_POSITION:
692                 if (!CDAUDIO_GetCDStatus(wcda)) return MCIERR_INTERNAL;
693                 lpParms->dwReturn = wcda->dwCurFrame;
694             if (dwFlags & MCI_STATUS_START) {
695                     lpParms->dwReturn = wcda->dwFirstOffset;
696                 TRACE(cdaudio,"get MCI_STATUS_START !\n");
697             }
698             if (dwFlags & MCI_TRACK) {
699                     if (lpParms->dwTrack > wcda->nTracks)
700                     return MCIERR_OUTOFRANGE;
701                     lpParms->dwReturn = wcda->lpdwTrackPos[lpParms->dwTrack - 1];
702                 TRACE(cdaudio,"get MCI_TRACK #%lu !\n", lpParms->dwTrack);
703             }
704                 lpParms->dwReturn = CDAUDIO_CalcTime(wcda, lpParms->dwReturn);
705                 TRACE(cdaudio,"MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
706             return 0;
707         case MCI_STATUS_READY:
708             TRACE(cdaudio,"MCI_STATUS_READY !\n");
709             lpParms->dwReturn = TRUE;
710             return 0;
711         case MCI_STATUS_TIME_FORMAT:
712                 lpParms->dwReturn = wcda->dwTimeFormat;
713                 TRACE(cdaudio,"MCI_STATUS_TIME_FORMAT =%08lx!\n", lpParms->dwReturn);
714                 return 0;
715                 /* FIXME: the constant used here are not defined in mmsystem.h */
716                 /* MCI_CDA_STATUS_TYPE_TRACK is very likely to be 0x00004001 */
717             case MCI_CDA_STATUS_TYPE_TRACK:
718                 if (!(dwFlags & MCI_TRACK)) return MCIERR_MISSING_PARAMETER;
719                 lpParms->dwReturn = 0xFFFFFFFF; /* FIXME: MCI_CDA_TRACK_AUDIO ou MCI_CDA_TRACK_OTHER */
720                 TRACE(cdaudio, "MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
721             return 0;
722         default:
723             WARN(cdaudio, "unknown command %08lX !\n", lpParms->dwItem);
724             return MCIERR_UNRECOGNIZED_COMMAND;
725         }
726     }
727     }
728     WARN(cdaudio, "not MCI_STATUS_ITEM !\n");
729     return 0;
730 #else
731     return MMSYSERR_NOTENABLED;
732 #endif
733 }
734
735
736 /**************************************************************************
737  *                              CDAUDIO_mciPlay                 [internal]
738  */
739 static DWORD CDAUDIO_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
740 {
741 #if defined(linux) || defined(__FreeBSD__)
742     int         start, end;
743     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
744     DWORD               ret = 0;
745 #ifdef linux
746     struct      cdrom_msf       msf;
747 #elif defined(__FreeBSD__)
748     struct      ioc_play_msf    msf;
749 #endif
750     
751     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
752     
753     if (lpParms == NULL) {
754         ret = MCIERR_NULL_PARAMETER_BLOCK;
755     } else if (wcda == NULL) {
756         ret = MCIERR_INVALID_DEVICE_ID;
757     } else {
758         start = 0;              
759         end = wcda->dwTotalLen;
760         wcda->nCurTrack = 1;
761     if (dwFlags & MCI_FROM) {
762             start = CDAUDIO_CalcFrame(wcda, lpParms->dwFrom); 
763             TRACE(cdaudio,"MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
764     }
765     if (dwFlags & MCI_TO) {
766             end = CDAUDIO_CalcFrame(wcda, lpParms->dwTo);
767             TRACE(cdaudio, "MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
768     }
769         start += wcda->dwFirstOffset;   
770         end += wcda->dwFirstOffset;
771 #ifdef linux
772     msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
773     msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
774     msf.cdmsf_frame0 = start % CDFRAMES_PERSEC;
775     msf.cdmsf_min1 = end / CDFRAMES_PERMIN;
776     msf.cdmsf_sec1 = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
777     msf.cdmsf_frame1 = end % CDFRAMES_PERSEC;
778 #elif defined(__FreeBSD__)
779     msf.start_m     = start / CDFRAMES_PERMIN;
780     msf.start_s     = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
781     msf.start_f     = start % CDFRAMES_PERSEC;
782     msf.end_m       = end / CDFRAMES_PERMIN;
783     msf.end_s       = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
784     msf.end_f       = end % CDFRAMES_PERSEC;
785 #endif
786         if (ioctl(wcda->unixdev,
787 #ifdef linux
788               CDROMSTART
789 #elif defined(__FreeBSD__)
790               CDIOCSTART
791 #endif
792               )) {
793         WARN(cdaudio, "motor doesn't start !\n");
794         return MCIERR_HARDWARE;
795     }
796         if (ioctl(wcda->unixdev, 
797 #ifdef linux
798               CDROMPLAYMSF
799 #elif defined(__FreeBSD__)
800               CDIOCPLAYMSF
801 #endif
802               , &msf)) {
803         WARN(cdaudio, "device doesn't play !\n");
804         return MCIERR_HARDWARE;
805     }
806 #ifdef linux
807     TRACE(cdaudio,"msf = %d:%d:%d %d:%d:%d\n",
808           msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
809           msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
810 #elif defined(__FreeBSD__)
811     TRACE(cdaudio,"msf = %d:%d:%d %d:%d:%d\n",
812           msf.start_m, msf.start_s, msf.start_f,
813           msf.end_m,   msf.end_s,   msf.end_f);
814 #endif
815         wcda->mciMode = MCI_MODE_PLAY;
816     if (dwFlags & MCI_NOTIFY) {
817             TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
818         /*
819           mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
820               wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
821         */
822     }
823     }
824     return ret;
825
826 #else
827     return MCIERR_HARDWARE;
828 #endif
829 }
830
831 /**************************************************************************
832  *                              CDAUDIO_mciStop                 [internal]
833  */
834 static DWORD CDAUDIO_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
835 {
836 #if defined(linux) || defined(__FreeBSD__)
837     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
838
839     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
840
841     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
842     
843     if (ioctl(wcda->unixdev,
844 #ifdef linux
845               CDROMSTOP
846 #elif defined(__FreeBSD__)
847               CDIOCSTOP
848 #endif
849               )) return MCIERR_HARDWARE;
850     wcda->mciMode = MCI_MODE_STOP;
851     if (lpParms && (dwFlags & MCI_NOTIFY)) {
852         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
853         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
854                           wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
855     }
856     return 0;
857 #else
858     return MCIERR_HARDWARE;
859 #endif
860 }
861
862 /**************************************************************************
863  *                              CDAUDIO_mciPause                [internal]
864  */
865 static DWORD CDAUDIO_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
866 {
867 #if defined(linux) || defined(__FreeBSD__)
868     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
869
870     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
871
872     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
873
874     if (ioctl(wcda->unixdev,
875 #ifdef linux
876               CDROMPAUSE
877 #elif defined(__FreeBSD__)
878               CDIOCPAUSE
879 #endif
880               )) return MCIERR_HARDWARE;
881     wcda->mciMode = MCI_MODE_PAUSE;
882     if (lpParms && (dwFlags & MCI_NOTIFY)) {
883         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
884         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
885                           wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
886     }
887     return 0;
888 #else
889     return MCIERR_HARDWARE;
890 #endif
891 }
892
893 /**************************************************************************
894  *                              CDAUDIO_mciResume               [internal]
895  */
896 static DWORD CDAUDIO_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
897 {
898 #if defined(linux) || defined(__FreeBSD__)
899     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
900
901     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
902
903     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
904     
905     if (ioctl(wcda->unixdev, 
906 #ifdef linux
907               CDROMRESUME
908 #elif defined(__FreeBSD__)
909               CDIOCRESUME
910 #endif
911               )) return MCIERR_HARDWARE;
912     wcda->mciMode = MCI_MODE_STOP;
913     if (lpParms && (dwFlags & MCI_NOTIFY)) {
914         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
915         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
916                           wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
917     }
918     return 0;
919 #else
920     return MCIERR_HARDWARE;
921 #endif
922 }
923
924 /**************************************************************************
925  *                              CDAUDIO_mciSeek                 [internal]
926  */
927 static DWORD CDAUDIO_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
928 {
929 #if defined(linux) || defined(__FreeBSD__)
930     DWORD       dwRet;
931     MCI_PLAY_PARMS PlayParms;
932     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
933
934     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
935
936     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
937     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
938     
939     if (ioctl(wcda->unixdev,
940 #ifdef linux
941               CDROMRESUME
942 #elif defined(__FreeBSD__)
943               CDIOCRESUME
944 #endif
945               )) {
946         perror("ioctl CDROMRESUME");
947         return MCIERR_HARDWARE;
948     }
949     wcda->mciMode = MCI_MODE_SEEK;
950     switch(dwFlags) {
951     case MCI_SEEK_TO_START:
952         PlayParms.dwFrom = 0;
953         break;
954     case MCI_SEEK_TO_END:
955         PlayParms.dwFrom = wcda->dwTotalLen;
956         break;
957     case MCI_TO:
958         PlayParms.dwFrom = lpParms->dwTo;
959         break;
960     }
961     dwRet = CDAUDIO_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &PlayParms);
962     if (dwRet != 0) return dwRet;
963     dwRet = CDAUDIO_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&PlayParms);
964     if (dwFlags & MCI_NOTIFY) {
965         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
966         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
967                           wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
968     }
969     return dwRet;
970 #else
971     return MCIERR_HARDWARE;
972 #endif
973 }
974
975 /**************************************************************************
976  *                              CDAUDIO_mciSetDoor              [internal]
977  */
978 static DWORD    CDAUDIO_mciSetDoor(UINT16 wDevID, int open)
979 {
980     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
981
982     TRACE(cdaudio, "(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
983
984     if (wcda == NULL) return MCIERR_INVALID_DEVICE_ID;
985
986 #ifdef __FreeBSD__
987     if (ioctl(wcda->unixdev, CDIOCALLOW)) return MCIERR_HARDWARE;
988     if (open) {
989         if (ioctl(wcda->unixdev, CDIOCEJECT)) return MCIERR_HARDWARE;
990         wcda->mciMode = MCI_MODE_OPEN;
991     } else {
992         if (ioctl(wcda->unixdev, CDIOCCLOSE)) return MCIERR_HARDWARE;
993         wcda->mciMode = MCI_MODE_STOP;
994     }
995     if (ioctl(wcda->unixdev, CDIOCPREVENT)) return MCIERR_HARDWARE;
996 #elif linux
997     if (open) {
998         if (ioctl(wcda->unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
999         wcda->mciMode = MCI_MODE_OPEN;
1000     } else {
1001         if (ioctl(wcda->unixdev, CDROMEJECT, 1)) return MCIERR_HARDWARE;
1002         wcda->mciMode = MCI_MODE_STOP;
1003     }
1004 #endif
1005     wcda->nTracks = 0;
1006     return 0;
1007 }
1008
1009 /**************************************************************************
1010  *                              CDAUDIO_mciSet                  [internal]
1011  */
1012 static DWORD CDAUDIO_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1013 {
1014 #if defined(linux) || defined(__FreeBSD__)
1015     WINE_CDAUDIO*       wcda = CDAUDIO_mciGetOpenDrv(wDevID);
1016     
1017     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1018     
1019     if (wcda == NULL)   return MCIERR_INVALID_DEVICE_ID;
1020     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;;
1021     /*
1022       TRACE(cdaudio,"dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
1023       TRACE(cdaudio,"dwAudio=%08lX\n", lpParms->dwAudio);
1024     */
1025     if (dwFlags & MCI_SET_TIME_FORMAT) {
1026         switch (lpParms->dwTimeFormat) {
1027         case MCI_FORMAT_MILLISECONDS:
1028             TRACE(cdaudio, "MCI_FORMAT_MILLISECONDS !\n");
1029             break;
1030         case MCI_FORMAT_MSF:
1031             TRACE(cdaudio,"MCI_FORMAT_MSF !\n");
1032             break;
1033         case MCI_FORMAT_TMSF:
1034             TRACE(cdaudio,"MCI_FORMAT_TMSF !\n");
1035             break;
1036         default:
1037             WARN(cdaudio, "bad time format !\n");
1038             return MCIERR_BAD_TIME_FORMAT;
1039         }
1040         wcda->dwTimeFormat = lpParms->dwTimeFormat;
1041     }
1042     if (dwFlags & MCI_SET_DOOR_OPEN) {
1043         CDAUDIO_mciSetDoor(wDevID, TRUE);
1044     }
1045     if (dwFlags & MCI_SET_DOOR_CLOSED) {
1046         CDAUDIO_mciSetDoor(wDevID, TRUE);
1047     }
1048     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
1049     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
1050     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
1051     if (dwFlags & MCI_NOTIFY) {
1052         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
1053               lpParms->dwCallback);
1054         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
1055                           wcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
1056     }
1057     return 0;
1058 #else
1059     return MCIERR_HARDWARE;
1060 #endif
1061 }
1062
1063 /**************************************************************************
1064  *                      MCICDAUDIO_DriverProc32         [sample driver]
1065  */
1066 LONG MCICDAUDIO_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
1067                           DWORD dwParam1, DWORD dwParam2)
1068 {
1069 #if defined(linux) || defined(__FreeBSD__)
1070     switch(wMsg) {
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;
1081
1082     case MCI_OPEN_DRIVER:       return CDAUDIO_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS32A)dwParam2); 
1083     case MCI_CLOSE_DRIVER:      return CDAUDIO_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1084     case MCI_GETDEVCAPS:        return CDAUDIO_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1085     case MCI_INFO:              return CDAUDIO_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
1086     case MCI_STATUS:            return CDAUDIO_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
1087     case MCI_SET:               return CDAUDIO_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
1088     case MCI_PLAY:              return CDAUDIO_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
1089     case MCI_STOP:              return CDAUDIO_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1090     case MCI_PAUSE:             return CDAUDIO_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1091     case MCI_RESUME:            return CDAUDIO_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1092     case MCI_SEEK:              return CDAUDIO_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
1093         /* FIXME: I wonder if those two next items are really called ? */
1094     case MCI_SET_DOOR_OPEN:     return CDAUDIO_mciSetDoor(dwDevID, TRUE);
1095     case MCI_SET_DOOR_CLOSED:   return CDAUDIO_mciSetDoor(dwDevID, FALSE);
1096     case MCI_LOAD:              
1097     case MCI_SAVE:              
1098     case MCI_FREEZE:            
1099     case MCI_PUT:               
1100     case MCI_REALIZE:           
1101     case MCI_UNFREEZE:          
1102     case MCI_UPDATE:            
1103     case MCI_WHERE:             
1104     case MCI_WINDOW:            
1105     case MCI_STEP:              
1106     case MCI_SPIN:              
1107     case MCI_ESCAPE:            
1108     case MCI_COPY:              
1109     case MCI_CUT:               
1110     case MCI_DELETE:            
1111     case MCI_PASTE:             
1112         WARN(cdaudio, "Unsupported command=%s\n", MCI_CommandToString(wMsg));
1113         break;
1114     case MCI_OPEN:
1115     case MCI_CLOSE:
1116         FIXME(cdaudio, "Shouldn't receive a MCI_OPEN or CLOSE message\n");
1117         break;
1118     default:
1119         TRACE(cdaudio, "Sending msg=%s to default driver proc\n", MCI_CommandToString(wMsg));
1120         return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1121     }
1122     return MCIERR_UNRECOGNIZED_COMMAND;
1123 #else
1124     return MCIERR_HARDWARE;
1125 #endif
1126 }
1127
1128 /*-----------------------------------------------------------------------*/