1// #include <dpmi.h>
2#include "quakedef.h"
3// #include "dosisms.h"
4
5extern	cvar_t	bgmvolume;
6
7#define ADDRESS_MODE_HSG		0
8#define ADDRESS_MODE_RED_BOOK	1
9
10#define STATUS_ERROR_BIT	0x8000
11#define STATUS_BUSY_BIT		0x0200
12#define STATUS_DONE_BIT		0x0100
13#define STATUS_ERROR_MASK	0x00ff
14
15#define ERROR_WRITE_PROTECT		0
16#define ERROR_UNKNOWN_UNIT		1
17#define ERROR_DRIVE_NOT_READY	2
18#define ERROR_UNKNOWN_COMMAND	3
19#define ERROR_CRC_ERROR			4
20#define ERROR_BAD_REQUEST_LEN	5
21#define ERROR_SEEK_ERROR		6
22#define ERROR_UNKNOWN_MEDIA		7
23#define ERROR_SECTOR_NOT_FOUND	8
24#define ERROR_OUT_OF_PAPER		9
25#define ERROR_WRITE_FAULT		10
26#define ERROR_READ_FAULT		11
27#define ERROR_GENERAL_FAILURE	12
28#define ERROR_RESERVED_13		13
29#define ERROR_RESERVED_14		14
30#define ERROR_BAD_DISK_CHANGE	15
31
32#define COMMAND_READ			3
33#define COMMAND_WRITE			12
34#define COMMAND_PLAY_AUDIO		132
35#define COMMAND_STOP_AUDIO		133
36#define COMMAND_RESUME_AUDIO	136
37
38#define READ_REQUEST_AUDIO_CHANNEL_INFO		4
39#define READ_REQUEST_DEVICE_STATUS			6
40#define READ_REQUEST_MEDIA_CHANGE			9
41#define READ_REQUEST_AUDIO_DISK_INFO		10
42#define READ_REQUEST_AUDIO_TRACK_INFO		11
43#define READ_REQUEST_AUDIO_STATUS			15
44
45#define WRITE_REQUEST_EJECT					0
46#define WRITE_REQUEST_RESET					2
47#define WRITE_REQUEST_AUDIO_CHANNEL_INFO	3
48
49#define STATUS_DOOR_OPEN					0x00000001
50#define STATUS_DOOR_UNLOCKED				0x00000002
51#define STATUS_RAW_SUPPORT					0x00000004
52#define STATUS_READ_WRITE					0x00000008
53#define STATUS_AUDIO_SUPPORT				0x00000010
54#define STATUS_INTERLEAVE_SUPPORT			0x00000020
55#define STATUS_BIT_6_RESERVED				0x00000040
56#define STATUS_PREFETCH_SUPPORT				0x00000080
57#define STATUS_AUDIO_MANIPLUATION_SUPPORT	0x00000100
58#define STATUS_RED_BOOK_ADDRESS_SUPPORT		0x00000200
59
60#define MEDIA_NOT_CHANGED		1
61#define MEDIA_STATUS_UNKNOWN	0
62#define MEDIA_CHANGED			-1
63
64#define AUDIO_CONTROL_MASK				0xd0
65#define AUDIO_CONTROL_DATA_TRACK		0x40
66#define AUDIO_CONTROL_AUDIO_2_TRACK		0x00
67#define AUDIO_CONTROL_AUDIO_2P_TRACK	0x10
68#define AUDIO_CONTROL_AUDIO_4_TRACK		0x80
69#define AUDIO_CONTROL_AUDIO_4P_TRACK	0x90
70
71#define AUDIO_STATUS_PAUSED				0x0001
72
73#pragma pack(1)
74
75struct playAudioRequest
76{
77	char	addressingMode;
78	int		startLocation;
79	int		sectors;
80};
81
82struct readRequest
83{
84	char	mediaDescriptor;
85	short	bufferOffset;
86	short	bufferSegment;
87	short	length;
88	short	startSector;
89	int		volumeID;
90};
91
92struct writeRequest
93{
94	char	mediaDescriptor;
95	short	bufferOffset;
96	short	bufferSegment;
97	short	length;
98	short	startSector;
99	int		volumeID;
100};
101
102struct cd_request
103{
104	char	headerLength;
105	char	unit;
106	char	command;
107	short	status;
108	char	reserved[8];
109	union
110	{
111		struct	playAudioRequest	playAudio;
112		struct	readRequest			read;
113		struct	writeRequest		write;
114	} x;
115};
116
117
118struct audioChannelInfo_s
119{
120	char	code;
121	char	channel0input;
122	char	channel0volume;
123	char	channel1input;
124	char	channel1volume;
125	char	channel2input;
126	char	channel2volume;
127	char	channel3input;
128	char	channel3volume;
129};
130
131struct deviceStatus_s
132{
133	char	code;
134	int		status;
135};
136
137struct mediaChange_s
138{
139	char	code;
140	char	status;
141};
142
143struct audioDiskInfo_s
144{
145	char	code;
146	char	lowTrack;
147	char	highTrack;
148	int		leadOutStart;
149};
150
151struct audioTrackInfo_s
152{
153	char	code;
154	char	track;
155	int		start;
156	char	control;
157};
158
159struct audioStatus_s
160{
161	char	code;
162	short	status;
163	int		PRstartLocation;
164	int		PRendLocation;
165};
166
167struct reset_s
168{
169	char	code;
170};
171
172union readInfo_u
173{
174	struct audioChannelInfo_s	audioChannelInfo;
175	struct deviceStatus_s		deviceStatus;
176	struct mediaChange_s		mediaChange;
177	struct audioDiskInfo_s		audioDiskInfo;
178	struct audioTrackInfo_s		audioTrackInfo;
179	struct audioStatus_s		audioStatus;
180	struct reset_s				reset;
181};
182
183#pragma pack()
184
185#define MAXIMUM_TRACKS			32
186
187typedef struct
188{
189	int			start;
190	int			length;
191	qboolean	isData;
192} track_info;
193
194typedef struct
195{
196	qboolean	valid;
197	int			leadOutAddress;
198	track_info	track[MAXIMUM_TRACKS];
199	byte		lowTrack;
200	byte		highTrack;
201} cd_info;
202
203static struct cd_request	*cdRequest;
204static union readInfo_u		*readInfo;
205static cd_info				cd;
206
207static qboolean	playing = false;
208static qboolean	wasPlaying = false;
209static qboolean	mediaCheck = false;
210static qboolean	initialized = false;
211static qboolean	enabled = true;
212static qboolean playLooping = false;
213static short	cdRequestSegment;
214static short	cdRequestOffset;
215static short	readInfoSegment;
216static short	readInfoOffset;
217static byte 	remap[256];
218static byte		cdrom;
219static byte		playTrack;
220static byte		cdvolume;
221
222
223static int RedBookToSector(int rb)
224{
225	byte	minute;
226	byte	second;
227	byte	frame;
228
229	minute = (rb >> 16) & 0xff;
230	second = (rb >> 8) & 0xff;
231	frame = rb & 0xff;
232	return minute * 60 * 75 + second * 75 + frame;
233}
234
235
236static void CDAudio_Reset(void)
237{
238#if 0
239	cdRequest->headerLength = 13;
240	cdRequest->unit = 0;
241	cdRequest->command = COMMAND_WRITE;
242	cdRequest->status = 0;
243
244	cdRequest->x.write.mediaDescriptor = 0;
245	cdRequest->x.write.bufferOffset = readInfoOffset;
246	cdRequest->x.write.bufferSegment = readInfoSegment;
247	cdRequest->x.write.length = sizeof(struct reset_s);
248	cdRequest->x.write.startSector = 0;
249	cdRequest->x.write.volumeID = 0;
250
251	readInfo->reset.code = WRITE_REQUEST_RESET;
252
253	regs.x.ax = 0x1510;
254	regs.x.cx = cdrom;
255	regs.x.es = cdRequestSegment;
256	regs.x.bx = cdRequestOffset;
257	dos_int86 (0x2f);
258
259#endif
260}
261
262
263static void CDAudio_Eject(void)
264{
265#if 0
266	cdRequest->headerLength = 13;
267	cdRequest->unit = 0;
268	cdRequest->command = COMMAND_WRITE;
269	cdRequest->status = 0;
270
271	cdRequest->x.write.mediaDescriptor = 0;
272	cdRequest->x.write.bufferOffset = readInfoOffset;
273	cdRequest->x.write.bufferSegment = readInfoSegment;
274	cdRequest->x.write.length = sizeof(struct reset_s);
275	cdRequest->x.write.startSector = 0;
276	cdRequest->x.write.volumeID = 0;
277
278	readInfo->reset.code = WRITE_REQUEST_EJECT;
279
280	regs.x.ax = 0x1510;
281	regs.x.cx = cdrom;
282	regs.x.es = cdRequestSegment;
283	regs.x.bx = cdRequestOffset;
284	dos_int86 (0x2f);
285
286#endif
287
288}
289
290
291static int CDAudio_GetAudioTrackInfo(byte track, int *start)
292{
293#if 0
294	byte	control;
295
296	cdRequest->headerLength = 13;
297	cdRequest->unit = 0;
298	cdRequest->command = COMMAND_READ;
299	cdRequest->status = 0;
300
301	cdRequest->x.read.mediaDescriptor = 0;
302	cdRequest->x.read.bufferOffset = readInfoOffset;
303	cdRequest->x.read.bufferSegment = readInfoSegment;
304	cdRequest->x.read.length = sizeof(struct audioTrackInfo_s);
305	cdRequest->x.read.startSector = 0;
306	cdRequest->x.read.volumeID = 0;
307
308	readInfo->audioTrackInfo.code = READ_REQUEST_AUDIO_TRACK_INFO;
309	readInfo->audioTrackInfo.track = track;
310
311	regs.x.ax = 0x1510;
312	regs.x.cx = cdrom;
313	regs.x.es = cdRequestSegment;
314	regs.x.bx = cdRequestOffset;
315	dos_int86 (0x2f);
316
317	if (cdRequest->status & STATUS_ERROR_BIT)
318	{
319		Con_DPrintf("CDAudio_GetAudioTrackInfo %04x\n", cdRequest->status & 	0xffff);
320		return -1;
321	}
322
323	*start = readInfo->audioTrackInfo.start;
324	control = readInfo->audioTrackInfo.control & AUDIO_CONTROL_MASK;
325	return (control & AUDIO_CONTROL_DATA_TRACK);
326
327#endif
328
329	return 0;
330
331}
332
333
334static int CDAudio_GetAudioDiskInfo(void)
335{
336#if 0
337	int n;
338
339	cdRequest->headerLength = 13;
340	cdRequest->unit = 0;
341	cdRequest->command = COMMAND_READ;
342	cdRequest->status = 0;
343
344	cdRequest->x.read.mediaDescriptor = 0;
345	cdRequest->x.read.bufferOffset = readInfoOffset;
346	cdRequest->x.read.bufferSegment = readInfoSegment;
347	cdRequest->x.read.length = sizeof(struct audioDiskInfo_s);
348	cdRequest->x.read.startSector = 0;
349	cdRequest->x.read.volumeID = 0;
350
351	readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_DISK_INFO;
352
353	regs.x.ax = 0x1510;
354	regs.x.cx = cdrom;
355	regs.x.es = cdRequestSegment;
356	regs.x.bx = cdRequestOffset;
357	dos_int86 (0x2f);
358
359	if (cdRequest->status & STATUS_ERROR_BIT)
360	{
361		Con_DPrintf("CDAudio_GetAudioDiskInfo %04x\n", cdRequest->status & 	0xffff);
362		return -1;
363	}
364
365	cd.valid = true;
366	cd.lowTrack = readInfo->audioDiskInfo.lowTrack;
367	cd.highTrack = readInfo->audioDiskInfo.highTrack;
368	cd.leadOutAddress = readInfo->audioDiskInfo.leadOutStart;
369
370	for (n = cd.lowTrack; n <= cd.highTrack; n++)
371	{
372		cd.track[n].isData = CDAudio_GetAudioTrackInfo (n, &cd.track[n].start);
373		if (n > cd.lowTrack)
374		{
375			cd.track[n-1].length = RedBookToSector(cd.track[n].start) - RedBookToSector(cd.track[n-1].start);
376			if (n == cd.highTrack)
377				cd.track[n].length = RedBookToSector(cd.leadOutAddress) - RedBookToSector(cd.track[n].start);
378		}
379	}
380
381#endif
382
383	return 0;
384}
385
386
387static int CDAudio_GetAudioStatus(void)
388{
389#if 0
390	cdRequest->headerLength = 13;
391	cdRequest->unit = 0;
392	cdRequest->command = COMMAND_READ;
393	cdRequest->status = 0;
394
395	cdRequest->x.read.mediaDescriptor = 0;
396	cdRequest->x.read.bufferOffset = readInfoOffset;
397	cdRequest->x.read.bufferSegment = readInfoSegment;
398	cdRequest->x.read.length = sizeof(struct audioStatus_s);
399	cdRequest->x.read.startSector = 0;
400	cdRequest->x.read.volumeID = 0;
401
402	readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_STATUS;
403
404	regs.x.ax = 0x1510;
405	regs.x.cx = cdrom;
406	regs.x.es = cdRequestSegment;
407	regs.x.bx = cdRequestOffset;
408	dos_int86 (0x2f);
409
410	if (cdRequest->status & STATUS_ERROR_BIT)
411		return -1;
412	return 0;
413#endif
414	return 0;
415}
416
417
418static int CDAudio_MediaChange(void)
419{
420#if 0
421	cdRequest->headerLength = 13;
422	cdRequest->unit = 0;
423	cdRequest->command = COMMAND_READ;
424	cdRequest->status = 0;
425
426	cdRequest->x.read.mediaDescriptor = 0;
427	cdRequest->x.read.bufferOffset = readInfoOffset;
428	cdRequest->x.read.bufferSegment = readInfoSegment;
429	cdRequest->x.read.length = sizeof(struct mediaChange_s);
430	cdRequest->x.read.startSector = 0;
431	cdRequest->x.read.volumeID = 0;
432
433	readInfo->mediaChange.code = READ_REQUEST_MEDIA_CHANGE;
434
435	regs.x.ax = 0x1510;
436	regs.x.cx = cdrom;
437	regs.x.es = cdRequestSegment;
438	regs.x.bx = cdRequestOffset;
439	dos_int86 (0x2f);
440
441	return readInfo->mediaChange.status;
442#endif
443	return 0;
444}
445
446
447byte CDAudio_GetVolume (void)
448{
449	return cdvolume;
450}
451
452
453// we set the volume to 0 first and then to the desired volume
454// some cd-rom drivers seem to need it done this way
455void CDAudio_SetVolume (byte volume)
456{
457	if (!initialized || !enabled)
458		return;
459
460#if 0
461
462	cdRequest->headerLength = 13;
463	cdRequest->unit = 0;
464	cdRequest->command = COMMAND_WRITE;
465	cdRequest->status = 0;
466
467	cdRequest->x.read.mediaDescriptor = 0;
468	cdRequest->x.read.bufferOffset = readInfoOffset;
469	cdRequest->x.read.bufferSegment = readInfoSegment;
470	cdRequest->x.read.length = sizeof(struct audioChannelInfo_s);
471	cdRequest->x.read.startSector = 0;
472	cdRequest->x.read.volumeID = 0;
473
474	readInfo->audioChannelInfo.code = WRITE_REQUEST_AUDIO_CHANNEL_INFO;
475	readInfo->audioChannelInfo.channel0input = 0;
476	readInfo->audioChannelInfo.channel0volume = 0;
477	readInfo->audioChannelInfo.channel1input = 1;
478	readInfo->audioChannelInfo.channel1volume = 0;
479	readInfo->audioChannelInfo.channel2input = 2;
480	readInfo->audioChannelInfo.channel2volume = 0;
481	readInfo->audioChannelInfo.channel3input = 3;
482	readInfo->audioChannelInfo.channel3volume = 0;
483
484	regs.x.ax = 0x1510;
485	regs.x.cx = cdrom;
486	regs.x.es = cdRequestSegment;
487	regs.x.bx = cdRequestOffset;
488	dos_int86 (0x2f);
489
490	readInfo->audioChannelInfo.channel0volume = volume;
491	readInfo->audioChannelInfo.channel1volume = volume;
492
493	regs.x.ax = 0x1510;
494	regs.x.cx = cdrom;
495	regs.x.es = cdRequestSegment;
496	regs.x.bx = cdRequestOffset;
497	dos_int86 (0x2f);
498
499#endif
500
501	cdvolume = volume;
502}
503
504
505void CDAudio_Play(byte track, qboolean looping)
506{
507
508#if 0
509	if (!initialized || !enabled)
510		return;
511
512	if (!cd.valid)
513		return;
514
515	track = remap[track];
516
517	if (playing)
518	{
519		if (playTrack == track)
520			return;
521		CDAudio_Stop();
522	}
523
524	playLooping = looping;
525
526	if (track < cd.lowTrack || track > cd.highTrack)
527	{
528		Con_DPrintf("CDAudio_Play: Bad track number %u.\n", track);
529		return;
530	}
531
532	playTrack = track;
533
534	if (cd.track[track].isData)
535	{
536		Con_DPrintf("CDAudio_Play: Can not play data.\n");
537		return;
538	}
539
540	cdRequest->headerLength = 13;
541	cdRequest->unit = 0;
542	cdRequest->command = COMMAND_PLAY_AUDIO;
543	cdRequest->status = 0;
544
545	cdRequest->x.playAudio.addressingMode = ADDRESS_MODE_RED_BOOK;
546	cdRequest->x.playAudio.startLocation = cd.track[track].start;
547	cdRequest->x.playAudio.sectors = cd.track[track].length;
548
549	regs.x.ax = 0x1510;
550	regs.x.cx = cdrom;
551	regs.x.es = cdRequestSegment;
552	regs.x.bx = cdRequestOffset;
553	dos_int86 (0x2f);
554
555	if (cdRequest->status & STATUS_ERROR_BIT)
556	{
557		Con_DPrintf("CDAudio_Play: track %u failed\n", track);
558		cd.valid = false;
559		playing = false;
560		return;
561	}
562
563#endif
564
565	playing = true;
566}
567
568
569void CDAudio_Stop(void)
570{
571	if (!initialized || !enabled)
572		return;
573
574#if 0
575	cdRequest->headerLength = 13;
576	cdRequest->unit = 0;
577	cdRequest->command = COMMAND_STOP_AUDIO;
578	cdRequest->status = 0;
579
580	regs.x.ax = 0x1510;
581	regs.x.cx = cdrom;
582	regs.x.es = cdRequestSegment;
583	regs.x.bx = cdRequestOffset;
584	dos_int86 (0x2f);
585#endif
586
587	wasPlaying = playing;
588	playing = false;
589}
590
591
592void CDAudio_Resume(void)
593{
594	if (!initialized || !enabled)
595		return;
596
597	if (!cd.valid)
598		return;
599
600	if (!wasPlaying)
601		return;
602
603#if 0
604	cdRequest->headerLength = 13;
605	cdRequest->unit = 0;
606	cdRequest->command = COMMAND_RESUME_AUDIO;
607	cdRequest->status = 0;
608
609	regs.x.ax = 0x1510;
610	regs.x.cx = cdrom;
611	regs.x.es = cdRequestSegment;
612	regs.x.bx = cdRequestOffset;
613	dos_int86 (0x2f);
614#endif
615
616	playing = true;
617}
618
619static void CD_f (void)
620{
621	char	*command;
622	int		ret;
623	int		n;
624	int		startAddress;
625	startAddress = 0;
626
627	if (Cmd_Argc() < 2)
628		return;
629
630	command = Cmd_Argv (1);
631
632	if (Q_strcasecmp(command, "on") == 0)
633	{
634		enabled = true;
635		return;
636	}
637
638	if (Q_strcasecmp(command, "off") == 0)
639	{
640		if (playing)
641			CDAudio_Stop();
642		enabled = false;
643		return;
644	}
645
646	if (Q_strcasecmp(command, "reset") == 0)
647	{
648		enabled = true;
649		if (playing)
650			CDAudio_Stop();
651		for (n = 0; n < 256; n++)
652			remap[n] = n;
653		CDAudio_Reset();
654		CDAudio_GetAudioDiskInfo();
655		return;
656	}
657
658	if (Q_strcasecmp(command, "remap") == 0)
659	{
660		ret = Cmd_Argc() - 2;
661		if (ret <= 0)
662		{
663			for (n = 1; n < 256; n++)
664				if (remap[n] != n)
665					Con_Printf("  %u -> %u\n", n, remap[n]);
666			return;
667		}
668		for (n = 1; n <= ret; n++)
669			remap[n] = Q_atoi(Cmd_Argv (n+1));
670		return;
671	}
672
673	if (!cd.valid)
674	{
675		Con_Printf("No CD in player.\n");
676		return;
677	}
678
679	if (Q_strcasecmp(command, "play") == 0)
680	{
681		CDAudio_Play(Q_atoi(Cmd_Argv (2)), false);
682		return;
683	}
684
685	if (Q_strcasecmp(command, "loop") == 0)
686	{
687		CDAudio_Play(Q_atoi(Cmd_Argv (2)), true);
688		return;
689	}
690
691	if (Q_strcasecmp(command, "stop") == 0)
692	{
693		CDAudio_Stop();
694		return;
695	}
696
697	if (Q_strcasecmp(command, "resume") == 0)
698	{
699		CDAudio_Resume();
700		return;
701	}
702
703	if (Q_strcasecmp(command, "eject") == 0)
704	{
705		if (playing)
706			CDAudio_Stop();
707		CDAudio_Eject();
708		cd.valid = false;
709		return;
710	}
711
712	if (Q_strcasecmp(command, "info") == 0)
713	{
714		Con_Printf("%u tracks\n", cd.highTrack - cd.lowTrack + 1);
715		for (n = cd.lowTrack; n <= cd.highTrack; n++)
716		{
717			ret = CDAudio_GetAudioTrackInfo (n, &startAddress);
718			Con_Printf("Track %2u: %s at %2u:%02u\n", n, ret ? "data " : "music", (startAddress >> 16) & 0xff, (startAddress >> 8) & 0xff);
719		}
720		if (playing)
721			Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
722		Con_Printf("Volume is %u\n", cdvolume);
723		CDAudio_MediaChange();
724		Con_Printf("Status %04x\n", cdRequest->status & 0xffff);
725		return;
726	}
727}
728
729void CDAudio_Update(void)
730{
731	int		ret;
732	int		newVolume;
733	static	double lastUpdate;
734
735	if (!initialized || !enabled)
736		return;
737
738	if ((realtime - lastUpdate) < 0.25)
739		return;
740	lastUpdate = realtime;
741
742	if (mediaCheck)
743	{
744		static	double lastCheck;
745
746		if ((realtime - lastCheck) < 5.0)
747			return;
748		lastCheck = realtime;
749
750		ret = CDAudio_MediaChange();
751		if (ret == MEDIA_CHANGED)
752		{
753			Con_DPrintf("CDAudio: media changed\n");
754			playing = false;
755			wasPlaying = false;
756			cd.valid = false;
757			CDAudio_GetAudioDiskInfo();
758			return;
759		}
760	}
761
762	newVolume = (int)(bgmvolume.value * 255.0);
763	if (newVolume < 0)
764	{
765		Cvar_SetValue ("bgmvolume", 0.0);
766		newVolume = 0;
767	}
768	else if (newVolume > 255)
769	{
770		Cvar_SetValue ("bgmvolume", 1.0);
771		newVolume = 255;
772	}
773	if (cdvolume != newVolume)
774		CDAudio_SetVolume (newVolume);
775
776	if (playing)
777	{
778		CDAudio_GetAudioStatus();
779		if ((cdRequest->status & STATUS_BUSY_BIT) == 0)
780		{
781			playing = false;
782			if (playLooping)
783				CDAudio_Play(playTrack, true);
784		}
785	}
786}
787
788
789qboolean CDAudio_Playing(void)
790{
791	return playing;
792}
793
794
795int CDAudio_Init(void)
796{
797	char	*memory;
798	int		n;
799
800#if 0
801
802	if (cls.state == ca_dedicated)
803		return -1;
804
805	if (COM_CheckParm("-nocdaudio"))
806		return -1;
807
808	if (COM_CheckParm("-cdmediacheck"))
809		mediaCheck = true;
810
811	regs.x.ax = 0x1500;
812	regs.x.bx = 0;
813	dos_int86 (0x2f);
814	if (regs.x.bx == 0)
815	{
816		Con_NotifyBox (
817			"MSCDEX not loaded, music is\n"
818			"disabled.  Use \"-nocdaudio\" if you\n"
819			"wish to avoid this message in the\n"
820			"future.  See README.TXT for help.\n"
821			);
822		return -1;
823	}
824	if (regs.x.bx > 1)
825		Con_DPrintf("CDAudio_Init: First CD-ROM drive will be used\n");
826	cdrom = regs.x.cx;
827
828	regs.x.ax = 0x150c;
829	regs.x.bx = 0;
830	dos_int86 (0x2f);
831	if (regs.x.bx == 0)
832	{
833		Con_NotifyBox (
834			"MSCDEX version 2.00 or later\n"
835			"required for music. See README.TXT\n"
836			"for help.\n"
837			);
838		Con_DPrintf("CDAudio_Init: MSCDEX version 2.00 or later required.\n");
839		return -1;
840	}
841
842	memory = dos_getmemory(sizeof(struct cd_request
843) + sizeof(union readInfo_u));
844	if (memory == NULL)
845	{
846		Con_DPrintf("CDAudio_Init: Unable to allocate low memory.\n");
847		return -1;
848	}
849
850	cdRequest = (struct cd_request *)memory;
851	cdRequestSegment = ptr2real(cdRequest) >> 4;
852	cdRequestOffset = ptr2real(cdRequest) & 0xf;
853
854	readInfo = (union readInfo_u *)(memory + sizeof(struct cd_request));
855	readInfoSegment = ptr2real(readInfo) >> 4;
856	readInfoOffset = ptr2real(readInfo) & 0xf;
857
858#endif
859
860	for (n = 0; n < 256; n++)
861		remap[n] = n;
862	initialized = true;
863
864	CDAudio_SetVolume (255);
865	if (CDAudio_GetAudioDiskInfo())
866	{
867		Con_Printf("CDAudio_Init: No CD in player.\n");
868		enabled = false;
869	}
870
871	Cmd_AddCommand ("cd", CD_f);
872
873	Con_Printf("CD Audio Initialized\n");
874
875	return 0;
876}
877
878
879void CDAudio_Shutdown(void)
880{
881	if (!initialized)
882		return;
883	CDAudio_Stop();
884}
885