I_CDMUS.C 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. //**************************************************************************
  2. //**
  3. //** i_cdmus.c
  4. //**
  5. //**************************************************************************
  6. // HEADER FILES ------------------------------------------------------------
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <dos.h>
  10. #include <stddef.h>
  11. #include <string.h>
  12. #include "h2def.h"
  13. #include "i_sound.h"
  14. // MACROS ------------------------------------------------------------------
  15. #define MAX_AUDIO_TRACKS 25
  16. #define MULTIPLEX_INT 0x2f
  17. #define CDROM_GETDRIVECOUNT 0x1500
  18. #define CDROM_SENDDEVICEREQ 0x1510
  19. #define CDROM_GETVERSION 0x150c
  20. #define HSG_MODE 0
  21. #define RED_MODE 1
  22. #define DRC_IOCTLINPUT 0x03
  23. #define DRC_IOCTLOUTPUT 0x0c
  24. #define DRC_PLAYAUDIO 0x84
  25. #define DRC_STOPAUDIO 0x85
  26. #define DRC_RESUMEAUDIO 0x88
  27. #define DPMI_INT 0x31
  28. #define DPMI_ALLOCREALMEM 0x0100
  29. #define DPMI_FREEREALMEM 0x0101
  30. #define DPMI_SIMREALINT 0x0300
  31. // IOCTL input commands
  32. #define ADRDEVHEAD 0 // Return Address of Device Header
  33. #define HEADLOCATION 1 // Location of Head
  34. #define RESERVED 2 // Reserved
  35. #define ERRSTATISTICS 3 // Error Statistics
  36. #define AUDIOCHANINFO 4 // Audio Channel Info
  37. #define READDRVBYTES 5 // Read Drive Bytes
  38. #define DEVICESTATUS 6 // Device Status
  39. #define GETSECTORSIZE 7 // Return Sector Size
  40. #define GETVOLSIZE 8 // Return Volume Size
  41. #define MEDIACHANGED 9 // Media Changed
  42. #define AUDIODISKINFO 10 // Audio Disk Info
  43. #define AUDIOTRACKINFO 11 // Audio Track Info
  44. #define AUDIOQCHANINFO 12 // Audio Q-Channel Info
  45. #define AUDIOSUBINFO 13 // Audio Sub-Channel Info
  46. #define UPCCODE 14 // UPC Code
  47. #define AUDIOSTATUSINFO 15 // Audio Status Info
  48. // IOCTL output commands
  49. #define EJECTDISK 0 // Eject Disk
  50. #define DOORLOCK 1 // Lock/Unlock Door
  51. #define RESETDRIVE 2 // Reset Drive
  52. #define AUDIOCHANCONTROL 3 // Audio Channel Control
  53. #define WRITEDEVCONTROL 4 // Write Device Control String
  54. #define CLOSETRAY 5 // Close Tray
  55. // TYPES -------------------------------------------------------------------
  56. typedef signed char S_BYTE;
  57. typedef unsigned char U_BYTE;
  58. typedef signed short S_WORD;
  59. typedef unsigned short U_WORD;
  60. typedef signed int S_LONG;
  61. typedef unsigned int U_LONG;
  62. typedef struct {
  63. U_LONG size;
  64. void **address;
  65. U_WORD *segment;
  66. U_WORD *selector;
  67. } DOSChunk_t;
  68. typedef struct {
  69. U_LONG edi;
  70. U_LONG esi;
  71. U_LONG ebp;
  72. U_LONG reserved;
  73. U_LONG ebx;
  74. U_LONG edx;
  75. U_LONG ecx;
  76. U_LONG eax;
  77. U_WORD flags;
  78. U_WORD es;
  79. U_WORD ds;
  80. U_WORD fs;
  81. U_WORD gs;
  82. U_WORD ip;
  83. U_WORD cs;
  84. U_WORD sp;
  85. U_WORD ss;
  86. } RegBlock_t;
  87. typedef struct {
  88. short lengthMin;
  89. short lengthSec;
  90. int redStart;
  91. int sectorStart;
  92. int sectorLength;
  93. } AudioTrack_t;
  94. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  95. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  96. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  97. static U_WORD InputIOCTL(S_WORD request, U_LONG pctrlblk);
  98. static U_WORD OutputIOCTL(S_WORD request, U_LONG pctrlblk);
  99. static U_LONG RedToSectors(U_LONG red);
  100. static int AllocIOCTLBuffers(void);
  101. static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock);
  102. static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
  103. U_WORD *selector);
  104. static void DPMI_FreeRealMem(U_WORD selector);
  105. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  106. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  107. int cd_Error;
  108. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  109. static int cd_DriveCount;
  110. static int cd_FirstDrive;
  111. static int cd_CurDrive;
  112. static U_WORD cd_Version;
  113. static int cd_FirstTrack;
  114. static int cd_LastTrack;
  115. static int cd_TrackCount;
  116. static U_WORD cd_LeadOutMin;
  117. static U_WORD cd_LeadOutSec;
  118. static U_LONG cd_LeadOutRed;
  119. static U_LONG cd_LeadOutSector;
  120. static U_LONG cd_IOCTLBufferTotal;
  121. static AudioTrack_t cd_AudioTracks[MAX_AUDIO_TRACKS];
  122. static int OkInit = 0;
  123. static RegBlock_t RegBlock;
  124. static struct PlayReq_s { // CD-ROM Play Audio Device Request Struct
  125. U_BYTE headerSize;
  126. U_BYTE subUnitCode;
  127. U_BYTE command; // = DRC_PLAYAUDIO
  128. U_WORD status;
  129. U_BYTE reserved[8];
  130. U_BYTE addressMode;
  131. U_LONG startSector;
  132. U_LONG numberToRead;
  133. } *cd_PlayReq;
  134. static U_WORD cd_PlayReqSeg;
  135. static U_WORD cd_PlayReqSel;
  136. static struct StopReq_s { // CD-ROM Stop Audio Device Request Struct
  137. U_BYTE headerSize;
  138. U_BYTE subUnitCode;
  139. U_BYTE command; // = DRC_STOPAUDIO
  140. U_WORD status;
  141. U_BYTE reserved[8];
  142. } *cd_StopReq;
  143. static U_WORD cd_StopReqSeg;
  144. static U_WORD cd_StopReqSel;
  145. static struct ResumeReq_s { // CD-ROM Resume Audio Device Request Struct
  146. U_BYTE headerSize;
  147. U_BYTE subUnitCode;
  148. U_BYTE command; // = DRC_RESUMEAUDIO
  149. U_WORD status;
  150. U_BYTE reserved[8];
  151. } *cd_ResumeReq;
  152. static U_WORD cd_ResumeReqSeg;
  153. static U_WORD cd_ResumeReqSel;
  154. // IOCTL Input command data buffer structures
  155. static struct IOCTLIn_s { // IOCTL Input Struct
  156. U_BYTE headerSize;
  157. U_BYTE subUnitCode;
  158. U_BYTE command; // = DRC_IOCTLINPUT
  159. U_WORD status;
  160. U_BYTE reserved[8];
  161. U_BYTE mediaDescriptor;
  162. U_LONG ctrlBlkAddr;
  163. U_WORD tranSize;
  164. U_WORD startSector;
  165. U_LONG volPtr;
  166. } *cd_IOCTLIn;
  167. static U_WORD cd_IOCTLInSeg;
  168. static U_WORD cd_IOCTLInSel;
  169. static struct RAddrDevHead_s {
  170. U_BYTE code; // ADRDEVHEAD
  171. U_LONG devHdrAddr; // Address of device header
  172. } *cd_RAddrDevHead;
  173. static U_WORD cd_RAddrDevHeadSeg;
  174. static U_WORD cd_RAddrDevHeadSel;
  175. static struct LocHead_s {
  176. U_BYTE code; // HEADLOCATION
  177. U_BYTE addrMode; // Addressing mode
  178. U_LONG headLocation; // Location of drive head
  179. } *cd_LocHead;
  180. static U_WORD cd_LocHeadSeg;
  181. static U_WORD cd_LocHeadSel;
  182. static struct ErrStat_s {
  183. U_BYTE code; // ERRSTATISTICS
  184. U_BYTE errVal; // Error statistics
  185. } *cd_ErrStat;
  186. static U_WORD cd_ErrStatSeg;
  187. static U_WORD cd_ErrStatSel;
  188. static struct AudChanInfo_s {
  189. U_BYTE code; // AUDIOCHANINFO
  190. U_BYTE inChanOut0; // Input chan(0,1,2,or 3) for output chan 0
  191. U_BYTE volumeOut0; // Volume control (0-0xff) for output chan 0
  192. U_BYTE inChanOut1; // Input chan(0,1,2,or 3) for output chan 1
  193. U_BYTE volumeOut1; // Volume control (0-0xff) for output chan 1
  194. U_BYTE inChanOut2; // Input chan(0,1,2,or 3) for output chan 2
  195. U_BYTE volumeOut2; // Volume control (0-0xff) for output chan 2
  196. U_BYTE inChanOut3; // Input chan(0,1,2,or 3) for output chan 3
  197. U_BYTE volumeOut3; // Volume control (0-0xff) for output chan 3
  198. } *cd_AudChanInfo;
  199. static U_WORD cd_AudChanInfoSeg;
  200. static U_WORD cd_AudChanInfoSel;
  201. static struct RDrvBytes_s {
  202. U_BYTE code; // READDRVBYTES
  203. U_BYTE numBytes; // Number of bytes to read
  204. U_BYTE rBuffer[128]; // Read buffer
  205. } *cd_RDrvBytes;
  206. static U_WORD cd_RDrvBytesSeg;
  207. static U_WORD cd_RDrvBytesSel;
  208. static struct DevStat_s {
  209. U_BYTE code; // DEVICESTATUS
  210. U_LONG devParams; // Device parameters
  211. } *cd_DevStat;
  212. static U_WORD cd_DevStatSeg;
  213. static U_WORD cd_DevStatSel;
  214. static struct SectSize_s {
  215. U_BYTE code; // GETSECTORSIZE
  216. U_BYTE readMode; // Read mode
  217. U_WORD sectorSize; // Sector size
  218. } *cd_SectSize;
  219. static U_WORD cd_SectSizeSeg;
  220. static U_WORD cd_SectSizeSel;
  221. static struct VolSize_s {
  222. U_BYTE code; // GETVOLSIZE
  223. U_LONG volumeSize; // Volume size
  224. } *cd_VolSize;
  225. static U_WORD cd_VolSizeSeg;
  226. static U_WORD cd_VolSizeSel;
  227. static struct MedChng_s {
  228. U_BYTE code; // MEDIACHANGED
  229. U_BYTE changed; // Media byte
  230. } *cd_MedChng;
  231. static U_WORD cd_MedChngSeg;
  232. static U_WORD cd_MedChngSel;
  233. static struct DiskInfo_s {
  234. U_BYTE code; // AUDIODISKINFO
  235. U_BYTE lowTrack; // Lowest track number
  236. U_BYTE highTrack; // Highest track number
  237. U_LONG startLeadOut; // Starting point of the lead-out track
  238. } *cd_DiskInfo;
  239. static U_WORD cd_DiskInfoSeg;
  240. static U_WORD cd_DiskInfoSel;
  241. static struct TrackInfo_s {
  242. U_BYTE code; // AUDIOTRACKINFO
  243. U_BYTE track; // Track number
  244. U_LONG start; // Starting point of the track
  245. U_BYTE ctrlInfo; // Track control information
  246. } *cd_TrackInfo;
  247. static U_WORD cd_TrackInfoSeg;
  248. static U_WORD cd_TrackInfoSel;
  249. static struct QInfo_s {
  250. U_BYTE code; // AUDIOQCHANINFO
  251. U_BYTE control; // CONTROL and ADR byte
  252. U_BYTE tno; // Track number (TNO)
  253. U_BYTE index; // (POINT) or Index(X)
  254. U_BYTE min; // (MIN) Running time within a track
  255. U_BYTE sec; // (SEC) " " " " "
  256. U_BYTE frame; // (FRAME) " " " " "
  257. U_BYTE zero; // (ZERO) " " " " "
  258. U_BYTE aMin; // (AMIN) or (PMIN) Running time on disk
  259. U_BYTE aSec; // (ASEC) or (PSEC) " " " "
  260. U_BYTE aFrame; // (AFRAME) or (PFRAME)" " " "
  261. } *cd_QInfo;
  262. static U_WORD cd_QInfoSeg;
  263. static U_WORD cd_QInfoSel;
  264. static struct SubChanInfo_s {
  265. U_BYTE code; // AUDIOSUBINFO
  266. U_LONG startSectAddr; // Starting sector address
  267. U_LONG transAddr; // Transfer address
  268. U_LONG numSects; // Number of sectors to read
  269. } *cd_SubChanInfo;
  270. static U_WORD cd_SubChanInfoSeg;
  271. static U_WORD cd_SubChanInfoSel;
  272. static struct UPCCode_s {
  273. U_BYTE code; // UPCCODE
  274. U_BYTE control; // CONTROL and ADR byte
  275. U_BYTE upc[7]; // UPC/EAN code
  276. U_BYTE zero; // Zero
  277. U_BYTE aFrame; // Aframe
  278. } *cd_UPCCode;
  279. static U_WORD cd_UPCCodeSeg;
  280. static U_WORD cd_UPCCodeSel;
  281. static struct AudStat_s {
  282. U_BYTE code; // AUDIOSTATUSINFO
  283. U_WORD status; // Audio status bits
  284. U_LONG startPlay; // Starting location of last Play/Resume
  285. U_LONG endPlay; // Ending location for last Play/Resume
  286. } *cd_AudStat;
  287. static U_WORD cd_AudStatSeg;
  288. static U_WORD cd_AudStatSel;
  289. // IOCTL Output command data buffer structures
  290. static struct IOCTLOut_s { // IOCTL Output struct
  291. U_BYTE headerSize;
  292. U_BYTE subUnitCode;
  293. U_BYTE command; // = DRC_IOCTLOUTPUT
  294. U_WORD status;
  295. U_BYTE reserved[8];
  296. U_BYTE mediaDescriptor;
  297. U_LONG ctrlBlkAddr;
  298. U_WORD tranSize;
  299. U_WORD startSector;
  300. U_LONG volPtr;
  301. } *cd_IOCTLOut;
  302. static U_WORD cd_IOCTLOutSeg;
  303. static U_WORD cd_IOCTLOutSel;
  304. static struct Eject_s {
  305. U_BYTE code; // EJECTDISK
  306. } *cd_Eject;
  307. static U_WORD cd_EjectSeg;
  308. static U_WORD cd_EjectSel;
  309. static struct LockDoor_s {
  310. U_BYTE code; // DOORLOCK
  311. U_BYTE lock; // Lock function : 0 = unlock, 1 = lock
  312. } *cd_LockDoor;
  313. static U_WORD cd_LockDoorSeg;
  314. static U_WORD cd_LockDoorSel;
  315. static struct ResetDrv_s {
  316. U_BYTE code; // RESETDRIVE
  317. } *cd_ResetDrv;
  318. static U_WORD cd_ResetDrvSeg;
  319. static U_WORD cd_ResetDrvSel;
  320. static struct AudInfo_s {
  321. U_BYTE code; // AUDIOCHANCONTROL
  322. U_BYTE inChanOut0; // Input chan(0,1,2,or 3) for output chan 0
  323. U_BYTE volumeOut0; // Volume control (0-0xff) for output chan 0
  324. U_BYTE inChanOut1; // Input chan(0,1,2,or 3) for output chan 1
  325. U_BYTE volumeOut1; // Volume control (0-0xff) for output chan 1
  326. U_BYTE inChanOut2; // Input chan(0,1,2,or 3) for output chan 2
  327. U_BYTE volumeOut2; // Volume control (0-0xff) for output chan 2
  328. U_BYTE inChanOut3; // Input chan(0,1,2,or 3) for output chan 3
  329. U_BYTE volumeOut3; // Volume control (0-0xff) for output chan 3
  330. } *cd_AudInfo;
  331. static U_WORD cd_AudInfoSeg;
  332. static U_WORD cd_AudInfoSel;
  333. static struct WDrvBytes_s {
  334. U_BYTE code; // WRITEDEVCONTROL
  335. U_BYTE buf[5]; // Write buffer - size ??
  336. } *cd_WDrvBytes;
  337. static U_WORD cd_WDrvBytesSeg;
  338. static U_WORD cd_WDrvBytesSel;
  339. static struct CloseTray_s {
  340. U_BYTE code; // CLOSETRAY
  341. } *cd_CloseTray;
  342. static U_WORD cd_CloseTraySeg;
  343. static U_WORD cd_CloseTraySel;
  344. static U_WORD InCtrlBlkSize[16] = {
  345. 0x05, 0x06, 0x00, 0x00,
  346. 0x09, 0x82, 0x05, 0x04,
  347. 0x05, 0x02, 0x07, 0x07,
  348. 0x0b, 0x0d, 0x0b, 0x0b
  349. };
  350. static U_WORD OutCtrlBlkSize[6] = {
  351. 0x01, 0x02,
  352. 0x01, 0x09,
  353. 0x06, 0x01
  354. };
  355. // Structures for allocating conventional memory
  356. static DOSChunk_t DOSChunks[] = {
  357. {
  358. sizeof(struct PlayReq_s),
  359. &cd_PlayReq, &cd_PlayReqSeg, &cd_PlayReqSel
  360. },
  361. {
  362. sizeof(struct StopReq_s),
  363. &cd_StopReq, &cd_StopReqSeg, &cd_StopReqSel
  364. },
  365. {
  366. sizeof(struct ResumeReq_s),
  367. &cd_ResumeReq, &cd_ResumeReqSeg, &cd_ResumeReqSel
  368. },
  369. {
  370. sizeof(struct IOCTLOut_s),
  371. &cd_IOCTLOut, &cd_IOCTLOutSeg, &cd_IOCTLOutSel
  372. },
  373. {
  374. sizeof(struct Eject_s),
  375. &cd_Eject, &cd_EjectSeg, &cd_EjectSel
  376. },
  377. {
  378. sizeof(struct LockDoor_s),
  379. &cd_LockDoor, &cd_LockDoorSeg, &cd_LockDoorSel
  380. },
  381. {
  382. sizeof(struct ResetDrv_s),
  383. &cd_ResetDrv, &cd_ResetDrvSeg, &cd_ResetDrvSel
  384. },
  385. {
  386. sizeof(struct AudInfo_s),
  387. &cd_AudInfo, &cd_AudInfoSeg, &cd_AudInfoSel
  388. },
  389. {
  390. sizeof(struct WDrvBytes_s),
  391. &cd_WDrvBytes, &cd_WDrvBytesSeg, &cd_WDrvBytesSel
  392. },
  393. {
  394. sizeof(struct CloseTray_s),
  395. &cd_CloseTray, &cd_CloseTraySeg, &cd_CloseTraySel
  396. },
  397. {
  398. sizeof(struct IOCTLIn_s),
  399. &cd_IOCTLIn, &cd_IOCTLInSeg, &cd_IOCTLInSel
  400. },
  401. {
  402. sizeof(struct RAddrDevHead_s),
  403. &cd_RAddrDevHead, &cd_RAddrDevHeadSeg, &cd_RAddrDevHeadSel
  404. },
  405. {
  406. sizeof(struct LocHead_s),
  407. &cd_LocHead, &cd_LocHeadSeg, &cd_LocHeadSel
  408. },
  409. {
  410. sizeof(struct ErrStat_s),
  411. &cd_ErrStat, &cd_ErrStatSeg, &cd_ErrStatSel
  412. },
  413. {
  414. sizeof(struct AudChanInfo_s),
  415. &cd_AudChanInfo, &cd_AudChanInfoSeg, &cd_AudChanInfoSel
  416. },
  417. {
  418. sizeof(struct RDrvBytes_s),
  419. &cd_RDrvBytes, &cd_RDrvBytesSeg, &cd_RDrvBytesSel
  420. },
  421. {
  422. sizeof(struct DevStat_s),
  423. &cd_DevStat, &cd_DevStatSeg, &cd_DevStatSel
  424. },
  425. {
  426. sizeof(struct SectSize_s),
  427. &cd_SectSize, &cd_SectSizeSeg, &cd_SectSizeSel
  428. },
  429. {
  430. sizeof(struct VolSize_s),
  431. &cd_VolSize, &cd_VolSizeSeg, &cd_VolSizeSel
  432. },
  433. {
  434. sizeof(struct MedChng_s),
  435. &cd_MedChng, &cd_MedChngSeg, &cd_MedChngSel
  436. },
  437. {
  438. sizeof(struct DiskInfo_s),
  439. &cd_DiskInfo, &cd_DiskInfoSeg, &cd_DiskInfoSel
  440. },
  441. {
  442. sizeof(struct TrackInfo_s),
  443. &cd_TrackInfo, &cd_TrackInfoSeg, &cd_TrackInfoSel
  444. },
  445. {
  446. sizeof(struct QInfo_s),
  447. &cd_QInfo, &cd_QInfoSeg, &cd_QInfoSel
  448. },
  449. {
  450. sizeof(struct SubChanInfo_s),
  451. &cd_SubChanInfo, &cd_SubChanInfoSeg, &cd_SubChanInfoSel
  452. },
  453. {
  454. sizeof(struct UPCCode_s),
  455. &cd_UPCCode, &cd_UPCCodeSeg, &cd_UPCCodeSel
  456. },
  457. {
  458. sizeof(struct AudStat_s),
  459. &cd_AudStat, &cd_AudStatSeg, &cd_AudStatSel
  460. },
  461. {
  462. 0, NULL, NULL, NULL
  463. }
  464. };
  465. // CODE --------------------------------------------------------------------
  466. //==========================================================================
  467. //
  468. // I_CDMusInit
  469. //
  470. // Initializes the CD audio system. Must be called before using any
  471. // other I_CDMus functions.
  472. //
  473. // Returns: 0 (ok) or -1 (error, in cd_Error).
  474. //
  475. //==========================================================================
  476. int I_CDMusInit(void)
  477. {
  478. int i;
  479. int sect;
  480. int maxTrack;
  481. S_BYTE startMin1 = 0;
  482. S_BYTE startSec1 = 0;
  483. S_BYTE startMin2 = 0;
  484. S_BYTE startSec2 = 0;
  485. S_BYTE lengthMin = 0;
  486. S_BYTE lengthSec = 0;
  487. if(OkInit != 1)
  488. { // Only execute if uninitialized
  489. // Get number of CD-ROM drives and first drive
  490. memset(&RegBlock, 0, sizeof(RegBlock));
  491. RegBlock.eax = CDROM_GETDRIVECOUNT;
  492. RegBlock.ebx = 0;
  493. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  494. cd_DriveCount = RegBlock.ebx;
  495. // MSCDEX not installed if number of drives = 0
  496. if(cd_DriveCount == 0)
  497. {
  498. cd_Error = CDERR_NOTINSTALLED;
  499. return -1;
  500. }
  501. cd_FirstDrive = RegBlock.ecx;
  502. cd_CurDrive = cd_FirstDrive;
  503. // Allocate the IOCTL buffers
  504. if(AllocIOCTLBuffers() == -1)
  505. {
  506. cd_Error = CDERR_IOCTLBUFFMEM;
  507. return -1;
  508. }
  509. // Get MSCDEX version
  510. // Major version in upper byte, minor version in lower byte
  511. memset(&RegBlock, 0, sizeof(RegBlock));
  512. RegBlock.eax = CDROM_GETVERSION;
  513. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  514. cd_Version = RegBlock.ebx;
  515. // Check device status to make sure we can read Audio CD's
  516. InputIOCTL(DEVICESTATUS, cd_DevStatSeg);
  517. if((cd_DevStat->devParams & 0x0010) == 0)
  518. {
  519. cd_Error = CDERR_NOAUDIOSUPPORT;
  520. return -1;
  521. }
  522. }
  523. // Force audio to stop playing
  524. I_CDMusStop();
  525. // Make sure we have the current TOC
  526. InputIOCTL(MEDIACHANGED, cd_MedChngSeg);
  527. // Set track variables
  528. InputIOCTL(AUDIODISKINFO, cd_DiskInfoSeg);
  529. cd_FirstTrack = cd_DiskInfo->lowTrack;
  530. cd_LastTrack = cd_DiskInfo->highTrack;
  531. if(cd_FirstTrack == 0 && cd_FirstTrack == cd_LastTrack)
  532. {
  533. cd_Error = CDERR_NOAUDIOTRACKS;
  534. return -1;
  535. }
  536. cd_TrackCount = cd_LastTrack-cd_FirstTrack+1;
  537. cd_LeadOutMin = cd_DiskInfo->startLeadOut>>16 & 0xFF;
  538. cd_LeadOutSec = cd_DiskInfo->startLeadOut>>8 & 0xFF;
  539. cd_LeadOutRed = cd_DiskInfo->startLeadOut;
  540. cd_LeadOutSector = RedToSectors(cd_DiskInfo->startLeadOut);
  541. // Create Red Book start, sector start, and sector length
  542. // for all tracks
  543. sect = cd_LeadOutSector;
  544. for(i = cd_LastTrack; i >= cd_FirstTrack; i--)
  545. {
  546. cd_TrackInfo->track = i;
  547. InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  548. if(i < MAX_AUDIO_TRACKS)
  549. {
  550. cd_AudioTracks[i].redStart = cd_TrackInfo->start;
  551. cd_AudioTracks[i].sectorStart =
  552. RedToSectors(cd_TrackInfo->start);
  553. cd_AudioTracks[i].sectorLength =
  554. sect-RedToSectors(cd_TrackInfo->start);
  555. }
  556. sect = RedToSectors(cd_TrackInfo->start);
  557. }
  558. // Create track lengths in minutes and seconds
  559. if(cd_LastTrack >= MAX_AUDIO_TRACKS)
  560. {
  561. maxTrack = MAX_AUDIO_TRACKS-1;
  562. }
  563. else
  564. {
  565. maxTrack = cd_LastTrack;
  566. }
  567. cd_TrackInfo->track = cd_FirstTrack;
  568. InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  569. startMin1 = (cd_TrackInfo->start >> 16);
  570. startSec1 = (cd_TrackInfo->start >> 8);
  571. for(i = cd_FirstTrack; i <= maxTrack; i++)
  572. {
  573. cd_TrackInfo->track = i+1;
  574. if(i < cd_LastTrack)
  575. {
  576. InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
  577. startMin2 = (cd_TrackInfo->start >> 16);
  578. startSec2 = (cd_TrackInfo->start >> 8);
  579. }
  580. else
  581. {
  582. startMin2 = cd_LeadOutRed>>16;
  583. startSec2 = cd_LeadOutRed>>8;
  584. }
  585. lengthSec = startSec2 - startSec1;
  586. lengthMin = startMin2 - startMin1;
  587. if(lengthSec < 0)
  588. {
  589. lengthSec += 60;
  590. lengthMin--;
  591. }
  592. cd_AudioTracks[i].lengthMin = lengthMin;
  593. cd_AudioTracks[i].lengthSec = lengthSec;
  594. startMin1 = startMin2;
  595. startSec1 = startSec2;
  596. }
  597. // Clip high tracks
  598. cd_LastTrack = maxTrack;
  599. OkInit = 1;
  600. return 0;
  601. }
  602. //==========================================================================
  603. //
  604. // I_CDMusPlay
  605. //
  606. // Play an audio CD track.
  607. //
  608. // Returns: 0 (ok) or -1 (error, in cd_Error).
  609. //
  610. //==========================================================================
  611. int I_CDMusPlay(int track)
  612. {
  613. int start;
  614. int len;
  615. if(track < cd_FirstTrack || track > cd_LastTrack)
  616. {
  617. cd_Error = CDERR_BADTRACK;
  618. return(-1);
  619. }
  620. I_CDMusStop();
  621. start = cd_AudioTracks[track].redStart;
  622. len = cd_AudioTracks[track].sectorLength;
  623. cd_PlayReq->addressMode = RED_MODE;
  624. cd_PlayReq->startSector = start;
  625. cd_PlayReq->numberToRead = len;
  626. memset(&RegBlock, 0, sizeof(RegBlock));
  627. RegBlock.eax = CDROM_SENDDEVICEREQ;
  628. RegBlock.ecx = cd_CurDrive;
  629. RegBlock.ebx = 0;
  630. RegBlock.es = cd_PlayReqSeg;
  631. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  632. if(cd_PlayReq->status&0x8000)
  633. {
  634. cd_Error = CDERR_DEVREQBASE+(cd_PlayReq->status)&0x00ff;
  635. return(-1);
  636. }
  637. return(0);
  638. }
  639. //==========================================================================
  640. //
  641. // I_CDMusStop
  642. //
  643. // Stops the playing of an audio CD.
  644. //
  645. // Returns: 0 (ok) or -1 (error, in cd_Error).
  646. //
  647. //==========================================================================
  648. int I_CDMusStop(void)
  649. {
  650. memset(&RegBlock, 0, sizeof(RegBlock));
  651. RegBlock.eax = CDROM_SENDDEVICEREQ;
  652. RegBlock.ecx = cd_CurDrive;
  653. RegBlock.ebx = 0;
  654. RegBlock.es = cd_StopReqSeg;
  655. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  656. if(cd_StopReq->status&0x8000)
  657. {
  658. cd_Error = CDERR_DEVREQBASE+(cd_StopReq->status)&0x00ff;
  659. return -1;
  660. }
  661. return 0;
  662. }
  663. //==========================================================================
  664. //
  665. // I_CDMusResume
  666. //
  667. // Resumes the playing of an audio CD.
  668. //
  669. // Returns: 0 (ok) or -1 (error, in cd_Error).
  670. //
  671. //==========================================================================
  672. int I_CDMusResume(void)
  673. {
  674. memset(&RegBlock, 0, sizeof(RegBlock));
  675. RegBlock.eax = CDROM_SENDDEVICEREQ;
  676. RegBlock.ecx = cd_CurDrive;
  677. RegBlock.ebx = 0;
  678. RegBlock.es = cd_ResumeReqSeg;
  679. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  680. if(cd_ResumeReq->status&0x8000)
  681. {
  682. cd_Error = CDERR_DEVREQBASE+(cd_ResumeReq->status)&0x00ff;
  683. return -1;
  684. }
  685. return 0;
  686. }
  687. //==========================================================================
  688. //
  689. // I_CDMusSetVolume
  690. //
  691. // Sets the CD audio volume (0 - 255).
  692. //
  693. // Returns: 0 (ok) or -1 (error, in cd_Error).
  694. //
  695. //==========================================================================
  696. int I_CDMusSetVolume(int volume)
  697. {
  698. if(!OkInit)
  699. {
  700. cd_Error = CDERR_NOTINSTALLED;
  701. return -1;
  702. }
  703. // Read current channel info
  704. InputIOCTL(AUDIOCHANINFO, cd_AudChanInfoSeg);
  705. // Change the volumes
  706. cd_AudChanInfo->volumeOut0 =
  707. cd_AudChanInfo->volumeOut1 =
  708. cd_AudChanInfo->volumeOut2 =
  709. cd_AudChanInfo->volumeOut3 = volume;
  710. // Write modified channel info
  711. OutputIOCTL(AUDIOCHANCONTROL, cd_AudChanInfoSeg);
  712. return 0;
  713. }
  714. //==========================================================================
  715. //
  716. // I_CDMusFirstTrack
  717. //
  718. // Returns: the number of the first track.
  719. //
  720. //==========================================================================
  721. int I_CDMusFirstTrack(void)
  722. {
  723. return cd_FirstTrack;
  724. }
  725. //==========================================================================
  726. //
  727. // I_CDMusLastTrack
  728. //
  729. // Returns: the number of the last track.
  730. //
  731. //==========================================================================
  732. int I_CDMusLastTrack(void)
  733. {
  734. return cd_LastTrack;
  735. }
  736. //==========================================================================
  737. //
  738. // I_CDMusTrackLength
  739. //
  740. // Returns: Length of the given track in seconds, or -1 (error, in
  741. // cd_Error).
  742. //
  743. //==========================================================================
  744. int I_CDMusTrackLength(int track)
  745. {
  746. if(track < cd_FirstTrack || track > cd_LastTrack)
  747. {
  748. cd_Error = CDERR_BADTRACK;
  749. return -1;
  750. }
  751. return cd_AudioTracks[track].lengthMin*60
  752. +cd_AudioTracks[track].lengthSec;
  753. }
  754. //==========================================================================
  755. //
  756. // AllocIOCTLBuffers
  757. //
  758. // Allocates conventional memory for the IOCTL input and output buffers.
  759. // Sets cd_IOCTLBufferTotal to the total allocated.
  760. //
  761. // Returns: 0 (ok) or -1 (error, in cd_Error).
  762. //
  763. //==========================================================================
  764. static int AllocIOCTLBuffers(void)
  765. {
  766. int i;
  767. int size;
  768. DOSChunk_t *ck;
  769. cd_IOCTLBufferTotal = 0;
  770. for(i = 0; DOSChunks[i].size != 0; i++)
  771. {
  772. ck = &DOSChunks[i];
  773. size = ck->size;
  774. cd_IOCTLBufferTotal += (size+15)&0xfffffff0;
  775. *ck->address = DPMI_AllocRealMem(size, ck->segment, ck->selector);
  776. if(*ck->address == NULL)
  777. {
  778. return -1;
  779. }
  780. memset(*ck->address, 0, size);
  781. }
  782. cd_IOCTLIn->headerSize = sizeof(struct IOCTLIn_s);
  783. cd_IOCTLIn->command = DRC_IOCTLINPUT;
  784. cd_IOCTLOut->headerSize = sizeof(struct IOCTLOut_s);
  785. cd_IOCTLOut->command = DRC_IOCTLOUTPUT;
  786. cd_PlayReq->headerSize = sizeof(struct PlayReq_s);
  787. cd_PlayReq->command = DRC_PLAYAUDIO;
  788. cd_StopReq->headerSize = sizeof(struct StopReq_s);
  789. cd_StopReq->command = DRC_STOPAUDIO;
  790. cd_ResumeReq->headerSize = sizeof(struct ResumeReq_s);
  791. cd_ResumeReq->command = DRC_RESUMEAUDIO;
  792. return 0;
  793. }
  794. //==========================================================================
  795. //
  796. // InputIOCTL
  797. //
  798. // Sends an IOCTL input device request command.
  799. //
  800. // Returns: the status of the request.
  801. //
  802. //==========================================================================
  803. static U_WORD InputIOCTL(S_LONG request, U_WORD buffSeg)
  804. {
  805. U_BYTE *code;
  806. code = (U_BYTE *)(buffSeg<<4);
  807. *code = (U_BYTE)request;
  808. cd_IOCTLIn->ctrlBlkAddr = buffSeg<<16;
  809. cd_IOCTLIn->tranSize = InCtrlBlkSize[request];
  810. memset(&RegBlock, 0, sizeof(RegBlock));
  811. RegBlock.eax = CDROM_SENDDEVICEREQ;
  812. RegBlock.ecx = cd_CurDrive;
  813. RegBlock.ebx = 0;
  814. RegBlock.es = cd_IOCTLInSeg;
  815. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  816. return cd_IOCTLIn->status;
  817. }
  818. //==========================================================================
  819. //
  820. // OutputIOCTL
  821. //
  822. // Sends an IOCTL output device request command.
  823. //
  824. // Returns: the status of the request.
  825. //
  826. //==========================================================================
  827. static U_WORD OutputIOCTL(S_LONG request, U_WORD buffSeg)
  828. {
  829. U_BYTE *code;
  830. code = (U_BYTE *)(buffSeg<<4);
  831. *code = (U_BYTE)request;
  832. cd_IOCTLOut->ctrlBlkAddr = buffSeg<<16;
  833. cd_IOCTLOut->tranSize = OutCtrlBlkSize[request];
  834. RegBlock.eax = CDROM_SENDDEVICEREQ;
  835. RegBlock.ecx = cd_CurDrive;
  836. RegBlock.ebx = 0;
  837. RegBlock.es = cd_IOCTLOutSeg;
  838. DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
  839. return cd_IOCTLOut->status;
  840. }
  841. //==========================================================================
  842. //
  843. // RedToSectors
  844. //
  845. // Converts Red Book addresses to HSG sectors.
  846. // Sectors = Minutes * 60 * 75 + Seconds * 75 + Frame - 150
  847. //
  848. // Returns: HSG sectors.
  849. //
  850. //==========================================================================
  851. static U_LONG RedToSectors(U_LONG red)
  852. {
  853. U_LONG sector;
  854. sector = ((red&0x00ff0000) >> 16) * 60 * 75;
  855. sector += ((red&0x0000ff00) >> 8) * 75;
  856. sector += (red&0x000000ff);
  857. return sector-150;
  858. }
  859. //==========================================================================
  860. //
  861. // DPMI_SimRealInt
  862. //
  863. //==========================================================================
  864. static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock)
  865. {
  866. union REGS regs;
  867. struct SREGS sRegs;
  868. regs.x.eax = DPMI_SIMREALINT;
  869. regs.x.ebx = intr;
  870. regs.x.ecx = 0;
  871. regs.x.edi = FP_OFF((void far *)rBlock);
  872. sRegs.es = FP_SEG((void far *)rBlock);
  873. sRegs.ds = FP_SEG((void far *)rBlock);
  874. int386x(DPMI_INT, &regs, &regs, &sRegs);
  875. }
  876. //==========================================================================
  877. //
  878. // DPMI_AllocRealMem
  879. //
  880. //==========================================================================
  881. static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
  882. U_WORD *selector)
  883. {
  884. union REGS inRegs;
  885. union REGS outRegs;
  886. inRegs.x.eax = DPMI_ALLOCREALMEM;
  887. inRegs.x.ebx = (size+15)/16;
  888. int386(DPMI_INT, &inRegs, &outRegs);
  889. if(outRegs.x.cflag)
  890. {
  891. return NULL;
  892. }
  893. *segment = outRegs.x.eax&0xffff;
  894. *selector = outRegs.x.edx&0xffff;
  895. return (void *)(outRegs.x.eax<<4);
  896. }
  897. //==========================================================================
  898. //
  899. // DPMI_FreeRealMem
  900. //
  901. //==========================================================================
  902. static void DPMI_FreeRealMem(U_WORD selector)
  903. {
  904. union REGS regs;
  905. regs.x.eax = DPMI_FREEREALMEM;
  906. regs.x.edx = selector;
  907. int386(DPMI_INT, &regs, &regs);
  908. }