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
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(mcicda);
26 int nUseCount; /* Incremented for each shared open */
27 BOOL fShareable; /* TRUE if first open was shareable */
28 WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
29 HANDLE hCallback; /* Callback handle for pending notification */
35 /*-----------------------------------------------------------------------*/
37 /**************************************************************************
38 * MCICDA_drvOpen [internal]
40 static DWORD MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
42 WINE_MCICDAUDIO* wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCICDAUDIO));
47 wmcda->wDevID = modp->wDeviceID;
48 mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
49 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
50 modp->wType = MCI_DEVTYPE_CD_AUDIO;
51 return modp->wDeviceID;
54 /**************************************************************************
55 * MCICDA_drvClose [internal]
57 static DWORD MCICDA_drvClose(DWORD dwDevID)
59 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
62 HeapFree(GetProcessHeap(), 0, wmcda);
63 mciSetDriverData(dwDevID, 0);
68 /**************************************************************************
69 * MCICDA_GetOpenDrv [internal]
71 static WINE_MCICDAUDIO* MCICDA_GetOpenDrv(UINT wDevID)
73 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
75 if (wmcda == NULL || wmcda->nUseCount == 0) {
76 WARN("Invalid wDevID=%u\n", wDevID);
82 /**************************************************************************
83 * MCICDA_Mode [internal]
85 static int MCICDA_Mode(int wcdaMode)
88 case WINE_CDA_DONTKNOW: return MCI_MODE_STOP;
89 case WINE_CDA_NOTREADY: return MCI_MODE_STOP;
90 case WINE_CDA_OPEN: return MCI_MODE_OPEN;
91 case WINE_CDA_PLAY: return MCI_MODE_PLAY;
92 case WINE_CDA_STOP: return MCI_MODE_STOP;
93 case WINE_CDA_PAUSE: return MCI_MODE_PAUSE;
95 FIXME("Unknown mode %04x\n", wcdaMode);
100 /**************************************************************************
101 * MCICDA_GetError [internal]
103 static int MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
105 switch (wmcda->wcda.cdaMode) {
106 case WINE_CDA_DONTKNOW:
107 case WINE_CDA_NOTREADY: return MCIERR_DEVICE_NOT_READY;
108 case WINE_CDA_OPEN: return MCIERR_HARDWARE;
111 case WINE_CDA_PAUSE: break;
113 FIXME("Unknown mode %04x\n", wmcda->wcda.cdaMode);
115 return MCIERR_DRIVER_INTERNAL;
118 /**************************************************************************
119 * MCICDA_CalcFrame [internal]
121 static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
126 TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
128 switch (wmcda->dwTimeFormat) {
129 case MCI_FORMAT_MILLISECONDS:
130 dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
131 TRACE("MILLISECONDS %lu\n", dwFrame);
134 TRACE("MSF %02u:%02u:%02u\n",
135 MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
136 dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
137 dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
138 dwFrame += MCI_MSF_FRAME(dwTime);
140 case MCI_FORMAT_TMSF:
141 default: /* unknown format ! force TMSF ! ... */
142 wTrack = MCI_TMSF_TRACK(dwTime);
143 TRACE("MSF %02u-%02u:%02u:%02u\n",
144 MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
145 MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
146 TRACE("TMSF trackpos[%u]=%lu\n",
147 wTrack, wmcda->wcda.lpdwTrackPos[wTrack - 1]);
148 dwFrame = wmcda->wcda.lpdwTrackPos[wTrack - 1];
149 dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
150 dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
151 dwFrame += MCI_TMSF_FRAME(dwTime);
157 /**************************************************************************
158 * MCICDA_CalcTime [internal]
160 static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame,
169 TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);
172 case MCI_FORMAT_MILLISECONDS:
173 dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
174 TRACE("MILLISECONDS %lu\n", dwTime);
178 wMinutes = dwFrame / CDFRAMES_PERMIN;
179 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
180 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
181 dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
182 TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
183 wMinutes, wSeconds, wFrames, dwTime);
184 *lpRet = MCI_COLONIZED3_RETURN;
186 case MCI_FORMAT_TMSF:
187 default: /* unknown format ! force TMSF ! ... */
188 if (dwFrame < wmcda->wcda.dwFirstFrame || dwFrame > wmcda->wcda.dwLastFrame) {
189 ERR("Out of range value %lu [%lu,%lu]\n",
190 dwFrame, wmcda->wcda.dwFirstFrame, wmcda->wcda.dwLastFrame);
194 for (wTrack = 1; wTrack < wmcda->wcda.nTracks; wTrack++) {
195 if (wmcda->wcda.lpdwTrackPos[wTrack] > dwFrame)
198 dwFrame -= wmcda->wcda.lpdwTrackPos[wTrack - 1];
199 wMinutes = dwFrame / CDFRAMES_PERMIN;
200 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
201 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
202 dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
203 TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
204 *lpRet = MCI_COLONIZED4_RETURN;
210 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
211 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
213 /**************************************************************************
214 * MCICDA_Open [internal]
216 static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
219 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
220 MCI_SEEK_PARMS seekParms;
223 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
225 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
226 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
228 dwDeviceID = lpOpenParms->wDeviceID;
230 if (wmcda->nUseCount > 0) {
231 /* The driver is already open on this channel */
232 /* If the driver was opened shareable before and this open specifies */
233 /* shareable then increment the use count */
234 if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
237 return MCIERR_MUST_USE_SHAREABLE;
239 wmcda->nUseCount = 1;
240 wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
242 if (dwFlags & MCI_OPEN_ELEMENT) {
243 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
244 WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort", (DWORD)lpOpenParms->lpstrElementName);
245 return MCIERR_NO_ELEMENT_ALLOWED;
247 WARN("MCI_OPEN_ELEMENT %s ignored\n",lpOpenParms->lpstrElementName);
248 /*return MCIERR_NO_ELEMENT_ALLOWED;
249 bon 19991106 allows cdplayer.exe to run*/
252 wmcda->wNotifyDeviceID = dwDeviceID;
253 if (CDROM_Open(&wmcda->wcda, -1) == -1) {
255 return MCIERR_HARDWARE;
257 wmcda->mciMode = MCI_MODE_STOP;
258 wmcda->dwTimeFormat = MCI_FORMAT_MSF;
260 dev = CDROM_OpenDev(&wmcda->wcda);
261 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
262 wmcda->mciMode = MCI_MODE_OPEN;
264 MCICDA_Seek(wDevID, MCI_SEEK_TO_START, &seekParms);
271 /**************************************************************************
272 * MCICDA_Close [internal]
274 static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
276 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
278 TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
280 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
282 if (wmcda->nUseCount == 1) {
283 CDROM_Close(&wmcda->wcda);
289 /**************************************************************************
290 * MCICDA_GetDevCaps [internal]
292 static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags,
293 LPMCI_GETDEVCAPS_PARMS lpParms)
297 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
299 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
301 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
302 TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
304 switch (lpParms->dwItem) {
305 case MCI_GETDEVCAPS_CAN_RECORD:
306 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
307 ret = MCI_RESOURCE_RETURNED;
309 case MCI_GETDEVCAPS_HAS_AUDIO:
310 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
311 ret = MCI_RESOURCE_RETURNED;
313 case MCI_GETDEVCAPS_HAS_VIDEO:
314 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
315 ret = MCI_RESOURCE_RETURNED;
317 case MCI_GETDEVCAPS_DEVICE_TYPE:
318 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
319 ret = MCI_RESOURCE_RETURNED;
321 case MCI_GETDEVCAPS_USES_FILES:
322 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
323 ret = MCI_RESOURCE_RETURNED;
325 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
326 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
327 ret = MCI_RESOURCE_RETURNED;
329 case MCI_GETDEVCAPS_CAN_EJECT:
330 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
331 ret = MCI_RESOURCE_RETURNED;
333 case MCI_GETDEVCAPS_CAN_PLAY:
334 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
335 ret = MCI_RESOURCE_RETURNED;
337 case MCI_GETDEVCAPS_CAN_SAVE:
338 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
339 ret = MCI_RESOURCE_RETURNED;
342 ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
343 return MCIERR_UNRECOGNIZED_COMMAND;
346 TRACE("No GetDevCaps-Item !\n");
347 return MCIERR_UNRECOGNIZED_COMMAND;
349 TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
353 /**************************************************************************
354 * MCICDA_Info [internal]
356 static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
359 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
363 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
365 if (lpParms == NULL || lpParms->lpstrReturn == NULL)
366 return MCIERR_NULL_PARAMETER_BLOCK;
367 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
369 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
371 if (dwFlags & MCI_INFO_PRODUCT) {
372 str = "Wine's audio CD";
373 } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
374 ret = MCIERR_NO_IDENTITY;
375 } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
377 int dev = CDROM_OpenDev(&wmcda->wcda);
379 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev)) {
381 return MCICDA_GetError(wmcda);
385 res = CDROM_Audio_GetSerial(&wmcda->wcda);
386 if (wmcda->wcda.nTracks <= 2) {
387 /* there are some other values added when # of tracks < 3
388 * for most Audio CD it will do without
390 FIXME("Value is not correct !! "
391 "Please report with full audio CD information (-debugmsg +cdrom,mcicda)\n");
393 sprintf(buffer, "%lu", res);
396 WARN("Don't know this info command (%lu)\n", dwFlags);
397 ret = MCIERR_UNRECOGNIZED_COMMAND;
400 if (lpParms->dwRetSize <= strlen(str)) {
401 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
402 ret = MCIERR_PARAM_OVERFLOW;
404 strcpy(lpParms->lpstrReturn, str);
407 *lpParms->lpstrReturn = 0;
409 TRACE("=> %s (%ld)\n", lpParms->lpstrReturn, ret);
413 /**************************************************************************
414 * MCICDA_Status [internal]
416 static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
418 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
421 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
423 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
424 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
426 if (dwFlags & MCI_NOTIFY) {
427 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
428 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
429 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
431 if (dwFlags & MCI_STATUS_ITEM) {
432 TRACE("dwItem = %lx\n", lpParms->dwItem);
433 switch (lpParms->dwItem) {
434 case MCI_STATUS_CURRENT_TRACK:
435 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1)) {
436 return MCICDA_GetError(wmcda);
438 lpParms->dwReturn = wmcda->wcda.nCurTrack;
439 TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
441 case MCI_STATUS_LENGTH:
442 if (wmcda->wcda.nTracks == 0) {
443 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, -1)) {
444 WARN("error reading TracksInfo !\n");
445 return MCICDA_GetError(wmcda);
448 if (dwFlags & MCI_TRACK) {
449 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
450 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
451 return MCIERR_OUTOFRANGE;
452 lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
453 /* Windows returns one frame less than the total track length for the
454 last track on the CD. See CDDB HOWTO. Verified on Win95OSR2. */
455 if (lpParms->dwTrack == wmcda->wcda.nTracks)
458 /* Sum of the lengths of all of the tracks. Inherits the
459 'off by one frame' behavior from the length of the last track.
460 See above comment. */
461 lpParms->dwReturn = wmcda->wcda.dwLastFrame - wmcda->wcda.dwFirstFrame - 1;
463 lpParms->dwReturn = MCICDA_CalcTime(wmcda,
464 (wmcda->dwTimeFormat == MCI_FORMAT_TMSF)
465 ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
468 TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
470 case MCI_STATUS_MODE:
471 CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
472 lpParms->dwReturn = MCICDA_Mode(wmcda->wcda.cdaMode);
473 if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
474 TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
475 lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
476 ret = MCI_RESOURCE_RETURNED;
478 case MCI_STATUS_MEDIA_PRESENT:
479 CDROM_Audio_GetCDStatus(&wmcda->wcda, -1);
480 lpParms->dwReturn = (wmcda->wcda.nTracks == 0 ||
481 wmcda->wcda.cdaMode == WINE_CDA_OPEN) ?
482 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
483 TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
484 ret = MCI_RESOURCE_RETURNED;
486 case MCI_STATUS_NUMBER_OF_TRACKS:
487 lpParms->dwReturn = CDROM_Audio_GetNumberOfTracks(&wmcda->wcda, -1);
488 TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
489 if (lpParms->dwReturn == (WORD)-1)
490 return MCICDA_GetError(wmcda);
492 case MCI_STATUS_POSITION:
493 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, -1))
494 return MCICDA_GetError(wmcda);
495 if(wmcda->wcda.cdaMode == WINE_CDA_OPEN)
496 return MCIERR_HARDWARE;
497 lpParms->dwReturn = wmcda->wcda.dwCurFrame;
498 if (dwFlags & MCI_STATUS_START) {
499 lpParms->dwReturn = wmcda->wcda.dwFirstFrame;
500 TRACE("get MCI_STATUS_START !\n");
502 if (dwFlags & MCI_TRACK) {
503 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
504 return MCIERR_OUTOFRANGE;
505 lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
506 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
508 lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
509 TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
511 case MCI_STATUS_READY:
512 TRACE("MCI_STATUS_READY !\n");
513 lpParms->dwReturn = (wmcda->wcda.cdaMode == WINE_CDA_DONTKNOW ||
514 wmcda->wcda.cdaMode == WINE_CDA_NOTREADY) ?
515 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
516 TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
517 ret = MCI_RESOURCE_RETURNED;
519 case MCI_STATUS_TIME_FORMAT:
520 lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
521 TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
522 ret = MCI_RESOURCE_RETURNED;
524 case 4001: /* FIXME: for bogus FullCD */
525 case MCI_CDA_STATUS_TYPE_TRACK:
526 if (!(dwFlags & MCI_TRACK))
527 ret = MCIERR_MISSING_PARAMETER;
529 if(!CDROM_Audio_GetTracksInfo(&wmcda->wcda, -1)) {
530 WARN("Error reading tracks info\n");
531 return MCICDA_GetError(wmcda);
533 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
534 ret = MCIERR_OUTOFRANGE;
536 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] &
537 CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
539 TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
542 FIXME("unknown command %08lX !\n", lpParms->dwItem);
543 return MCIERR_UNRECOGNIZED_COMMAND;
546 WARN("not MCI_STATUS_ITEM !\n");
551 /**************************************************************************
552 * MCICDA_Play [internal]
554 static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
557 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
561 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
564 return MCIERR_NULL_PARAMETER_BLOCK;
567 return MCIERR_INVALID_DEVICE_ID;
569 dev = CDROM_OpenDev(&wmcda->wcda);
570 if (wmcda->wcda.nTracks == 0) {
571 if (!CDROM_Audio_GetTracksInfo(&wmcda->wcda, dev)) {
572 WARN("error reading TracksInfo !\n");
573 ret = MCIERR_DRIVER_INTERNAL;
577 wmcda->wcda.nCurTrack = 1;
578 if (dwFlags & MCI_FROM) {
579 start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
580 TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
582 if (!CDROM_Audio_GetCDStatus(&wmcda->wcda, dev))
584 ret = MCIERR_DRIVER_INTERNAL;
587 start = wmcda->wcda.dwCurFrame;
589 if (dwFlags & MCI_TO) {
590 end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
591 TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
593 end = wmcda->wcda.dwLastFrame;
595 if (CDROM_Audio_Play(&wmcda->wcda, start, end, dev) == -1)
597 ret = MCIERR_HARDWARE;
600 wmcda->mciMode = MCI_MODE_PLAY;
601 if (dwFlags & MCI_NOTIFY) {
602 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
604 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
605 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
614 /**************************************************************************
615 * MCICDA_Stop [internal]
617 static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
619 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
621 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
623 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
625 if (CDROM_Audio_Stop(&wmcda->wcda, -1) == -1)
626 return MCIERR_HARDWARE;
628 wmcda->mciMode = MCI_MODE_STOP;
629 if (lpParms && (dwFlags & MCI_NOTIFY)) {
630 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
631 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
632 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
637 /**************************************************************************
638 * MCICDA_Pause [internal]
640 static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
642 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
644 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
646 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
648 if (CDROM_Audio_Pause(&wmcda->wcda, 1, -1) == -1)
649 return MCIERR_HARDWARE;
650 wmcda->mciMode = MCI_MODE_PAUSE;
651 if (lpParms && (dwFlags & MCI_NOTIFY)) {
652 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
653 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
654 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
659 /**************************************************************************
660 * MCICDA_Resume [internal]
662 static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
664 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
666 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
668 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
670 if (CDROM_Audio_Pause(&wmcda->wcda, 0, -1) == -1)
671 return MCIERR_HARDWARE;
672 wmcda->mciMode = MCI_MODE_STOP;
673 if (lpParms && (dwFlags & MCI_NOTIFY)) {
674 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
675 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
676 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
681 /**************************************************************************
682 * MCICDA_Seek [internal]
684 static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
687 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
689 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
691 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
692 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
694 wmcda->mciMode = MCI_MODE_SEEK;
695 switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
696 case MCI_SEEK_TO_START:
697 TRACE("Seeking to start\n");
698 at = wmcda->wcda.dwFirstFrame;
700 case MCI_SEEK_TO_END:
701 TRACE("Seeking to end\n");
702 at = wmcda->wcda.dwLastFrame;
705 TRACE("Seeking to %lu\n", lpParms->dwTo);
709 TRACE("Seeking to ??=%lu\n", dwFlags);
710 return MCIERR_UNSUPPORTED_FUNCTION;
712 if (CDROM_Audio_Seek(&wmcda->wcda, at, -1) == -1) {
713 return MCIERR_HARDWARE;
715 if (dwFlags & MCI_NOTIFY) {
716 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
717 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
718 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
723 /**************************************************************************
724 * MCICDA_SetDoor [internal]
726 static DWORD MCICDA_SetDoor(UINT wDevID, int open)
728 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
730 TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
732 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
734 if (CDROM_SetDoor(&wmcda->wcda, open, -1) == -1)
735 return MCIERR_HARDWARE;
736 wmcda->mciMode = (open) ? MCI_MODE_OPEN : MCI_MODE_STOP;
740 /**************************************************************************
741 * MCICDA_Set [internal]
743 static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
745 WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
747 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
749 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
751 if (dwFlags & MCI_SET_DOOR_OPEN) {
752 MCICDA_SetDoor(wDevID, TRUE);
754 if (dwFlags & MCI_SET_DOOR_CLOSED) {
755 MCICDA_SetDoor(wDevID, FALSE);
758 /* only functions which require valid lpParms below this line ! */
759 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
761 TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
762 TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
764 if (dwFlags & MCI_SET_TIME_FORMAT) {
765 switch (lpParms->dwTimeFormat) {
766 case MCI_FORMAT_MILLISECONDS:
767 TRACE("MCI_FORMAT_MILLISECONDS !\n");
770 TRACE("MCI_FORMAT_MSF !\n");
772 case MCI_FORMAT_TMSF:
773 TRACE("MCI_FORMAT_TMSF !\n");
776 WARN("bad time format !\n");
777 return MCIERR_BAD_TIME_FORMAT;
779 wmcda->dwTimeFormat = lpParms->dwTimeFormat;
781 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
782 if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
783 if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
784 if (dwFlags & MCI_NOTIFY) {
785 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
786 lpParms->dwCallback);
787 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
788 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
793 /**************************************************************************
794 * MCICDA_DriverProc [exported]
796 LONG CALLBACK MCICDA_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
797 DWORD dwParam1, DWORD dwParam2)
800 case DRV_LOAD: return 1;
801 case DRV_FREE: return 1;
802 case DRV_OPEN: return MCICDA_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
803 case DRV_CLOSE: return MCICDA_drvClose(dwDevID);
804 case DRV_ENABLE: return 1;
805 case DRV_DISABLE: return 1;
806 case DRV_QUERYCONFIGURE: return 1;
807 case DRV_CONFIGURE: MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
808 case DRV_INSTALL: return DRVCNF_RESTART;
809 case DRV_REMOVE: return DRVCNF_RESTART;
811 case MCI_OPEN_DRIVER: return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
812 case MCI_CLOSE_DRIVER: return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
813 case MCI_GETDEVCAPS: return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
814 case MCI_INFO: return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
815 case MCI_STATUS: return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
816 case MCI_SET: return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
817 case MCI_PLAY: return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
818 case MCI_STOP: return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
819 case MCI_PAUSE: return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
820 case MCI_RESUME: return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
821 case MCI_SEEK: return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
822 /* FIXME: I wonder if those two next items are really called ? */
823 case MCI_SET_DOOR_OPEN: FIXME("MCI_SET_DOOR_OPEN called. Please report this.\n");
824 return MCICDA_SetDoor(dwDevID, TRUE);
825 case MCI_SET_DOOR_CLOSED: FIXME("MCI_SET_DOOR_CLOSED called. Please report this.\n");
826 return MCICDA_SetDoor(dwDevID, FALSE);
827 /* commands that should be supported */
843 FIXME("Unsupported yet command [%lu]\n", wMsg);
845 /* commands that should report an error */
847 TRACE("Unsupported command [%lu]\n", wMsg);
851 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
854 TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
855 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
857 return MCIERR_UNRECOGNIZED_COMMAND;
860 /*-----------------------------------------------------------------------*/