1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * MCI driver for audio CD (MCICDA)
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1998-99 Eric Pouech
7 * Copyright 2000 Andreas Mohr
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(mcicda);
23 int nUseCount; /* Incremented for each shared open */
24 BOOL fShareable; /* TRUE if first open was shareable */
25 WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
26 HANDLE hCallback; /* Callback handle for pending notification */
32 /*-----------------------------------------------------------------------*/
34 /**************************************************************************
35 * MCICDA_drvOpen [internal]
37 static DWORD MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
39 WINE_MCICDAUDIO* wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCICDAUDIO));
44 wmcda->wDevID = modp->wDeviceID;
45 mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
46 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
47 modp->wType = MCI_DEVTYPE_CD_AUDIO;
48 return modp->wDeviceID;
51 /**************************************************************************
52 * MCICDA_drvClose [internal]
54 static DWORD MCICDA_drvClose(DWORD dwDevID)
56 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
59 HeapFree(GetProcessHeap(), 0, wmcda);
60 mciSetDriverData(dwDevID, 0);
65 /**************************************************************************
66 * MCICDA_GetOpenDrv [internal]
68 static WINE_MCICDAUDIO* MCICDA_GetOpenDrv(UINT wDevID)
70 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
72 if (wmcda == NULL || wmcda->nUseCount == 0) {
73 WARN("Invalid wDevID=%u\n", wDevID);
79 /**************************************************************************
80 * MCICDA_Mode [internal]
82 static int MCICDA_Mode(int wcdaMode)
85 case WINE_CDA_DONTKNOW: return MCI_MODE_STOP;
86 case WINE_CDA_NOTREADY: return MCI_MODE_STOP;
87 case WINE_CDA_OPEN: return MCI_MODE_OPEN;
88 case WINE_CDA_PLAY: return MCI_MODE_PLAY;
89 case WINE_CDA_STOP: return MCI_MODE_STOP;
90 case WINE_CDA_PAUSE: return MCI_MODE_PAUSE;
92 FIXME("Unknown mode %04x\n", wcdaMode);
97 /**************************************************************************
98 * MCICDA_GetError [internal]
100 static int MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
102 switch (wmcda->wcda.cdaMode) {
103 case WINE_CDA_DONTKNOW:
104 case WINE_CDA_NOTREADY: return MCIERR_DEVICE_NOT_READY;
105 case WINE_CDA_OPEN: return MCIERR_DEVICE_OPEN;
108 case WINE_CDA_PAUSE: break;
110 FIXME("Unknown mode %04x\n", wmcda->wcda.cdaMode);
112 return MCIERR_DRIVER_INTERNAL;
115 /**************************************************************************
116 * MCICDA_CalcFrame [internal]
118 static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
123 TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
125 switch (wmcda->dwTimeFormat) {
126 case MCI_FORMAT_MILLISECONDS:
127 dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
128 TRACE("MILLISECONDS %lu\n", dwFrame);
131 TRACE("MSF %02u:%02u:%02u\n",
132 MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
133 dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
134 dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
135 dwFrame += MCI_MSF_FRAME(dwTime);
137 case MCI_FORMAT_TMSF:
138 default: /* unknown format ! force TMSF ! ... */
139 wTrack = MCI_TMSF_TRACK(dwTime);
140 TRACE("MSF %02u-%02u:%02u:%02u\n",
141 MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
142 MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
143 TRACE("TMSF trackpos[%u]=%lu\n",
144 wTrack, wmcda->wcda.lpdwTrackPos[wTrack - 1]);
145 dwFrame = wmcda->wcda.lpdwTrackPos[wTrack - 1];
146 dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
147 dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
148 dwFrame += MCI_TMSF_FRAME(dwTime);
154 /**************************************************************************
155 * MCICDA_CalcTime [internal]
157 static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame,
166 TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);
169 case MCI_FORMAT_MILLISECONDS:
170 dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
171 TRACE("MILLISECONDS %lu\n", dwTime);
175 wMinutes = dwFrame / CDFRAMES_PERMIN;
176 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
177 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
178 dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
179 TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
180 wMinutes, wSeconds, wFrames, dwTime);
181 *lpRet = MCI_COLONIZED3_RETURN;
183 case MCI_FORMAT_TMSF:
184 default: /* unknown format ! force TMSF ! ... */
185 if (dwFrame < wmcda->wcda.dwFirstFrame || dwFrame > wmcda->wcda.dwLastFrame) {
186 ERR("Out of range value %lu [%lu,%lu]\n",
187 dwFrame, wmcda->wcda.dwFirstFrame, wmcda->wcda.dwLastFrame);
191 for (wTrack = 1; wTrack < wmcda->wcda.nTracks; wTrack++) {
192 if (wmcda->wcda.lpdwTrackPos[wTrack] > dwFrame)
195 dwFrame -= wmcda->wcda.lpdwTrackPos[wTrack - 1];
196 wMinutes = dwFrame / CDFRAMES_PERMIN;
197 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
198 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
199 dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
200 TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
201 *lpRet = MCI_COLONIZED4_RETURN;
207 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
208 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
210 /**************************************************************************
211 * MCICDA_Open [internal]
213 static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
216 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
217 MCI_SEEK_PARMS seekParms;
220 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
222 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
223 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
225 dwDeviceID = lpOpenParms->wDeviceID;
227 if (wmcda->nUseCount > 0) {
228 /* The driver is already open on this channel */
229 /* If the driver was opened shareable before and this open specifies */
230 /* shareable then increment the use count */
231 if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
234 return MCIERR_MUST_USE_SHAREABLE;
236 wmcda->nUseCount = 1;
237 wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
239 if (dwFlags & MCI_OPEN_ELEMENT) {
240 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
241 WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort", (DWORD)lpOpenParms->lpstrElementName);
242 return MCIERR_NO_ELEMENT_ALLOWED;
244 WARN("MCI_OPEN_ELEMENT %s ignored\n",lpOpenParms->lpstrElementName);
245 /*return MCIERR_NO_ELEMENT_ALLOWED;
246 bon 19991106 allows cdplayer.exe to run*/
249 wmcda->wNotifyDeviceID = dwDeviceID;
250 if (CDROM_Open(&wmcda->wcda, -1) == -1) {
252 return MCIERR_HARDWARE;
254 wmcda->mciMode = MCI_MODE_STOP;
255 wmcda->dwTimeFormat = MCI_FORMAT_MSF;
257 dev = CDROM_OpenDev(&wmcda->wcda);
258 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
259 wmcda->mciMode = MCI_MODE_OPEN;
261 MCICDA_Seek(wDevID, MCI_SEEK_TO_START, &seekParms);
268 /**************************************************************************
269 * MCICDA_Close [internal]
271 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
273 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
275 TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
277 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
279 if (wmcda->nUseCount == 1) {
280 CDROM_Close(&wmcda->wcda);
286 /**************************************************************************
287 * MCICDA_GetDevCaps [internal]
289 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags,
290 LPMCI_GETDEVCAPS_PARMS lpParms)
294 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
296 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
298 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
299 TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
301 switch (lpParms->dwItem) {
302 case MCI_GETDEVCAPS_CAN_RECORD:
303 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
304 ret = MCI_RESOURCE_RETURNED;
306 case MCI_GETDEVCAPS_HAS_AUDIO:
307 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
308 ret = MCI_RESOURCE_RETURNED;
310 case MCI_GETDEVCAPS_HAS_VIDEO:
311 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
312 ret = MCI_RESOURCE_RETURNED;
314 case MCI_GETDEVCAPS_DEVICE_TYPE:
315 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
316 ret = MCI_RESOURCE_RETURNED;
318 case MCI_GETDEVCAPS_USES_FILES:
319 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
320 ret = MCI_RESOURCE_RETURNED;
322 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
323 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
324 ret = MCI_RESOURCE_RETURNED;
326 case MCI_GETDEVCAPS_CAN_EJECT:
327 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
328 ret = MCI_RESOURCE_RETURNED;
330 case MCI_GETDEVCAPS_CAN_PLAY:
331 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
332 ret = MCI_RESOURCE_RETURNED;
334 case MCI_GETDEVCAPS_CAN_SAVE:
335 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
336 ret = MCI_RESOURCE_RETURNED;
339 ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
340 return MCIERR_UNRECOGNIZED_COMMAND;
343 TRACE("No GetDevCaps-Item !\n");
344 return MCIERR_UNRECOGNIZED_COMMAND;
346 TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
350 /**************************************************************************
351 * MCICDA_Info [internal]
353 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
356 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
360 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
362 if (lpParms == NULL || lpParms->lpstrReturn == NULL)
363 return MCIERR_NULL_PARAMETER_BLOCK;
364 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
366 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
368 if (dwFlags & MCI_INFO_PRODUCT) {
369 str = "Wine's audio CD";
370 } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
371 ret = MCIERR_NO_IDENTITY;
372 } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
374 int dev = CDROM_OpenDev(&wmcda->wcda);
376 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev)) {
378 return MCICDA_GetError(wmcda);
382 res = CDROM_Audio_GetSerial(&wmcda->wcda);
383 if (wmcda->wcda.nTracks <= 2) {
384 /* there are some other values added when # of tracks < 3
385 * for most Audio CD it will do without
387 FIXME("Value is not correct !! "
388 "Please report with full audio CD information (-debugmsg +cdrom,mcicda)\n");
390 sprintf(buffer, "%lu", res);
393 WARN("Don't know this info command (%lu)\n", dwFlags);
394 ret = MCIERR_UNRECOGNIZED_COMMAND;
397 if (lpParms->dwRetSize <= strlen(str)) {
398 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
399 ret = MCIERR_PARAM_OVERFLOW;
401 strcpy(lpParms->lpstrReturn, str);
404 *lpParms->lpstrReturn = 0;
406 TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
410 /**************************************************************************
411 * MCICDA_Status [internal]
413 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
415 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
418 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
420 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
421 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
423 if (dwFlags & MCI_NOTIFY) {
424 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
425 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
426 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
428 if (dwFlags & MCI_STATUS_ITEM) {
429 switch (lpParms->dwItem) {
430 case MCI_STATUS_CURRENT_TRACK:
431 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1)) {
432 return MCICDA_GetError(wmcda);
434 lpParms->dwReturn = wmcda->wcda.nCurTrack;
435 TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
437 case MCI_STATUS_LENGTH:
438 if (wmcda->wcda.nTracks == 0) {
439 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, -1)) {
440 WARN("error reading TracksInfo !\n");
441 return MCICDA_GetError(wmcda);
444 if (dwFlags & MCI_TRACK) {
445 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
446 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
447 return MCIERR_OUTOFRANGE;
448 lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
449 /* Windows returns one frame less than the total track length for the
450 last track on the CD. See CDDB HOWTO. Verified on Win95OSR2. */
451 if (lpParms->dwTrack == wmcda->wcda.nTracks)
454 /* Sum of the lengths of all of the tracks. Inherits the
455 'off by one frame' behavior from the length of the last track.
456 See above comment. */
457 lpParms->dwReturn = wmcda->wcda.dwLastFrame - wmcda->wcda.dwFirstFrame - 1;
459 lpParms->dwReturn = MCICDA_CalcTime(wmcda,
460 (wmcda->dwTimeFormat == MCI_FORMAT_TMSF)
461 ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
464 TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
466 case MCI_STATUS_MODE:
467 CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
468 lpParms->dwReturn = MCICDA_Mode(wmcda->wcda.cdaMode);
469 if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
470 TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
471 lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
472 ret = MCI_RESOURCE_RETURNED;
474 case MCI_STATUS_MEDIA_PRESENT:
475 CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
476 lpParms->dwReturn = (wmcda->wcda.nTracks == 0 ||
477 wmcda->wcda.cdaMode == WINE_CDA_OPEN) ?
478 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
479 TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
480 ret = MCI_RESOURCE_RETURNED;
482 case MCI_STATUS_NUMBER_OF_TRACKS:
483 lpParms->dwReturn = CDROM_Audio_GetNumberOfTracks(&wmcda->wcda, -1);
484 TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
485 if (lpParms->dwReturn == (WORD)-1)
486 return MCICDA_GetError(wmcda);
488 case MCI_STATUS_POSITION:
489 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1))
490 return MCICDA_GetError(wmcda);
491 if(wmcda->wcda.cdaMode == WINE_CDA_OPEN)
492 return MCIERR_HARDWARE;
493 lpParms->dwReturn = wmcda->wcda.dwCurFrame;
494 if (dwFlags & MCI_STATUS_START) {
495 lpParms->dwReturn = wmcda->wcda.dwFirstFrame;
496 TRACE("get MCI_STATUS_START !\n");
498 if (dwFlags & MCI_TRACK) {
499 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
500 return MCIERR_OUTOFRANGE;
501 lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
502 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
504 lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
505 TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
507 case MCI_STATUS_READY:
508 TRACE("MCI_STATUS_READY !\n");
509 lpParms->dwReturn = (wmcda->wcda.cdaMode == WINE_CDA_DONTKNOW ||
510 wmcda->wcda.cdaMode == WINE_CDA_NOTREADY) ?
511 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
512 TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
513 ret = MCI_RESOURCE_RETURNED;
515 case MCI_STATUS_TIME_FORMAT:
516 lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
517 TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
518 ret = MCI_RESOURCE_RETURNED;
520 case 4001: /* FIXME: for bogus FullCD */
521 case MCI_CDA_STATUS_TYPE_TRACK:
522 if (!(dwFlags & MCI_TRACK))
523 ret = MCIERR_MISSING_PARAMETER;
524 else if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
525 ret = MCIERR_OUTOFRANGE;
527 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] &
528 CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
529 TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
532 FIXME("unknown command %08lX !\n", lpParms->dwItem);
533 return MCIERR_UNRECOGNIZED_COMMAND;
536 WARN("not MCI_STATUS_ITEM !\n");
541 /**************************************************************************
542 * MCICDA_Play [internal]
544 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
547 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
551 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
554 return MCIERR_NULL_PARAMETER_BLOCK;
557 return MCIERR_INVALID_DEVICE_ID;
559 dev = CDROM_OpenDev(&wmcda->wcda);
560 if (wmcda->wcda.nTracks == 0) {
561 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
562 WARN("error reading TracksInfo !\n");
563 ret = MCIERR_DRIVER_INTERNAL;
567 wmcda->wcda.nCurTrack = 1;
568 if (dwFlags & MCI_FROM) {
569 start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
570 TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
572 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev))
574 ret = MCIERR_DRIVER_INTERNAL;
577 start = wmcda->wcda.dwCurFrame;
579 if (dwFlags & MCI_TO) {
580 end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
581 TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
583 end = wmcda->wcda.dwLastFrame;
585 if (CDROM_Audio_Play(&wmcda->wcda, start, end, dev) == -1)
587 ret = MCIERR_HARDWARE;
590 wmcda->mciMode = MCI_MODE_PLAY;
591 if (dwFlags & MCI_NOTIFY) {
592 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
594 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
595 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
604 /**************************************************************************
605 * MCICDA_Stop [internal]
607 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
609 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
611 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
613 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
615 if (CDROM_Audio_Stop(&wmcda->wcda, -1) == -1)
616 return MCIERR_HARDWARE;
618 wmcda->mciMode = MCI_MODE_STOP;
619 if (lpParms && (dwFlags & MCI_NOTIFY)) {
620 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
621 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
622 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
627 /**************************************************************************
628 * MCICDA_Pause [internal]
630 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
632 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
634 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
636 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
638 if (CDROM_Audio_Pause(&wmcda->wcda, 1, -1) == -1)
639 return MCIERR_HARDWARE;
640 wmcda->mciMode = MCI_MODE_PAUSE;
641 if (lpParms && (dwFlags & MCI_NOTIFY)) {
642 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
643 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
644 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
649 /**************************************************************************
650 * MCICDA_Resume [internal]
652 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
654 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
656 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
658 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
660 if (CDROM_Audio_Pause(&wmcda->wcda, 0, -1) == -1)
661 return MCIERR_HARDWARE;
662 wmcda->mciMode = MCI_MODE_STOP;
663 if (lpParms && (dwFlags & MCI_NOTIFY)) {
664 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
665 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
666 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
671 /**************************************************************************
672 * MCICDA_Seek [internal]
674 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
677 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
679 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
681 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
682 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
684 wmcda->mciMode = MCI_MODE_SEEK;
685 switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
686 case MCI_SEEK_TO_START:
687 TRACE("Seeking to start\n");
688 at = wmcda->wcda.dwFirstFrame;
690 case MCI_SEEK_TO_END:
691 TRACE("Seeking to end\n");
692 at = wmcda->wcda.dwLastFrame;
695 TRACE("Seeking to %lu\n", lpParms->dwTo);
699 TRACE("Seeking to ??=%lu\n", dwFlags);
700 return MCIERR_UNSUPPORTED_FUNCTION;
702 if (CDROM_Audio_Seek(&wmcda->wcda, at, -1) == -1) {
703 return MCIERR_HARDWARE;
705 if (dwFlags & MCI_NOTIFY) {
706 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
707 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
708 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
713 /**************************************************************************
714 * MCICDA_SetDoor [internal]
716 static DWORD MCICDA_SetDoor(UINT wDevID, int open)
718 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
720 TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
722 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
724 if (CDROM_SetDoor(&wmcda->wcda, open, -1) == -1)
725 return MCIERR_HARDWARE;
726 wmcda->mciMode = (open) ? MCI_MODE_OPEN : MCI_MODE_STOP;
730 /**************************************************************************
731 * MCICDA_Set [internal]
733 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
735 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
737 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
739 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
741 if (dwFlags & MCI_SET_DOOR_OPEN) {
742 MCICDA_SetDoor(wDevID, TRUE);
744 if (dwFlags & MCI_SET_DOOR_CLOSED) {
745 MCICDA_SetDoor(wDevID, FALSE);
748 /* only functions which require valid lpParms below this line ! */
749 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
751 TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
752 TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
754 if (dwFlags & MCI_SET_TIME_FORMAT) {
755 switch (lpParms->dwTimeFormat) {
756 case MCI_FORMAT_MILLISECONDS:
757 TRACE("MCI_FORMAT_MILLISECONDS !\n");
760 TRACE("MCI_FORMAT_MSF !\n");
762 case MCI_FORMAT_TMSF:
763 TRACE("MCI_FORMAT_TMSF !\n");
766 WARN("bad time format !\n");
767 return MCIERR_BAD_TIME_FORMAT;
769 wmcda->dwTimeFormat = lpParms->dwTimeFormat;
771 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
772 if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
773 if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
774 if (dwFlags & MCI_NOTIFY) {
775 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
776 lpParms->dwCallback);
777 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
778 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
783 /**************************************************************************
784 * MCICDA_DriverProc [exported]
786 LONG CALLBACK MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
787 DWORD dwParam1, DWORD dwParam2)
790 case DRV_LOAD: return 1;
791 case DRV_FREE: return 1;
792 case DRV_OPEN: return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
793 case DRV_CLOSE: return MCICDA_drvClose(dwDevID);
794 case DRV_ENABLE: return 1;
795 case DRV_DISABLE: return 1;
796 case DRV_QUERYCONFIGURE: return 1;
797 case DRV_CONFIGURE: MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
798 case DRV_INSTALL: return DRVCNF_RESTART;
799 case DRV_REMOVE: return DRVCNF_RESTART;
801 case MCI_OPEN_DRIVER: return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
802 case MCI_CLOSE_DRIVER: return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
803 case MCI_GETDEVCAPS: return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
804 case MCI_INFO: return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
805 case MCI_STATUS: return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
806 case MCI_SET: return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
807 case MCI_PLAY: return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
808 case MCI_STOP: return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
809 case MCI_PAUSE: return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
810 case MCI_RESUME: return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
811 case MCI_SEEK: return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
812 /* FIXME: I wonder if those two next items are really called ? */
813 case MCI_SET_DOOR_OPEN: FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
814 return MCICDA_SetDoor(dwDevID, TRUE);
815 case MCI_SET_DOOR_CLOSED: FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
816 return MCICDA_SetDoor(dwDevID, FALSE);
817 /* commands that should be supported */
833 FIXME("Unsupported yet command [%lu]\n", wMsg);
835 /* commands that should report an error */
837 TRACE("Unsupported command [%lu]\n", wMsg);
841 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
844 TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
845 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
847 return MCIERR_UNRECOGNIZED_COMMAND;
850 /*-----------------------------------------------------------------------*/