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