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