Small, suboptimal, fix for 32 bit cdaudio open routines. Needs proper
[wine] / multimedia / mcianim.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample MCI ANIMATION Wine Driver for Linux
4  *
5  * Copyright 1994 Martin Ayotte
6  */
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include "windows.h"
14 #include "user.h"
15 #include "driver.h"
16 #include "mmsystem.h"
17 #include "debug.h"
18
19 #define MAX_ANIMDRV             2
20
21 #define ANIMFRAMES_PERSEC       30
22 #define ANIMFRAMES_PERMIN       1800
23 #define SECONDS_PERMIN          60
24
25 typedef struct {
26         int             nUseCount;          /* Incremented for each shared open */
27         BOOL16          fShareable;         /* TRUE if first open was shareable */
28         WORD            wNotifyDeviceID;    /* MCI device ID with a pending notification */
29         HANDLE16        hCallback;          /* Callback handle for pending notification */
30         MCI_OPEN_PARMS16 openParms;
31         DWORD           dwTimeFormat;
32         int             mode;
33         UINT16          nCurTrack;
34         DWORD           dwCurFrame;
35         UINT16          nTracks;
36         DWORD           dwTotalLen;
37         LPDWORD         lpdwTrackLen;
38         LPDWORD         lpdwTrackPos;
39 } WINE_ANIM;
40
41 static WINE_ANIM        AnimDev[MAX_ANIMDRV];
42
43
44 /*-----------------------------------------------------------------------*/
45
46 /**************************************************************************
47  *                              ANIM_mciOpen                    [internal]
48  */
49 static DWORD ANIM_mciOpen(UINT16 wDevID, DWORD dwFlags, void* lp, BOOL32 is32)
50 {
51     DWORD               dwDeviceID;
52
53     TRACE(mcianim,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lp);
54     if (lp == NULL) return MCIERR_INTERNAL;
55     if (AnimDev[wDevID].nUseCount > 0) {
56         /* The driver already open on this channel */
57         /* If the driver was opened shareable before and this open specifies */
58         /* shareable then increment the use count */
59         if (AnimDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
60             ++AnimDev[wDevID].nUseCount;
61         else
62             return MCIERR_MUST_USE_SHAREABLE;
63     }
64     else {
65         AnimDev[wDevID].nUseCount = 1;
66         AnimDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
67     }
68
69     if (is32)   dwDeviceID = ((LPMCI_OPEN_PARMS32A)lp)->wDeviceID;
70     else        dwDeviceID = ((LPMCI_OPEN_PARMS16)lp)->wDeviceID;
71
72     TRACE(mcianim,"wDevID=%04X\n", wDevID);
73     /* FIXME this is not consistent with other implementations */
74     if (is32)   ((LPMCI_OPEN_PARMS32A)lp)->wDeviceID = wDevID;
75     else        ((LPMCI_OPEN_PARMS16)lp)->wDeviceID = wDevID;
76
77     /*TRACE(mcianim,"lpParms->wDevID=%04X\n", lpParms->wDeviceID);*/
78     if (dwFlags & MCI_OPEN_ELEMENT) {
79         LPSTR           lpstrElementName;
80
81         if (is32)       lpstrElementName = ((LPMCI_OPEN_PARMS32A)lp)->lpstrElementName;
82         else            lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(((LPMCI_OPEN_PARMS16)lp)->lpstrElementName);
83
84         TRACE(mcianim,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
85         if (lpstrElementName && strlen(lpstrElementName) > 0) {
86         }
87         FIXME(mcianim, "element is not opened\n");
88     }
89     memcpy(&AnimDev[wDevID].openParms, lp, sizeof(MCI_OPEN_PARMS16));
90     AnimDev[wDevID].wNotifyDeviceID = dwDeviceID;
91     AnimDev[wDevID].mode = 0;
92     AnimDev[wDevID].dwTimeFormat = MCI_FORMAT_TMSF;
93     AnimDev[wDevID].nCurTrack = 0;
94     AnimDev[wDevID].nTracks = 0;
95     AnimDev[wDevID].dwTotalLen = 0;
96     AnimDev[wDevID].lpdwTrackLen = NULL;
97     AnimDev[wDevID].lpdwTrackPos = NULL;
98     /*
99       Moved to mmsystem.c mciOpen routine 
100       
101       if (dwFlags & MCI_NOTIFY) {
102       TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
103       lpParms->dwCallback);
104       mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
105       AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
106       }
107     */
108     return 0;
109 }
110
111 /**************************************************************************
112  *                              ANIM_mciClose           [internal]
113  */
114 static DWORD ANIM_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
115 {
116     TRACE(mcianim,"(%u, %08lX, %p);\n", 
117           wDevID, dwParam, lpParms);
118     if (AnimDev[wDevID].lpdwTrackLen != NULL) free(AnimDev[wDevID].lpdwTrackLen);
119     if (AnimDev[wDevID].lpdwTrackPos != NULL) free(AnimDev[wDevID].lpdwTrackPos);
120     return 0;
121 }
122
123 /**************************************************************************
124  *                              ANIM_mciGetDevCaps      [internal]
125  */
126 static DWORD ANIM_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
127                                 LPMCI_GETDEVCAPS_PARMS lpParms)
128 {
129     TRACE(mcianim,"(%u, %08lX, %p);\n", 
130           wDevID, dwFlags, lpParms);
131     if (lpParms == NULL) return MCIERR_INTERNAL;
132     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
133         TRACE(mcianim, "MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n",
134               lpParms->dwItem);
135         switch(lpParms->dwItem) {
136         case MCI_GETDEVCAPS_CAN_RECORD:
137             lpParms->dwReturn = FALSE;
138             break;
139         case MCI_GETDEVCAPS_HAS_AUDIO:
140             lpParms->dwReturn = FALSE;
141             break;
142         case MCI_GETDEVCAPS_HAS_VIDEO:
143             lpParms->dwReturn = FALSE;
144             break;
145         case MCI_GETDEVCAPS_DEVICE_TYPE:
146             lpParms->dwReturn = MCI_DEVTYPE_ANIMATION;
147             break;
148         case MCI_GETDEVCAPS_USES_FILES:
149             lpParms->dwReturn = TRUE;
150             break;
151         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
152             lpParms->dwReturn = FALSE;
153             break;
154         case MCI_GETDEVCAPS_CAN_EJECT:
155             lpParms->dwReturn = TRUE;
156             break;
157         case MCI_GETDEVCAPS_CAN_PLAY:
158             lpParms->dwReturn = FALSE;
159             break;
160         case MCI_GETDEVCAPS_CAN_SAVE:
161             lpParms->dwReturn = FALSE;
162             break;
163         default:
164             return MCIERR_UNRECOGNIZED_COMMAND;
165         }
166     }
167     TRACE(mcianim, "lpParms->dwReturn=%08lX;\n", 
168           lpParms->dwReturn);
169     return 0;
170 }
171
172
173 /**************************************************************************
174  *                              ANIM_CalcTime                   [internal]
175  */
176 static DWORD ANIM_CalcTime(UINT16 wDevID, DWORD dwFormatType, DWORD dwFrame)
177 {
178     DWORD       dwTime = 0;
179     UINT16      wTrack;
180     UINT16      wMinutes;
181     UINT16      wSeconds;
182     UINT16      wFrames;
183     TRACE(mcianim,"(%u, %08lX, %lu);\n", 
184           wDevID, dwFormatType, dwFrame);
185     
186     switch (dwFormatType) {
187     case MCI_FORMAT_MILLISECONDS:
188         dwTime = dwFrame / ANIMFRAMES_PERSEC * 1000;
189         TRACE(mcianim, "MILLISECONDS %lu\n", dwTime);
190         break;
191     case MCI_FORMAT_MSF:
192         wMinutes = dwFrame / ANIMFRAMES_PERMIN;
193         wSeconds = (dwFrame - ANIMFRAMES_PERMIN * wMinutes) / ANIMFRAMES_PERSEC;
194         wFrames = dwFrame - ANIMFRAMES_PERMIN * wMinutes - 
195             ANIMFRAMES_PERSEC * wSeconds;
196         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
197         TRACE(mcianim,"MSF %02u:%02u:%02u -> dwTime=%lu\n",
198               wMinutes, wSeconds, wFrames, dwTime);
199         break;
200     default:
201         /* unknown format ! force TMSF ! ... */
202         dwFormatType = MCI_FORMAT_TMSF;
203     case MCI_FORMAT_TMSF:
204         for (wTrack = 0; wTrack < AnimDev[wDevID].nTracks; wTrack++) {
205             /*                          dwTime += AnimDev[wDevID].lpdwTrackLen[wTrack - 1];
206                                         TRACE(mcianim, "Adding trk#%u curpos=%u \n", dwTime);
207                                         if (dwTime >= dwFrame) break; */
208             if (AnimDev[wDevID].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
209         }
210         wMinutes = dwFrame / ANIMFRAMES_PERMIN;
211         wSeconds = (dwFrame - ANIMFRAMES_PERMIN * wMinutes) / ANIMFRAMES_PERSEC;
212         wFrames = dwFrame - ANIMFRAMES_PERMIN * wMinutes - 
213             ANIMFRAMES_PERSEC * wSeconds;
214         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
215         TRACE(mcianim, "%02u-%02u:%02u:%02u\n",
216               wTrack, wMinutes, wSeconds, wFrames);
217         break;
218     }
219     return dwTime;
220 }
221
222
223 /**************************************************************************
224  *                              ANIM_CalcFrame                  [internal]
225  */
226 static DWORD ANIM_CalcFrame(UINT16 wDevID, DWORD dwFormatType, DWORD dwTime)
227 {
228     DWORD       dwFrame = 0;
229     UINT16      wTrack;
230     TRACE(mcianim,"(%u, %08lX, %lu);\n", 
231           wDevID, dwFormatType, dwTime);
232     
233     switch (dwFormatType) {
234     case MCI_FORMAT_MILLISECONDS:
235         dwFrame = dwTime * ANIMFRAMES_PERSEC / 1000;
236         TRACE(mcianim, "MILLISECONDS %lu\n", dwFrame);
237         break;
238     case MCI_FORMAT_MSF:
239         TRACE(mcianim, "MSF %02u:%02u:%02u\n",
240               MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), 
241               MCI_MSF_FRAME(dwTime));
242         dwFrame += ANIMFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
243         dwFrame += ANIMFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
244         dwFrame += MCI_MSF_FRAME(dwTime);
245         break;
246     default:
247         /* unknown format ! force TMSF ! ... */
248         dwFormatType = MCI_FORMAT_TMSF;
249     case MCI_FORMAT_TMSF:
250         wTrack = MCI_TMSF_TRACK(dwTime);
251         TRACE(mcianim, "TMSF %02u-%02u:%02u:%02u\n",
252               MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime), 
253               MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
254         TRACE(mcianim, "TMSF trackpos[%u]=%lu\n",
255               wTrack, AnimDev[wDevID].lpdwTrackPos[wTrack - 1]);
256         dwFrame = AnimDev[wDevID].lpdwTrackPos[wTrack - 1];
257         dwFrame += ANIMFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
258         dwFrame += ANIMFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
259         dwFrame += MCI_TMSF_FRAME(dwTime);
260         break;
261     }
262     return dwFrame;
263 }
264
265
266 /**************************************************************************
267  *                              ANIM_mciInfo                    [internal]
268  */
269 static DWORD ANIM_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
270 {
271     TRACE(mcianim,"(%u, %08lX, %p);\n", 
272           wDevID, dwFlags, lpParms);
273     if (lpParms == NULL) return MCIERR_INTERNAL;
274     lpParms->lpstrReturn = NULL;
275     switch(dwFlags) {
276     case MCI_INFO_PRODUCT:
277         lpParms->lpstrReturn = "Linux ANIMATION 0.5";
278         break;
279     case MCI_INFO_FILE:
280         lpParms->lpstrReturn = 
281             (LPSTR)AnimDev[wDevID].openParms.lpstrElementName;
282         break;
283     case MCI_ANIM_INFO_TEXT:
284         lpParms->lpstrReturn = "Animation Window";
285         break;
286     default:
287         return MCIERR_UNRECOGNIZED_COMMAND;
288     }
289     if (lpParms->lpstrReturn != NULL)
290         lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
291     else
292         lpParms->dwRetSize = 0;
293     return 0;
294 }
295
296 /**************************************************************************
297  *                              ANIM_mciStatus          [internal]
298  */
299 static DWORD ANIM_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
300 {
301     TRACE(mcianim,"(%u, %08lX, %p);\n", 
302           wDevID, dwFlags, lpParms);
303     if (lpParms == NULL) return MCIERR_INTERNAL;
304     if (dwFlags & MCI_NOTIFY) {
305         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
306               lpParms->dwCallback);
307         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
308                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
309     }
310     if (dwFlags & MCI_STATUS_ITEM) {
311         switch(lpParms->dwItem) {
312         case MCI_STATUS_CURRENT_TRACK:
313             lpParms->dwReturn = AnimDev[wDevID].nCurTrack;
314             TRACE(mcianim,"CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
315             return 0;
316         case MCI_STATUS_LENGTH:
317             if (dwFlags & MCI_TRACK) {
318                 TRACE(mcianim,"MCI_TRACK #%lu LENGTH=??? !\n",
319                       lpParms->dwTrack);
320                 if (lpParms->dwTrack > AnimDev[wDevID].nTracks)
321                     return MCIERR_OUTOFRANGE;
322                 lpParms->dwReturn = AnimDev[wDevID].lpdwTrackLen[lpParms->dwTrack];
323             }
324             else
325                 lpParms->dwReturn = AnimDev[wDevID].dwTotalLen;
326             lpParms->dwReturn = ANIM_CalcTime(wDevID, 
327                                               AnimDev[wDevID].dwTimeFormat, lpParms->dwReturn);
328             TRACE(mcianim,"LENGTH=%lu !\n", lpParms->dwReturn);
329             return 0;
330         case MCI_STATUS_MODE:
331             lpParms->dwReturn = AnimDev[wDevID].mode;
332             TRACE(mcianim,"MCI_STATUS_MODE=%08lX !\n",
333                   lpParms->dwReturn);
334             return 0;
335         case MCI_STATUS_MEDIA_PRESENT:
336             lpParms->dwReturn = TRUE;
337             TRACE(mcianim,"MCI_STATUS_MEDIA_PRESENT !\n");
338             return 0;
339         case MCI_STATUS_NUMBER_OF_TRACKS:
340             lpParms->dwReturn = 1;
341             TRACE(mcianim,"MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n",
342                   lpParms->dwReturn);
343             if (lpParms->dwReturn == (WORD)-1) return MCIERR_INTERNAL;
344             return 0;
345         case MCI_STATUS_POSITION:
346             lpParms->dwReturn = AnimDev[wDevID].dwCurFrame;
347             if (dwFlags & MCI_STATUS_START) {
348                 lpParms->dwReturn = 0;
349                 TRACE(mcianim,"get MCI_STATUS_START !\n");
350             }
351             if (dwFlags & MCI_TRACK) {
352                 if (lpParms->dwTrack > AnimDev[wDevID].nTracks)
353                     return MCIERR_OUTOFRANGE;
354                 lpParms->dwReturn = AnimDev[wDevID].lpdwTrackPos[lpParms->dwTrack - 1];
355                 TRACE(mcianim,"get MCI_TRACK #%lu !\n", lpParms->dwTrack);
356             }
357             lpParms->dwReturn = ANIM_CalcTime(wDevID, 
358                                               AnimDev[wDevID].dwTimeFormat, lpParms->dwReturn);
359             TRACE(mcianim,"MCI_STATUS_POSITION=%08lX !\n",
360                   lpParms->dwReturn);
361             return 0;
362         case MCI_STATUS_READY:
363             TRACE(mcianim,"MCI_STATUS_READY !\n");
364             lpParms->dwReturn = TRUE;
365             return 0;
366         case MCI_STATUS_TIME_FORMAT:
367             TRACE(mcianim,"MCI_STATUS_TIME_FORMAT !\n");
368             lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
369             return 0;
370         default:
371             WARN(mcianim,"Unknown command %08lX !\n", lpParms->dwItem);
372             return MCIERR_UNRECOGNIZED_COMMAND;
373         }
374     }
375     WARN(mcianim,"Not MCI_STATUS_ITEM !\n");
376     return 0;
377 }
378
379
380 /**************************************************************************
381  *                              ANIM_mciPlay                    [internal]
382  */
383 static DWORD ANIM_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
384 {
385     int         start, end;
386     TRACE(mcianim,"(%u, %08lX, %p);\n", 
387           wDevID, dwFlags, lpParms);
388     if (lpParms == NULL) return MCIERR_INTERNAL;
389     start = 0;          end = AnimDev[wDevID].dwTotalLen;
390     AnimDev[wDevID].nCurTrack = 1;
391     if (dwFlags & MCI_FROM) {
392         start = ANIM_CalcFrame(wDevID, 
393                                AnimDev[wDevID].dwTimeFormat, lpParms->dwFrom); 
394         TRACE(mcianim,"MCI_FROM=%08lX -> %u \n",
395               lpParms->dwFrom, start);
396     }
397     if (dwFlags & MCI_TO) {
398         end = ANIM_CalcFrame(wDevID, 
399                              AnimDev[wDevID].dwTimeFormat, lpParms->dwTo);
400         TRACE(mcianim, "MCI_TO=%08lX -> %u \n",
401               lpParms->dwTo, end);
402     }
403     AnimDev[wDevID].mode = MCI_MODE_PLAY;
404     if (dwFlags & MCI_NOTIFY) {
405         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
406               lpParms->dwCallback);
407         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
408                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
409     }
410     return 0;
411 }
412
413 /**************************************************************************
414  *                              ANIM_mciStop                    [internal]
415  */
416 static DWORD ANIM_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
417 {
418     TRACE(mcianim,"(%u, %08lX, %p);\n", 
419           wDevID, dwFlags, lpParms);
420     if (lpParms == NULL) return MCIERR_INTERNAL;
421     AnimDev[wDevID].mode = MCI_MODE_STOP;
422     if (dwFlags & MCI_NOTIFY) {
423         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
424               lpParms->dwCallback);
425         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
426                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
427     }
428     return 0;
429 }
430
431 /**************************************************************************
432  *                              ANIM_mciPause           [internal]
433  */
434 static DWORD ANIM_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
435 {
436     TRACE(mcianim,"(%u, %08lX, %p);\n", 
437           wDevID, dwFlags, lpParms);
438     if (lpParms == NULL) return MCIERR_INTERNAL;
439     AnimDev[wDevID].mode = MCI_MODE_PAUSE;
440     if (dwFlags & MCI_NOTIFY) {
441         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
442               lpParms->dwCallback);
443         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
444                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
445     }
446     return 0;
447 }
448
449 /**************************************************************************
450  *                              ANIM_mciResume          [internal]
451  */
452 static DWORD ANIM_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
453 {
454     TRACE(mcianim,"(%u, %08lX, %p);\n", 
455           wDevID, dwFlags, lpParms);
456     if (lpParms == NULL) return MCIERR_INTERNAL;
457     AnimDev[wDevID].mode = MCI_MODE_STOP;
458     if (dwFlags & MCI_NOTIFY) {
459         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
460               lpParms->dwCallback);
461         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
462                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
463     }
464     return 0;
465 }
466
467 /**************************************************************************
468  *                              ANIM_mciSeek                    [internal]
469  */
470 static DWORD ANIM_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
471 {
472     DWORD       dwRet;
473     MCI_PLAY_PARMS PlayParms;
474     TRACE(mcianim,"(%u, %08lX, %p);\n", 
475           wDevID, dwFlags, lpParms);
476     if (lpParms == NULL) return MCIERR_INTERNAL;
477     AnimDev[wDevID].mode = MCI_MODE_SEEK;
478     switch(dwFlags) {
479     case MCI_SEEK_TO_START:
480         PlayParms.dwFrom = 0;
481         break;
482     case MCI_SEEK_TO_END:
483         PlayParms.dwFrom = AnimDev[wDevID].dwTotalLen;
484         break;
485     case MCI_TO:
486         PlayParms.dwFrom = lpParms->dwTo;
487         break;
488     }
489     dwRet = ANIM_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &PlayParms);
490     if (dwRet != 0) return dwRet;
491     dwRet = ANIM_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&PlayParms);
492     if (dwFlags & MCI_NOTIFY) {
493         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
494               lpParms->dwCallback);
495         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
496                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
497     }
498     return dwRet;
499 }
500
501
502 /**************************************************************************
503  *                              ANIM_mciSet                     [internal]
504  */
505 static DWORD ANIM_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
506 {
507     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
508     if (lpParms == NULL) return MCIERR_INTERNAL;
509     /*
510       TRACE(mcianim,"(dwTimeFormat=%08lX)\n", lpParms->dwTimeFormat);
511       TRACE(mcianim,"(dwAudio=%08lX)\n", lpParms->dwAudio);
512     */
513     if (dwFlags & MCI_SET_TIME_FORMAT) {
514         switch (lpParms->dwTimeFormat) {
515         case MCI_FORMAT_MILLISECONDS:
516             TRACE(mcianim, "MCI_FORMAT_MILLISECONDS !\n");
517             break;
518         case MCI_FORMAT_MSF:
519             TRACE(mcianim,"MCI_FORMAT_MSF !\n");
520             break;
521         case MCI_FORMAT_TMSF:
522             TRACE(mcianim,"MCI_FORMAT_TMSF !\n");
523             break;
524         default:
525             WARN(mcianim,"Bad time format !\n");
526             return MCIERR_BAD_TIME_FORMAT;
527         }
528         AnimDev[wDevID].dwTimeFormat = lpParms->dwTimeFormat;
529     }
530     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
531     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
532     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
533     if (dwFlags & MCI_NOTIFY) {
534         TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
535               lpParms->dwCallback);
536         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
537                         AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
538     }
539     return 0;
540 }
541
542
543 /**************************************************************************
544  *                              ANIM_DriverProc16       [sample driver]
545  */
546 LONG ANIM_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
547                        DWORD dwParam1, DWORD dwParam2)
548 {
549     switch(wMsg) {
550     case DRV_LOAD:              return 1;
551     case DRV_FREE:              return 1;
552     case DRV_OPEN:
553     case MCI_OPEN_DRIVER:
554     case MCI_OPEN:              return ANIM_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2), FALSE);
555     case DRV_CLOSE:
556     case MCI_CLOSE_DRIVER:
557     case MCI_CLOSE:             return ANIM_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
558     case DRV_ENABLE:            return 1;
559     case DRV_DISABLE:           return 1;
560     case DRV_QUERYCONFIGURE:    return 1;
561     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
562     case DRV_INSTALL:           return DRVCNF_RESTART;
563     case DRV_REMOVE:            return DRVCNF_RESTART;
564     case MCI_GETDEVCAPS:        return ANIM_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
565     case MCI_INFO:              return ANIM_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
566     case MCI_STATUS:            return ANIM_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
567     case MCI_SET:               return ANIM_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
568     case MCI_PLAY:              return ANIM_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
569     case MCI_STOP:              return ANIM_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
570     case MCI_PAUSE:             return ANIM_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
571     case MCI_RESUME:            return ANIM_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
572     case MCI_SEEK:              return ANIM_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)PTR_SEG_TO_LIN(dwParam2));
573     default:                    return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
574     }
575 }
576 /**************************************************************************
577  *                              ANIM_DriverProc32               [sample driver]
578  */
579 LONG ANIM_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
580                        DWORD dwParam1, DWORD dwParam2)
581 {
582     switch(wMsg) {
583     case DRV_LOAD:              return 1;
584     case DRV_FREE:              return 1;
585     case DRV_OPEN:
586     case MCI_OPEN_DRIVER:
587     case MCI_OPEN:              return ANIM_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS32A)dwParam2, TRUE); 
588     case DRV_CLOSE:
589     case MCI_CLOSE_DRIVER:
590     case MCI_CLOSE:             return ANIM_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
591     case DRV_ENABLE:            return 1;
592     case DRV_DISABLE:           return 1;
593     case DRV_QUERYCONFIGURE:    return 1;
594     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
595     case DRV_INSTALL:           return DRVCNF_RESTART;
596     case DRV_REMOVE:            return DRVCNF_RESTART;
597     case MCI_GETDEVCAPS:        return ANIM_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
598     case MCI_INFO:              return ANIM_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
599     case MCI_STATUS:            return ANIM_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
600     case MCI_SET:               return ANIM_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
601     case MCI_PLAY:              return ANIM_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
602     case MCI_STOP:              return ANIM_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
603     case MCI_PAUSE:             return ANIM_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
604     case MCI_RESUME:            return ANIM_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
605     case MCI_SEEK:              return ANIM_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
606     default:                    return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
607     }
608 }
609
610
611 /*-----------------------------------------------------------------------*/