Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1722 lines
45 KiB

  1. /*******************************Module*Header*********************************\
  2. * Module Name: mcicda.c
  3. *
  4. * Media Control Architecture Redbook CD Audio Driver
  5. *
  6. * Created: 4/25/90
  7. * Author: DLL (DavidLe)
  8. *
  9. * History:
  10. * DavidLe - Based on MCI Pioneer Videodisc Driver
  11. * MikeRo 12/90 - 1/91
  12. * RobinSp 10th March 1992 - Move to Windows NT
  13. *
  14. * Copyright (c) 1990-1999 Microsoft Corporation
  15. *
  16. \****************************************************************************/
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #include <mmddk.h>
  20. #include "mcicda.h"
  21. #include "cda.h"
  22. #include "cdio.h"
  23. #define CHECK_MSF
  24. #define MCICDA_BAD_TIME 0xFFFFFFFF
  25. HANDLE hInstance;
  26. UINT_PTR wTimerID;
  27. int nWaitingDrives;
  28. DRIVEDATA DriveTable[MCIRBOOK_MAX_DRIVES];
  29. // MBR This
  30. void CALLBACK TimerProc (
  31. HWND hwnd,
  32. UINT uMessage,
  33. UINT uTimer,
  34. DWORD dwParam)
  35. {
  36. DID i;
  37. int wStatus;
  38. for (i = 0; i < MCIRBOOK_MAX_DRIVES; ++i) {
  39. EnterCrit( CdInfo[i].DeviceCritSec );
  40. if (DriveTable[i].bActiveTimer) {
  41. // MBR can other conditions beside successful completion of the
  42. // play cause the != DISC_PLAYING?
  43. if ((wStatus = CDA_drive_status (i)) != DISC_PLAYING)
  44. {
  45. if (--nWaitingDrives <= 0)
  46. KillTimer (NULL, uTimer);
  47. DriveTable[i].dwPlayTo = MCICDA_BAD_TIME;
  48. DriveTable[i].bActiveTimer = FALSE;
  49. switch (wStatus)
  50. {
  51. case DISC_PLAYING:
  52. case DISC_PAUSED:
  53. case DISC_READY:
  54. wStatus = MCI_NOTIFY_SUCCESSFUL;
  55. break;
  56. default:
  57. wStatus = MCI_NOTIFY_FAILURE;
  58. break;
  59. }
  60. mciDriverNotify (DriveTable[i].hCallback,
  61. DriveTable[i].wDeviceID, wStatus);
  62. }
  63. }
  64. LeaveCrit( CdInfo[i].DeviceCritSec );
  65. }
  66. }
  67. /*****************************************************************************
  68. @doc INTERNAL MCICDA
  69. @api UINT | notify | This function handles the notify
  70. for all mci commands.
  71. @parm DID | didDrive | Drive identifier
  72. @parm WORD | wDeviceID | Calling device ID
  73. @parm BOOL | wStartTimer | A boolean indicating that a timer is to be
  74. started
  75. @parm UINT | wFlag | The flag to be passed by mciDriverNotify
  76. @parm LPMCI_GENERIC_PARMS | lpParms | For direct callback
  77. *****************************************************************************/
  78. UINT
  79. notify ( DID didDrive,
  80. MCIDEVICEID wDeviceID,
  81. BOOL wStartTimer,
  82. UINT wFlag,
  83. LPMCI_GENERIC_PARMS lpParms)
  84. {
  85. if (DriveTable[didDrive].bActiveTimer)
  86. {
  87. mciDriverNotify (DriveTable[didDrive].hCallback, wDeviceID,
  88. MCI_NOTIFY_SUPERSEDED);
  89. if (--nWaitingDrives <= 0)
  90. KillTimer (NULL, wTimerID);
  91. DriveTable[didDrive].bActiveTimer = FALSE;
  92. }
  93. if (!wStartTimer)
  94. mciDriverNotify ((HWND)lpParms->dwCallback, wDeviceID,
  95. wFlag);
  96. else
  97. {
  98. if (!DriveTable[didDrive].bActiveTimer &&
  99. nWaitingDrives++ == 0)
  100. {
  101. // MBR every 1/10 of a sec. Should this be a parameter?
  102. wTimerID = SetTimer (NULL, 1, 100, (TIMERPROC)TimerProc);
  103. if (wTimerID == 0)
  104. return MCICDAERR_NO_TIMERS;
  105. }
  106. DriveTable[didDrive].wDeviceID = wDeviceID;
  107. DriveTable[didDrive].bActiveTimer = TRUE;
  108. DriveTable[didDrive].hCallback = (HANDLE)lpParms->dwCallback;
  109. }
  110. return 0;
  111. }
  112. /*****************************************************************************
  113. @doc INTERNAL MCICDA
  114. @api void | abort_notify |
  115. @parm PINSTDATA | pInst | application instance data
  116. @rdesc
  117. @comm
  118. *****************************************************************************/
  119. void abort_notify (PINSTDATA pInst)
  120. {
  121. DID didDrive = pInst->uDevice;
  122. if (DriveTable[didDrive].bActiveTimer)
  123. {
  124. mciDriverNotify (DriveTable[didDrive].hCallback,
  125. pInst->uMCIDeviceID,
  126. MCI_NOTIFY_ABORTED);
  127. // Kill timer if appropriate
  128. if (--nWaitingDrives == 0)
  129. KillTimer (NULL, wTimerID);
  130. DriveTable[didDrive].dwPlayTo = MCICDA_BAD_TIME;
  131. DriveTable[didDrive].bActiveTimer = FALSE;
  132. }
  133. }
  134. /*
  135. Return TRUE if the drive is in a playable state
  136. */
  137. UINT disc_ready (DID didDrive)
  138. {
  139. // The disk is ready if we can read its TOC (note the
  140. // kernel driver works out if the TOC really needs reading
  141. if (CDA_disc_ready(didDrive)) {
  142. if (CDA_num_tracks(didDrive)) {
  143. return TRUE;
  144. } else {
  145. CDA_reset_drive(didDrive);
  146. return FALSE;
  147. }
  148. } else
  149. return FALSE;
  150. }
  151. /*
  152. * @func redbook | flip3 | Put minute/second/frame values in different order
  153. *
  154. * @parm redbook | rbIn | Current position as track|minute|second|frame
  155. *
  156. * @rdesc (redbook)0|frame|second|minute
  157. */
  158. redbook flip3 (redbook rbIn)
  159. {
  160. return MAKERED(MCI_MSF_MINUTE(rbIn),
  161. MCI_MSF_SECOND(rbIn),
  162. MCI_MSF_FRAME(rbIn));
  163. }
  164. /*
  165. * @func redbook | flip4 | Put track/minute/second/frame values in different order
  166. *
  167. * @parm redbook | rbIn | Current position as track|minute|second|frame
  168. *
  169. * @rdesc (redbook)frame|second|minute|track
  170. */
  171. redbook flip4 (redbook rbIn)
  172. {
  173. redbook rbOut;
  174. LPSTR lpOut = (LPSTR)&rbOut,
  175. lpIn = (LPSTR)&rbIn;
  176. lpOut[0] = lpIn[3];
  177. lpOut[1] = lpIn[2];
  178. lpOut[2] = lpIn[1];
  179. lpOut[3] = lpIn[0];
  180. return rbOut;
  181. }
  182. // MBR Return the absolute redbook time of track sTrack, rbTime into track
  183. /*****************************************************************************
  184. @doc INTERNAL MCICDA
  185. @api redbook | track_time | Return the absolute redbook time of
  186. track sTrack, rbTime into track
  187. @parm DID | didDrive |
  188. @parm int | sTrack |
  189. @parm redbook | rbTime |
  190. @rdesc
  191. @comm
  192. *****************************************************************************/
  193. redbook track_time (DID didDrive, int sTrack, redbook rbTime)
  194. {
  195. redbook rbTemp;
  196. rbTemp = CDA_track_start (didDrive, sTrack);
  197. if (rbTemp == INVALID_TRACK)
  198. return rbTemp;
  199. return redadd (rbTime, rbTemp);
  200. }
  201. redbook miltored(DWORD dwMill)
  202. {
  203. unsigned char m, s, f;
  204. long r1, r2;
  205. r1 = dwMill % 60000;
  206. m = (unsigned char) ((dwMill - r1) / 60000);
  207. r2 = r1 % 1000;
  208. s = (unsigned char) ((r1 - r2) / 1000);
  209. f = (unsigned char) ((r2 * 75) / 1000);
  210. return MAKERED(m, s, f);
  211. }
  212. DWORD redtomil(redbook rbRed)
  213. {
  214. // Adding an extra one ms to prevent rounding errors at start
  215. return (DWORD)REDMINUTE(rbRed) * 60000 +
  216. (DWORD)REDSECOND(rbRed) * 1000 +
  217. ((DWORD)REDFRAME(rbRed) * 1000) / 75 +
  218. 1;
  219. }
  220. #ifdef AUDIOPHILE
  221. DWORD NEAR PASCAL mcSeek(
  222. PINSTDATA pInst,
  223. DWORD dwFlags,
  224. LPMCI_SEEK_PARMS lpSeek );
  225. DWORD NEAR PASCAL GetAudioPhileInfo(LPCTSTR lpCDAFileName)
  226. {
  227. OFSTRUCT of;
  228. RIFFCDA cda;
  229. HFILE hf;
  230. //
  231. // open the file and read the CDA info.
  232. //
  233. if ((hf = _lopen (lpCDAFileName)) == HFILE_ERROR)
  234. return 0;
  235. _lread(hf, &cda, sizeof(cda));
  236. _lclose(hf);
  237. if (cda.dwRIFF != RIFF_RIFF || cda.dwCDDA != RIFF_CDDA)
  238. {
  239. return 0;
  240. }
  241. return MCI_MAKE_TMSF(cda.wTrack,0,0,0);
  242. }
  243. #endif
  244. DWORD mcOpen (
  245. PINSTDATA pInst,
  246. DWORD dwFlags,
  247. LPMCI_OPEN_PARMS lpOpen)
  248. {
  249. DID didDrive = (DID)pInst->uDevice;
  250. DID didOld = (DID)pInst->uDevice;
  251. UCHAR Volume;
  252. DWORD dwTempVol;
  253. int nUseCount;
  254. /* Instance Initialization */
  255. pInst->dwTimeFormat = MCI_FORMAT_MSF;
  256. /* If an ELEMENT_ID is specified, this could be a drive letter */
  257. if (dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID))
  258. {
  259. if ((dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID)) == (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID))
  260. {
  261. dprintf2(("mcOpen, (%08lX), Flags not compatible", (DWORD)didDrive));
  262. return MCIERR_FLAGS_NOT_COMPATIBLE;
  263. }
  264. //
  265. // Find the device corresponding to this name
  266. //
  267. if (COMMAND_SUCCESSFUL !=
  268. CDA_get_drive(lpOpen->lpstrElementName, &didDrive))
  269. {
  270. dprintf2(("mcOpen, (%08lX), Failed to get corresponding device", (DWORD)didDrive));
  271. return MCIERR_INVALID_FILE;
  272. }
  273. dprintf2(("mcOpen, changing from drive (%08lx) to drive (%08lX)", (DWORD)(pInst->uDevice), (DWORD)didDrive));
  274. pInst->uDevice = didDrive;
  275. }
  276. /* Device Initialization */
  277. nUseCount = DriveTable[didDrive].nUseCount;
  278. if (nUseCount > 0)
  279. {
  280. // This drive is already open as another MCI device
  281. if (dwFlags & MCI_OPEN_SHAREABLE &&
  282. DriveTable[didDrive].bShareable)
  283. {
  284. // Shareable was specified so just increment the use count
  285. nUseCount++;
  286. dprintf2(("mcOpen, drive (%08lx), Incrementing UseCount, now = %ld",
  287. (DWORD)didDrive, (DWORD)nUseCount));
  288. }
  289. else
  290. {
  291. dprintf2(("mcOpen, drive (%08lx), tryed to share without specifing MCI_OPEN_SHAREABLE",
  292. (DWORD)didDrive));
  293. return MCIERR_MUST_USE_SHAREABLE;
  294. }
  295. }
  296. else
  297. {
  298. nUseCount = 1;
  299. }
  300. if (!CDA_open(didDrive))
  301. {
  302. dprintf2(("mcOpen, drive (%08lx), failed to open, UseCount = %ld",
  303. (DWORD)didDrive, (DWORD)nUseCount));
  304. return MCIERR_DEVICE_OPEN;
  305. }
  306. //
  307. // Don't call disc_ready here because it will read the table of
  308. // contents and on some drivers this will terminate any play
  309. // unnecessarily
  310. //
  311. if (CDA_drive_status (didDrive) == DISC_PLAYING)
  312. DriveTable[didDrive].bDiscPlayed = TRUE;
  313. else
  314. DriveTable[didDrive].bDiscPlayed = FALSE;
  315. DriveTable[didDrive].bActiveTimer = FALSE;
  316. DriveTable[didDrive].dwPlayTo = MCICDA_BAD_TIME;
  317. DriveTable[didDrive].bShareable = (dwFlags & MCI_OPEN_SHAREABLE) != 0;
  318. DriveTable[didDrive].nUseCount = nUseCount;
  319. dprintf2(("mcOpen, drive (%08lx), Setting UseCount = %ld",
  320. (DWORD)didDrive, (DWORD)nUseCount));
  321. //dstewart: fix for when vol in registry is > 8 bits
  322. dwTempVol = CDAudio_GetUnitVolume(didDrive);
  323. if (dwTempVol > 0xFF)
  324. {
  325. dwTempVol = 0xFF;
  326. }
  327. Volume = (UCHAR)dwTempVol;
  328. CDA_set_audio_volume_all (didDrive, Volume);
  329. #ifdef AUDIOPHILE
  330. /*
  331. * AudioPhile track information handler.
  332. *
  333. * The new CDROM file system for Windows 4.0 produces files that describe
  334. * CDAudio tracks. If a user wants to play a track, she should be able
  335. * to double click on the track. So, we add open element support here
  336. * and add an mplayer association s.t. the file may be read and the disc
  337. * played back. We need to reject the Phile if a CDROM of this ID can't
  338. * be found. A message box should be displayed if the disc is incorrect.
  339. * Repercussions of this feature are that we need to simulate a disc in
  340. * a data structure.
  341. */
  342. if (dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID))
  343. {
  344. MCI_SEEK_PARMS Seek;
  345. pInst->dwTimeFormat = MCI_FORMAT_TMSF;
  346. Seek.dwTo = GetAudioPhileInfo(lpOpen->lpstrElementName);
  347. if (Seek.dwTo != 0L)
  348. mcSeek(pInst, MCI_TO, (LPMCI_SEEK_PARMS)&Seek);
  349. }
  350. #endif
  351. return 0;
  352. }
  353. #define MSF_BITS ((redbook) 0x00FFFFFF)
  354. /*****************************************************************************
  355. @doc INTERNAL MCICDA
  356. @api redbook | convert_time | Take a DWORD time value and
  357. convert from current time format into redbook.
  358. @parm PINSTDATA | pInst | Pointer to application instance data
  359. @parm DWORD | dwTimeIn |
  360. @rdesc Return MCICDA_BAD_TIME if out of range.
  361. @comm
  362. *****************************************************************************/
  363. redbook convert_time(
  364. PINSTDATA pInst,
  365. DWORD dwTimeIn )
  366. {
  367. DID didDrive = (DID)pInst->uDevice;
  368. redbook rbTime;
  369. short nTrack;
  370. switch (pInst->dwTimeFormat)
  371. {
  372. case MCI_FORMAT_MILLISECONDS:
  373. rbTime = miltored (dwTimeIn);
  374. return rbTime;
  375. case MCI_FORMAT_MSF:
  376. dprintf3(("Time IN: %lu",dwTimeIn));
  377. rbTime = flip3 (dwTimeIn);
  378. dprintf3(("Time OUT: %d:%d:%d:%d", REDTRACK(rbTime), REDMINUTE(rbTime),REDSECOND(rbTime), REDFRAME(rbTime)));
  379. break;
  380. case MCI_FORMAT_TMSF:
  381. nTrack = (short)(dwTimeIn & 0xFF);
  382. if (nTrack > CDA_num_tracks( didDrive))
  383. return MCICDA_BAD_TIME;
  384. rbTime = track_time (didDrive, nTrack, flip3 (dwTimeIn >> 8));
  385. if (rbTime == INVALID_TRACK)
  386. return MCICDA_BAD_TIME;
  387. break;
  388. }
  389. #ifdef CHECK_MSF
  390. if ((REDFRAME(rbTime)>74) || (REDMINUTE(rbTime)>99) ||
  391. (REDSECOND(rbTime)>59))
  392. return MCICDA_BAD_TIME;
  393. #endif
  394. return rbTime;
  395. }
  396. /*****************************************************************************
  397. @doc INTERNAL MCICDA
  398. @api DWORD | seek | Process the MCI_SEEK command
  399. @parm PINSTDATA | pInst | Pointer to application instance data
  400. @parm DWORD | dwFlags |
  401. @parm LPMCI_SEEK_PARMS | lpSeek |
  402. @rdesc
  403. @comm
  404. *****************************************************************************/
  405. DWORD mcSeek(
  406. PINSTDATA pInst,
  407. DWORD dwFlags,
  408. LPMCI_SEEK_PARMS lpSeek )
  409. {
  410. DID didDrive = pInst->uDevice;
  411. redbook rbTime = 0;
  412. LPSTR lpTime = (LPSTR) &rbTime;
  413. redbook rbStart;
  414. redbook rbEnd;
  415. BOOL fForceAudio;
  416. dprintf3(("Seek, drive %d TO %8x", didDrive, lpSeek->dwTo));
  417. abort_notify (pInst);
  418. if ( !disc_ready (didDrive))
  419. return MCIERR_HARDWARE;
  420. if ((rbStart = CDA_track_start( didDrive, 1)) == INVALID_TRACK)
  421. return MCIERR_HARDWARE;
  422. rbStart &= MSF_BITS;
  423. if ((rbEnd = CDA_disc_end( didDrive)) == INVALID_TRACK)
  424. return MCIERR_HARDWARE;
  425. rbEnd &= MSF_BITS;
  426. // Check only one positioning command is given.
  427. // First isolate the bits we want
  428. // Then subtract 1. This removes the least significant bit, and puts
  429. // ones in any lower bit positions. Leaves other bits untouched.
  430. // If any bits are left on, more than one of TO, START or END was given
  431. // Note: if NO flags are given this ends up ANDING 0 with -1 == 0
  432. // which is OK.
  433. #define SEEK_BITS (dwFlags & (MCI_TO | MCI_SEEK_TO_START | MCI_SEEK_TO_END))
  434. #define CHECK_FLAGS (((SEEK_BITS)-1) & (SEEK_BITS))
  435. if (CHECK_FLAGS) {
  436. return MCIERR_FLAGS_NOT_COMPATIBLE;
  437. }
  438. if (dwFlags & MCI_TO)
  439. {
  440. // When the above test is reviewed and proven to pick out
  441. // incompatible flags delete these lines.
  442. // Note: we detect more incompatible cases than Win 16 - this
  443. // is deliberate and fixes a Win 16 bug. CurtisP has seen this code.
  444. //if (dwFlags & (MCI_SEEK_TO_START | MCI_SEEK_TO_END))
  445. // return MCIERR_FLAGS_NOT_COMPATIBLE;
  446. if ((rbTime = convert_time (pInst, lpSeek->dwTo)) == MCICDA_BAD_TIME)
  447. return MCIERR_OUTOFRANGE;
  448. // if seek pos is before valid audio return an error
  449. if ( rbTime < rbStart)
  450. return MCIERR_OUTOFRANGE;
  451. // similarly, if seek pos is past end of disk return an error
  452. else if (rbTime > rbEnd)
  453. return MCIERR_OUTOFRANGE;
  454. fForceAudio = FALSE;
  455. } else if (dwFlags & MCI_SEEK_TO_START) {
  456. rbTime = rbStart;
  457. fForceAudio = TRUE; // We want the first audio track
  458. } else if (dwFlags & MCI_SEEK_TO_END) {
  459. rbTime = rbEnd;
  460. fForceAudio = TRUE; // We want the last audio track
  461. } else {
  462. return MCIERR_MISSING_PARAMETER;
  463. }
  464. // send seek command to driver
  465. if (CDA_seek_audio (didDrive, rbTime, fForceAudio) != COMMAND_SUCCESSFUL)
  466. return MCIERR_HARDWARE;
  467. if (CDA_pause_audio (didDrive) != COMMAND_SUCCESSFUL)
  468. return MCIERR_HARDWARE;
  469. DriveTable[didDrive].bDiscPlayed = TRUE;
  470. return 0;
  471. }
  472. /*****************************************************************************
  473. @doc INTERNAL MCICDA
  474. @api BOOL | wait |
  475. @parm DWORD | dwFlags |
  476. @parm PINSTDATA | pInst | Pointer to application instance data
  477. @rdesc Return TRUE if BREAK was pressed
  478. @comm If the wait flag is set then wait until the device is no longer playing
  479. *****************************************************************************/
  480. BOOL wait (
  481. DWORD dwFlags,
  482. PINSTDATA pInst )
  483. {
  484. DID didDrive = pInst->uDevice;
  485. MCIDEVICEID wDeviceID = pInst->uMCIDeviceID;
  486. if (dwFlags & MCI_WAIT)
  487. {
  488. //Note: jyg This is interesting. I've noticed that some drives do give
  489. // sporadic errors. Thus this retry stuff. 5X is enough to
  490. // determine true failure.
  491. int status, retry=0;
  492. retry:
  493. while ((status = CDA_drive_status (didDrive)) == DISC_PLAYING) {
  494. LeaveCrit( CdInfo[didDrive].DeviceCritSec );
  495. if (mciDriverYield (wDeviceID) != 0) {
  496. EnterCrit( CdInfo[didDrive].DeviceCritSec );
  497. return TRUE;
  498. }
  499. Sleep(50);
  500. EnterCrit( CdInfo[didDrive].DeviceCritSec );
  501. }
  502. if (status == DISC_NOT_READY && retry++ < 5)
  503. goto retry;
  504. }
  505. return FALSE;
  506. }
  507. /*****************************************************************************
  508. @doc INTERNAL MCICDA
  509. @api DWORD | play | Process the MCI_PLAY command
  510. @parm PINSTDATA | pInst | Pointer to application instance data
  511. @parm DWORD | dwFlags |
  512. @parm LPMCI_PLAY_PARMS | lpPlay |
  513. @parm BOOL FAR * | bBreak |
  514. @rdesc
  515. @comm
  516. *****************************************************************************/
  517. DWORD mcPlay(
  518. PINSTDATA pInst,
  519. DWORD dwFlags,
  520. LPMCI_PLAY_PARMS lpPlay,
  521. BOOL FAR * bBreak )
  522. {
  523. DID didDrive = pInst->uDevice;
  524. redbook rbFrom, rbTo;
  525. redbook dStart, dEnd;
  526. BOOL bAbort = FALSE;
  527. if (!disc_ready (didDrive)) // MBR could return more specific error
  528. return MCIERR_HARDWARE;
  529. // do we have both from and to parameters?
  530. // If so then do a "seek" instead
  531. if ((dwFlags & (MCI_FROM | MCI_TO)) == (MCI_FROM | MCI_TO))
  532. if (lpPlay->dwTo == lpPlay->dwFrom)
  533. // Convert a 'play x to x' into 'seek to x'
  534. {
  535. MCI_SEEK_PARMS Seek;
  536. Seek.dwTo = lpPlay->dwFrom;
  537. Seek.dwCallback = lpPlay->dwCallback;
  538. return mcSeek(pInst, dwFlags, (LPMCI_SEEK_PARMS)&Seek);
  539. }
  540. // mask is to ignore track number in the upper byte
  541. // which appears at some times
  542. dStart = CDA_track_start( didDrive, 1) & MSF_BITS;
  543. dEnd = CDA_disc_end( didDrive) & MSF_BITS;
  544. if (dwFlags & MCI_TO)
  545. {
  546. if ((rbTo = convert_time (pInst, lpPlay->dwTo))
  547. == MCICDA_BAD_TIME)
  548. return MCIERR_OUTOFRANGE;
  549. } else
  550. rbTo = dEnd;
  551. if (dwFlags & MCI_FROM)
  552. {
  553. if ((rbFrom = convert_time (pInst, lpPlay->dwFrom))
  554. == MCICDA_BAD_TIME)
  555. return MCIERR_OUTOFRANGE;
  556. } else // no FROM
  557. {
  558. // If the disk has never played the current position is indeterminate so
  559. // we must start from the beginning
  560. if (!DriveTable[didDrive].bDiscPlayed)
  561. {
  562. // Initial position is at the beginning of track 1
  563. rbFrom = track_time (didDrive, (int)1, (redbook)0);
  564. if (rbFrom == INVALID_TRACK)
  565. return MCIERR_HARDWARE;
  566. } else if ((!(dwFlags & MCI_TO) ||
  567. rbTo == DriveTable[didDrive].dwPlayTo) &&
  568. CDA_drive_status (didDrive) == DISC_PLAYING)
  569. // Disc is playing and no (or redundent) "to" position was
  570. // specified so do nothng
  571. goto exit_fn;
  572. else
  573. {
  574. CDA_time_info (didDrive, NULL, &rbFrom);
  575. // Current position in track 0 means play starting from track 1
  576. if (REDTRACK(rbFrom) == 0)
  577. {
  578. rbFrom = track_time (didDrive, (int)1, (redbook)0);
  579. if (rbFrom == INVALID_TRACK)
  580. return MCIERR_HARDWARE;
  581. }
  582. rbFrom &= MSF_BITS;
  583. // Some drives (SONY) will return an illegal position
  584. if (rbFrom < dStart)
  585. rbFrom = dStart;
  586. }
  587. }
  588. rbFrom &= MSF_BITS;
  589. rbTo &= MSF_BITS;
  590. if (dwFlags & MCI_TO)
  591. {
  592. if (rbFrom > rbTo || rbTo > dEnd)
  593. return MCIERR_OUTOFRANGE;
  594. } else {
  595. rbTo = dEnd;
  596. }
  597. // if From is before audio start return an error
  598. if ( rbFrom < dStart)
  599. return MCIERR_OUTOFRANGE;
  600. if (dwFlags & MCI_FROM) {
  601. // Try a seek - don't care if it works (!)
  602. CDA_seek_audio(didDrive, rbFrom, TRUE);
  603. }
  604. // send play command to driver
  605. if (CDA_play_audio(didDrive, rbFrom, rbTo)
  606. != COMMAND_SUCCESSFUL)
  607. return MCIERR_HARDWARE; // values should be vaild so err is hard
  608. DriveTable[didDrive].bDiscPlayed = TRUE;
  609. exit_fn:;
  610. // Abort if either from or (a new) to position is specified
  611. if (dwFlags & MCI_FROM || rbTo != DriveTable[didDrive].dwPlayTo)
  612. abort_notify (pInst);
  613. *bBreak = wait(dwFlags, pInst);
  614. DriveTable[didDrive].dwPlayTo = rbTo;
  615. return 0;
  616. }
  617. /*****************************************************************************
  618. @doc INTERNAL MCICDA
  619. @api DWORD | mcGetDevCaps | Process the MCI_GETDEVCAPS command
  620. @parm PINSTDATA | pInst | Pointer to application data instance
  621. @parm DWORD | dwFlags |
  622. @parm LPMCI_GETDEVCAPS_PARMS | lpCaps |
  623. @rdesc
  624. @comm
  625. *****************************************************************************/
  626. DWORD mcGetDevCaps(
  627. PINSTDATA pInst,
  628. DWORD dwFlags,
  629. LPMCI_GETDEVCAPS_PARMS lpCaps )
  630. {
  631. DWORD dwReturn = 0;
  632. if (!(dwFlags & MCI_GETDEVCAPS_ITEM))
  633. return MCIERR_MISSING_PARAMETER;
  634. switch (lpCaps->dwItem)
  635. {
  636. case MCI_GETDEVCAPS_CAN_RECORD:
  637. case MCI_GETDEVCAPS_CAN_SAVE:
  638. case MCI_GETDEVCAPS_HAS_VIDEO:
  639. case MCI_GETDEVCAPS_USES_FILES:
  640. case MCI_GETDEVCAPS_COMPOUND_DEVICE:
  641. lpCaps->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
  642. dwReturn = MCI_RESOURCE_RETURNED;
  643. break;
  644. case MCI_GETDEVCAPS_HAS_AUDIO:
  645. case MCI_GETDEVCAPS_CAN_EJECT: // mbr - bogus...
  646. case MCI_GETDEVCAPS_CAN_PLAY:
  647. lpCaps->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
  648. dwReturn = MCI_RESOURCE_RETURNED;
  649. break;
  650. case MCI_GETDEVCAPS_DEVICE_TYPE:
  651. lpCaps->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO,
  652. MCI_DEVTYPE_CD_AUDIO);
  653. dwReturn = MCI_RESOURCE_RETURNED;
  654. break;
  655. default:
  656. dwReturn = MCIERR_UNSUPPORTED_FUNCTION;
  657. break;
  658. }
  659. return dwReturn;
  660. }
  661. /*****************************************************************************
  662. @doc INTERNAL MCICDA
  663. @api DWORD | mcStatus | Process the MCI_STATUS command
  664. @parm PINSTDATA | pInst | Pointer to application instance data
  665. @parm DWORD | dwFlags |
  666. @parm LPMCI_STATUS_PARMS | lpStatus |
  667. @rdesc
  668. @comm
  669. *****************************************************************************/
  670. DWORD mcStatus (
  671. PINSTDATA pInst,
  672. DWORD dwFlags,
  673. LPMCI_STATUS_PARMS lpStatus)
  674. {
  675. DID didDrive = (DID)pInst->uDevice;
  676. DWORD dwReturn = 0;
  677. if (!(dwFlags & MCI_STATUS_ITEM))
  678. return MCIERR_MISSING_PARAMETER;
  679. switch (lpStatus->dwItem)
  680. {
  681. case MCI_STATUS_MEDIA_PRESENT:
  682. {
  683. if (CDA_traystate(didDrive) != TRAY_OPEN && CDA_disc_ready(didDrive))
  684. {
  685. lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
  686. }
  687. else
  688. {
  689. lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
  690. }
  691. dwReturn = MCI_RESOURCE_RETURNED;
  692. break;
  693. }
  694. case MCI_STATUS_READY:
  695. {
  696. switch (CDA_drive_status (didDrive))
  697. {
  698. case DISC_PLAYING:
  699. case DISC_PAUSED:
  700. case DISC_READY:
  701. lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
  702. break;
  703. default:
  704. lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
  705. break;
  706. }
  707. dwReturn = MCI_RESOURCE_RETURNED;
  708. break;
  709. }
  710. case MCI_STATUS_MODE:
  711. {
  712. int n;
  713. switch (CDA_drive_status (didDrive))
  714. {
  715. case DISC_PLAYING:
  716. n = MCI_MODE_PLAY;
  717. break;
  718. case DISC_PAUSED:
  719. n = MCI_MODE_STOP; // HACK HACK!
  720. break;
  721. case DISC_READY:
  722. n = MCI_MODE_STOP;
  723. break;
  724. default:
  725. if (CDA_traystate (didDrive) == TRAY_OPEN)
  726. {
  727. n = MCI_MODE_OPEN;
  728. }
  729. else
  730. {
  731. n = MCI_MODE_NOT_READY;
  732. }
  733. break;
  734. }
  735. lpStatus->dwReturn = (DWORD)MAKEMCIRESOURCE(n, n);
  736. dwReturn = MCI_RESOURCE_RETURNED;
  737. break;
  738. }
  739. case MCI_STATUS_TIME_FORMAT:
  740. {
  741. int n;
  742. n = (WORD)pInst->dwTimeFormat;
  743. lpStatus->dwReturn = (DWORD)MAKEMCIRESOURCE(n,n + MCI_FORMAT_RETURN_BASE);
  744. dwReturn = MCI_RESOURCE_RETURNED;
  745. break;
  746. }
  747. case MCI_STATUS_POSITION:
  748. {
  749. int n;
  750. redbook tracktime, disctime;
  751. if (dwFlags & MCI_TRACK)
  752. {
  753. if (dwFlags & MCI_STATUS_START)
  754. {
  755. return MCIERR_FLAGS_NOT_COMPATIBLE;
  756. }
  757. if (!disc_ready(didDrive))
  758. {
  759. return MCIERR_HARDWARE;
  760. }
  761. if ((n = CDA_num_tracks (didDrive)) == 0)
  762. {
  763. return MCIERR_HARDWARE;
  764. }
  765. if (!lpStatus->dwTrack || lpStatus->dwTrack > (DWORD)n)
  766. {
  767. return MCIERR_OUTOFRANGE;
  768. }
  769. lpStatus->dwReturn =
  770. CDA_track_start (didDrive, (short)lpStatus->dwTrack);
  771. switch (pInst->dwTimeFormat)
  772. {
  773. case MCI_FORMAT_MILLISECONDS:
  774. lpStatus->dwReturn = redtomil ((redbook)lpStatus->dwReturn);
  775. dwReturn = 0;
  776. break;
  777. case MCI_FORMAT_TMSF:
  778. lpStatus->dwReturn = lpStatus->dwTrack;
  779. dwReturn = MCI_COLONIZED4_RETURN;
  780. break;
  781. case MCI_FORMAT_MSF:
  782. lpStatus->dwReturn = flip3 ((redbook)lpStatus->dwReturn);
  783. dwReturn = MCI_COLONIZED3_RETURN;
  784. break;
  785. }
  786. } else if (dwFlags & MCI_STATUS_START)
  787. {
  788. if (!disc_ready(didDrive))
  789. {
  790. return MCIERR_HARDWARE;
  791. }
  792. if ((n = CDA_num_tracks (didDrive)) == 0)
  793. {
  794. return MCIERR_HARDWARE;
  795. }
  796. lpStatus->dwReturn =
  797. CDA_track_start (didDrive, 1);
  798. switch (pInst->dwTimeFormat)
  799. {
  800. case MCI_FORMAT_MILLISECONDS:
  801. lpStatus->dwReturn = redtomil ((redbook)lpStatus->dwReturn);
  802. dwReturn = 0;
  803. break;
  804. case MCI_FORMAT_TMSF:
  805. lpStatus->dwReturn = 1;
  806. dwReturn = MCI_COLONIZED4_RETURN;
  807. break;
  808. case MCI_FORMAT_MSF:
  809. lpStatus->dwReturn = flip3 ((redbook)lpStatus->dwReturn);
  810. dwReturn = MCI_COLONIZED3_RETURN;
  811. break;
  812. }
  813. } else
  814. {
  815. if (!DriveTable[didDrive].bDiscPlayed)
  816. {
  817. tracktime = REDTH(0, 1);
  818. if (!disc_ready(didDrive))
  819. return MCIERR_HARDWARE;
  820. disctime = CDA_track_start( didDrive, 1);
  821. } else if (CDA_time_info(didDrive, &tracktime, &disctime) != COMMAND_SUCCESSFUL)
  822. {
  823. return MCIERR_HARDWARE;
  824. }
  825. if (REDTRACK(tracktime) == 0)
  826. {
  827. tracktime = (redbook)0;
  828. disctime = (redbook)0;
  829. }
  830. switch (pInst->dwTimeFormat)
  831. {
  832. case MCI_FORMAT_MILLISECONDS:
  833. lpStatus->dwReturn = redtomil (disctime);
  834. dwReturn = 0;
  835. break;
  836. case MCI_FORMAT_MSF:
  837. lpStatus->dwReturn = flip3(disctime);
  838. dwReturn = MCI_COLONIZED3_RETURN;
  839. break;
  840. case MCI_FORMAT_TMSF:
  841. lpStatus->dwReturn = flip4 (tracktime);
  842. dwReturn = MCI_COLONIZED4_RETURN;
  843. break;
  844. }
  845. }
  846. break;
  847. }
  848. case MCI_STATUS_LENGTH:
  849. {
  850. if (!disc_ready(didDrive))
  851. {
  852. return MCIERR_HARDWARE;
  853. }
  854. if (dwFlags & MCI_TRACK)
  855. {
  856. lpStatus->dwReturn =
  857. CDA_track_length (didDrive, (short)lpStatus->dwTrack);
  858. if (lpStatus->dwReturn == INVALID_TRACK)
  859. {
  860. return MCIERR_OUTOFRANGE;
  861. }
  862. switch (pInst->dwTimeFormat)
  863. {
  864. case MCI_FORMAT_MILLISECONDS:
  865. lpStatus->dwReturn = redtomil ((redbook)lpStatus->dwReturn);
  866. dwReturn = 0;
  867. break;
  868. case MCI_FORMAT_MSF:
  869. case MCI_FORMAT_TMSF:
  870. lpStatus->dwReturn = flip3((redbook)lpStatus->dwReturn);
  871. dwReturn = MCI_COLONIZED3_RETURN;
  872. break;
  873. }
  874. } else
  875. {
  876. // Subtract one to match SEEK_TO_END
  877. lpStatus->dwReturn = CDA_disc_length (didDrive);
  878. switch (pInst->dwTimeFormat)
  879. {
  880. case MCI_FORMAT_MILLISECONDS:
  881. lpStatus->dwReturn = redtomil ((redbook)lpStatus->dwReturn);
  882. dwReturn = 0;
  883. break;
  884. case MCI_FORMAT_MSF:
  885. case MCI_FORMAT_TMSF:
  886. lpStatus->dwReturn = flip3((redbook)lpStatus->dwReturn);
  887. dwReturn = MCI_COLONIZED3_RETURN;
  888. break;
  889. }
  890. }
  891. break;
  892. }
  893. case MCI_STATUS_NUMBER_OF_TRACKS:
  894. {
  895. if (!disc_ready(didDrive))
  896. {
  897. return MCIERR_HARDWARE;
  898. }
  899. lpStatus->dwReturn = (DWORD)CDA_num_tracks (didDrive);
  900. dwReturn = 0;
  901. break;
  902. }
  903. case MCI_STATUS_CURRENT_TRACK:
  904. {
  905. redbook tracktime;
  906. if (!DriveTable[didDrive].bDiscPlayed)
  907. {
  908. lpStatus->dwReturn = 1;
  909. }
  910. else
  911. {
  912. if (CDA_time_info(didDrive, &tracktime, NULL) != COMMAND_SUCCESSFUL)
  913. {
  914. return MCIERR_HARDWARE;
  915. }
  916. lpStatus->dwReturn = REDTRACK (tracktime);
  917. }
  918. break;
  919. }
  920. case MCI_CDA_STATUS_TYPE_TRACK:
  921. {
  922. if (!disc_ready(didDrive))
  923. {
  924. return MCIERR_HARDWARE;
  925. }
  926. if (dwFlags & MCI_TRACK)
  927. {
  928. DWORD dwTmp;
  929. dwTmp = CDA_track_type (didDrive, (int)lpStatus->dwTrack);
  930. switch (dwTmp)
  931. {
  932. case INVALID_TRACK:
  933. return MCIERR_OUTOFRANGE;
  934. case MCI_CDA_TRACK_AUDIO:
  935. lpStatus->dwReturn =
  936. (DWORD)MAKEMCIRESOURCE(dwTmp,MCI_CDA_AUDIO_S);
  937. break;
  938. case MCI_CDA_TRACK_OTHER:
  939. lpStatus->dwReturn =
  940. (DWORD)MAKEMCIRESOURCE(dwTmp,MCI_CDA_OTHER_S);
  941. break;
  942. }
  943. dwReturn = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER;
  944. }
  945. break;
  946. }
  947. case MCI_STATUS_TRACK_POS:
  948. {
  949. // Note: This code is a major hack that does an end-run around
  950. // past the normal MCI functionality. The only reason it
  951. // is here is because the new functionality replaces 3 MCI
  952. // calls in CDPLAYER to get the position,track, and status
  953. // with this one call.
  954. // This means what used to take ~15 IOCTL's to accomplish
  955. // now takes ~1 IOCTL. Since CDPLAYER generates one of
  956. // these messages every 1/2 second for updating it's timer
  957. // display. This is a major reduction in system traffic
  958. // for SCSI and IDE CD-Roms drivers.
  959. DWORD status;
  960. DWORD mciStatus;
  961. redbook tracktime, disctime;
  962. int rc;
  963. STATUSTRACKPOS stp;
  964. PSTATUSTRACKPOS pSTP;
  965. if (!DriveTable[didDrive].bDiscPlayed)
  966. {
  967. tracktime = REDTH(0, 1);
  968. if (!disc_ready(didDrive))
  969. {
  970. dprintf(("mcStatus (%08LX), MCI_STATUS_TRACK_POS, Disc Not Ready", (DWORD)didDrive));
  971. return MCIERR_HARDWARE;
  972. }
  973. disctime = CDA_track_start( didDrive, 1);
  974. status = CDA_drive_status (didDrive);
  975. switch (status)
  976. {
  977. case DISC_PLAYING:
  978. mciStatus = MCI_MODE_PLAY;
  979. break;
  980. case DISC_PAUSED:
  981. mciStatus = MCI_MODE_STOP; // HACK HACK!
  982. break;
  983. case DISC_READY:
  984. mciStatus = MCI_MODE_STOP;
  985. break;
  986. default:
  987. if (CDA_traystate (didDrive) == TRAY_OPEN)
  988. mciStatus = MCI_MODE_OPEN;
  989. else
  990. mciStatus = MCI_MODE_NOT_READY;
  991. break;
  992. }
  993. }
  994. else
  995. {
  996. rc = CDA_status_track_pos (didDrive, &status, &tracktime, &disctime);
  997. if (rc != COMMAND_SUCCESSFUL)
  998. {
  999. dprintf(("mcStatus (%08LX), MCI_STATUS_TRACK_POS, CDA_status_track_pos failed", (DWORD)didDrive));
  1000. return MCIERR_HARDWARE;
  1001. }
  1002. if (REDTRACK(tracktime) == 0)
  1003. {
  1004. tracktime = (redbook)0;
  1005. disctime = (redbook)0;
  1006. }
  1007. switch (status)
  1008. {
  1009. case DISC_PLAYING:
  1010. mciStatus = MCI_MODE_PLAY;
  1011. break;
  1012. case DISC_PAUSED:
  1013. mciStatus = MCI_MODE_STOP; // HACK HACK!
  1014. break;
  1015. case DISC_READY:
  1016. mciStatus = MCI_MODE_STOP;
  1017. break;
  1018. case DISC_NOT_IN_CDROM:
  1019. mciStatus = MCI_MODE_OPEN;
  1020. break;
  1021. default:
  1022. mciStatus = MCI_MODE_NOT_READY;
  1023. break;
  1024. }
  1025. }
  1026. stp.dwStatus = mciStatus;
  1027. stp.dwTrack = REDTRACK (tracktime);
  1028. switch (pInst->dwTimeFormat)
  1029. {
  1030. case MCI_FORMAT_MILLISECONDS:
  1031. stp.dwDiscTime = redtomil ((redbook)disctime);
  1032. dwReturn = 0;
  1033. break;
  1034. case MCI_FORMAT_MSF:
  1035. stp.dwDiscTime = flip3(disctime);
  1036. dwReturn = MCI_COLONIZED3_RETURN;
  1037. break;
  1038. case MCI_FORMAT_TMSF:
  1039. stp.dwDiscTime = flip4 (tracktime);
  1040. dwReturn = MCI_COLONIZED4_RETURN;
  1041. break;
  1042. }
  1043. pSTP = (PSTATUSTRACKPOS)lpStatus->dwReturn;
  1044. if (pSTP == NULL)
  1045. {
  1046. return MCIERR_MISSING_PARAMETER;
  1047. }
  1048. pSTP->dwStatus = stp.dwStatus;
  1049. pSTP->dwTrack = stp.dwTrack;
  1050. pSTP->dwDiscTime = stp.dwDiscTime;
  1051. break;
  1052. }
  1053. default:
  1054. {
  1055. dwReturn = MCIERR_UNSUPPORTED_FUNCTION;
  1056. break;
  1057. }
  1058. }
  1059. return dwReturn;
  1060. }
  1061. /*****************************************************************************
  1062. @doc INTERNAL MCICDA
  1063. @api DWORD | mcClose | Process the MCI_CLOSE command
  1064. @parm PINSTDATA | pInst | Pointer to application data instance
  1065. @rdesc
  1066. @comm
  1067. *****************************************************************************/
  1068. DWORD mcClose(
  1069. PINSTDATA pInst)
  1070. {
  1071. DID didDrive;
  1072. MCIDEVICEID wDeviceID;
  1073. int nUseCount;
  1074. if (!pInst)
  1075. {
  1076. dprintf2(("mcClose, passed in NULL pointer"));
  1077. return 0;
  1078. }
  1079. didDrive = pInst->uDevice;
  1080. wDeviceID = pInst->uMCIDeviceID;
  1081. if (DriveTable[didDrive].nUseCount == 0)
  1082. {
  1083. dprintf2(("mcClose (%08lX), nUseCount already ZERO!!!", (DWORD)didDrive));
  1084. }
  1085. else if (--DriveTable[didDrive].nUseCount == 0)
  1086. {
  1087. dprintf2(("mcClose, Actually closing device (%08lX)", (DWORD)didDrive));
  1088. CDA_close(didDrive);
  1089. CDA_terminate_audio ();
  1090. }
  1091. else
  1092. {
  1093. dprintf2(("mcClose, Enter, device (%08lx), decremented useCount = %ld",
  1094. (DWORD)didDrive, DriveTable[didDrive].nUseCount));
  1095. // Note: Having this here prevents a mis-count problem
  1096. CDA_close(didDrive);
  1097. }
  1098. // Abort any notify if the use count is 0 or if the notify is for the device
  1099. // being closed
  1100. if ((DriveTable[didDrive].nUseCount == 0) ||
  1101. (wDeviceID == DriveTable[didDrive].wDeviceID))
  1102. {
  1103. abort_notify (pInst);
  1104. }
  1105. mciSetDriverData(pInst->uMCIDeviceID, 0L);
  1106. LocalFree((HLOCAL)pInst);
  1107. dprintf2(("mcClose, Exit, device (%08lx), useCount = %ld",
  1108. (DWORD)didDrive, DriveTable[didDrive].nUseCount));
  1109. return 0;
  1110. }
  1111. /*****************************************************************************
  1112. @doc INTERNAL MCICDA
  1113. @api DWORD | mcStop | Process the MCI_STOP command
  1114. @parm PINSTDATA | pInst | Pointer to application data instance
  1115. @parm DWORD | dwFlags |
  1116. @rdesc
  1117. *****************************************************************************/
  1118. DWORD mcStop(
  1119. PINSTDATA pInst,
  1120. DWORD dwFlags,
  1121. LPMCI_GENERIC_PARMS lpGeneric)
  1122. {
  1123. DID didDrive = pInst->uDevice;
  1124. if (!disc_ready (didDrive))
  1125. return MCIERR_HARDWARE;
  1126. abort_notify (pInst);
  1127. if (CDA_stop_audio(didDrive) != COMMAND_SUCCESSFUL)
  1128. return MCIERR_HARDWARE;
  1129. return 0;
  1130. }
  1131. /*****************************************************************************
  1132. @doc INTERNAL MCICDA
  1133. @api DWORD | mcPause | Process the MCI_PAUSE command
  1134. @parm PINSTDATA | pInst | Pointer to application data instance
  1135. @parm DWORD | dwFlags |
  1136. @rdesc
  1137. *****************************************************************************/
  1138. DWORD mcPause(
  1139. PINSTDATA pInst,
  1140. DWORD dwFlags,
  1141. LPMCI_GENERIC_PARMS lpGeneric)
  1142. {
  1143. DID didDrive = pInst->uDevice;
  1144. if (!disc_ready (didDrive))
  1145. return MCIERR_HARDWARE;
  1146. abort_notify (pInst);
  1147. if (CDA_pause_audio(didDrive) != COMMAND_SUCCESSFUL)
  1148. return MCIERR_HARDWARE;
  1149. return 0;
  1150. }
  1151. /*****************************************************************************
  1152. @doc INTERNAL MCICDA
  1153. @api DWORD | mcResume | Process the MCI_PAUSE command
  1154. @parm PINSTDATA | pInst | Pointer to application data instance
  1155. @parm DWORD | dwFlags |
  1156. @rdesc
  1157. *****************************************************************************/
  1158. DWORD mcResume(
  1159. PINSTDATA pInst,
  1160. DWORD dwFlags,
  1161. LPMCI_GENERIC_PARMS lpGeneric)
  1162. {
  1163. DID didDrive = pInst->uDevice;
  1164. if (!disc_ready (didDrive))
  1165. return MCIERR_HARDWARE;
  1166. abort_notify (pInst);
  1167. if (CDA_resume_audio(didDrive) != COMMAND_SUCCESSFUL)
  1168. return MCIERR_HARDWARE;
  1169. return 0;
  1170. }
  1171. // MBR cda.c!SendDriverReq masks off the actual error bits and just
  1172. // leaves the upper bit set - this is ok for now. There exists
  1173. // no seperate "command is known but not supported" error at
  1174. // the driver level, so if the driver returns "unrecognized
  1175. // command", we return "unsupported function".
  1176. #define ERRQ(X) (((X)==0) ? MCIERR_UNSUPPORTED_FUNCTION : 0)
  1177. /*****************************************************************************
  1178. @doc INTERNAL MCICDA
  1179. @api DWORD | mcSet | Process the MCI_SET command
  1180. @parm DWORD | dwFlags |
  1181. @parm LPMCI_SET_PARMS | lpSet |
  1182. @rdesc
  1183. @comm
  1184. *****************************************************************************/
  1185. DWORD mcSet(
  1186. PINSTDATA pInst,
  1187. DWORD dwFlags,
  1188. LPMCI_SET_PARMS lpSet )
  1189. {
  1190. DID didDrive = pInst->uDevice;
  1191. UINT wErr = 0;
  1192. dwFlags &= ~(MCI_NOTIFY | MCI_WAIT);
  1193. if (!dwFlags)
  1194. return MCIERR_MISSING_PARAMETER;
  1195. if (dwFlags & MCI_SET_TIME_FORMAT)
  1196. {
  1197. DWORD wFormat = lpSet->dwTimeFormat;
  1198. switch (wFormat)
  1199. {
  1200. case MCI_FORMAT_MILLISECONDS:
  1201. case MCI_FORMAT_MSF:
  1202. case MCI_FORMAT_TMSF:
  1203. pInst->dwTimeFormat = wFormat;
  1204. break;
  1205. default:
  1206. wErr = MCIERR_BAD_TIME_FORMAT;
  1207. break;
  1208. }
  1209. }
  1210. if (!wErr && (dwFlags & MCI_SET_DOOR_OPEN))
  1211. {
  1212. abort_notify (pInst);
  1213. CDA_stop_audio (didDrive);
  1214. CDA_eject(didDrive);
  1215. DriveTable[didDrive].bDiscPlayed = FALSE;
  1216. }
  1217. if (!wErr && (dwFlags & MCI_SET_AUDIO))
  1218. {
  1219. UCHAR wVolume;
  1220. if (dwFlags & MCI_SET_ON && dwFlags & MCI_SET_OFF)
  1221. return MCIERR_FLAGS_NOT_COMPATIBLE;
  1222. if (dwFlags & MCI_SET_ON)
  1223. wVolume = 255;
  1224. else if (dwFlags & MCI_SET_OFF)
  1225. wVolume = 0;
  1226. else
  1227. return MCIERR_MISSING_PARAMETER;
  1228. switch (lpSet->dwAudio)
  1229. {
  1230. case MCI_SET_AUDIO_ALL:
  1231. if (CDA_set_audio_volume_all (didDrive, wVolume)
  1232. != COMMAND_SUCCESSFUL)
  1233. wErr = MCIERR_HARDWARE;
  1234. break;
  1235. case MCI_SET_AUDIO_LEFT:
  1236. if (CDA_set_audio_volume (didDrive, 0, wVolume)
  1237. != COMMAND_SUCCESSFUL)
  1238. wErr = MCIERR_HARDWARE;
  1239. break;
  1240. case MCI_SET_AUDIO_RIGHT:
  1241. if (CDA_set_audio_volume (didDrive, 1, wVolume)
  1242. != COMMAND_SUCCESSFUL)
  1243. wErr = MCIERR_HARDWARE;
  1244. break;
  1245. }
  1246. }
  1247. if (!wErr && dwFlags & MCI_SET_DOOR_CLOSED)
  1248. CDA_closetray (didDrive);
  1249. return wErr;
  1250. }
  1251. /*****************************************************************************
  1252. @doc INTERNAL MCICDA
  1253. @api DWORD | mcInfo | Process the MCI_INFO command
  1254. @parm PINSTDATA | pInst | Pointer to application instance data
  1255. @parm DWORD | dwFlags |
  1256. @parm LPMCI_INFO_PARMS | lpInfo |
  1257. @rdesc
  1258. @comm
  1259. *****************************************************************************/
  1260. DWORD mcInfo (
  1261. PINSTDATA pInst,
  1262. DWORD dwFlags,
  1263. LPMCI_INFO_PARMS lpInfo )
  1264. {
  1265. DID didDrive = pInst->uDevice;
  1266. DWORD wReturnBufferLength;
  1267. wReturnBufferLength = LOWORD(lpInfo->dwRetSize);
  1268. if (!lpInfo->lpstrReturn || !wReturnBufferLength)
  1269. return MCIERR_PARAM_OVERFLOW;
  1270. if (dwFlags & MCI_INFO_PRODUCT)
  1271. {
  1272. *(lpInfo->lpstrReturn) = '\0';
  1273. lpInfo->dwRetSize = (DWORD)LoadString(hInstance, IDS_PRODUCTNAME, lpInfo->lpstrReturn, (int)wReturnBufferLength);
  1274. return 0;
  1275. }
  1276. else if (dwFlags & MCI_INFO_MEDIA_UPC)
  1277. {
  1278. unsigned char upc[16];
  1279. int i;
  1280. if (!disc_ready(didDrive))
  1281. return MCIERR_HARDWARE;
  1282. if (CDA_disc_upc(didDrive, lpInfo->lpstrReturn) != COMMAND_SUCCESSFUL)
  1283. return MCIERR_NO_IDENTITY;
  1284. return 0;
  1285. }
  1286. else if (dwFlags & MCI_INFO_MEDIA_IDENTITY)
  1287. {
  1288. DWORD dwId;
  1289. if (!disc_ready(didDrive))
  1290. return MCIERR_HARDWARE;
  1291. dwId = CDA_disc_id(didDrive);
  1292. if (dwId == (DWORD)-1L)
  1293. return MCIERR_HARDWARE;
  1294. wsprintf(lpInfo->lpstrReturn,TEXT("%lu"),dwId);
  1295. return 0;
  1296. } else
  1297. return MCIERR_MISSING_PARAMETER;
  1298. }
  1299. /*
  1300. * @doc INTERNAL MCIRBOOK
  1301. *
  1302. * @api DWORD | mciDriverEntry | Single entry point for MCI drivers
  1303. *
  1304. * @parm MCIDEVICEID | wDeviceID | The MCI device ID
  1305. *
  1306. * @parm UINT | message | The requested action to be performed.
  1307. *
  1308. * @parm LPARAM | lParam1 | Data for this message. Defined seperately for
  1309. * each message
  1310. *
  1311. * @parm LPARAM | lParam2 | Data for this message. Defined seperately for
  1312. * each message
  1313. *
  1314. * @rdesc Defined seperately for each message.
  1315. *
  1316. */
  1317. DWORD CD_MCI_Handler (MCIDEVICEID wDeviceID,
  1318. UINT message,
  1319. DWORD_PTR lParam1,
  1320. DWORD_PTR lParam2)
  1321. {
  1322. DID didDrive;
  1323. LPMCI_GENERIC_PARMS lpGeneric = (LPMCI_GENERIC_PARMS)lParam2;
  1324. BOOL bDelayed = FALSE;
  1325. DWORD dwErr = 0, wNotifyErr;
  1326. DWORD dwPlayTo = MCICDA_BAD_TIME;
  1327. WORD wNotifyStatus = MCI_NOTIFY_SUCCESSFUL;
  1328. PINSTDATA pInst;
  1329. pInst = (PINSTDATA)mciGetDriverData(wDeviceID);
  1330. didDrive = (DID)pInst->uDevice;
  1331. EnterCrit( CdInfo[didDrive].DeviceCritSec );
  1332. switch (message)
  1333. {
  1334. case MCI_OPEN_DRIVER:
  1335. dwErr = mcOpen (pInst, (DWORD)lParam1, (LPMCI_OPEN_PARMS)lParam2);
  1336. break;
  1337. case MCI_CLOSE_DRIVER:
  1338. dwErr = mcClose (pInst);
  1339. break;
  1340. case MCI_PLAY:
  1341. {
  1342. BOOL bBreak = FALSE;
  1343. dwErr = mcPlay (pInst, (DWORD)lParam1, (LPMCI_PLAY_PARMS)lParam2, &bBreak);
  1344. if (dwErr == 0 && (DWORD)lParam1 & MCI_WAIT && (DWORD)lParam1 & MCI_NOTIFY)
  1345. {
  1346. switch (CDA_drive_status (didDrive))
  1347. {
  1348. case DISC_PLAYING:
  1349. case DISC_PAUSED:
  1350. case DISC_READY:
  1351. break;
  1352. default:
  1353. wNotifyStatus = MCI_NOTIFY_FAILURE;
  1354. break;
  1355. }
  1356. }
  1357. // If MCI_WAIT is not set or if the wait loop was broken out of then delay
  1358. if (!((DWORD)lParam1 & MCI_WAIT) || bBreak)
  1359. bDelayed = TRUE;
  1360. break;
  1361. }
  1362. case MCI_SEEK:
  1363. dwErr = mcSeek (pInst, (DWORD)lParam1, (LPMCI_SEEK_PARMS)lParam2);
  1364. break;
  1365. case MCI_STOP:
  1366. dwErr = mcStop ( pInst, (DWORD)lParam1, (LPMCI_GENERIC_PARMS)lParam2);
  1367. break;
  1368. case MCI_PAUSE:
  1369. dwErr = mcPause ( pInst, (DWORD)lParam1, (LPMCI_GENERIC_PARMS)lParam2);
  1370. break;
  1371. case MCI_GETDEVCAPS:
  1372. dwErr = mcGetDevCaps (pInst, (DWORD)lParam1, (LPMCI_GETDEVCAPS_PARMS)lParam2);
  1373. break;
  1374. case MCI_STATUS:
  1375. dwErr = mcStatus (pInst, (DWORD)lParam1, (LPMCI_STATUS_PARMS)lParam2);
  1376. break;
  1377. case MCI_SET:
  1378. dwErr = mcSet (pInst, (DWORD)lParam1, (LPMCI_SET_PARMS)lParam2);
  1379. break;
  1380. case MCI_INFO:
  1381. dwErr = mcInfo (pInst, (DWORD)lParam1, (LPMCI_INFO_PARMS)lParam2);
  1382. break;
  1383. case MCI_RECORD:
  1384. case MCI_LOAD:
  1385. case MCI_SAVE:
  1386. LeaveCrit( CdInfo[didDrive].DeviceCritSec );
  1387. return MCIERR_UNSUPPORTED_FUNCTION;
  1388. case MCI_RESUME:
  1389. dwErr = mcResume ( pInst, (DWORD)lParam1, (LPMCI_GENERIC_PARMS)lParam2);
  1390. break;
  1391. default:
  1392. LeaveCrit( CdInfo[didDrive].DeviceCritSec );
  1393. return MCIERR_UNRECOGNIZED_COMMAND;
  1394. } /* switch */
  1395. /* it is possible that the instance information has disappeared if
  1396. * CLOSE NOTIFY is requested. Therefore NOTIFY should never take
  1397. * instance data.
  1398. */
  1399. if ((DWORD)lParam1 & MCI_NOTIFY && LOWORD (dwErr) == 0)
  1400. if ((wNotifyErr =
  1401. notify (didDrive, wDeviceID, bDelayed, wNotifyStatus,
  1402. (LPMCI_GENERIC_PARMS)lParam2)) != 0) {
  1403. LeaveCrit( CdInfo[didDrive].DeviceCritSec );
  1404. return wNotifyErr;
  1405. }
  1406. LeaveCrit( CdInfo[didDrive].DeviceCritSec );
  1407. return dwErr;
  1408. }