Source code of Windows XP (NT5)
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.

1220 lines
29 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: cdapimci.c
  3. *
  4. * This module encapsulates the CD-ROM device into a set of callable apis.
  5. * The api's are implemented using the cdaudio mci interface.
  6. *
  7. * Created: 26-04-93
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved.
  11. \**************************************************************************/
  12. #ifndef USE_IOCTLS
  13. #pragma warning( once : 4201 4214 )
  14. #define NOOLE
  15. #include <windows.h> /* required for all Windows applications */
  16. #include <windowsx.h>
  17. #include <string.h>
  18. #include "resource.h"
  19. #include "cdplayer.h"
  20. #include "cdapi.h"
  21. #include "scan.h"
  22. #include "trklst.h"
  23. /* -------------------------------------------------------------------------
  24. **
  25. ** High level routines
  26. **
  27. ** -------------------------------------------------------------------------
  28. */
  29. /******************************Public*Routine******************************\
  30. * OpenCdRom
  31. *
  32. *
  33. *
  34. * History:
  35. * dd-mm-94 - StephenE - Created
  36. *
  37. \**************************************************************************/
  38. MCIDEVICEID
  39. OpenCdRom(
  40. TCHAR chDrive,
  41. LPDWORD lpdwErrCode
  42. )
  43. {
  44. MCI_OPEN_PARMS mciOpen;
  45. TCHAR szElementName[4];
  46. TCHAR szAliasName[32];
  47. DWORD dwFlags;
  48. DWORD dwAliasCount = GetCurrentTime();
  49. DWORD dwRet;
  50. ZeroMemory( &mciOpen, sizeof(mciOpen) );
  51. mciOpen.lpstrDeviceType = (LPTSTR)MCI_DEVTYPE_CD_AUDIO;
  52. wsprintf( szElementName, TEXT("%c:"), chDrive );
  53. wsprintf( szAliasName, TEXT("SJE%lu:"), dwAliasCount );
  54. mciOpen.lpstrElementName = szElementName;
  55. mciOpen.lpstrAlias = szAliasName;
  56. #ifdef DAYTONA
  57. dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE | MCI_OPEN_ALIAS |
  58. MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT;
  59. #else
  60. dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS |
  61. MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT;
  62. #endif
  63. dwRet = mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD)(LPVOID)&mciOpen);
  64. if ( dwRet == MMSYSERR_NOERROR ) {
  65. MCI_SET_PARMS mciSet;
  66. ZeroMemory( &mciSet, sizeof(mciSet) );
  67. mciSet.dwTimeFormat = MCI_FORMAT_MSF;
  68. mciSendCommand( mciOpen.wDeviceID, MCI_SET,
  69. MCI_SET_TIME_FORMAT, (DWORD)(LPVOID)&mciSet );
  70. }
  71. else {
  72. /*
  73. ** Only return the error code if we have been given a valid pointer
  74. */
  75. if (lpdwErrCode != NULL) {
  76. *lpdwErrCode = dwRet;
  77. }
  78. mciOpen.wDeviceID = 0;
  79. }
  80. return mciOpen.wDeviceID;
  81. }
  82. /******************************Public*Routine******************************\
  83. * CloseCdRom
  84. *
  85. *
  86. *
  87. * History:
  88. * dd-mm-94 - StephenE - Created
  89. *
  90. \**************************************************************************/
  91. void
  92. CloseCdRom(
  93. MCIDEVICEID DevHandle
  94. )
  95. {
  96. mciSendCommand( DevHandle, MCI_CLOSE, 0L, 0L );
  97. }
  98. /******************************Public*Routine******************************\
  99. * CheckStatus
  100. *
  101. * Check return code for known bad codes and inform
  102. * user how to correct (if possible) the problem.
  103. *
  104. * History:
  105. * 18-11-93 - StephenE - Created
  106. *
  107. \**************************************************************************/
  108. void
  109. CheckStatus(
  110. LPSTR szCaller,
  111. DWORD status,
  112. int cdrom
  113. )
  114. {
  115. #if DBG
  116. TCHAR s[200];
  117. TCHAR err[100];
  118. #endif
  119. if (status==ERROR_SUCCESS)
  120. return;
  121. switch (status) {
  122. case MCIERR_HARDWARE:
  123. NoMediaUpdate( cdrom );
  124. break;
  125. }
  126. #if DBG
  127. mciGetErrorString( status, err, sizeof(err) / sizeof(TCHAR) );
  128. wsprintf( s, IdStr( STR_ERR_GEN ), g_Devices[cdrom]->drive, err );
  129. OutputDebugString (s);
  130. OutputDebugString (TEXT("\r\n"));
  131. SetWindowText( g_hwndStatusbar, s );
  132. #endif
  133. }
  134. /******************************Public*Routine******************************\
  135. * CheckUnitCdrom
  136. *
  137. * Queries the device state, checking to see if a disc has been ejected or
  138. * inserted.
  139. *
  140. * History:
  141. * 18-11-93 - StephenE - Created
  142. *
  143. \**************************************************************************/
  144. void
  145. CheckUnitCdrom(
  146. int cdrom,
  147. BOOL fForceRescan
  148. )
  149. {
  150. DWORD status;
  151. if ((cdrom < 0) || (cdrom >= MAX_CD_DEVICES))
  152. {
  153. return;
  154. }
  155. if (fForceRescan)
  156. {
  157. // Close Device to force read of correct TOC
  158. if (g_Devices[cdrom]->hCd != 0L)
  159. {
  160. CloseCdRom (g_Devices[cdrom]->hCd);
  161. g_Devices[cdrom]->hCd = 0L;
  162. }
  163. }
  164. if ( g_Devices[cdrom]->hCd == 0L ) {
  165. g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive, NULL );
  166. if ( g_Devices[cdrom]->hCd == 0 ) {
  167. return;
  168. }
  169. else {
  170. /*
  171. ** Force a rescan of this disc.
  172. */
  173. g_Devices[cdrom]->State = CD_NO_CD;
  174. }
  175. }
  176. status = TestUnitReadyCdrom( g_Devices[cdrom]->hCd );
  177. if (g_Devices[cdrom]->State & CD_NO_CD)
  178. {
  179. if (status == ERROR_SUCCESS) {
  180. /*
  181. ** A new disc has been inserted, scan it now.
  182. */
  183. RescanDevice( g_hwndApp, cdrom );
  184. }
  185. }
  186. else {
  187. if (status != ERROR_SUCCESS) {
  188. /*
  189. ** Disc has been ejected.
  190. */
  191. NoMediaUpdate( cdrom );
  192. }
  193. }
  194. }
  195. /******************************Public*Routine******************************\
  196. * NoMediaUpdate
  197. *
  198. * Update the user display when it is found that no media is in the device.
  199. *
  200. * History:
  201. * 18-11-93 - StephenE - Created
  202. *
  203. \**************************************************************************/
  204. void
  205. NoMediaUpdate(
  206. int cdrom
  207. )
  208. {
  209. BOOL fChangePlayButtons;
  210. if ( cdrom == g_CurrCdrom ) {
  211. fChangePlayButtons = TRUE;
  212. }
  213. else {
  214. fChangePlayButtons = FALSE;
  215. }
  216. g_Devices[cdrom]->State = (CD_NO_CD | CD_STOPPED);
  217. if (fChangePlayButtons) {
  218. SetPlayButtonsEnableState();
  219. }
  220. TimeAdjustInitialize( cdrom );
  221. }
  222. /******************************Public*Routine******************************\
  223. * EjectTheCdromDisc
  224. *
  225. * Eject the disc from the specified cdrom device.
  226. *
  227. * History:
  228. * 18-11-93 - StephenE - Created
  229. *
  230. \**************************************************************************/
  231. BOOL
  232. EjectTheCdromDisc(
  233. int cdrom
  234. )
  235. {
  236. DWORD status;
  237. /*
  238. ** Stop the drive first
  239. */
  240. status = StopCdrom( g_Devices[cdrom]->hCd );
  241. /*
  242. ** Eject the disc
  243. */
  244. status = EjectCdrom( g_Devices[cdrom]->hCd );
  245. CheckStatus( "EjectCdrom", status, cdrom );
  246. return status == ERROR_SUCCESS;
  247. }
  248. /******************************Public*Routine******************************\
  249. * PlayCurrTrack
  250. *
  251. * Set cdrom device playing from start MSF to end MSF of current
  252. * track.
  253. *
  254. * History:
  255. * 18-11-93 - StephenE - Created
  256. *
  257. \**************************************************************************/
  258. BOOL
  259. PlayCurrTrack(
  260. int cdrom
  261. )
  262. {
  263. DWORD status;
  264. MCI_PLAY_PARMS pam;
  265. int min,sec,endindex;
  266. PTRACK_PLAY tr;
  267. tr = CURRTRACK( cdrom );
  268. if (tr==NULL) {
  269. return( FALSE );
  270. }
  271. sec = TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec;
  272. min = TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin;
  273. min+= (sec / 60);
  274. sec = (sec % 60);
  275. pam.dwFrom = MCI_MAKE_MSF( min, sec, TRACK_F(cdrom,tr->TocIndex) );
  276. endindex = FindContiguousEnd( cdrom, tr );
  277. pam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex),
  278. TRACK_S(cdrom,endindex),
  279. TRACK_F(cdrom,endindex) );
  280. #if DBG
  281. {
  282. long lAddress, lEndPos, lStartPos;
  283. dprintf( "Playing from : %2.2d:%2.2d:%2.2d",
  284. MCI_MSF_MINUTE(pam.dwFrom),
  285. MCI_MSF_SECOND(pam.dwFrom),
  286. MCI_MSF_FRAME( pam.dwFrom) );
  287. dprintf( "Playing to : %2.2d:%2.2d:%2.2d",
  288. MCI_MSF_MINUTE(pam.dwTo),
  289. MCI_MSF_SECOND(pam.dwTo),
  290. MCI_MSF_FRAME( pam.dwTo) );
  291. lAddress = pam.dwFrom;
  292. lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  293. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  294. (MCI_MSF_FRAME(lAddress));
  295. lAddress = pam.dwTo;
  296. lEndPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  297. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  298. (MCI_MSF_FRAME(lAddress));
  299. lAddress = lEndPos - lStartPos;
  300. lStartPos =
  301. MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE),
  302. (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND,
  303. (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND);
  304. lAddress = lStartPos;
  305. dprintf( "Play length : %2.2d:%2.2d:%2.2d",
  306. MCI_MSF_MINUTE(lAddress),
  307. MCI_MSF_SECOND(lAddress),
  308. MCI_MSF_FRAME( lAddress) );
  309. }
  310. #endif
  311. status = PlayCdrom( g_Devices[cdrom]->hCd, &pam );
  312. CheckStatus( "PlayCurrTrack", status, cdrom );
  313. return status == ERROR_SUCCESS;
  314. }
  315. /******************************Public*Routine******************************\
  316. * StopTheCdromDrive
  317. *
  318. * Tell the cdrom device to stop playing
  319. *
  320. * History:
  321. * 18-11-93 - StephenE - Created
  322. *
  323. \**************************************************************************/
  324. BOOL
  325. StopTheCdromDrive(
  326. int cdrom
  327. )
  328. {
  329. DWORD status;
  330. status = StopCdrom( g_Devices[cdrom]->hCd );
  331. CheckStatus( "StopCdrom", status, cdrom );
  332. return status == ERROR_SUCCESS;
  333. }
  334. /******************************Public*Routine******************************\
  335. * PauseTheCdromDrive
  336. *
  337. * Tell the cdrom device to pause playing
  338. *
  339. * History:
  340. * 18-11-93 - StephenE - Created
  341. *
  342. \**************************************************************************/
  343. BOOL
  344. PauseTheCdromDrive(
  345. int cdrom
  346. )
  347. {
  348. DWORD status;
  349. status = PauseCdrom( g_Devices[cdrom]->hCd );
  350. CheckStatus( "PauseCdrom", status, cdrom );
  351. return status == ERROR_SUCCESS;
  352. }
  353. /******************************Public*Routine******************************\
  354. * ResumeTheCdromDrive
  355. *
  356. * Tell the cdrom device to resume playing
  357. *
  358. * History:
  359. * 18-11-93 - StephenE - Created
  360. *
  361. \**************************************************************************/
  362. BOOL
  363. ResumeTheCdromDrive(
  364. int cdrom
  365. )
  366. {
  367. DWORD status;
  368. status = ResumeCdrom( g_Devices[cdrom]->hCd, cdrom );
  369. CheckStatus( "ResumeCdrom", status, cdrom );
  370. if ( status == ERROR_NOT_READY ) {
  371. NoMediaUpdate( cdrom );
  372. }
  373. return status == ERROR_SUCCESS;
  374. }
  375. /******************************Public*Routine******************************\
  376. * SeekToCurrSecond
  377. *
  378. * Seek to the position on the disc represented by the
  379. * current time (position) information in gDevices, and
  380. * continue playing to the end of the current track.
  381. *
  382. * History:
  383. * 18-11-93 - StephenE - Created
  384. *
  385. \**************************************************************************/
  386. BOOL
  387. SeekToCurrSecond(
  388. int cdrom
  389. )
  390. {
  391. DWORD status;
  392. int endindex;
  393. PTRACK_PLAY tr;
  394. UCHAR StartingF, StartingS, StartingM;
  395. /*
  396. ** Build starting and ending positions for play
  397. */
  398. tr = CDTIME(cdrom).CurrTrack;
  399. if (tr == NULL) {
  400. return FALSE;
  401. }
  402. StartingM = (TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin);
  403. StartingS = (TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec);
  404. StartingF = (TRACK_F(cdrom,tr->TocIndex));
  405. if (StartingS > 59) {
  406. StartingM++;
  407. StartingS -= (UCHAR)60;
  408. }
  409. if (g_Devices[ cdrom ]->State & CD_PLAYING) {
  410. MCI_PLAY_PARMS mciPlay;
  411. endindex = FindContiguousEnd( cdrom, tr );
  412. mciPlay.dwFrom = MCI_MAKE_MSF( StartingM, StartingS, StartingF );
  413. mciPlay.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex),
  414. TRACK_S(cdrom,endindex),
  415. TRACK_F(cdrom,endindex) );
  416. status = PlayCdrom( g_Devices[ cdrom ]->hCd, &mciPlay );
  417. }
  418. else {
  419. MCI_SEEK_PARMS mciSeek;
  420. mciSeek.dwTo = MCI_MAKE_MSF( StartingM, StartingS, StartingF );
  421. status = SeekCdrom( g_Devices[ cdrom ]->hCd, &mciSeek );
  422. }
  423. CheckStatus( "SeekToCurrSec", status, cdrom );
  424. return status == ERROR_SUCCESS;
  425. }
  426. /******************************Public*Routine******************************\
  427. * GetCurrPos
  428. *
  429. * Query cdrom device for its current position and status
  430. * and return information in callers buffer.
  431. *
  432. * History:
  433. * 18-11-93 - StephenE - Created
  434. *
  435. \**************************************************************************/
  436. BOOL
  437. GetCurrPos(
  438. int cdrom,
  439. PCURRPOS CpPtr
  440. )
  441. {
  442. DWORD status;
  443. DWORD dwStatus;
  444. DWORD dwTrack;
  445. DWORD dwAbsPos;
  446. /*
  447. ** Tell lower layer what we want it to do...in this case,
  448. ** we need to specify which SubQData format we want returned.
  449. ** This is exported from scsicdrom.sys to the user layer
  450. ** so that it could be implemented in one call, instead of
  451. ** four separate calls (there are four SubQData formats)
  452. */
  453. /*
  454. ** Set up for current position SubQData format.
  455. */
  456. if (CDTIME(cdrom).CurrTrack != NULL) {
  457. //status = GetCdromCurrentPosition( g_Devices[ cdrom ]->hCd, &dwAbsPos );
  458. status = StatusTrackPosCdrom ( g_Devices[ cdrom ]->hCd, &dwStatus, &dwTrack, &dwAbsPos);
  459. }
  460. else {
  461. status = MCIERR_INTERNAL;
  462. }
  463. if (status == ERROR_SUCCESS) {
  464. int iTrack;
  465. LONG lAbsPosF;
  466. LONG lStartPos;
  467. LONG lTrackPos;
  468. //iTrack = (int)GetCdromCurrentTrack( g_Devices[ cdrom ]->hCd );
  469. iTrack = (int)dwTrack;
  470. //CpPtr->AudioStatus = GetCdromMode( g_Devices[ cdrom ]->hCd );
  471. CpPtr->AudioStatus = dwStatus;
  472. CpPtr->Track = iTrack;
  473. CpPtr->Index = 1;
  474. iTrack--;
  475. lStartPos = (TRACK_M(cdrom, iTrack ) * FRAMES_PER_MINUTE) +
  476. (TRACK_S(cdrom, iTrack ) * FRAMES_PER_SECOND) +
  477. (TRACK_F(cdrom, iTrack ));
  478. lAbsPosF = (MCI_MSF_MINUTE(dwAbsPos) * FRAMES_PER_MINUTE) +
  479. (MCI_MSF_SECOND(dwAbsPos) * FRAMES_PER_SECOND) +
  480. (MCI_MSF_FRAME(dwAbsPos));
  481. lTrackPos = lAbsPosF - lStartPos;
  482. /*
  483. ** Are we in the track lead in zone ?
  484. */
  485. if ( lTrackPos < 0 ) {
  486. /*
  487. ** Have we just entered the lead in zone
  488. */
  489. if (!g_Devices[cdrom]->fProcessingLeadIn) {
  490. g_Devices[cdrom]->fProcessingLeadIn = TRUE;
  491. /*
  492. ** Is the track that we are currently in the next track
  493. ** that we actually want to play. If it is then everything is
  494. ** OK. If it isn't then we need to hack the current position
  495. ** information so that it looks like we sre still playing the
  496. ** previous track.
  497. */
  498. if ( CURRTRACK(cdrom)->nextplay
  499. && CURRTRACK(cdrom)->nextplay->TocIndex == iTrack) {
  500. g_Devices[cdrom]->fShowLeadIn = TRUE;
  501. }
  502. else {
  503. g_Devices[cdrom]->fShowLeadIn = FALSE;
  504. }
  505. }
  506. if (g_Devices[cdrom]->fShowLeadIn) {
  507. CpPtr->Index = 0;
  508. lTrackPos = -lTrackPos;
  509. }
  510. else {
  511. CpPtr->Track = iTrack;
  512. iTrack--;
  513. lTrackPos = lAbsPosF
  514. - g_Devices[cdrom]->toc.TrackData[iTrack].AddressF;
  515. }
  516. }
  517. else {
  518. g_Devices[cdrom]->fShowLeadIn = FALSE;
  519. g_Devices[cdrom]->fProcessingLeadIn = FALSE;
  520. }
  521. CpPtr->m = (int)(lTrackPos / FRAMES_PER_MINUTE);
  522. CpPtr->s = (int)(lTrackPos % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
  523. CpPtr->f = (int)(lTrackPos % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND;
  524. CpPtr->ab_m = (int)MCI_MSF_MINUTE(dwAbsPos);
  525. CpPtr->ab_s = (int)MCI_MSF_SECOND(dwAbsPos);
  526. CpPtr->ab_f = (int)MCI_MSF_FRAME(dwAbsPos);
  527. /*
  528. ** Round up to the nearest second.
  529. */
  530. if (CpPtr->f > (FRAMES_PER_SECOND / 2) ) {
  531. if ( ++CpPtr->s > 59 ) {
  532. CpPtr->s = 0;
  533. CpPtr->m++;
  534. }
  535. }
  536. else {
  537. CpPtr->f = 0;
  538. }
  539. if (CpPtr->ab_f > (FRAMES_PER_SECOND / 2) ) {
  540. if ( ++CpPtr->ab_s > 59 ) {
  541. CpPtr->ab_s = 0;
  542. CpPtr->ab_m++;
  543. }
  544. }
  545. else {
  546. CpPtr->ab_f = 0;
  547. }
  548. }
  549. else {
  550. ZeroMemory( CpPtr, sizeof(*CpPtr) );
  551. }
  552. CheckStatus( "GetCurrPos", status, cdrom );
  553. return status==ERROR_SUCCESS;
  554. }
  555. /******************************Public*Routine******************************\
  556. * SeekToTrackAndHold
  557. *
  558. * Seek to specified track and enter hold state.
  559. *
  560. * History:
  561. * 18-11-93 - StephenE - Created
  562. *
  563. \**************************************************************************/
  564. BOOL
  565. SeekToTrackAndHold(
  566. int cdrom,
  567. int tindex
  568. )
  569. {
  570. DWORD status;
  571. MCI_SEEK_PARMS sam;
  572. sam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,tindex),
  573. TRACK_S(cdrom,tindex),
  574. TRACK_F(cdrom,tindex) );
  575. status = SeekCdrom( g_Devices[ cdrom ]->hCd, &sam );
  576. CheckStatus( "SeekToTrackAndHold", status, cdrom );
  577. return status == ERROR_SUCCESS;
  578. }
  579. /* -------------------------------------------------------------------------
  580. **
  581. ** Low level routines
  582. **
  583. ** -------------------------------------------------------------------------
  584. */
  585. /******************************Public*Routine******************************\
  586. * GetCdromTOC
  587. *
  588. * This routine will get the table of contents from
  589. * a CDRom device.
  590. *
  591. *
  592. * History:
  593. * 18-11-93 - StephenE - Created
  594. *
  595. \**************************************************************************/
  596. DWORD
  597. GetCdromTOC(
  598. MCIDEVICEID DevHandle,
  599. PCDROM_TOC TocPtr
  600. )
  601. {
  602. MCI_STATUS_PARMS mciStatus;
  603. long lAddress, lStartPos, lDiskLen;
  604. int i;
  605. DWORD dwRet;
  606. #if DBG
  607. dprintf( "Reading TOC for drive %d", DevHandle );
  608. #endif
  609. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  610. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  611. //
  612. // NOTE: none of the mciSendCommand calls below bother to check the
  613. // return code. This is asking for trouble... but if the
  614. // commands fail we cannot do much about it.
  615. //
  616. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  617. MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus);
  618. TocPtr->FirstTrack = 1;
  619. TocPtr->LastTrack = (UCHAR)mciStatus.dwReturn;
  620. mciStatus.dwItem = MCI_STATUS_POSITION;
  621. for ( i = 0; i < TocPtr->LastTrack; i++ ) {
  622. mciStatus.dwTrack = i + 1;
  623. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  624. MCI_STATUS_ITEM | MCI_TRACK,
  625. (DWORD)(LPVOID)&mciStatus);
  626. TocPtr->TrackData[i].TrackNumber = (UCHAR)(i + 1);
  627. lAddress = TocPtr->TrackData[i].Address = mciStatus.dwReturn;
  628. lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  629. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  630. (MCI_MSF_FRAME( lAddress));
  631. TocPtr->TrackData[i].AddressF = lStartPos;
  632. }
  633. mciStatus.dwItem = MCI_STATUS_LENGTH;
  634. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  635. MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus);
  636. /*
  637. ** Convert the absolute start address of the first track
  638. ** into Frames
  639. */
  640. lAddress = TocPtr->TrackData[0].Address;
  641. lStartPos = TocPtr->TrackData[0].AddressF;
  642. /*
  643. ** Convert the total disk length into Frames
  644. */
  645. lAddress = mciStatus.dwReturn;
  646. lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  647. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  648. (MCI_MSF_FRAME(lAddress));
  649. /*
  650. ** Now, determine the absolute start position of the sentinel
  651. ** track. That is, the special track that marks the end of the
  652. ** disk.
  653. */
  654. lAddress = lStartPos + lDiskLen;
  655. TocPtr->TrackData[i].TrackNumber = 0;
  656. TocPtr->TrackData[i].Address =
  657. MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE),
  658. (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND,
  659. (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND);
  660. return (TocPtr->LastTrack != 0) ? ERROR_SUCCESS : MCIERR_INTERNAL;
  661. }
  662. /******************************Public*Routine******************************\
  663. * StopCdrom
  664. *
  665. * This routine will stop a CDRom device that is playing.
  666. *
  667. *
  668. * History:
  669. * 18-11-93 - StephenE - Created
  670. *
  671. \**************************************************************************/
  672. DWORD
  673. StopCdrom(
  674. MCIDEVICEID DevHandle
  675. )
  676. {
  677. MCI_GENERIC_PARMS mciGen;
  678. ZeroMemory( &mciGen, sizeof(mciGen) );
  679. return mciSendCommand( DevHandle, MCI_STOP, 0L, (DWORD)(LPVOID)&mciGen );
  680. }
  681. /******************************Public*Routine******************************\
  682. * PauseCdrom
  683. *
  684. * This routine will pause a CDRom device.
  685. *
  686. * History:
  687. * 18-11-93 - StephenE - Created
  688. *
  689. \**************************************************************************/
  690. DWORD
  691. PauseCdrom(
  692. MCIDEVICEID DevHandle
  693. )
  694. {
  695. MCI_GENERIC_PARMS mciGen;
  696. ZeroMemory( &mciGen, sizeof(mciGen) );
  697. return mciSendCommand( DevHandle, MCI_PAUSE, 0L, (DWORD)(LPVOID)&mciGen );
  698. }
  699. /******************************Public*Routine******************************\
  700. * ResumeCdrom
  701. *
  702. * This routine will resume a paused CDRom device.
  703. *
  704. * History:
  705. * 18-11-93 - StephenE - Created
  706. *
  707. \**************************************************************************/
  708. DWORD
  709. ResumeCdrom(
  710. MCIDEVICEID DevHandle,
  711. int cdrom
  712. )
  713. {
  714. MCI_GENERIC_PARMS mciGen;
  715. DWORD dwRet;
  716. static int fCanResume = -1;
  717. ZeroMemory( &mciGen, sizeof(mciGen) );
  718. switch (fCanResume) {
  719. case -1:
  720. dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD)(LPVOID)&mciGen );
  721. fCanResume = (dwRet == MMSYSERR_NOERROR ? 1 : 0);
  722. if (0 == fCanResume) {
  723. dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE);
  724. }
  725. break;
  726. case 0:
  727. dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE);
  728. break;
  729. case 1:
  730. dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD)(LPVOID)&mciGen );
  731. break;
  732. }
  733. return dwRet;
  734. }
  735. /******************************Public*Routine******************************\
  736. * PlayCdrom
  737. *
  738. * This routine plays a CDRom device starting and ending at the MSF
  739. * positions specified in the structure passed in.
  740. *
  741. * History:
  742. * 18-11-93 - StephenE - Created
  743. *
  744. \**************************************************************************/
  745. DWORD
  746. PlayCdrom(
  747. MCIDEVICEID DevHandle,
  748. MCI_PLAY_PARMS *mciPlay
  749. )
  750. {
  751. return mciSendCommand( DevHandle, MCI_PLAY,
  752. MCI_FROM | MCI_TO, (DWORD)(LPVOID)mciPlay );
  753. }
  754. /******************************Public*Routine******************************\
  755. * IsCdromTrackAudio
  756. *
  757. *
  758. *
  759. * History:
  760. * dd-mm-94 - StephenE - Created
  761. *
  762. \**************************************************************************/
  763. BOOL
  764. IsCdromTrackAudio(
  765. CDHANDLE DevHandle,
  766. int iTrackNumber
  767. )
  768. {
  769. MCI_STATUS_PARMS mciStatus;
  770. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  771. mciStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  772. mciStatus.dwTrack = iTrackNumber + 1;
  773. mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
  774. (DWORD)(LPVOID)&mciStatus);
  775. return mciStatus.dwReturn == MCI_CDA_TRACK_AUDIO;
  776. }
  777. /******************************Public*Routine******************************\
  778. * GetCdromCurrentPosition
  779. *
  780. * Gets the current ABSOLUTE position of the specified cdrom device.
  781. *
  782. * History:
  783. * 18-11-93 - StephenE - Created
  784. *
  785. \**************************************************************************/
  786. DWORD
  787. GetCdromCurrentPosition(
  788. CDHANDLE DevHandle,
  789. DWORD *lpdwPosition
  790. )
  791. {
  792. MCI_STATUS_PARMS mciStatus;
  793. DWORD dwErr;
  794. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  795. mciStatus.dwItem = MCI_STATUS_POSITION;
  796. dwErr = mciSendCommand( DevHandle, MCI_STATUS,
  797. MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus );
  798. *lpdwPosition = mciStatus.dwReturn;
  799. return dwErr;
  800. }
  801. /******************************Public*Routine******************************\
  802. * GetCdromMode
  803. *
  804. * Gets the current mode of the cdrom.
  805. *
  806. * History:
  807. * 18-11-93 - StephenE - Created
  808. *
  809. \**************************************************************************/
  810. DWORD
  811. GetCdromMode(
  812. MCIDEVICEID DevHandle
  813. )
  814. {
  815. MCI_STATUS_PARMS mciStatus;
  816. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  817. mciStatus.dwItem = MCI_STATUS_MODE;
  818. mciSendCommand( DevHandle, MCI_STATUS,
  819. MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus );
  820. return mciStatus.dwReturn;
  821. }
  822. /******************************Public*Routine******************************\
  823. * GetCdromCurrentTrack
  824. *
  825. * Gets the current track of the cdrom.
  826. *
  827. * History:
  828. * 18-11-93 - StephenE - Created
  829. *
  830. \**************************************************************************/
  831. DWORD
  832. GetCdromCurrentTrack(
  833. MCIDEVICEID DevHandle
  834. )
  835. {
  836. MCI_STATUS_PARMS mciStatus;
  837. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  838. mciStatus.dwItem = MCI_STATUS_CURRENT_TRACK;
  839. mciSendCommand( DevHandle, MCI_STATUS,
  840. MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus );
  841. return mciStatus.dwReturn;
  842. }
  843. /******************************Public*Routine******************************\
  844. * SeekCdrom
  845. *
  846. * This routine seek to an MSF address on the audio CD and enters
  847. * a hold (paused) state.
  848. *
  849. *
  850. * History:
  851. * 18-11-93 - StephenE - Created
  852. *
  853. \**************************************************************************/
  854. DWORD
  855. SeekCdrom(
  856. MCIDEVICEID DevHandle,
  857. MCI_SEEK_PARMS *mciSeek
  858. )
  859. {
  860. return mciSendCommand( DevHandle, MCI_SEEK,
  861. MCI_TO, (DWORD)(LPVOID)mciSeek );
  862. }
  863. /******************************Public*Routine******************************\
  864. * EjectCdrom
  865. *
  866. * This routine will eject a disc from a CDRom device or close the tray if
  867. * it is open.
  868. *
  869. * History:
  870. * 18-11-93 - StephenE - Created
  871. *
  872. \**************************************************************************/
  873. DWORD
  874. EjectCdrom(
  875. MCIDEVICEID DevHandle
  876. )
  877. {
  878. MCI_SET_PARMS mciSet;
  879. ZeroMemory( &mciSet, sizeof(mciSet) );
  880. if (GetCdromMode(DevHandle) == MCI_MODE_OPEN) {
  881. return mciSendCommand( DevHandle, MCI_SET,
  882. MCI_SET_DOOR_CLOSED, (DWORD)(LPVOID)&mciSet );
  883. }
  884. else {
  885. return mciSendCommand( DevHandle, MCI_SET,
  886. MCI_SET_DOOR_OPEN, (DWORD)(LPVOID)&mciSet );
  887. }
  888. }
  889. /******************************Public*Routine******************************\
  890. * TestUnitReadyCdrom
  891. *
  892. * This routine will retrieve the status of the CDRom device.
  893. *
  894. * History:
  895. * 18-11-93 - StephenE - Created
  896. *
  897. \**************************************************************************/
  898. DWORD
  899. TestUnitReadyCdrom(
  900. MCIDEVICEID DevHandle
  901. )
  902. {
  903. MCI_STATUS_PARMS mciStatus;
  904. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  905. mciStatus.dwItem = MCI_STATUS_MEDIA_PRESENT;
  906. if ( mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM,
  907. (DWORD)(LPVOID)&mciStatus ) == MMSYSERR_NOERROR ) {
  908. return mciStatus.dwReturn ? ERROR_SUCCESS : ERROR_NOT_READY;
  909. }
  910. return ERROR_NOT_READY;
  911. }
  912. /******************************Public*Routine******************************\
  913. * StatusTrackPosCdrom
  914. *
  915. * This routine will retrieve the
  916. * status, current track, and current position of the CDRom device.
  917. *
  918. * History:
  919. * 18-11-93 - StephenE - Created
  920. *
  921. \**************************************************************************/
  922. DWORD
  923. StatusTrackPosCdrom(
  924. MCIDEVICEID DevHandle,
  925. DWORD * pStatus,
  926. DWORD * pTrack,
  927. DWORD * pPos
  928. )
  929. {
  930. DWORD dwErr;
  931. MCI_STATUS_PARMS mciStatus;
  932. PSTATUSTRACKPOS pSTP = NULL;
  933. STATUSTRACKPOS stp;
  934. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  935. // Note: This is a non-standard MCI call (I.E. HACK!)
  936. // the only reason for this behavior is it reduces
  937. // the number of IOCTL's per 1/2 second on the HeartBeat
  938. // thread for updating the timer display from ~15 to only
  939. // ~1 on average. Resulting in a major reduction in
  940. // system traffic on the SCSI or IDE bus.
  941. // Note: we are passing down a structre to MCICDA containing
  942. // the position, track, and status values which it will
  943. // fill in for us and return.
  944. mciStatus.dwItem = MCI_STATUS_TRACK_POS;
  945. mciStatus.dwReturn = (DWORD)&stp;
  946. dwErr = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM,
  947. (DWORD)(LPVOID)&mciStatus );
  948. if (dwErr == MMSYSERR_NOERROR)
  949. {
  950. pSTP = (PSTATUSTRACKPOS)mciStatus.dwReturn;
  951. if (pSTP)
  952. {
  953. if (pStatus)
  954. *pStatus = pSTP->dwStatus;
  955. if (pTrack)
  956. *pTrack = pSTP->dwTrack;
  957. if (pPos)
  958. *pPos = pSTP->dwDiscTime;
  959. pSTP = NULL;
  960. }
  961. }
  962. return dwErr;
  963. } // End StatusTrackPosCdrom
  964. #endif