Removed a few dependencies on kernel32 functions.
[wine] / dlls / winmm / mcicda / mcicda.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * MCI driver for audio CD (MCICDA)
4  *
5  * Copyright 1994    Martin Ayotte
6  * Copyright 1998-99 Eric Pouech
7  * Copyright 2000    Andreas Mohr
8  */
9
10 #include "config.h"
11 #include <stdio.h>
12 #include "windef.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "mmddk.h"
16 #include "cdrom.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(mcicda);
20
21 typedef struct {
22     UINT                wDevID;
23     int                 nUseCount;          /* Incremented for each shared open */
24     BOOL                fShareable;         /* TRUE if first open was shareable */
25     WORD                wNotifyDeviceID;    /* MCI device ID with a pending notification */
26     HANDLE              hCallback;          /* Callback handle for pending notification */
27     DWORD               dwTimeFormat;
28     WINE_CDAUDIO        wcda;
29     int                 mciMode;
30 } WINE_MCICDAUDIO;
31
32 /*-----------------------------------------------------------------------*/
33
34 /**************************************************************************
35  *                              MCICDA_drvOpen                  [internal]      
36  */
37 static  DWORD   MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
38 {
39     WINE_MCICDAUDIO*    wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  sizeof(WINE_MCICDAUDIO));
40
41     if (!wmcda)
42         return 0;
43
44     wmcda->wDevID = modp->wDeviceID;
45     mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
46     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
47     modp->wType = MCI_DEVTYPE_CD_AUDIO;
48     return modp->wDeviceID;
49 }
50
51 /**************************************************************************
52  *                              MCICDA_drvClose                 [internal]      
53  */
54 static  DWORD   MCICDA_drvClose(DWORD dwDevID)
55 {
56     WINE_MCICDAUDIO*  wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
57
58     if (wmcda) {
59         HeapFree(GetProcessHeap(), 0, wmcda);
60         mciSetDriverData(dwDevID, 0);
61     }
62     return 0;
63 }
64
65 /**************************************************************************
66  *                              MCICDA_GetOpenDrv               [internal]      
67  */
68 static WINE_MCICDAUDIO*  MCICDA_GetOpenDrv(UINT wDevID)
69 {
70     WINE_MCICDAUDIO*    wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
71     
72     if (wmcda == NULL || wmcda->nUseCount == 0 || wmcda->wcda.unixdev <= 0) {
73         WARN("Invalid wDevID=%u\n", wDevID);
74         return 0;
75     }
76     return wmcda;
77 }
78
79 /**************************************************************************
80  *                              MCICDA_Mode                     [internal]
81  */
82 static  int     MCICDA_Mode(int wcdaMode)
83 {
84     switch (wcdaMode) {
85     case WINE_CDA_DONTKNOW:     return MCI_MODE_STOP;
86     case WINE_CDA_NOTREADY:     return MCI_MODE_STOP;
87     case WINE_CDA_OPEN:         return MCI_MODE_OPEN;
88     case WINE_CDA_PLAY:         return MCI_MODE_PLAY;
89     case WINE_CDA_STOP:         return MCI_MODE_STOP;
90     case WINE_CDA_PAUSE:        return MCI_MODE_PAUSE;
91     default:
92         FIXME("Unknown mode %04x\n", wcdaMode);
93     }
94     return MCI_MODE_STOP;
95 }
96
97 /**************************************************************************
98  *                              MCICDA_GetError                 [internal]
99  */
100 static  int     MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
101 {
102     switch (wmcda->wcda.cdaMode) {
103     case WINE_CDA_DONTKNOW:
104     case WINE_CDA_NOTREADY:     return MCIERR_DEVICE_NOT_READY;
105     case WINE_CDA_OPEN:         return MCIERR_DEVICE_OPEN;
106     case WINE_CDA_PLAY:         
107     case WINE_CDA_STOP:         
108     case WINE_CDA_PAUSE:        break;
109     default:
110         FIXME("Unknown mode %04x\n", wmcda->wcda.cdaMode);
111     }
112     return MCIERR_DRIVER_INTERNAL;
113 }
114
115 /**************************************************************************
116  *                      MCICDA_CalcFrame                        [internal]
117  */
118 static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
119 {
120     DWORD       dwFrame = 0;
121     UINT        wTrack;
122     
123     TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
124     
125     switch (wmcda->dwTimeFormat) {
126     case MCI_FORMAT_MILLISECONDS:
127         dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
128         TRACE("MILLISECONDS %lu\n", dwFrame);
129         break;
130     case MCI_FORMAT_MSF:
131         TRACE("MSF %02u:%02u:%02u\n",
132               MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
133         dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
134         dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
135         dwFrame += MCI_MSF_FRAME(dwTime);
136         break;
137     case MCI_FORMAT_TMSF:
138     default: /* unknown format ! force TMSF ! ... */
139         wTrack = MCI_TMSF_TRACK(dwTime);
140         TRACE("MSF %02u-%02u:%02u:%02u\n",
141               MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime), 
142               MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
143         TRACE("TMSF trackpos[%u]=%lu\n",
144               wTrack, wmcda->wcda.lpdwTrackPos[wTrack - 1]);
145         dwFrame = wmcda->wcda.lpdwTrackPos[wTrack - 1];
146         dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
147         dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
148         dwFrame += MCI_TMSF_FRAME(dwTime);
149         break;
150     }
151     return dwFrame;
152 }
153
154 /**************************************************************************
155  *                      MCICDA_CalcTime                         [internal]
156  */
157 static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, 
158                               LPDWORD lpRet)
159 {
160     DWORD       dwTime = 0;
161     UINT        wTrack;
162     UINT        wMinutes;
163     UINT        wSeconds;
164     UINT        wFrames;
165     
166     TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);
167     
168     switch (tf) {
169     case MCI_FORMAT_MILLISECONDS:
170         dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
171         TRACE("MILLISECONDS %lu\n", dwTime);
172         *lpRet = 0;
173         break;
174     case MCI_FORMAT_MSF:
175         wMinutes = dwFrame / CDFRAMES_PERMIN;
176         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
177         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
178         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
179         TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
180               wMinutes, wSeconds, wFrames, dwTime);
181         *lpRet = MCI_COLONIZED3_RETURN;
182         break;
183     case MCI_FORMAT_TMSF:
184     default:    /* unknown format ! force TMSF ! ... */
185         if (dwFrame < wmcda->wcda.dwFirstFrame || dwFrame > wmcda->wcda.dwLastFrame) {
186             ERR("Out of range value %lu [%lu,%lu]\n", 
187                 dwFrame, wmcda->wcda.dwFirstFrame, wmcda->wcda.dwLastFrame);
188             *lpRet = 0;
189             return 0;
190         }
191         for (wTrack = 1; wTrack < wmcda->wcda.nTracks; wTrack++) {
192             if (wmcda->wcda.lpdwTrackPos[wTrack] > dwFrame)
193                 break;
194         }
195         dwFrame -= wmcda->wcda.lpdwTrackPos[wTrack - 1];
196         wMinutes = dwFrame / CDFRAMES_PERMIN;
197         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
198         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
199         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
200         TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
201         *lpRet = MCI_COLONIZED4_RETURN;
202         break;
203     }
204     return dwTime;
205 }
206
207 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
208 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
209
210 /**************************************************************************
211  *                              MCICDA_Open                     [internal]
212  */
213 static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
214 {
215     DWORD               dwDeviceID;
216     WINE_MCICDAUDIO*    wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
217     MCI_SEEK_PARMS      seekParms;
218
219     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
220     
221     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
222     if (wmcda == NULL)                  return MCIERR_INVALID_DEVICE_ID;
223
224     dwDeviceID = lpOpenParms->wDeviceID;
225
226     if (wmcda->nUseCount > 0) {
227         /* The driver is already open on this channel */
228         /* If the driver was opened shareable before and this open specifies */
229         /* shareable then increment the use count */
230         if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
231             ++wmcda->nUseCount;
232         else
233             return MCIERR_MUST_USE_SHAREABLE;
234     } else {
235         wmcda->nUseCount = 1;
236         wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
237     }
238     if (dwFlags & MCI_OPEN_ELEMENT) {
239         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
240             WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort", (DWORD)lpOpenParms->lpstrElementName);
241             return MCIERR_NO_ELEMENT_ALLOWED;
242         }
243         WARN("MCI_OPEN_ELEMENT %s ignored\n",lpOpenParms->lpstrElementName);
244         /*return MCIERR_NO_ELEMENT_ALLOWED; 
245           bon 19991106 allows cdplayer.exe to run*/
246     }
247
248     wmcda->wNotifyDeviceID = dwDeviceID;
249     if (CDROM_Open(&wmcda->wcda, -1) == -1) {
250         --wmcda->nUseCount;
251         return MCIERR_HARDWARE;
252     }
253     wmcda->mciMode = MCI_MODE_STOP;
254     wmcda->dwTimeFormat = MCI_FORMAT_MSF;
255     if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda)) {
256         WARN("error reading TracksInfo !\n");
257         return MCIERR_INTERNAL;
258     }
259     
260     MCICDA_Seek(wDevID, MCI_SEEK_TO_START, &seekParms);
261
262     return 0;
263 }
264
265 /**************************************************************************
266  *                              MCICDA_Close                    [internal]
267  */
268 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
269 {
270     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
271
272     TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
273
274     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
275     
276     if (wmcda->nUseCount == 1) {
277         CDROM_Close(&wmcda->wcda);
278     }
279     wmcda->nUseCount--;
280     return 0;
281 }
282
283 /**************************************************************************
284  *                              MCICDA_GetDevCaps               [internal]
285  */
286 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags, 
287                                    LPMCI_GETDEVCAPS_PARMS lpParms)
288 {
289     DWORD       ret = 0;
290
291     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
292
293     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
294
295     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
296         TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
297
298         switch (lpParms->dwItem) {
299         case MCI_GETDEVCAPS_CAN_RECORD:
300             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
301             ret = MCI_RESOURCE_RETURNED;
302             break;
303         case MCI_GETDEVCAPS_HAS_AUDIO:
304             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
305             ret = MCI_RESOURCE_RETURNED;
306             break;
307         case MCI_GETDEVCAPS_HAS_VIDEO:
308             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
309             ret = MCI_RESOURCE_RETURNED;
310             break;
311         case MCI_GETDEVCAPS_DEVICE_TYPE:
312             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
313             ret = MCI_RESOURCE_RETURNED;
314             break;
315         case MCI_GETDEVCAPS_USES_FILES:
316             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
317             ret = MCI_RESOURCE_RETURNED;
318             break;
319         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
320             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
321             ret = MCI_RESOURCE_RETURNED;
322             break;
323         case MCI_GETDEVCAPS_CAN_EJECT:
324             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
325             ret = MCI_RESOURCE_RETURNED;
326             break;
327         case MCI_GETDEVCAPS_CAN_PLAY:
328             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
329             ret = MCI_RESOURCE_RETURNED;
330             break;
331         case MCI_GETDEVCAPS_CAN_SAVE:
332             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
333             ret = MCI_RESOURCE_RETURNED;
334             break;
335         default:
336             ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
337             return MCIERR_UNRECOGNIZED_COMMAND;
338         }
339     } else {
340         TRACE("No GetDevCaps-Item !\n");
341         return MCIERR_UNRECOGNIZED_COMMAND;
342     }
343     TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
344     return ret;
345 }
346
347 /**************************************************************************
348  *                              MCICDA_Info                     [internal]
349  */
350 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
351 {
352     LPSTR               str = NULL;
353     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
354     DWORD               ret = 0;
355     char                buffer[16];
356
357     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
358     
359     if (lpParms == NULL || lpParms->lpstrReturn == NULL)
360         return MCIERR_NULL_PARAMETER_BLOCK;
361     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
362
363     TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
364     
365     if (dwFlags & MCI_INFO_PRODUCT) {
366         str = "Wine's audio CD";
367     } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
368         ret = MCIERR_NO_IDENTITY;
369     } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
370         DWORD   res = 0;
371
372         if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) {
373             return MCICDA_GetError(wmcda);
374         }
375
376         res = CDROM_Audio_GetSerial(&wmcda->wcda);
377         if (wmcda->wcda.nTracks <= 2) {
378             /* there are some other values added when # of tracks < 3
379              * for most Audio CD it will do without
380              */
381             FIXME("Value is not correct !! "
382                   "Please report with full audio CD information (-debugmsg +cdrom,mcicda)\n");
383         }
384         sprintf(buffer, "%lu", res);
385         str = buffer;
386     } else {
387         WARN("Don't know this info command (%lu)\n", dwFlags);
388         ret = MCIERR_UNRECOGNIZED_COMMAND;
389     }
390     if (str) {
391         if (lpParms->dwRetSize <= strlen(str)) {
392             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
393             ret = MCIERR_PARAM_OVERFLOW;
394         } else {
395             strcpy(lpParms->lpstrReturn, str);
396         }       
397     } else {
398         *lpParms->lpstrReturn = 0;
399     }
400     TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
401     return ret;
402 }
403
404 /**************************************************************************
405  *                              MCICDA_Status                   [internal]
406  */
407 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
408 {
409     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
410     DWORD               ret = 0;
411
412     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
413     
414     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
415     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
416
417     if (dwFlags & MCI_NOTIFY) {
418         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
419         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
420                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
421     }
422     if (dwFlags & MCI_STATUS_ITEM) {
423         switch (lpParms->dwItem) {
424         case MCI_STATUS_CURRENT_TRACK:
425             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) {
426                 return MCICDA_GetError(wmcda);
427             }
428             lpParms->dwReturn = wmcda->wcda.nCurTrack;
429             TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
430             break;
431         case MCI_STATUS_LENGTH:
432             if (wmcda->wcda.nTracks == 0) {
433                 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda)) {
434                     WARN("error reading TracksInfo !\n");
435                     return MCICDA_GetError(wmcda);
436                 }
437             }
438             if (dwFlags & MCI_TRACK) {
439                 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
440                 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
441                     return MCIERR_OUTOFRANGE;
442                 lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
443                 /* Windows returns one frame less than the total track length for the
444                    last track on the CD.  See CDDB HOWTO.  Verified on Win95OSR2. */
445                 if (lpParms->dwTrack == wmcda->wcda.nTracks)
446                     lpParms->dwReturn--;
447             } else {
448                 /* Sum of the lengths of all of the tracks.  Inherits the
449                    'off by one frame' behavior from the length of the last track.
450                    See above comment. */
451                 lpParms->dwReturn = wmcda->wcda.dwLastFrame - wmcda->wcda.dwFirstFrame - 1;
452             }
453             lpParms->dwReturn = MCICDA_CalcTime(wmcda, 
454                                                  (wmcda->dwTimeFormat == MCI_FORMAT_TMSF) 
455                                                     ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
456                                                  lpParms->dwReturn,
457                                                  &ret);
458             TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
459             break;
460         case MCI_STATUS_MODE:
461             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) 
462                 return MCICDA_GetError(wmcda);
463             lpParms->dwReturn = MCICDA_Mode(wmcda->wcda.cdaMode);
464             if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
465             TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
466             lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
467             ret = MCI_RESOURCE_RETURNED;
468             break;
469         case MCI_STATUS_MEDIA_PRESENT:
470             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) 
471                 return MCICDA_GetError(wmcda);
472             lpParms->dwReturn = (wmcda->wcda.nTracks == 0) ? 
473                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
474             TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
475             ret = MCI_RESOURCE_RETURNED;
476             break;
477         case MCI_STATUS_NUMBER_OF_TRACKS:
478             lpParms->dwReturn = CDROM_Audio_GetNumberOfTracks(&wmcda->wcda);
479             TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
480             if (lpParms->dwReturn == (WORD)-1) 
481                 return MCICDA_GetError(wmcda);
482             break;
483         case MCI_STATUS_POSITION:
484             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) 
485                 return MCICDA_GetError(wmcda);
486             lpParms->dwReturn = wmcda->wcda.dwCurFrame;
487             if (dwFlags & MCI_STATUS_START) {
488                 lpParms->dwReturn = wmcda->wcda.dwFirstFrame;
489                 TRACE("get MCI_STATUS_START !\n");
490             }
491             if (dwFlags & MCI_TRACK) {
492                 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
493                     return MCIERR_OUTOFRANGE;
494                 lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
495                 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
496             }
497             lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
498             TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
499             break;
500         case MCI_STATUS_READY:
501             TRACE("MCI_STATUS_READY !\n");
502             lpParms->dwReturn = (wmcda->wcda.cdaMode == WINE_CDA_DONTKNOW ||
503                                  wmcda->wcda.cdaMode == WINE_CDA_NOTREADY) ?
504                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
505             TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
506             ret = MCI_RESOURCE_RETURNED;
507             break;
508         case MCI_STATUS_TIME_FORMAT:
509             lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
510             TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
511             ret = MCI_RESOURCE_RETURNED;
512             break;
513         case 4001: /* FIXME: for bogus FullCD */
514         case MCI_CDA_STATUS_TYPE_TRACK:
515             if (!(dwFlags & MCI_TRACK)) 
516                 ret = MCIERR_MISSING_PARAMETER;
517             else if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
518                 ret = MCIERR_OUTOFRANGE;
519             else
520                 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] & 
521                                      CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
522             TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
523             break;
524         default:
525             FIXME("unknown command %08lX !\n", lpParms->dwItem);
526             return MCIERR_UNRECOGNIZED_COMMAND;
527         }
528     } else {
529         WARN("not MCI_STATUS_ITEM !\n");
530     }
531     return ret;
532 }
533
534 /**************************************************************************
535  *                              MCICDA_Play                     [internal]
536  */
537 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
538 {
539     int                 start, end;
540     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
541     DWORD               ret = 0;
542     
543     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
544     
545     if (lpParms == NULL) {
546         ret = MCIERR_NULL_PARAMETER_BLOCK;
547     } else if (wmcda == NULL) {
548         ret = MCIERR_INVALID_DEVICE_ID;
549     } else {
550         if (wmcda->wcda.nTracks == 0) {
551             if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda)) {
552                 WARN("error reading TracksInfo !\n");
553                 return MCIERR_DRIVER_INTERNAL;
554             }
555         }
556         wmcda->wcda.nCurTrack = 1;
557         if (dwFlags & MCI_FROM) {
558             start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
559             TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
560         } else {
561             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda)) return MCIERR_DRIVER_INTERNAL;
562             start = wmcda->wcda.dwCurFrame;
563         }
564         if (dwFlags & MCI_TO) {
565             end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
566             TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
567         } else {
568             end = wmcda->wcda.dwLastFrame;
569         }
570         
571         if (CDROM_Audio_Play(&wmcda->wcda, start, end) == -1)
572             return MCIERR_HARDWARE;
573         wmcda->mciMode = MCI_MODE_PLAY;
574         if (dwFlags & MCI_NOTIFY) {
575             TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
576             /*
577               mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
578               wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
579             */
580         }
581     }
582     return ret;
583 }
584
585 /**************************************************************************
586  *                              MCICDA_Stop                     [internal]
587  */
588 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
589 {
590     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
591     
592     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
593     
594     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
595     
596     if (CDROM_Audio_Stop(&wmcda->wcda) == -1)
597         return MCIERR_HARDWARE;
598
599     wmcda->mciMode = MCI_MODE_STOP;
600     if (lpParms && (dwFlags & MCI_NOTIFY)) {
601         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
602         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
603                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
604     }
605     return 0;
606 }
607
608 /**************************************************************************
609  *                              MCICDA_Pause                    [internal]
610  */
611 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
612 {
613     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
614     
615     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
616     
617     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
618     
619     if (CDROM_Audio_Pause(&wmcda->wcda, 1) == -1)
620         return MCIERR_HARDWARE;
621     wmcda->mciMode = MCI_MODE_PAUSE;
622     if (lpParms && (dwFlags & MCI_NOTIFY)) {
623         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
624         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
625                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
626     }
627     return 0;
628 }
629
630 /**************************************************************************
631  *                              MCICDA_Resume                   [internal]
632  */
633 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
634 {
635     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
636     
637     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
638     
639     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
640     
641     if (CDROM_Audio_Pause(&wmcda->wcda, 0) == -1)
642         return MCIERR_HARDWARE;
643     wmcda->mciMode = MCI_MODE_STOP;
644     if (lpParms && (dwFlags & MCI_NOTIFY)) {
645         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
646         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
647                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
648     }
649     return 0;
650 }
651
652 /**************************************************************************
653  *                              MCICDA_Seek                     [internal]
654  */
655 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
656 {
657     DWORD               at;
658     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
659     
660     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
661     
662     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
663     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
664     
665     wmcda->mciMode = MCI_MODE_SEEK;
666     switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
667     case MCI_SEEK_TO_START:
668         TRACE("Seeking to start\n");
669         at = wmcda->wcda.dwFirstFrame;
670         break;
671     case MCI_SEEK_TO_END:
672         TRACE("Seeking to end\n");
673         at = wmcda->wcda.dwLastFrame;
674         break;
675     case MCI_TO:
676         TRACE("Seeking to %lu\n", lpParms->dwTo);
677         at = lpParms->dwTo;
678         break;
679     default:
680         TRACE("Seeking to ??=%lu\n", dwFlags);
681         return MCIERR_UNSUPPORTED_FUNCTION;
682     }
683     if (CDROM_Audio_Seek(&wmcda->wcda, at) == -1) {
684         return MCIERR_HARDWARE;
685     }
686     if (dwFlags & MCI_NOTIFY) {
687         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
688         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
689                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
690     }
691     return 0;
692 }
693
694 /**************************************************************************
695  *                              MCICDA_SetDoor                  [internal]
696  */
697 static DWORD    MCICDA_SetDoor(UINT wDevID, int open)
698 {
699     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
700     
701     TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
702     
703     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
704     
705     if (CDROM_SetDoor(&wmcda->wcda, open) == -1)
706         return MCIERR_HARDWARE;
707     wmcda->mciMode = (open) ? MCI_MODE_OPEN : MCI_MODE_STOP;
708     return 0;
709 }
710
711 /**************************************************************************
712  *                              MCICDA_Set                      [internal]
713  */
714 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
715 {
716     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
717     
718     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
719     
720     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
721     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
722     /*
723       TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
724       TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
725     */
726     if (dwFlags & MCI_SET_TIME_FORMAT) {
727         switch (lpParms->dwTimeFormat) {
728         case MCI_FORMAT_MILLISECONDS:
729             TRACE("MCI_FORMAT_MILLISECONDS !\n");
730             break;
731         case MCI_FORMAT_MSF:
732             TRACE("MCI_FORMAT_MSF !\n");
733             break;
734         case MCI_FORMAT_TMSF:
735             TRACE("MCI_FORMAT_TMSF !\n");
736             break;
737         default:
738             WARN("bad time format !\n");
739             return MCIERR_BAD_TIME_FORMAT;
740         }
741         wmcda->dwTimeFormat = lpParms->dwTimeFormat;
742     }
743     if (dwFlags & MCI_SET_DOOR_OPEN) {
744         MCICDA_SetDoor(wDevID, TRUE);
745     }
746     if (dwFlags & MCI_SET_DOOR_CLOSED) {
747         MCICDA_SetDoor(wDevID, FALSE);
748     }
749     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
750     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
751     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
752     if (dwFlags & MCI_NOTIFY) {
753         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
754               lpParms->dwCallback);
755         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
756                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
757     }
758     return 0;
759 }
760
761 /**************************************************************************
762  *                      MCICDA_DriverProc                       [exported]
763  */
764 LONG CALLBACK   MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
765                                       DWORD dwParam1, DWORD dwParam2)
766 {
767     switch(wMsg) {
768     case DRV_LOAD:              return 1;
769     case DRV_FREE:              return 1;
770     case DRV_OPEN:              return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
771     case DRV_CLOSE:             return MCICDA_drvClose(dwDevID);
772     case DRV_ENABLE:            return 1;       
773     case DRV_DISABLE:           return 1;
774     case DRV_QUERYCONFIGURE:    return 1;
775     case DRV_CONFIGURE:         MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
776     case DRV_INSTALL:           return DRVCNF_RESTART;
777     case DRV_REMOVE:            return DRVCNF_RESTART;
778         
779     case MCI_OPEN_DRIVER:       return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
780     case MCI_CLOSE_DRIVER:      return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
781     case MCI_GETDEVCAPS:        return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
782     case MCI_INFO:              return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
783     case MCI_STATUS:            return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
784     case MCI_SET:               return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
785     case MCI_PLAY:              return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
786     case MCI_STOP:              return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
787     case MCI_PAUSE:             return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
788     case MCI_RESUME:            return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
789     case MCI_SEEK:              return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
790     /* FIXME: I wonder if those two next items are really called ? */
791     case MCI_SET_DOOR_OPEN:     FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
792                                 return MCICDA_SetDoor(dwDevID, TRUE);
793     case MCI_SET_DOOR_CLOSED:   FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
794                                 return MCICDA_SetDoor(dwDevID, FALSE);
795     /* commands that should be supported */
796     case MCI_LOAD:              
797     case MCI_SAVE:              
798     case MCI_FREEZE:            
799     case MCI_PUT:               
800     case MCI_REALIZE:           
801     case MCI_UNFREEZE:          
802     case MCI_UPDATE:            
803     case MCI_WHERE:             
804     case MCI_STEP:              
805     case MCI_SPIN:              
806     case MCI_ESCAPE:            
807     case MCI_COPY:              
808     case MCI_CUT:               
809     case MCI_DELETE:            
810     case MCI_PASTE:             
811         FIXME("Unsupported yet command [%lu]\n", wMsg);
812         break;
813     /* commands that should report an error */
814     case MCI_WINDOW:            
815         TRACE("Unsupported command [%lu]\n", wMsg);
816         break;
817     case MCI_OPEN:
818     case MCI_CLOSE:
819         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
820         break;
821     default:
822         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
823         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
824     }
825     return MCIERR_UNRECOGNIZED_COMMAND;
826 }
827
828 /*-----------------------------------------------------------------------*/