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