- Applied to all MCI drivers Dmitry's fix for MCI_STATUS_TIME_FORMAT
[wine.git] / dlls / winmm / mcicda / mcicda.c
blob3be9a69b0f9d1d73b216108fdd2bd04d7b02a8a7
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 <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "ntstatus.h"
34 #include "wownt32.h"
35 #include "mmddk.h"
36 #include "winioctl.h"
37 #include "ntddstor.h"
38 #include "ntddcdrm.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mcicda);
43 #define CDFRAMES_PERSEC 75
44 #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
45 #define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
46 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
48 typedef struct {
49 UINT wDevID;
50 int nUseCount; /* Incremented for each shared open */
51 BOOL fShareable; /* TRUE if first open was shareable */
52 WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
53 HANDLE hCallback; /* Callback handle for pending notification */
54 DWORD dwTimeFormat;
55 HANDLE handle;
56 } WINE_MCICDAUDIO;
58 /*-----------------------------------------------------------------------*/
60 /**************************************************************************
61 * MCICDA_drvOpen [internal]
63 static DWORD MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
65 WINE_MCICDAUDIO* wmcda;
67 if (!modp) return 0xFFFFFFFF;
69 wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCICDAUDIO));
71 if (!wmcda)
72 return 0;
74 wmcda->wDevID = modp->wDeviceID;
75 mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
76 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
77 modp->wType = MCI_DEVTYPE_CD_AUDIO;
78 return modp->wDeviceID;
81 /**************************************************************************
82 * MCICDA_drvClose [internal]
84 static DWORD MCICDA_drvClose(DWORD dwDevID)
86 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
88 if (wmcda) {
89 HeapFree(GetProcessHeap(), 0, wmcda);
90 mciSetDriverData(dwDevID, 0);
92 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
95 /**************************************************************************
96 * MCICDA_GetOpenDrv [internal]
98 static WINE_MCICDAUDIO* MCICDA_GetOpenDrv(UINT wDevID)
100 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
102 if (wmcda == NULL || wmcda->nUseCount == 0) {
103 WARN("Invalid wDevID=%u\n", wDevID);
104 return 0;
106 return wmcda;
109 /**************************************************************************
110 * MCICDA_GetStatus [internal]
112 static DWORD MCICDA_GetStatus(WINE_MCICDAUDIO* wmcda)
114 CDROM_SUB_Q_DATA_FORMAT fmt;
115 SUB_Q_CHANNEL_DATA data;
116 DWORD br;
117 DWORD mode = MCI_MODE_NOT_READY;
119 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
120 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
121 &data, sizeof(data), &br, NULL)) {
122 if (GetLastError() == STATUS_NO_MEDIA_IN_DEVICE) mode = MCI_MODE_OPEN;
123 } else {
124 switch (data.CurrentPosition.Header.AudioStatus)
126 case AUDIO_STATUS_IN_PROGRESS: mode = MCI_MODE_PLAY; break;
127 case AUDIO_STATUS_PAUSED: mode = MCI_MODE_PAUSE; break;
128 case AUDIO_STATUS_NO_STATUS:
129 case AUDIO_STATUS_PLAY_COMPLETE: mode = MCI_MODE_STOP; break;
130 case AUDIO_STATUS_PLAY_ERROR:
131 case AUDIO_STATUS_NOT_SUPPORTED:
132 default:
133 break;
136 return mode;
139 /**************************************************************************
140 * MCICDA_GetError [internal]
142 static int MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
144 switch (GetLastError())
146 case STATUS_NO_MEDIA_IN_DEVICE: return MCIERR_DEVICE_NOT_READY;
147 case STATUS_IO_DEVICE_ERROR: return MCIERR_HARDWARE;
148 default:
149 FIXME("Unknown mode %lx\n", GetLastError());
151 return MCIERR_DRIVER_INTERNAL;
154 /**************************************************************************
155 * MCICDA_CalcFrame [internal]
157 static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
159 DWORD dwFrame = 0;
160 UINT wTrack;
161 CDROM_TOC toc;
162 DWORD br;
163 BYTE* addr;
165 TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
167 switch (wmcda->dwTimeFormat) {
168 case MCI_FORMAT_MILLISECONDS:
169 dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
170 TRACE("MILLISECONDS %lu\n", dwFrame);
171 break;
172 case MCI_FORMAT_MSF:
173 TRACE("MSF %02u:%02u:%02u\n",
174 MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
175 dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
176 dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
177 dwFrame += MCI_MSF_FRAME(dwTime);
178 break;
179 case MCI_FORMAT_TMSF:
180 default: /* unknown format ! force TMSF ! ... */
181 wTrack = MCI_TMSF_TRACK(dwTime);
182 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
183 &toc, sizeof(toc), &br, NULL))
184 return 0;
185 if (wTrack < toc.FirstTrack || wTrack > toc.LastTrack)
186 return 0;
187 TRACE("MSF %02u-%02u:%02u:%02u\n",
188 MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
189 MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
190 addr = toc.TrackData[wTrack - toc.FirstTrack].Address;
191 TRACE("TMSF trackpos[%u]=%d:%d:%d\n",
192 wTrack, addr[1], addr[2], addr[3]);
193 dwFrame = CDFRAMES_PERMIN * (addr[1] + MCI_TMSF_MINUTE(dwTime)) +
194 CDFRAMES_PERSEC * (addr[2] + MCI_TMSF_SECOND(dwTime)) +
195 addr[3] + MCI_TMSF_FRAME(dwTime);
196 break;
198 return dwFrame;
201 /**************************************************************************
202 * MCICDA_CalcTime [internal]
204 static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LPDWORD lpRet)
206 DWORD dwTime = 0;
207 UINT wTrack;
208 UINT wMinutes;
209 UINT wSeconds;
210 UINT wFrames;
211 CDROM_TOC toc;
212 DWORD br;
214 TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);
216 switch (tf) {
217 case MCI_FORMAT_MILLISECONDS:
218 dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
219 TRACE("MILLISECONDS %lu\n", dwTime);
220 *lpRet = 0;
221 break;
222 case MCI_FORMAT_MSF:
223 wMinutes = dwFrame / CDFRAMES_PERMIN;
224 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
225 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
226 dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
227 TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
228 wMinutes, wSeconds, wFrames, dwTime);
229 *lpRet = MCI_COLONIZED3_RETURN;
230 break;
231 case MCI_FORMAT_TMSF:
232 default: /* unknown format ! force TMSF ! ... */
233 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
234 &toc, sizeof(toc), &br, NULL))
235 return 0;
236 if (dwFrame < FRAME_OF_TOC(toc, toc.FirstTrack) ||
237 dwFrame > FRAME_OF_TOC(toc, toc.LastTrack + 1)) {
238 ERR("Out of range value %lu [%u,%u]\n",
239 dwFrame, FRAME_OF_TOC(toc, toc.FirstTrack),
240 FRAME_OF_TOC(toc, toc.LastTrack + 1));
241 *lpRet = 0;
242 return 0;
244 for (wTrack = toc.FirstTrack; wTrack <= toc.LastTrack; wTrack++) {
245 if (FRAME_OF_TOC(toc, wTrack) > dwFrame)
246 break;
248 wTrack--;
249 dwFrame -= FRAME_OF_TOC(toc, wTrack);
250 wMinutes = dwFrame / CDFRAMES_PERMIN;
251 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
252 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
253 dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
254 TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
255 *lpRet = MCI_COLONIZED4_RETURN;
256 break;
258 return dwTime;
261 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
262 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
264 /**************************************************************************
265 * MCICDA_Open [internal]
267 static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
269 DWORD dwDeviceID;
270 DWORD ret = MCIERR_HARDWARE;
271 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
272 char root[7];
273 int count;
274 char drive = 0;
276 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
278 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
279 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
281 dwDeviceID = lpOpenParms->wDeviceID;
283 if (wmcda->nUseCount > 0) {
284 /* The driver is already open on this channel */
285 /* If the driver was opened shareable before and this open specifies */
286 /* shareable then increment the use count */
287 if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
288 ++wmcda->nUseCount;
289 else
290 return MCIERR_MUST_USE_SHAREABLE;
291 } else {
292 wmcda->nUseCount = 1;
293 wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
295 if (dwFlags & MCI_OPEN_ELEMENT) {
296 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
297 WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort\n", (DWORD)lpOpenParms->lpstrElementName);
298 return MCIERR_NO_ELEMENT_ALLOWED;
300 if (!isalpha(lpOpenParms->lpstrElementName[0]) || lpOpenParms->lpstrElementName[1] != ':' ||
301 lpOpenParms->lpstrElementName[2])
303 WARN("MCI_OPEN_ELEMENT unsupported format: %s\n", lpOpenParms->lpstrElementName);
304 ret = MCIERR_NO_ELEMENT_ALLOWED;
305 goto the_error;
307 drive = toupper(lpOpenParms->lpstrElementName[0]);
308 strcpy(root, "A:\\");
309 root[0] = drive;
310 if (GetDriveTypeA(root) != DRIVE_CDROM)
312 ret = MCIERR_INVALID_DEVICE_NAME;
313 goto the_error;
316 else
318 /* drive letter isn't passed... get the dwDeviceID'th cdrom in the system */
319 strcpy(root, "A:\\");
320 for (count = 0; root[0] <= 'Z'; root[0]++)
322 if (GetDriveTypeA(root) == DRIVE_CDROM && ++count >= dwDeviceID)
324 drive = root[0];
325 break;
328 if (!drive)
330 ret = MCIERR_INVALID_DEVICE_ID;
331 goto the_error;
335 wmcda->wNotifyDeviceID = dwDeviceID;
336 wmcda->dwTimeFormat = MCI_FORMAT_MSF;
338 /* now, open the handle */
339 strcpy(root, "\\\\.\\A:");
340 root[4] = drive;
341 wmcda->handle = CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
342 if (wmcda->handle != INVALID_HANDLE_VALUE)
343 return 0;
345 the_error:
346 --wmcda->nUseCount;
347 return ret;
350 /**************************************************************************
351 * MCICDA_Close [internal]
353 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
355 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
357 TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
359 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
361 if (--wmcda->nUseCount == 0) {
362 CloseHandle(wmcda->handle);
364 return 0;
367 /**************************************************************************
368 * MCICDA_GetDevCaps [internal]
370 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags,
371 LPMCI_GETDEVCAPS_PARMS lpParms)
373 DWORD ret = 0;
375 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
377 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
379 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
380 TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
382 switch (lpParms->dwItem) {
383 case MCI_GETDEVCAPS_CAN_RECORD:
384 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
385 ret = MCI_RESOURCE_RETURNED;
386 break;
387 case MCI_GETDEVCAPS_HAS_AUDIO:
388 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
389 ret = MCI_RESOURCE_RETURNED;
390 break;
391 case MCI_GETDEVCAPS_HAS_VIDEO:
392 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
393 ret = MCI_RESOURCE_RETURNED;
394 break;
395 case MCI_GETDEVCAPS_DEVICE_TYPE:
396 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
397 ret = MCI_RESOURCE_RETURNED;
398 break;
399 case MCI_GETDEVCAPS_USES_FILES:
400 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
401 ret = MCI_RESOURCE_RETURNED;
402 break;
403 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
404 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
405 ret = MCI_RESOURCE_RETURNED;
406 break;
407 case MCI_GETDEVCAPS_CAN_EJECT:
408 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
409 ret = MCI_RESOURCE_RETURNED;
410 break;
411 case MCI_GETDEVCAPS_CAN_PLAY:
412 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
413 ret = MCI_RESOURCE_RETURNED;
414 break;
415 case MCI_GETDEVCAPS_CAN_SAVE:
416 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
417 ret = MCI_RESOURCE_RETURNED;
418 break;
419 default:
420 ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
421 return MCIERR_UNRECOGNIZED_COMMAND;
423 } else {
424 TRACE("No GetDevCaps-Item !\n");
425 return MCIERR_UNRECOGNIZED_COMMAND;
427 TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
428 return ret;
431 static DWORD CDROM_Audio_GetSerial(CDROM_TOC* toc)
433 unsigned long serial = 0;
434 int i;
435 WORD wMagic;
436 DWORD dwStart, dwEnd;
439 * wMagic collects the wFrames from track 1
440 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
441 * frames.
442 * There it is collected for correcting the serial when there are less than
443 * 3 tracks.
445 wMagic = toc->TrackData[0].Address[3];
446 dwStart = FRAME_OF_TOC(*toc, toc->FirstTrack);
448 for (i = 0; i <= toc->LastTrack - toc->FirstTrack; i++) {
449 serial += (toc->TrackData[i].Address[1] << 16) |
450 (toc->TrackData[i].Address[2] << 8) | toc->TrackData[i].Address[3];
452 dwEnd = FRAME_OF_TOC(*toc, toc->LastTrack + 1);
454 if (toc->LastTrack - toc->FirstTrack + 1 < 3)
455 serial += wMagic + (dwEnd - dwStart);
457 return serial;
461 /**************************************************************************
462 * MCICDA_Info [internal]
464 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
466 LPCSTR str = NULL;
467 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
468 DWORD ret = 0;
469 char buffer[16];
471 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
473 if (lpParms == NULL || lpParms->lpstrReturn == NULL)
474 return MCIERR_NULL_PARAMETER_BLOCK;
475 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
477 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
479 if (dwFlags & MCI_INFO_PRODUCT) {
480 str = "Wine's audio CD";
481 } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
482 ret = MCIERR_NO_IDENTITY;
483 } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
484 DWORD res = 0;
485 CDROM_TOC toc;
486 DWORD br;
488 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
489 &toc, sizeof(toc), &br, NULL)) {
490 return MCICDA_GetError(wmcda);
493 res = CDROM_Audio_GetSerial(&toc);
494 sprintf(buffer, "%lu", res);
495 str = buffer;
496 } else {
497 WARN("Don't know this info command (%lu)\n", dwFlags);
498 ret = MCIERR_UNRECOGNIZED_COMMAND;
500 if (str) {
501 if (lpParms->dwRetSize <= strlen(str)) {
502 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
503 ret = MCIERR_PARAM_OVERFLOW;
504 } else {
505 strcpy(lpParms->lpstrReturn, str);
507 } else {
508 *lpParms->lpstrReturn = 0;
510 TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
511 return ret;
514 /**************************************************************************
515 * MCICDA_Status [internal]
517 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
519 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
520 DWORD idx;
521 DWORD ret = 0;
522 CDROM_SUB_Q_DATA_FORMAT fmt;
523 SUB_Q_CHANNEL_DATA data;
524 CDROM_TOC toc;
525 DWORD br;
527 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
529 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
530 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
532 if (dwFlags & MCI_NOTIFY) {
533 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
534 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
535 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
537 if (dwFlags & MCI_STATUS_ITEM) {
538 TRACE("dwItem = %lx\n", lpParms->dwItem);
539 switch (lpParms->dwItem) {
540 case MCI_STATUS_CURRENT_TRACK:
541 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
542 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
543 &data, sizeof(data), &br, NULL))
545 return MCICDA_GetError(wmcda);
547 lpParms->dwReturn = data.CurrentPosition.TrackNumber;
548 TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
549 break;
550 case MCI_STATUS_LENGTH:
551 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
552 &toc, sizeof(toc), &br, NULL)) {
553 WARN("error reading TOC !\n");
554 return MCICDA_GetError(wmcda);
556 if (dwFlags & MCI_TRACK) {
557 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
558 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
559 return MCIERR_OUTOFRANGE;
560 idx = lpParms->dwTrack - toc.FirstTrack;
561 lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack + 1) -
562 FRAME_OF_TOC(toc, lpParms->dwTrack);
563 /* Windows returns one frame less than the total track length for the
564 last track on the CD. See CDDB HOWTO. Verified on Win95OSR2. */
565 if (lpParms->dwTrack == toc.LastTrack)
566 lpParms->dwReturn--;
567 } else {
568 /* Sum of the lengths of all of the tracks. Inherits the
569 'off by one frame' behavior from the length of the last track.
570 See above comment. */
571 lpParms->dwReturn = FRAME_OF_TOC(toc, toc.LastTrack + 1) -
572 FRAME_OF_TOC(toc, toc.FirstTrack) - 1;
574 lpParms->dwReturn = MCICDA_CalcTime(wmcda,
575 (wmcda->dwTimeFormat == MCI_FORMAT_TMSF)
576 ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
577 lpParms->dwReturn,
578 &ret);
579 TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
580 break;
581 case MCI_STATUS_MODE:
582 lpParms->dwReturn = MCICDA_GetStatus(wmcda);
583 TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
584 lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
585 ret = MCI_RESOURCE_RETURNED;
586 break;
587 case MCI_STATUS_MEDIA_PRESENT:
588 lpParms->dwReturn = (MCICDA_GetStatus(wmcda) == MCI_MODE_OPEN) ?
589 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
590 TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
591 ret = MCI_RESOURCE_RETURNED;
592 break;
593 case MCI_STATUS_NUMBER_OF_TRACKS:
594 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
595 &toc, sizeof(toc), &br, NULL)) {
596 WARN("error reading TOC !\n");
597 return MCICDA_GetError(wmcda);
599 lpParms->dwReturn = toc.LastTrack - toc.FirstTrack + 1;
600 TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
601 if (lpParms->dwReturn == (WORD)-1)
602 return MCICDA_GetError(wmcda);
603 break;
604 case MCI_STATUS_POSITION:
605 if (dwFlags & MCI_STATUS_START) {
606 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
607 &toc, sizeof(toc), &br, NULL)) {
608 WARN("error reading TOC !\n");
609 return MCICDA_GetError(wmcda);
611 lpParms->dwReturn = FRAME_OF_TOC(toc, toc.FirstTrack);
612 TRACE("get MCI_STATUS_START !\n");
613 } else if (dwFlags & MCI_TRACK) {
614 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
615 &toc, sizeof(toc), &br, NULL)) {
616 WARN("error reading TOC !\n");
617 return MCICDA_GetError(wmcda);
619 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
620 return MCIERR_OUTOFRANGE;
621 lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack);
622 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
623 } else {
624 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
625 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
626 &data, sizeof(data), &br, NULL)) {
627 return MCICDA_GetError(wmcda);
629 lpParms->dwReturn = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
631 lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
632 TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
633 break;
634 case MCI_STATUS_READY:
635 TRACE("MCI_STATUS_READY !\n");
636 switch (MCICDA_GetStatus(wmcda))
638 case MCI_MODE_NOT_READY:
639 case MCI_MODE_OPEN:
640 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
641 break;
642 default:
643 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
644 break;
646 TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
647 ret = MCI_RESOURCE_RETURNED;
648 break;
649 case MCI_STATUS_TIME_FORMAT:
650 lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, MCI_FORMAT_RETURN_BASE + wmcda->dwTimeFormat);
651 TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
652 ret = MCI_RESOURCE_RETURNED;
653 break;
654 case 4001: /* FIXME: for bogus FullCD */
655 case MCI_CDA_STATUS_TYPE_TRACK:
656 if (!(dwFlags & MCI_TRACK))
657 ret = MCIERR_MISSING_PARAMETER;
658 else {
659 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
660 &toc, sizeof(toc), &br, NULL)) {
661 WARN("error reading TOC !\n");
662 return MCICDA_GetError(wmcda);
664 if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
665 ret = MCIERR_OUTOFRANGE;
666 else
667 lpParms->dwReturn = (toc.TrackData[lpParms->dwTrack - toc.FirstTrack].Control & 0x04) ?
668 MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
670 TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
671 break;
672 default:
673 FIXME("unknown command %08lX !\n", lpParms->dwItem);
674 return MCIERR_UNRECOGNIZED_COMMAND;
676 } else {
677 WARN("not MCI_STATUS_ITEM !\n");
679 return ret;
682 /**************************************************************************
683 * MCICDA_SkipDataTracks [internal]
685 static DWORD MCICDA_SkipDataTracks(WINE_MCICDAUDIO* wmcda,DWORD *frame)
687 int i;
688 DWORD br;
689 CDROM_TOC toc;
690 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
691 &toc, sizeof(toc), &br, NULL)) {
692 WARN("error reading TOC !\n");
693 return MCICDA_GetError(wmcda);
695 /* Locate first track whose starting frame is bigger than frame */
696 for(i=toc.FirstTrack;i<=toc.LastTrack+1;i++)
697 if ( FRAME_OF_TOC(toc, i) > *frame ) break;
698 if (i <= toc.FirstTrack && i>toc.LastTrack+1) {
699 i = 0; /* requested address is out of range: go back to start */
700 *frame = FRAME_OF_TOC(toc,toc.FirstTrack);
702 else
703 i--;
704 /* i points to last track whose start address is not greater than frame.
705 * Now skip non-audio tracks */
706 for(;i<=toc.LastTrack+1;i++)
707 if ( ! (toc.TrackData[i-toc.FirstTrack].Control & 4) )
708 break;
709 /* The frame will be an address in the next audio track or
710 * address of lead-out. */
711 if ( FRAME_OF_TOC(toc, i) > *frame )
712 *frame = FRAME_OF_TOC(toc, i);
713 return 0;
716 /**************************************************************************
717 * MCICDA_Play [internal]
719 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
721 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
722 DWORD ret = 0, start, end;
723 DWORD br;
724 CDROM_PLAY_AUDIO_MSF play;
725 CDROM_SUB_Q_DATA_FORMAT fmt;
726 SUB_Q_CHANNEL_DATA data;
727 CDROM_TOC toc;
729 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
731 if (lpParms == NULL)
732 return MCIERR_NULL_PARAMETER_BLOCK;
734 if (wmcda == NULL)
735 return MCIERR_INVALID_DEVICE_ID;
737 if (dwFlags & MCI_FROM) {
738 start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
739 if ( (ret=MCICDA_SkipDataTracks(wmcda, &start)) )
740 return ret;
741 TRACE("MCI_FROM=%08lX -> %lu \n", lpParms->dwFrom, start);
742 } else {
743 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
744 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
745 &data, sizeof(data), &br, NULL)) {
746 return MCICDA_GetError(wmcda);
748 start = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
749 if ( (ret=MCICDA_SkipDataTracks(wmcda, &start)) )
750 return ret;
752 if (dwFlags & MCI_TO) {
753 end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
754 TRACE("MCI_TO=%08lX -> %lu \n", lpParms->dwTo, end);
755 } else {
756 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
757 &toc, sizeof(toc), &br, NULL)) {
758 WARN("error reading TOC !\n");
759 return MCICDA_GetError(wmcda);
761 end = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
763 TRACE("Playing from %lu to %lu\n", start, end);
764 play.StartingM = start / CDFRAMES_PERMIN;
765 play.StartingS = (start / CDFRAMES_PERSEC) % 60;
766 play.StartingF = start % CDFRAMES_PERSEC;
767 play.EndingM = end / CDFRAMES_PERMIN;
768 play.EndingS = (end / CDFRAMES_PERSEC) % 60;
769 play.EndingF = end % CDFRAMES_PERSEC;
770 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_PLAY_AUDIO_MSF, &play, sizeof(play),
771 NULL, 0, &br, NULL)) {
772 ret = MCIERR_HARDWARE;
773 } else if (dwFlags & MCI_NOTIFY) {
774 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
776 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
777 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
780 return ret;
783 /**************************************************************************
784 * MCICDA_Stop [internal]
786 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
788 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
789 DWORD br;
791 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
793 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
795 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL))
796 return MCIERR_HARDWARE;
798 if (lpParms && (dwFlags & MCI_NOTIFY)) {
799 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
800 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
801 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
803 return 0;
806 /**************************************************************************
807 * MCICDA_Pause [internal]
809 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
811 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
812 DWORD br;
814 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
816 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
818 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL))
819 return MCIERR_HARDWARE;
821 if (lpParms && (dwFlags & MCI_NOTIFY)) {
822 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
823 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
824 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
826 return 0;
829 /**************************************************************************
830 * MCICDA_Resume [internal]
832 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
834 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
835 DWORD br;
837 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
839 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
841 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &br, NULL))
842 return MCIERR_HARDWARE;
844 if (lpParms && (dwFlags & MCI_NOTIFY)) {
845 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
846 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
847 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
849 return 0;
852 /**************************************************************************
853 * MCICDA_Seek [internal]
855 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
857 DWORD at;
858 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
859 CDROM_SEEK_AUDIO_MSF seek;
860 DWORD br, ret;
861 CDROM_TOC toc;
863 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
865 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
866 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
868 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
869 &toc, sizeof(toc), &br, NULL)) {
870 WARN("error reading TOC !\n");
871 return MCICDA_GetError(wmcda);
873 switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
874 case MCI_SEEK_TO_START:
875 TRACE("Seeking to start\n");
876 at = FRAME_OF_TOC(toc,toc.FirstTrack);
877 if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
878 return ret;
879 break;
880 case MCI_SEEK_TO_END:
881 TRACE("Seeking to end\n");
882 at = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
883 if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
884 return ret;
885 break;
886 case MCI_TO:
887 TRACE("Seeking to %lu\n", lpParms->dwTo);
888 at = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
889 if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
890 return ret;
891 break;
892 default:
893 TRACE("Unknown seek action %08lX\n",
894 (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)));
895 return MCIERR_UNSUPPORTED_FUNCTION;
897 seek.M = at / CDFRAMES_PERMIN;
898 seek.S = (at / CDFRAMES_PERSEC) % 60;
899 seek.F = at % CDFRAMES_PERSEC;
900 if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_SEEK_AUDIO_MSF, &seek, sizeof(seek),
901 NULL, 0, &br, NULL))
902 return MCIERR_HARDWARE;
904 if (dwFlags & MCI_NOTIFY) {
905 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
906 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
907 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
909 return 0;
912 /**************************************************************************
913 * MCICDA_SetDoor [internal]
915 static DWORD MCICDA_SetDoor(UINT wDevID, BOOL open)
917 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
918 DWORD br;
920 TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
922 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
924 if (!DeviceIoControl(wmcda->handle,
925 (open) ? IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA,
926 NULL, 0, NULL, 0, &br, NULL))
927 return MCIERR_HARDWARE;
929 return 0;
932 /**************************************************************************
933 * MCICDA_Set [internal]
935 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
937 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
939 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
941 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
943 if (dwFlags & MCI_SET_DOOR_OPEN) {
944 MCICDA_SetDoor(wDevID, TRUE);
946 if (dwFlags & MCI_SET_DOOR_CLOSED) {
947 MCICDA_SetDoor(wDevID, FALSE);
950 /* only functions which require valid lpParms below this line ! */
951 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
953 TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
954 TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
956 if (dwFlags & MCI_SET_TIME_FORMAT) {
957 switch (lpParms->dwTimeFormat) {
958 case MCI_FORMAT_MILLISECONDS:
959 TRACE("MCI_FORMAT_MILLISECONDS !\n");
960 break;
961 case MCI_FORMAT_MSF:
962 TRACE("MCI_FORMAT_MSF !\n");
963 break;
964 case MCI_FORMAT_TMSF:
965 TRACE("MCI_FORMAT_TMSF !\n");
966 break;
967 default:
968 WARN("bad time format !\n");
969 return MCIERR_BAD_TIME_FORMAT;
971 wmcda->dwTimeFormat = lpParms->dwTimeFormat;
973 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
974 if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
975 if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
976 if (dwFlags & MCI_NOTIFY) {
977 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
978 lpParms->dwCallback);
979 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
980 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
982 return 0;
985 /**************************************************************************
986 * DriverProc (MCICDA.@)
988 LONG CALLBACK MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
989 DWORD dwParam1, DWORD dwParam2)
991 switch(wMsg) {
992 case DRV_LOAD: return 1;
993 case DRV_FREE: return 1;
994 case DRV_OPEN: return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
995 case DRV_CLOSE: return MCICDA_drvClose(dwDevID);
996 case DRV_ENABLE: return 1;
997 case DRV_DISABLE: return 1;
998 case DRV_QUERYCONFIGURE: return 1;
999 case DRV_CONFIGURE: MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
1000 case DRV_INSTALL: return DRVCNF_RESTART;
1001 case DRV_REMOVE: return DRVCNF_RESTART;
1004 if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1006 switch (wMsg) {
1007 case MCI_OPEN_DRIVER: return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1008 case MCI_CLOSE_DRIVER: return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1009 case MCI_GETDEVCAPS: return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1010 case MCI_INFO: return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
1011 case MCI_STATUS: return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
1012 case MCI_SET: return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
1013 case MCI_PLAY: return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
1014 case MCI_STOP: return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1015 case MCI_PAUSE: return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1016 case MCI_RESUME: return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1017 case MCI_SEEK: return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
1018 /* FIXME: I wonder if those two next items are really called ? */
1019 case MCI_SET_DOOR_OPEN: FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
1020 return MCICDA_SetDoor(dwDevID, TRUE);
1021 case MCI_SET_DOOR_CLOSED: FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
1022 return MCICDA_SetDoor(dwDevID, FALSE);
1023 /* commands that should be supported */
1024 case MCI_LOAD:
1025 case MCI_SAVE:
1026 case MCI_FREEZE:
1027 case MCI_PUT:
1028 case MCI_REALIZE:
1029 case MCI_UNFREEZE:
1030 case MCI_UPDATE:
1031 case MCI_WHERE:
1032 case MCI_STEP:
1033 case MCI_SPIN:
1034 case MCI_ESCAPE:
1035 case MCI_COPY:
1036 case MCI_CUT:
1037 case MCI_DELETE:
1038 case MCI_PASTE:
1039 FIXME("Unsupported yet command [%lu]\n", wMsg);
1040 break;
1041 /* commands that should report an error */
1042 case MCI_WINDOW:
1043 TRACE("Unsupported command [%lu]\n", wMsg);
1044 break;
1045 case MCI_OPEN:
1046 case MCI_CLOSE:
1047 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1048 break;
1049 default:
1050 TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
1051 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1053 return MCIERR_UNRECOGNIZED_COMMAND;
1056 /*-----------------------------------------------------------------------*/