Better implementation of GetCalendarInfo{A,W}, not perfect.
[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  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "mmddk.h"
33 #include "winioctl.h"
34 #include "ntddstor.h"
35 #include "ntddcdrm.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(mcicda);
39
40 #define CDFRAMES_PERSEC                 75
41 #define CDFRAMES_PERMIN                 (CDFRAMES_PERSEC * 60)
42 #define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
43 #define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
44
45 typedef struct {
46     UINT                wDevID;
47     int                 nUseCount;          /* Incremented for each shared open */
48     BOOL                fShareable;         /* TRUE if first open was shareable */
49     WORD                wNotifyDeviceID;    /* MCI device ID with a pending notification */
50     HANDLE              hCallback;          /* Callback handle for pending notification */
51     DWORD               dwTimeFormat;
52     HANDLE              handle;
53 } WINE_MCICDAUDIO;
54
55 /*-----------------------------------------------------------------------*/
56
57 /**************************************************************************
58  *                              MCICDA_drvOpen                  [internal]      
59  */
60 static  DWORD   MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
61 {
62     WINE_MCICDAUDIO*    wmcda;
63
64     if (!modp) return 0xFFFFFFFF;
65
66     wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  sizeof(WINE_MCICDAUDIO));
67
68     if (!wmcda)
69         return 0;
70
71     wmcda->wDevID = modp->wDeviceID;
72     mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
73     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
74     modp->wType = MCI_DEVTYPE_CD_AUDIO;
75     return modp->wDeviceID;
76 }
77
78 /**************************************************************************
79  *                              MCICDA_drvClose                 [internal]      
80  */
81 static  DWORD   MCICDA_drvClose(DWORD dwDevID)
82 {
83     WINE_MCICDAUDIO*  wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
84
85     if (wmcda) {
86         HeapFree(GetProcessHeap(), 0, wmcda);
87         mciSetDriverData(dwDevID, 0);
88     }
89     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
90 }
91
92 /**************************************************************************
93  *                              MCICDA_GetOpenDrv               [internal]      
94  */
95 static WINE_MCICDAUDIO*  MCICDA_GetOpenDrv(UINT wDevID)
96 {
97     WINE_MCICDAUDIO*    wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
98     
99     if (wmcda == NULL || wmcda->nUseCount == 0) {
100         WARN("Invalid wDevID=%u\n", wDevID);
101         return 0;
102     }
103     return wmcda;
104 }
105
106 /**************************************************************************
107  *                              MCICDA_GetStatus                [internal]
108  */
109 static  DWORD    MCICDA_GetStatus(WINE_MCICDAUDIO* wmcda)
110 {
111     CDROM_SUB_Q_DATA_FORMAT     fmt;
112     SUB_Q_CHANNEL_DATA          data;
113     DWORD                       br;
114     DWORD                       mode = MCI_MODE_NOT_READY;
115
116     fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
117     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt), 
118                          &data, sizeof(data), &br, NULL)) {
119         if (GetLastError() == STATUS_NO_MEDIA_IN_DEVICE) mode = MCI_MODE_OPEN;
120     } else {
121         switch (data.CurrentPosition.Header.AudioStatus)
122         {
123         case AUDIO_STATUS_IN_PROGRESS:          mode = MCI_MODE_PLAY;   break;
124         case AUDIO_STATUS_PAUSED:               mode = MCI_MODE_PAUSE;  break;
125         case AUDIO_STATUS_NO_STATUS:
126         case AUDIO_STATUS_PLAY_COMPLETE:        mode = MCI_MODE_STOP;   break;
127         case AUDIO_STATUS_PLAY_ERROR:
128         case AUDIO_STATUS_NOT_SUPPORTED:
129         default:
130             break;
131         }
132     }
133     return mode;
134 }
135
136 /**************************************************************************
137  *                              MCICDA_GetError                 [internal]
138  */
139 static  int     MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
140 {
141     switch (GetLastError())
142     {
143     case STATUS_NO_MEDIA_IN_DEVICE:     return MCIERR_DEVICE_NOT_READY;
144     case STATUS_IO_DEVICE_ERROR:        return MCIERR_HARDWARE;
145     default:
146         FIXME("Unknown mode %lx\n", GetLastError());
147     }
148     return MCIERR_DRIVER_INTERNAL;
149 }
150
151 /**************************************************************************
152  *                      MCICDA_CalcFrame                        [internal]
153  */
154 static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
155 {
156     DWORD       dwFrame = 0;
157     UINT        wTrack;
158     CDROM_TOC   toc;
159     DWORD       br;
160     BYTE*       addr;
161     
162     TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
163     
164     switch (wmcda->dwTimeFormat) {
165     case MCI_FORMAT_MILLISECONDS:
166         dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
167         TRACE("MILLISECONDS %lu\n", dwFrame);
168         break;
169     case MCI_FORMAT_MSF:
170         TRACE("MSF %02u:%02u:%02u\n",
171               MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
172         dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
173         dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
174         dwFrame += MCI_MSF_FRAME(dwTime);
175         break;
176     case MCI_FORMAT_TMSF:
177     default: /* unknown format ! force TMSF ! ... */
178         wTrack = MCI_TMSF_TRACK(dwTime);
179         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
180                              &toc, sizeof(toc), &br, NULL))
181             return 0;
182         if (wTrack < toc.FirstTrack || wTrack > toc.LastTrack)
183             return 0;
184         TRACE("MSF %02u-%02u:%02u:%02u\n",
185               MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime), 
186               MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
187         addr = toc.TrackData[wTrack - toc.FirstTrack].Address;
188         TRACE("TMSF trackpos[%u]=%d:%d:%d\n",
189               wTrack, addr[0], addr[1], addr[2]);
190         dwFrame = CDFRAMES_PERMIN * (addr[0] + MCI_TMSF_MINUTE(dwTime)) +
191             CDFRAMES_PERSEC * (addr[1] + MCI_TMSF_SECOND(dwTime)) +
192             addr[2] + MCI_TMSF_FRAME(dwTime);
193         break;
194     }
195     return dwFrame;
196 }
197
198 /**************************************************************************
199  *                      MCICDA_CalcTime                         [internal]
200  */
201 static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LPDWORD lpRet)
202 {
203     DWORD       dwTime = 0;
204     UINT        wTrack;
205     UINT        wMinutes;
206     UINT        wSeconds;
207     UINT        wFrames;
208     CDROM_TOC   toc;
209     DWORD       br;
210     
211     TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);
212     
213     switch (tf) {
214     case MCI_FORMAT_MILLISECONDS:
215         dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
216         TRACE("MILLISECONDS %lu\n", dwTime);
217         *lpRet = 0;
218         break;
219     case MCI_FORMAT_MSF:
220         wMinutes = dwFrame / CDFRAMES_PERMIN;
221         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
222         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
223         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
224         TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
225               wMinutes, wSeconds, wFrames, dwTime);
226         *lpRet = MCI_COLONIZED3_RETURN;
227         break;
228     case MCI_FORMAT_TMSF:
229     default:    /* unknown format ! force TMSF ! ... */
230         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
231                              &toc, sizeof(toc), &br, NULL))
232             return 0;
233         if (dwFrame < FRAME_OF_TOC(toc, toc.FirstTrack) || 
234             dwFrame > FRAME_OF_TOC(toc, toc.LastTrack + 1)) {
235             ERR("Out of range value %lu [%u,%u]\n", 
236                 dwFrame, FRAME_OF_TOC(toc, toc.FirstTrack), 
237                 FRAME_OF_TOC(toc, toc.LastTrack + 1));
238             *lpRet = 0;
239             return 0;
240         }
241         for (wTrack = toc.FirstTrack; wTrack <= toc.LastTrack; wTrack++) {
242             if (FRAME_OF_TOC(toc, wTrack) > dwFrame)
243                 break;
244         }
245         wTrack--;
246         dwFrame -= FRAME_OF_TOC(toc, wTrack);
247         wMinutes = dwFrame / CDFRAMES_PERMIN;
248         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
249         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
250         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
251         TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
252         *lpRet = MCI_COLONIZED4_RETURN;
253         break;
254     }
255     return dwTime;
256 }
257
258 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
259 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
260
261 /**************************************************************************
262  *                              MCICDA_Open                     [internal]
263  */
264 static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
265 {
266     DWORD               dwDeviceID;
267     DWORD               ret = MCIERR_HARDWARE;
268     WINE_MCICDAUDIO*    wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
269     char                root[7];
270     int                 count;
271     char                drive = 0;
272
273     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
274     
275     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
276     if (wmcda == NULL)                  return MCIERR_INVALID_DEVICE_ID;
277
278     dwDeviceID = lpOpenParms->wDeviceID;
279
280     if (wmcda->nUseCount > 0) {
281         /* The driver is already open on this channel */
282         /* If the driver was opened shareable before and this open specifies */
283         /* shareable then increment the use count */
284         if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
285             ++wmcda->nUseCount;
286         else
287             return MCIERR_MUST_USE_SHAREABLE;
288     } else {
289         wmcda->nUseCount = 1;
290         wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
291     }
292     if (dwFlags & MCI_OPEN_ELEMENT) {
293         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
294             WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort\n", (DWORD)lpOpenParms->lpstrElementName);
295             return MCIERR_NO_ELEMENT_ALLOWED;
296         }
297         if (!isalpha(lpOpenParms->lpstrElementName[0]) || lpOpenParms->lpstrElementName[1] != ':' ||
298             lpOpenParms->lpstrElementName[2])
299         {
300             WARN("MCI_OPEN_ELEMENT unsupported format: %s\n", lpOpenParms->lpstrElementName);
301             ret = MCIERR_NO_ELEMENT_ALLOWED; 
302             goto the_error;
303         }
304         drive = toupper(lpOpenParms->lpstrElementName[0]);
305         strcpy(root, "A:\\");
306         root[0] = drive;
307         if (GetDriveTypeA(root) != DRIVE_CDROM)
308         {
309             ret = MCIERR_INVALID_DEVICE_NAME;
310             goto the_error;
311         }
312     }
313     else
314     {
315         /* drive letter isn't passed... get the dwDeviceID'th cdrom in the system */
316         strcpy(root, "A:\\");
317         for (count = 0; root[0] <= 'Z'; root[0]++)
318         {
319             if (GetDriveTypeA(root) == DRIVE_CDROM && ++count >= dwDeviceID)
320             {
321                 drive = root[0];
322                 break;
323             }
324         }
325         if (!drive)
326         {
327             ret = MCIERR_INVALID_DEVICE_ID;
328             goto the_error;
329         }
330     }
331
332     wmcda->wNotifyDeviceID = dwDeviceID;
333     wmcda->dwTimeFormat = MCI_FORMAT_MSF;
334
335     /* now, open the handle */
336     strcpy(root, "\\\\.\\A:");
337     root[4] = drive;
338     wmcda->handle = CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
339     if (wmcda->handle != INVALID_HANDLE_VALUE)
340         return 0;
341
342  the_error:
343     --wmcda->nUseCount;
344     return ret;
345 }
346
347 /**************************************************************************
348  *                              MCICDA_Close                    [internal]
349  */
350 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
351 {
352     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
353
354     TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
355
356     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
357     
358     if (--wmcda->nUseCount == 0) {
359         CloseHandle(wmcda->handle);
360     }
361     return 0;
362 }
363
364 /**************************************************************************
365  *                              MCICDA_GetDevCaps               [internal]
366  */
367 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags, 
368                                    LPMCI_GETDEVCAPS_PARMS lpParms)
369 {
370     DWORD       ret = 0;
371
372     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
373
374     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
375
376     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
377         TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
378
379         switch (lpParms->dwItem) {
380         case MCI_GETDEVCAPS_CAN_RECORD:
381             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
382             ret = MCI_RESOURCE_RETURNED;
383             break;
384         case MCI_GETDEVCAPS_HAS_AUDIO:
385             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
386             ret = MCI_RESOURCE_RETURNED;
387             break;
388         case MCI_GETDEVCAPS_HAS_VIDEO:
389             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
390             ret = MCI_RESOURCE_RETURNED;
391             break;
392         case MCI_GETDEVCAPS_DEVICE_TYPE:
393             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
394             ret = MCI_RESOURCE_RETURNED;
395             break;
396         case MCI_GETDEVCAPS_USES_FILES:
397             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
398             ret = MCI_RESOURCE_RETURNED;
399             break;
400         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
401             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
402             ret = MCI_RESOURCE_RETURNED;
403             break;
404         case MCI_GETDEVCAPS_CAN_EJECT:
405             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
406             ret = MCI_RESOURCE_RETURNED;
407             break;
408         case MCI_GETDEVCAPS_CAN_PLAY:
409             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
410             ret = MCI_RESOURCE_RETURNED;
411             break;
412         case MCI_GETDEVCAPS_CAN_SAVE:
413             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
414             ret = MCI_RESOURCE_RETURNED;
415             break;
416         default:
417             ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
418             return MCIERR_UNRECOGNIZED_COMMAND;
419         }
420     } else {
421         TRACE("No GetDevCaps-Item !\n");
422         return MCIERR_UNRECOGNIZED_COMMAND;
423     }
424     TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
425     return ret;
426 }
427
428 static DWORD CDROM_Audio_GetSerial(CDROM_TOC* toc)
429 {
430     unsigned long serial = 0;
431     int i;
432     WORD wMagic;
433     DWORD dwStart, dwEnd;
434  
435     /*
436      * wMagic collects the wFrames from track 1
437      * dwStart, dwEnd collect the beginning and end of the disc respectively, in
438      * frames.
439      * There it is collected for correcting the serial when there are less than
440      * 3 tracks.
441      */
442     wMagic = toc->TrackData[0].Address[3];
443     dwStart = FRAME_OF_TOC(*toc, toc->FirstTrack);
444
445     for (i = 0; i <= toc->LastTrack - toc->FirstTrack; i++) {
446         serial += (toc->TrackData[i].Address[1] << 16) | 
447             (toc->TrackData[i].Address[2] << 8) | toc->TrackData[i].Address[3];
448     }
449     dwEnd = FRAME_OF_TOC(*toc, toc->LastTrack + 1);
450  
451     if (toc->LastTrack - toc->FirstTrack + 1 < 3)
452         serial += wMagic + (dwEnd - dwStart);
453
454     return serial;
455 }
456     
457
458 /**************************************************************************
459  *                              MCICDA_Info                     [internal]
460  */
461 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
462 {
463     LPSTR               str = NULL;
464     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
465     DWORD               ret = 0;
466     char                buffer[16];
467
468     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
469     
470     if (lpParms == NULL || lpParms->lpstrReturn == NULL)
471         return MCIERR_NULL_PARAMETER_BLOCK;
472     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
473
474     TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
475     
476     if (dwFlags & MCI_INFO_PRODUCT) {
477         str = "Wine's audio CD";
478     } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
479         ret = MCIERR_NO_IDENTITY;
480     } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
481         DWORD       res = 0;
482         CDROM_TOC   toc;
483         DWORD       br;
484
485         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
486                              &toc, sizeof(toc), &br, NULL)) {
487             return MCICDA_GetError(wmcda);
488         }
489
490         res = CDROM_Audio_GetSerial(&toc);
491         sprintf(buffer, "%lu", res);
492         str = buffer;
493     } else {
494         WARN("Don't know this info command (%lu)\n", dwFlags);
495         ret = MCIERR_UNRECOGNIZED_COMMAND;
496     }
497     if (str) {
498         if (lpParms->dwRetSize <= strlen(str)) {
499             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
500             ret = MCIERR_PARAM_OVERFLOW;
501         } else {
502             strcpy(lpParms->lpstrReturn, str);
503         }       
504     } else {
505         *lpParms->lpstrReturn = 0;
506     }
507     TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
508     return ret;
509 }
510
511 /**************************************************************************
512  *                              MCICDA_Status                   [internal]
513  */
514 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
515 {
516     WINE_MCICDAUDIO*            wmcda = MCICDA_GetOpenDrv(wDevID);
517     DWORD                       idx;
518     DWORD                       ret = 0;
519     CDROM_SUB_Q_DATA_FORMAT     fmt;
520     SUB_Q_CHANNEL_DATA          data;
521     CDROM_TOC                   toc;
522     DWORD                       br;
523
524     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
525     
526     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
527     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
528
529     if (dwFlags & MCI_NOTIFY) {
530         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
531         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
532                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
533     }
534     if (dwFlags & MCI_STATUS_ITEM) {
535         TRACE("dwItem = %lx\n", lpParms->dwItem);
536         switch (lpParms->dwItem) {
537         case MCI_STATUS_CURRENT_TRACK:
538             fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
539             if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt), 
540                                  &data, sizeof(data), &br, NULL))
541             {
542                 return MCICDA_GetError(wmcda);
543             }
544             lpParms->dwReturn = data.CurrentPosition.TrackNumber;
545             TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
546             break;
547         case MCI_STATUS_LENGTH:
548             if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
549                                  &toc, sizeof(toc), &br, NULL)) {
550                 WARN("error reading TOC !\n");
551                 return MCICDA_GetError(wmcda);
552             }
553             if (dwFlags & MCI_TRACK) {
554                 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
555                 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
556                     return MCIERR_OUTOFRANGE;
557                 idx = lpParms->dwTrack - toc.FirstTrack;
558                 lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack + 1) - 
559                     FRAME_OF_TOC(toc, lpParms->dwTrack);
560                 /* Windows returns one frame less than the total track length for the
561                    last track on the CD.  See CDDB HOWTO.  Verified on Win95OSR2. */
562                 if (lpParms->dwTrack == toc.LastTrack)
563                     lpParms->dwReturn--;
564             } else {
565                 /* Sum of the lengths of all of the tracks.  Inherits the
566                    'off by one frame' behavior from the length of the last track.
567                    See above comment. */
568                 lpParms->dwReturn = FRAME_OF_TOC(toc, toc.LastTrack + 1) -
569                     FRAME_OF_TOC(toc, toc.FirstTrack) - 1;
570             }
571             lpParms->dwReturn = MCICDA_CalcTime(wmcda, 
572                                                  (wmcda->dwTimeFormat == MCI_FORMAT_TMSF) 
573                                                     ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
574                                                  lpParms->dwReturn,
575                                                  &ret);
576             TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
577             break;
578         case MCI_STATUS_MODE:
579             lpParms->dwReturn = MCICDA_GetStatus(wmcda);
580             TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
581             lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
582             ret = MCI_RESOURCE_RETURNED;
583             break;
584         case MCI_STATUS_MEDIA_PRESENT:
585             lpParms->dwReturn = (MCICDA_GetStatus(wmcda) == MCI_MODE_OPEN) ?
586                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
587             TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
588             ret = MCI_RESOURCE_RETURNED;
589             break;
590         case MCI_STATUS_NUMBER_OF_TRACKS:
591             if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
592                                  &toc, sizeof(toc), &br, NULL)) {
593                 WARN("error reading TOC !\n");
594                 return MCICDA_GetError(wmcda);
595             }
596             lpParms->dwReturn = toc.LastTrack - toc.FirstTrack + 1;
597             TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
598             if (lpParms->dwReturn == (WORD)-1) 
599                 return MCICDA_GetError(wmcda);
600             break;
601         case MCI_STATUS_POSITION:
602             if (dwFlags & MCI_STATUS_START) {
603                 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
604                                      &toc, sizeof(toc), &br, NULL)) {
605                     WARN("error reading TOC !\n");
606                     return MCICDA_GetError(wmcda);
607                 }
608                 lpParms->dwReturn = FRAME_OF_TOC(toc, toc.FirstTrack);
609                 TRACE("get MCI_STATUS_START !\n");
610             } else if (dwFlags & MCI_TRACK) {
611                 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
612                                      &toc, sizeof(toc), &br, NULL)) {
613                     WARN("error reading TOC !\n");
614                     return MCICDA_GetError(wmcda);
615                 }
616                 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
617                     return MCIERR_OUTOFRANGE;
618                 lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack);
619                 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
620             } else {
621                 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
622                 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt), 
623                                      &data, sizeof(data), &br, NULL)) {
624                     return MCICDA_GetError(wmcda);
625                 }
626                 lpParms->dwReturn = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
627             }
628             lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
629             TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
630             break;
631         case MCI_STATUS_READY:
632             TRACE("MCI_STATUS_READY !\n");
633             switch (MCICDA_GetStatus(wmcda))
634             {
635             case MCI_MODE_NOT_READY:
636             case MCI_MODE_OPEN:
637                 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
638                 break;
639             default:
640                 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
641                 break;
642             }
643             TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
644             ret = MCI_RESOURCE_RETURNED;
645             break;
646         case MCI_STATUS_TIME_FORMAT:
647             lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
648             TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
649             ret = MCI_RESOURCE_RETURNED;
650             break;
651         case 4001: /* FIXME: for bogus FullCD */
652         case MCI_CDA_STATUS_TYPE_TRACK:
653             if (!(dwFlags & MCI_TRACK)) 
654                 ret = MCIERR_MISSING_PARAMETER;
655             else {
656                 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
657                                      &toc, sizeof(toc), &br, NULL)) {
658                     WARN("error reading TOC !\n");
659                     return MCICDA_GetError(wmcda);
660                 }
661                 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
662                     ret = MCIERR_OUTOFRANGE;
663                 else
664                     lpParms->dwReturn = (toc.TrackData[lpParms->dwTrack - toc.FirstTrack].Control & 0x04) ?
665                                          MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
666             }
667             TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
668             break;
669         default:
670             FIXME("unknown command %08lX !\n", lpParms->dwItem);
671             return MCIERR_UNRECOGNIZED_COMMAND;
672         }
673     } else {
674         WARN("not MCI_STATUS_ITEM !\n");
675     }
676     return ret;
677 }
678
679 /**************************************************************************
680  *                              MCICDA_Play                     [internal]
681  */
682 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
683 {
684     WINE_MCICDAUDIO*            wmcda = MCICDA_GetOpenDrv(wDevID);
685     DWORD                       ret = 0, start, end;
686     CDROM_TOC                   toc;
687     DWORD                       br;
688     CDROM_PLAY_AUDIO_MSF        play;
689     CDROM_SUB_Q_DATA_FORMAT     fmt;
690     SUB_Q_CHANNEL_DATA          data;
691  
692     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
693     
694     if (lpParms == NULL)
695         return MCIERR_NULL_PARAMETER_BLOCK;
696
697     if (wmcda == NULL)
698         return MCIERR_INVALID_DEVICE_ID;
699
700     if (dwFlags & MCI_FROM) {
701         start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
702         TRACE("MCI_FROM=%08lX -> %lu \n", lpParms->dwFrom, start);
703     } else {
704         fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
705         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt), 
706                              &data, sizeof(data), &br, NULL)) {
707             return MCICDA_GetError(wmcda);
708         }
709         start = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
710     }
711     if (dwFlags & MCI_TO) {
712         end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
713         TRACE("MCI_TO=%08lX -> %lu \n", lpParms->dwTo, end);
714     } else {
715         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
716                              &toc, sizeof(toc), &br, NULL)) {
717             WARN("error reading TOC !\n");
718             return MCICDA_GetError(wmcda);
719         }
720         end = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
721     }
722     TRACE("Playing from %lu to %lu\n", start, end);
723     play.StartingM = start / CDFRAMES_PERMIN;
724     play.StartingS = (start / CDFRAMES_PERSEC) % 60;
725     play.StartingF = start % CDFRAMES_PERSEC;
726     play.EndingM   = end / CDFRAMES_PERMIN;
727     play.EndingS   = (end / CDFRAMES_PERSEC) % 60;
728     play.EndingF   = end % CDFRAMES_PERSEC;
729     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_PLAY_AUDIO_MSF, &play, sizeof(play), 
730                          NULL, 0, &br, NULL)) {
731         ret = MCIERR_HARDWARE;
732     } else if (dwFlags & MCI_NOTIFY) {
733         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
734         /*
735           mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
736           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
737         */
738     }
739     return ret;
740 }
741
742 /**************************************************************************
743  *                              MCICDA_Stop                     [internal]
744  */
745 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
746 {
747     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
748     DWORD               br;
749
750     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
751     
752     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
753     
754     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL))
755         return MCIERR_HARDWARE;
756
757     if (lpParms && (dwFlags & MCI_NOTIFY)) {
758         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
759         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
760                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
761     }
762     return 0;
763 }
764
765 /**************************************************************************
766  *                              MCICDA_Pause                    [internal]
767  */
768 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
769 {
770     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
771     DWORD               br;
772
773     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
774     
775     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
776     
777     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL))
778         return MCIERR_HARDWARE;
779
780     if (lpParms && (dwFlags & MCI_NOTIFY)) {
781         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
782         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
783                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
784     }
785     return 0;
786 }
787
788 /**************************************************************************
789  *                              MCICDA_Resume                   [internal]
790  */
791 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
792 {
793     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
794     DWORD               br;
795     
796     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
797     
798     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
799     
800     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &br, NULL))
801         return MCIERR_HARDWARE;
802
803     if (lpParms && (dwFlags & MCI_NOTIFY)) {
804         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
805         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
806                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
807     }
808     return 0;
809 }
810
811 /**************************************************************************
812  *                              MCICDA_Seek                     [internal]
813  */
814 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
815 {
816     DWORD                       at;
817     WINE_MCICDAUDIO*            wmcda = MCICDA_GetOpenDrv(wDevID);
818     CDROM_SEEK_AUDIO_MSF        seek;
819     CDROM_TOC                   toc;
820     DWORD                       br;
821
822     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
823     
824     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
825     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
826     
827     switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
828     case MCI_SEEK_TO_START:
829         TRACE("Seeking to start\n");
830         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
831                              &toc, sizeof(toc), &br, NULL)) {
832             WARN("error reading TOC !\n");
833             return MCICDA_GetError(wmcda);
834         }
835         at = FRAME_OF_TOC(toc, toc.FirstTrack);
836         break;
837     case MCI_SEEK_TO_END:
838         TRACE("Seeking to end\n");
839         if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, 
840                              &toc, sizeof(toc), &br, NULL)) {
841             WARN("error reading TOC !\n");
842             return MCICDA_GetError(wmcda);
843         }
844         at = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
845         break;
846     case MCI_TO:
847         TRACE("Seeking to %lu\n", lpParms->dwTo);
848         at = lpParms->dwTo;
849         break;
850     default:
851         TRACE("Unknown seek action %08lX\n",
852               (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)));
853         return MCIERR_UNSUPPORTED_FUNCTION;
854     }
855     seek.M = at / CDFRAMES_PERMIN;
856     seek.S = (at / CDFRAMES_PERSEC) % 60;
857     seek.F = at % CDFRAMES_PERSEC;
858     if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_SEEK_AUDIO_MSF, &seek, sizeof(seek), 
859                          NULL, 0, &br, NULL))
860         return MCIERR_HARDWARE;
861
862     if (dwFlags & MCI_NOTIFY) {
863         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
864         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
865                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
866     }
867     return 0;
868 }
869
870 /**************************************************************************
871  *                              MCICDA_SetDoor                  [internal]
872  */
873 static DWORD    MCICDA_SetDoor(UINT wDevID, BOOL open)
874 {
875     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
876     DWORD               br;
877
878     TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
879     
880     if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
881     
882     if (!DeviceIoControl(wmcda->handle, 
883                          (open) ? IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA,
884                          NULL, 0, NULL, 0, &br, NULL))
885         return MCIERR_HARDWARE;
886       
887     return 0;
888 }
889
890 /**************************************************************************
891  *                              MCICDA_Set                      [internal]
892  */
893 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
894 {
895     WINE_MCICDAUDIO*    wmcda = MCICDA_GetOpenDrv(wDevID);
896     
897     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
898     
899     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
900
901     if (dwFlags & MCI_SET_DOOR_OPEN) {
902         MCICDA_SetDoor(wDevID, TRUE);
903     }
904     if (dwFlags & MCI_SET_DOOR_CLOSED) {
905         MCICDA_SetDoor(wDevID, FALSE);
906     }
907
908     /* only functions which require valid lpParms below this line ! */
909     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
910     /*
911       TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
912       TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
913     */
914     if (dwFlags & MCI_SET_TIME_FORMAT) {
915         switch (lpParms->dwTimeFormat) {
916         case MCI_FORMAT_MILLISECONDS:
917             TRACE("MCI_FORMAT_MILLISECONDS !\n");
918             break;
919         case MCI_FORMAT_MSF:
920             TRACE("MCI_FORMAT_MSF !\n");
921             break;
922         case MCI_FORMAT_TMSF:
923             TRACE("MCI_FORMAT_TMSF !\n");
924             break;
925         default:
926             WARN("bad time format !\n");
927             return MCIERR_BAD_TIME_FORMAT;
928         }
929         wmcda->dwTimeFormat = lpParms->dwTimeFormat;
930     }
931     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
932     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
933     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
934     if (dwFlags & MCI_NOTIFY) {
935         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
936               lpParms->dwCallback);
937         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
938                         wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
939     }
940     return 0;
941 }
942
943 /**************************************************************************
944  *                      DriverProc (MCICDA.@)
945  */
946 LONG CALLBACK   MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
947                                       DWORD dwParam1, DWORD dwParam2)
948 {
949     switch(wMsg) {
950     case DRV_LOAD:              return 1;
951     case DRV_FREE:              return 1;
952     case DRV_OPEN:              return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
953     case DRV_CLOSE:             return MCICDA_drvClose(dwDevID);
954     case DRV_ENABLE:            return 1;       
955     case DRV_DISABLE:           return 1;
956     case DRV_QUERYCONFIGURE:    return 1;
957     case DRV_CONFIGURE:         MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
958     case DRV_INSTALL:           return DRVCNF_RESTART;
959     case DRV_REMOVE:            return DRVCNF_RESTART;
960     }
961     
962     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
963
964     switch (wMsg) {
965     case MCI_OPEN_DRIVER:       return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
966     case MCI_CLOSE_DRIVER:      return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
967     case MCI_GETDEVCAPS:        return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
968     case MCI_INFO:              return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
969     case MCI_STATUS:            return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
970     case MCI_SET:               return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
971     case MCI_PLAY:              return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
972     case MCI_STOP:              return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
973     case MCI_PAUSE:             return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
974     case MCI_RESUME:            return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
975     case MCI_SEEK:              return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
976     /* FIXME: I wonder if those two next items are really called ? */
977     case MCI_SET_DOOR_OPEN:     FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
978                                 return MCICDA_SetDoor(dwDevID, TRUE);
979     case MCI_SET_DOOR_CLOSED:   FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
980                                 return MCICDA_SetDoor(dwDevID, FALSE);
981     /* commands that should be supported */
982     case MCI_LOAD:              
983     case MCI_SAVE:              
984     case MCI_FREEZE:            
985     case MCI_PUT:               
986     case MCI_REALIZE:           
987     case MCI_UNFREEZE:          
988     case MCI_UPDATE:            
989     case MCI_WHERE:             
990     case MCI_STEP:              
991     case MCI_SPIN:              
992     case MCI_ESCAPE:            
993     case MCI_COPY:              
994     case MCI_CUT:               
995     case MCI_DELETE:            
996     case MCI_PASTE:             
997         FIXME("Unsupported yet command [%lu]\n", wMsg);
998         break;
999     /* commands that should report an error */
1000     case MCI_WINDOW:            
1001         TRACE("Unsupported command [%lu]\n", wMsg);
1002         break;
1003     case MCI_OPEN:
1004     case MCI_CLOSE:
1005         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1006         break;
1007     default:
1008         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
1009         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1010     }
1011     return MCIERR_UNRECOGNIZED_COMMAND;
1012 }
1013
1014 /*-----------------------------------------------------------------------*/