Added a first-cut version of MapVirtualKeyExW() that has the same
[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) {
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     int dev;
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     
257     dev = CDROM_OpenDev(&wmcda->wcda);
258     if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
259         wmcda->mciMode = MCI_MODE_OPEN;
260     } else {
261         MCICDA_Seek(wDevID, MCI_SEEK_TO_START, &seekParms);
262     }
263     CDROM_CloseDev(dev);
264
265     return 0;
266 }
267
268 /**************************************************************************
269  *                              MCICDA_Close                    [internal]
270  */
271 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
272 {
273     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
274
275     TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
276
277     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
278     
279     if (wmcda->nUseCount == 1) {
280         CDROM_Close(&wmcda->wcda);
281     }
282     wmcda->nUseCount--;
283     return 0;
284 }
285
286 /**************************************************************************
287  *                              MCICDA_GetDevCaps               [internal]
288  */
289 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags, 
290                                    LPMCI_GETDEVCAPS_PARMS lpParms)
291 {
292     DWORD       ret = 0;
293
294     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
295
296     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
297
298     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
299         TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
300
301         switch (lpParms->dwItem) {
302         case MCI_GETDEVCAPS_CAN_RECORD:
303             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
304             ret = MCI_RESOURCE_RETURNED;
305             break;
306         case MCI_GETDEVCAPS_HAS_AUDIO:
307             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
308             ret = MCI_RESOURCE_RETURNED;
309             break;
310         case MCI_GETDEVCAPS_HAS_VIDEO:
311             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
312             ret = MCI_RESOURCE_RETURNED;
313             break;
314         case MCI_GETDEVCAPS_DEVICE_TYPE:
315             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
316             ret = MCI_RESOURCE_RETURNED;
317             break;
318         case MCI_GETDEVCAPS_USES_FILES:
319             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
320             ret = MCI_RESOURCE_RETURNED;
321             break;
322         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
323             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
324             ret = MCI_RESOURCE_RETURNED;
325             break;
326         case MCI_GETDEVCAPS_CAN_EJECT:
327             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
328             ret = MCI_RESOURCE_RETURNED;
329             break;
330         case MCI_GETDEVCAPS_CAN_PLAY:
331             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
332             ret = MCI_RESOURCE_RETURNED;
333             break;
334         case MCI_GETDEVCAPS_CAN_SAVE:
335             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
336             ret = MCI_RESOURCE_RETURNED;
337             break;
338         default:
339             ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
340             return MCIERR_UNRECOGNIZED_COMMAND;
341         }
342     } else {
343         TRACE("No GetDevCaps-Item !\n");
344         return MCIERR_UNRECOGNIZED_COMMAND;
345     }
346     TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
347     return ret;
348 }
349
350 /**************************************************************************
351  *                              MCICDA_Info                     [internal]
352  */
353 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
354 {
355     LPSTR               str = NULL;
356     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
357     DWORD               ret = 0;
358     char                buffer[16];
359
360     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
361     
362     if (lpParms == NULL || lpParms->lpstrReturn == NULL)
363         return MCIERR_NULL_PARAMETER_BLOCK;
364     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
365
366     TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
367     
368     if (dwFlags & MCI_INFO_PRODUCT) {
369         str = "Wine's audio CD";
370     } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
371         ret = MCIERR_NO_IDENTITY;
372     } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
373         DWORD   res = 0;
374         int dev = CDROM_OpenDev(&wmcda->wcda);
375
376         if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev)) {
377             CDROM_CloseDev(dev);
378             return MCICDA_GetError(wmcda);
379         }
380         CDROM_CloseDev(dev);
381
382         res = CDROM_Audio_GetSerial(&wmcda->wcda);
383         if (wmcda->wcda.nTracks <= 2) {
384             /* there are some other values added when # of tracks < 3
385              * for most Audio CD it will do without
386              */
387             FIXME("Value is not correct !! "
388                   "Please report with full audio CD information (-debugmsg +cdrom,mcicda)\n");
389         }
390         sprintf(buffer, "%lu", res);
391         str = buffer;
392     } else {
393         WARN("Don't know this info command (%lu)\n", dwFlags);
394         ret = MCIERR_UNRECOGNIZED_COMMAND;
395     }
396     if (str) {
397         if (lpParms->dwRetSize <= strlen(str)) {
398             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
399             ret = MCIERR_PARAM_OVERFLOW;
400         } else {
401             strcpy(lpParms->lpstrReturn, str);
402         }       
403     } else {
404         *lpParms->lpstrReturn = 0;
405     }
406     TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
407     return ret;
408 }
409
410 /**************************************************************************
411  *                              MCICDA_Status                   [internal]
412  */
413 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
414 {
415     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
416     DWORD               ret = 0;
417
418     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
419     
420     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
421     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
422
423     if (dwFlags & MCI_NOTIFY) {
424         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
425         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
426                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
427     }
428     if (dwFlags & MCI_STATUS_ITEM) {
429         switch (lpParms->dwItem) {
430         case MCI_STATUS_CURRENT_TRACK:
431             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1)) {
432                 return MCICDA_GetError(wmcda);
433             }
434             lpParms->dwReturn = wmcda->wcda.nCurTrack;
435             TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
436             break;
437         case MCI_STATUS_LENGTH:
438             if (wmcda->wcda.nTracks == 0) {
439                 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, -1)) {
440                     WARN("error reading TracksInfo !\n");
441                     return MCICDA_GetError(wmcda);
442                 }
443             }
444             if (dwFlags & MCI_TRACK) {
445                 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
446                 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
447                     return MCIERR_OUTOFRANGE;
448                 lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
449                 /* Windows returns one frame less than the total track length for the
450                    last track on the CD.  See CDDB HOWTO.  Verified on Win95OSR2. */
451                 if (lpParms->dwTrack == wmcda->wcda.nTracks)
452                     lpParms->dwReturn--;
453             } else {
454                 /* Sum of the lengths of all of the tracks.  Inherits the
455                    'off by one frame' behavior from the length of the last track.
456                    See above comment. */
457                 lpParms->dwReturn = wmcda->wcda.dwLastFrame - wmcda->wcda.dwFirstFrame - 1;
458             }
459             lpParms->dwReturn = MCICDA_CalcTime(wmcda, 
460                                                  (wmcda->dwTimeFormat == MCI_FORMAT_TMSF) 
461                                                     ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
462                                                  lpParms->dwReturn,
463                                                  &ret);
464             TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
465             break;
466         case MCI_STATUS_MODE:
467             CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
468             lpParms->dwReturn = MCICDA_Mode(wmcda->wcda.cdaMode);
469             if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
470             TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
471             lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
472             ret = MCI_RESOURCE_RETURNED;
473             break;
474         case MCI_STATUS_MEDIA_PRESENT:
475             CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
476             lpParms->dwReturn = (wmcda->wcda.nTracks == 0 || 
477                                  wmcda->wcda.cdaMode == WINE_CDA_OPEN) ?
478                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
479             TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
480             ret = MCI_RESOURCE_RETURNED;
481             break;
482         case MCI_STATUS_NUMBER_OF_TRACKS:
483             lpParms->dwReturn = CDROM_Audio_GetNumberOfTracks(&wmcda->wcda, -1);
484             TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
485             if (lpParms->dwReturn == (WORD)-1) 
486                 return MCICDA_GetError(wmcda);
487             break;
488         case MCI_STATUS_POSITION:
489             if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1)) 
490                 return MCICDA_GetError(wmcda);
491             if(wmcda->wcda.cdaMode == WINE_CDA_OPEN)
492                 return MCIERR_HARDWARE;
493             lpParms->dwReturn = wmcda->wcda.dwCurFrame;
494             if (dwFlags & MCI_STATUS_START) {
495                 lpParms->dwReturn = wmcda->wcda.dwFirstFrame;
496                 TRACE("get MCI_STATUS_START !\n");
497             }
498             if (dwFlags & MCI_TRACK) {
499                 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
500                     return MCIERR_OUTOFRANGE;
501                 lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
502                 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
503             }
504             lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
505             TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
506             break;
507         case MCI_STATUS_READY:
508             TRACE("MCI_STATUS_READY !\n");
509             lpParms->dwReturn = (wmcda->wcda.cdaMode == WINE_CDA_DONTKNOW ||
510                                  wmcda->wcda.cdaMode == WINE_CDA_NOTREADY) ?
511                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
512             TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
513             ret = MCI_RESOURCE_RETURNED;
514             break;
515         case MCI_STATUS_TIME_FORMAT:
516             lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
517             TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
518             ret = MCI_RESOURCE_RETURNED;
519             break;
520         case 4001: /* FIXME: for bogus FullCD */
521         case MCI_CDA_STATUS_TYPE_TRACK:
522             if (!(dwFlags & MCI_TRACK)) 
523                 ret = MCIERR_MISSING_PARAMETER;
524             else if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
525                 ret = MCIERR_OUTOFRANGE;
526             else
527                 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] &
528                                      CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
529             TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
530             break;
531         default:
532             FIXME("unknown command %08lX !\n", lpParms->dwItem);
533             return MCIERR_UNRECOGNIZED_COMMAND;
534         }
535     } else {
536         WARN("not MCI_STATUS_ITEM !\n");
537     }
538     return ret;
539 }
540
541 /**************************************************************************
542  *                              MCICDA_Play                     [internal]
543  */
544 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
545 {
546     int                 start, end;
547     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
548     DWORD               ret = 0;
549     int dev = -1;
550     
551     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
552     
553     if (lpParms == NULL)
554         return MCIERR_NULL_PARAMETER_BLOCK;
555
556     if (wmcda == NULL)
557         return MCIERR_INVALID_DEVICE_ID;
558
559     dev = CDROM_OpenDev(&wmcda->wcda);
560     if (wmcda->wcda.nTracks == 0) {
561         if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
562             WARN("error reading TracksInfo !\n");
563             ret = MCIERR_DRIVER_INTERNAL;
564             goto end;
565         }
566     }
567     wmcda->wcda.nCurTrack = 1;
568     if (dwFlags & MCI_FROM) {
569         start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
570         TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
571     } else {
572         if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev))
573         {
574             ret = MCIERR_DRIVER_INTERNAL;
575             goto end;
576         }
577         start = wmcda->wcda.dwCurFrame;
578     }
579     if (dwFlags & MCI_TO) {
580         end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
581         TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
582     } else
583     end = wmcda->wcda.dwLastFrame;
584
585     if (CDROM_Audio_Play(&wmcda->wcda, start, end, dev) == -1)
586     {
587         ret = MCIERR_HARDWARE;
588         goto end;
589     }
590     wmcda->mciMode = MCI_MODE_PLAY;
591     if (dwFlags & MCI_NOTIFY) {
592         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
593         /*
594           mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
595           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
596         */
597     }
598 end:
599     if (dev != -1)
600         CDROM_CloseDev(dev);
601     return ret;
602 }
603
604 /**************************************************************************
605  *                              MCICDA_Stop                     [internal]
606  */
607 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
608 {
609     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
610     
611     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
612     
613     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
614     
615     if (CDROM_Audio_Stop(&wmcda->wcda, -1) == -1)
616         return MCIERR_HARDWARE;
617
618     wmcda->mciMode = MCI_MODE_STOP;
619     if (lpParms && (dwFlags & MCI_NOTIFY)) {
620         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
621         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
622                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
623     }
624     return 0;
625 }
626
627 /**************************************************************************
628  *                              MCICDA_Pause                    [internal]
629  */
630 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
631 {
632     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
633     
634     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
635     
636     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
637     
638     if (CDROM_Audio_Pause(&wmcda->wcda, 1, -1) == -1)
639         return MCIERR_HARDWARE;
640     wmcda->mciMode = MCI_MODE_PAUSE;
641     if (lpParms && (dwFlags & MCI_NOTIFY)) {
642         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
643         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
644                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
645     }
646     return 0;
647 }
648
649 /**************************************************************************
650  *                              MCICDA_Resume                   [internal]
651  */
652 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
653 {
654     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
655     
656     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
657     
658     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
659     
660     if (CDROM_Audio_Pause(&wmcda->wcda, 0, -1) == -1)
661         return MCIERR_HARDWARE;
662     wmcda->mciMode = MCI_MODE_STOP;
663     if (lpParms && (dwFlags & MCI_NOTIFY)) {
664         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
665         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
666                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
667     }
668     return 0;
669 }
670
671 /**************************************************************************
672  *                              MCICDA_Seek                     [internal]
673  */
674 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
675 {
676     DWORD               at;
677     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
678     
679     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
680     
681     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
682     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
683     
684     wmcda->mciMode = MCI_MODE_SEEK;
685     switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
686     case MCI_SEEK_TO_START:
687         TRACE("Seeking to start\n");
688         at = wmcda->wcda.dwFirstFrame;
689         break;
690     case MCI_SEEK_TO_END:
691         TRACE("Seeking to end\n");
692         at = wmcda->wcda.dwLastFrame;
693         break;
694     case MCI_TO:
695         TRACE("Seeking to %lu\n", lpParms->dwTo);
696         at = lpParms->dwTo;
697         break;
698     default:
699         TRACE("Seeking to ??=%lu\n", dwFlags);
700         return MCIERR_UNSUPPORTED_FUNCTION;
701     }
702     if (CDROM_Audio_Seek(&wmcda->wcda, at, -1) == -1) {
703         return MCIERR_HARDWARE;
704     }
705     if (dwFlags & MCI_NOTIFY) {
706         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
707         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
708                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
709     }
710     return 0;
711 }
712
713 /**************************************************************************
714  *                              MCICDA_SetDoor                  [internal]
715  */
716 static DWORD    MCICDA_SetDoor(UINT wDevID, int open)
717 {
718     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
719     
720     TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
721     
722     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
723     
724     if (CDROM_SetDoor(&wmcda->wcda, open, -1) == -1)
725         return MCIERR_HARDWARE;
726     wmcda->mciMode = (open) ? MCI_MODE_OPEN : MCI_MODE_STOP;
727     return 0;
728 }
729
730 /**************************************************************************
731  *                              MCICDA_Set                      [internal]
732  */
733 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
734 {
735     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
736     
737     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
738     
739     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
740
741     if (dwFlags & MCI_SET_DOOR_OPEN) {
742         MCICDA_SetDoor(wDevID, TRUE);
743     }
744     if (dwFlags & MCI_SET_DOOR_CLOSED) {
745         MCICDA_SetDoor(wDevID, FALSE);
746     }
747
748     /* only functions which require valid lpParms below this line ! */
749     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
750     /*
751       TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
752       TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
753     */
754     if (dwFlags & MCI_SET_TIME_FORMAT) {
755         switch (lpParms->dwTimeFormat) {
756         case MCI_FORMAT_MILLISECONDS:
757             TRACE("MCI_FORMAT_MILLISECONDS !\n");
758             break;
759         case MCI_FORMAT_MSF:
760             TRACE("MCI_FORMAT_MSF !\n");
761             break;
762         case MCI_FORMAT_TMSF:
763             TRACE("MCI_FORMAT_TMSF !\n");
764             break;
765         default:
766             WARN("bad time format !\n");
767             return MCIERR_BAD_TIME_FORMAT;
768         }
769         wmcda->dwTimeFormat = lpParms->dwTimeFormat;
770     }
771     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
772     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
773     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
774     if (dwFlags & MCI_NOTIFY) {
775         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
776               lpParms->dwCallback);
777         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
778                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
779     }
780     return 0;
781 }
782
783 /**************************************************************************
784  *                      MCICDA_DriverProc                       [exported]
785  */
786 LONG CALLBACK   MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
787                                       DWORD dwParam1, DWORD dwParam2)
788 {
789     switch(wMsg) {
790     case DRV_LOAD:              return 1;
791     case DRV_FREE:              return 1;
792     case DRV_OPEN:              return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
793     case DRV_CLOSE:             return MCICDA_drvClose(dwDevID);
794     case DRV_ENABLE:            return 1;       
795     case DRV_DISABLE:           return 1;
796     case DRV_QUERYCONFIGURE:    return 1;
797     case DRV_CONFIGURE:         MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
798     case DRV_INSTALL:           return DRVCNF_RESTART;
799     case DRV_REMOVE:            return DRVCNF_RESTART;
800         
801     case MCI_OPEN_DRIVER:       return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
802     case MCI_CLOSE_DRIVER:      return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
803     case MCI_GETDEVCAPS:        return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
804     case MCI_INFO:              return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
805     case MCI_STATUS:            return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
806     case MCI_SET:               return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
807     case MCI_PLAY:              return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
808     case MCI_STOP:              return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
809     case MCI_PAUSE:             return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
810     case MCI_RESUME:            return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
811     case MCI_SEEK:              return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
812     /* FIXME: I wonder if those two next items are really called ? */
813     case MCI_SET_DOOR_OPEN:     FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
814                                 return MCICDA_SetDoor(dwDevID, TRUE);
815     case MCI_SET_DOOR_CLOSED:   FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
816                                 return MCICDA_SetDoor(dwDevID, FALSE);
817     /* commands that should be supported */
818     case MCI_LOAD:              
819     case MCI_SAVE:              
820     case MCI_FREEZE:            
821     case MCI_PUT:               
822     case MCI_REALIZE:           
823     case MCI_UNFREEZE:          
824     case MCI_UPDATE:            
825     case MCI_WHERE:             
826     case MCI_STEP:              
827     case MCI_SPIN:              
828     case MCI_ESCAPE:            
829     case MCI_COPY:              
830     case MCI_CUT:               
831     case MCI_DELETE:            
832     case MCI_PASTE:             
833         FIXME("Unsupported yet command [%lu]\n", wMsg);
834         break;
835     /* commands that should report an error */
836     case MCI_WINDOW:            
837         TRACE("Unsupported command [%lu]\n", wMsg);
838         break;
839     case MCI_OPEN:
840     case MCI_CLOSE:
841         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
842         break;
843     default:
844         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
845         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
846     }
847     return MCIERR_UNRECOGNIZED_COMMAND;
848 }
849
850 /*-----------------------------------------------------------------------*/