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