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