Changed CreateDirectory LastError returns to match Win32 (found out by
[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         CDAUDIO_mciStop(wDevID, 0, NULL);
240         CDAUDIO_Close(&wmcda->wcda);
241     }
242     wmcda->nUseCount--;
243     return 0;
244 }
245
246 /**************************************************************************
247  *                              CDAUDIO_mciGetDevCaps           [internal]
248  */
249 static DWORD CDAUDIO_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
250                                    LPMCI_GETDEVCAPS_PARMS lpParms)
251 {
252     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
253
254     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
255
256     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
257         TRACE(cdaudio, "MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
258
259         switch(lpParms->dwItem) {
260         case MCI_GETDEVCAPS_CAN_RECORD:
261             lpParms->dwReturn = FALSE;
262             break;
263         case MCI_GETDEVCAPS_HAS_AUDIO:
264             lpParms->dwReturn = TRUE;
265             break;
266         case MCI_GETDEVCAPS_HAS_VIDEO:
267             lpParms->dwReturn = FALSE;
268             break;
269         case MCI_GETDEVCAPS_DEVICE_TYPE:
270             lpParms->dwReturn = MCI_DEVTYPE_CD_AUDIO;
271             break;
272         case MCI_GETDEVCAPS_USES_FILES:
273             lpParms->dwReturn = FALSE;
274             break;
275         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
276             lpParms->dwReturn = FALSE;
277             break;
278         case MCI_GETDEVCAPS_CAN_EJECT:
279             lpParms->dwReturn = TRUE;
280             break;
281         case MCI_GETDEVCAPS_CAN_PLAY:
282             lpParms->dwReturn = TRUE;
283             break;
284         case MCI_GETDEVCAPS_CAN_SAVE:
285             lpParms->dwReturn = FALSE;
286             break;
287         default:
288             return MCIERR_UNRECOGNIZED_COMMAND;
289         }
290     }
291     TRACE(cdaudio, "lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
292     return 0;
293 }
294
295 /**************************************************************************
296  *                              CDAUDIO_mciInfo                 [internal]
297  */
298 static DWORD CDAUDIO_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
299 {
300     DWORD               ret = 0;
301     LPSTR               str = 0;
302     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
303     
304     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
305     
306     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
307         ret = MCIERR_NULL_PARAMETER_BLOCK;
308     } else if (wmcda == NULL) {
309         ret = MCIERR_INVALID_DEVICE_ID;
310     } else {
311         TRACE(cdaudio, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
312         
313         switch(dwFlags) {
314         case MCI_INFO_PRODUCT:
315             str = "Wine's audio CD";
316             break;
317         default:
318             WARN(cdaudio, "Don't know this info command (%lu)\n", dwFlags);
319             ret = MCIERR_UNRECOGNIZED_COMMAND;
320         }
321     }
322     if (str) {
323         ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
324     } else {
325         lpParms->lpstrReturn[0] = 0;
326     }
327     
328     return ret;
329 }
330
331 /**************************************************************************
332  *                              CDAUDIO_mciStatus               [internal]
333  */
334 static DWORD CDAUDIO_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
335 {
336     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
337     DWORD               ret = 0;
338     
339     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
340     
341     if (lpParms == NULL) {
342         ret = MCIERR_NULL_PARAMETER_BLOCK;
343     } else if (wmcda == NULL) {
344         ret = MCIERR_INVALID_DEVICE_ID;
345     } else {
346         if (dwFlags & MCI_NOTIFY) {
347             TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
348             mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
349                               wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
350         }
351         if (dwFlags & MCI_STATUS_ITEM) {
352             switch (lpParms->dwItem) {
353             case MCI_STATUS_CURRENT_TRACK:
354                 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) {
355                     return CDAUDIO_mciGetError(wmcda);
356                 }
357                 lpParms->dwReturn = wmcda->wcda.nCurTrack;
358                 TRACE(cdaudio,"CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
359                 return 0;
360             case MCI_STATUS_LENGTH:
361                 if (wmcda->wcda.nTracks == 0) {
362                     if (!CDAUDIO_GetTracksInfo(&wmcda->wcda)) {
363                         WARN(cdaudio, "error reading TracksInfo !\n");
364                         return CDAUDIO_mciGetError(wmcda);
365                     }
366                 }
367                 if (dwFlags & MCI_TRACK) {
368                     TRACE(cdaudio,"MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
369                     if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
370                         return MCIERR_OUTOFRANGE;
371                     lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
372                 } else {
373                     lpParms->dwReturn = wmcda->wcda.dwTotalLen;
374                 }
375                 lpParms->dwReturn = CDAUDIO_CalcTime(wmcda, lpParms->dwReturn);
376                 TRACE(cdaudio,"LENGTH=%lu !\n", lpParms->dwReturn);
377                 return 0;
378             case MCI_STATUS_MODE:
379                 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) 
380                     return CDAUDIO_mciGetError(wmcda);
381                 lpParms->dwReturn = CDAUDIO_mciMode(wmcda->wcda.cdaMode);
382                 if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
383                 TRACE(cdaudio,"MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
384                 return 0;
385             case MCI_STATUS_MEDIA_PRESENT:
386                 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) 
387                     return CDAUDIO_mciGetError(wmcda);
388                 lpParms->dwReturn = (wmcda->wcda.nTracks > 0) ? TRUE : FALSE;
389                 TRACE(cdaudio,"MCI_STATUS_MEDIA_PRESENT =%s!\n", lpParms->dwReturn ? "Y" : "N");
390                 return 0;
391             case MCI_STATUS_NUMBER_OF_TRACKS:
392                 lpParms->dwReturn = CDAUDIO_GetNumberOfTracks(&wmcda->wcda);
393                 TRACE(cdaudio,"MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
394                 if (lpParms->dwReturn == (WORD)-1) 
395                     return CDAUDIO_mciGetError(wmcda);
396                 return 0;
397             case MCI_STATUS_POSITION:
398                 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) 
399                     return CDAUDIO_mciGetError(wmcda);
400                 lpParms->dwReturn = wmcda->wcda.dwCurFrame;
401                 if (dwFlags & MCI_STATUS_START) {
402                     lpParms->dwReturn = wmcda->wcda.dwFirstOffset;
403                     TRACE(cdaudio,"get MCI_STATUS_START !\n");
404                 }
405                 if (dwFlags & MCI_TRACK) {
406                     if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
407                         return MCIERR_OUTOFRANGE;
408                     lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
409                     TRACE(cdaudio,"get MCI_TRACK #%lu !\n", lpParms->dwTrack);
410                 }
411                 lpParms->dwReturn = CDAUDIO_CalcTime(wmcda, lpParms->dwReturn);
412                 TRACE(cdaudio,"MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
413                 return 0;
414             case MCI_STATUS_READY:
415                 TRACE(cdaudio,"MCI_STATUS_READY !\n");
416                 lpParms->dwReturn = (wmcda->wcda.cdaMode != WINE_CDA_DONTKNOW && wmcda->wcda.cdaMode != WINE_CDA_NOTREADY);
417                 TRACE(cdaudio,"MCI_STATUS_READY=%ld!\n", lpParms->dwReturn);
418                 return 0;
419             case MCI_STATUS_TIME_FORMAT:
420                 lpParms->dwReturn = wmcda->dwTimeFormat;
421                 TRACE(cdaudio,"MCI_STATUS_TIME_FORMAT =%08lx!\n", lpParms->dwReturn);
422                 return 0;
423             case MCI_CDA_STATUS_TYPE_TRACK:
424                 if (!(dwFlags & MCI_TRACK)) 
425                     return MCIERR_MISSING_PARAMETER;
426                 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
427                     return MCIERR_OUTOFRANGE;
428                 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] & 
429                                      CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
430                 TRACE(cdaudio, "MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
431                 return 0;
432             default:
433                 WARN(cdaudio, "unknown command %08lX !\n", lpParms->dwItem);
434                 return MCIERR_UNRECOGNIZED_COMMAND;
435             }
436         }
437     }
438     WARN(cdaudio, "not MCI_STATUS_ITEM !\n");
439     return 0;
440 }
441
442 /**************************************************************************
443  *                              CDAUDIO_mciPlay                 [internal]
444  */
445 static DWORD CDAUDIO_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
446 {
447     int                 start, end;
448     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
449     DWORD               ret = 0;
450     
451     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
452     
453     if (lpParms == NULL) {
454         ret = MCIERR_NULL_PARAMETER_BLOCK;
455     } else if (wmcda == NULL) {
456         ret = MCIERR_INVALID_DEVICE_ID;
457     } else {
458         if (wmcda->wcda.nTracks == 0) {
459             if (!CDAUDIO_GetTracksInfo(&wmcda->wcda)) {
460                 WARN(cdaudio, "error reading TracksInfo !\n");
461                 return MCIERR_DRIVER_INTERNAL;
462             }
463         }
464         end = wmcda->wcda.dwTotalLen;
465         wmcda->wcda.nCurTrack = 1;
466         if (dwFlags & MCI_FROM) {
467             start = CDAUDIO_CalcFrame(wmcda, lpParms->dwFrom); 
468             TRACE(cdaudio,"MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
469         } else {
470             if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) return MCIERR_DRIVER_INTERNAL;
471             start = wmcda->wcda.dwCurFrame;
472         }
473         if (dwFlags & MCI_TO) {
474             end = CDAUDIO_CalcFrame(wmcda, lpParms->dwTo);
475             TRACE(cdaudio, "MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
476         }
477         end += wmcda->wcda.dwFirstOffset;
478         
479         if (CDAUDIO_Play(&wmcda->wcda, start, end) == -1)
480             return MCIERR_HARDWARE;
481         wmcda->mciMode = MCI_MODE_PLAY;
482         if (dwFlags & MCI_NOTIFY) {
483             TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
484             /*
485               mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
486               wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
487             */
488         }
489     }
490     return ret;
491 }
492
493 /**************************************************************************
494  *                              CDAUDIO_mciStop                 [internal]
495  */
496 static DWORD CDAUDIO_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
497 {
498     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
499     
500     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
501     
502     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
503     
504     if (CDAUDIO_Stop(&wmcda->wcda) == -1)
505         return MCIERR_HARDWARE;
506     wmcda->mciMode = MCI_MODE_STOP;
507     if (lpParms && (dwFlags & MCI_NOTIFY)) {
508         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
509         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
510                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
511     }
512     return 0;
513 }
514
515 /**************************************************************************
516  *                              CDAUDIO_mciPause                [internal]
517  */
518 static DWORD CDAUDIO_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
519 {
520     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
521     
522     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
523     
524     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
525     
526     if (CDAUDIO_Pause(&wmcda->wcda, 1) == -1)
527         return MCIERR_HARDWARE;
528     wmcda->mciMode = MCI_MODE_PAUSE;
529     if (lpParms && (dwFlags & MCI_NOTIFY)) {
530         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
531         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
532                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
533     }
534     return 0;
535 }
536
537 /**************************************************************************
538  *                              CDAUDIO_mciResume               [internal]
539  */
540 static DWORD CDAUDIO_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
541 {
542     WINE_MCICDAUDIO*    wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
543     
544     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
545     
546     if (wmcda == NULL)  return MCIERR_INVALID_DEVICE_ID;
547     
548     if (CDAUDIO_Pause(&wmcda->wcda, 0) == -1)
549         return MCIERR_HARDWARE;
550     wmcda->mciMode = MCI_MODE_STOP;
551     if (lpParms && (dwFlags & MCI_NOTIFY)) {
552         TRACE(cdaudio, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
553         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
554                           wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
555     }
556     return 0;
557 }
558
559 /**************************************************************************
560  *                              CDAUDIO_mciSeek                 [internal]
561  */
562 static DWORD CDAUDIO_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
563 {
564     DWORD       dwRet;
565     MCI_PLAY_PARMS      playParms;
566     
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         playParms.dwFrom = 0;
579         break;
580     case MCI_SEEK_TO_END:
581         TRACE(cdaudio, "Seeking to end\n");
582         playParms.dwFrom = wmcda->wcda.dwTotalLen;
583         break;
584     case MCI_TO:
585         TRACE(cdaudio, "Seeking to %lu\n", lpParms->dwTo);
586         playParms.dwFrom = lpParms->dwTo;
587         break;
588     default:
589         TRACE(cdaudio, "Seeking to ??=%lu\n", dwFlags);
590         return MCIERR_UNSUPPORTED_FUNCTION;
591     }
592     dwRet = CDAUDIO_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &playParms);
593     if (dwRet != 0) return dwRet;
594     dwRet = CDAUDIO_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&playParms);
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 dwRet;
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_DriverProc32         [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 /*-----------------------------------------------------------------------*/