]> icculus.org git repositories - btb/d2x.git/blob - unused/bios/rbaudio.new
Enable global structs for mine saving functions
[btb/d2x.git] / unused / bios / rbaudio.new
1 /*
2  * $Source: /cvs/cvsroot/d2x/unused/bios/rbaudio.new,v $
3  * $Revision: 1.1.1.2 $
4  * $Author: bradleyb $
5  * $Date: 2001-01-19 03:33:50 $
6  *
7  * Redbook Audio Library  
8  *
9  * $Log: not supported by cvs2svn $
10  * Revision 1.18  1996/04/15  15:27:40  samir
11  * Play multiple tracks and PeekPlayStatus uses timer method!
12  * 
13  * Revision 1.17  1996/04/12  20:08:42  samir
14  * Added debugging info and Redbook / HSG detection
15  * 
16  * Revision 1.16  1996/04/12  19:13:29  matt
17  * Changed parameter name and added comments
18  * 
19  * Revision 1.15  1996/04/12  18:08:02  samir
20  * We now pass a cd drive letter to RBAInit.
21  * 
22  * Revision 1.14  1996/02/14  13:31:29  samir
23  * Fixed stupid bug that caused last track to never be played
24  * 
25  * Revision 1.13  1996/02/13  17:16:04  samir
26  * Added Pause and Resume Caps.
27  * 
28  * Revision 1.12  1996/01/11  10:08:01  matt
29  * RBARegisterCD wasn't checking SendRequest error code, so it was reporting
30  * CD tracks when there was no CD in the drive.
31  * 
32  * Revision 1.11  1996/01/10  20:15:45  samir
33  * Changed behavior of RBACheckMediaChange to work
34  * correctly, as well as calling this function in critical
35  * RBA functions to take care of CD changes.
36  * 
37  * Revision 1.10  1996/01/10  18:30:49  samir
38  * Changed property of RBCheckMediaChange which would
39  * not disable RBA if media had changed.  GetNumberOfTracks
40  * returns num. of tracks or if media changed, re-registers
41  * CD and then returns number of tracks.  If media has changed
42  * RBAPlayTrack will return an error.
43  * 
44  * Revision 1.9  1995/08/01  19:30:11  samir
45  * Added ability to get number of tracks on CD via call.
46  * 
47  * Revision 1.8  1995/07/20  16:13:56  samir
48  * Doesn't quit if CD isn't Redbook.
49  * 
50  * Revision 1.7  1995/05/10  11:37:51  samir
51  * Checks whether CD-ROM in drive at start of game
52  * 
53  * Revision 1.6  1995/05/09  18:00:08  samir
54  * Error cleaned.
55  * 
56  * Revision 1.5  1995/05/09  17:57:43  samir
57  * No CD in Drive, then diable RBA
58  * 
59  * Revision 1.4  1995/05/09  17:12:24  samir
60  * Added user detection of Redbook Audio.
61  * 
62  * Revision 1.3  1995/05/09  12:04:57  samir
63  * Added ability to known when a CD is playing
64  * and when it's stopped.
65  * 
66  * Revision 1.2  1995/05/08  11:33:37  samir
67  * Initial revision
68  * 
69  * 
70  */
71
72 char rbaudio_rcsid[] = "$Id: rbaudio.new,v 1.1.1.2 2001-01-19 03:33:50 bradleyb Exp $";
73
74
75 #include <dos.h>
76 #include <dpmi.h>
77 #include <string.h>
78
79 #include "mono.h"
80 #include "error.h"
81 #include "rbaudio.h"
82 #include "fix.h"
83 #include "timer.h"
84
85
86 #define HSG_CD_PLAYBACK 0
87 #define MSF_CD_PLAYBACK 1
88
89 #define RBERR_WRITEPROTVIOL     0
90 #define RBERR_UNKNOWNUNIT               1
91 #define RBERR_DRIVENOTREADY     2
92 #define RBERR_UNKNOWNCOMMAND    3
93 #define RBERR_CRCERROR                  4
94 #define RBERR_BADDRIVEREQ               5
95 #define RBERR_SEEKERROR                 6
96 #define RBERR_UNKNOWNMEDIA              7
97 #define RBERR_SECTORNOTFOUND    8
98 #define RBERR_WRITEFAULT                10
99 #define RBERR_READFAULT                 12
100 #define RBERR_GENERALFAILURE    13
101 #define RBERR_BADDISKCHANGE     15
102
103 #define RBSTAT_ERROR                            0x8000
104 #define RBSTAT_BUSY                             0x0200
105 #define RBSTAT_DONE                             0x0100
106
107 #pragma pack(1)
108
109
110 // Request Header       -----------------------------------------------------
111
112 typedef struct _REQHDR {
113         unsigned char length;
114         unsigned char subunit;
115         unsigned char func;
116         unsigned short status;
117         char array[8];
118 } REQHDR;
119
120 typedef struct _IOCTL {
121         char bpb;
122         unsigned short buffer_realoff;
123         unsigned short buffer_realseg;
124         unsigned short xferlen;
125         unsigned short sector;
126         unsigned long id;
127 } IOCTL;
128
129
130 //      CD Information -----------------------------------------------------
131
132 static struct {
133         char code;                       // Control Block Code
134         char track;                      // Track Number
135         long start;                      // Start of Track in MSF (Redbook)
136         unsigned char info;              // Track Control Info
137 } CDTrackInfo = {11,2,0L,0};
138
139 static struct {
140         REQHDR reqheader;
141         IOCTL ioctl;
142 } TrackInfoREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
143   
144 static struct {
145         unsigned char code;
146         unsigned long devstat;
147 } DevStat = {6,0};
148
149 static struct {
150         REQHDR  reqhdr;
151         IOCTL   ioctl;
152 } DevStatREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
153
154 static struct {
155         unsigned char code;
156         char byte;
157 } MedChg        = {9,0};
158
159 static struct {
160         REQHDR  reqhdr;
161         IOCTL   ioctl;
162 } MedChgREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
163
164 static struct {
165         REQHDR  reqhdr;
166 } StopREQ = {{13,0,133,0,""}};
167
168 static struct {
169         REQHDR  reqhdr;
170 } ResumeREQ = {{13,0,136,0,""}};
171
172 static struct {
173         unsigned char code;
174         unsigned char first;
175         unsigned char last;
176         unsigned long lead_out;
177 } CDInfo = {10,0,0,0L};
178
179 static struct {
180         REQHDR  reqhdr;
181         IOCTL   ioctl;
182 } CDInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
183
184 static struct {
185         REQHDR  reqheader;
186         char    mode;                                   // Play in HSG or MSF(RedBook)
187         unsigned long playbeg;
188         unsigned long playlen;                // HSG Format
189         char            empty;                                          // Empty byte used so that all requests have same size
190 } PlayREQ = {{13,0,132,0,""},0,0,0,0};
191
192 static struct {
193         unsigned char code;
194         unsigned char out0in;
195         unsigned char out0vol;
196         unsigned char out1in;
197         unsigned char out1vol;
198         unsigned char out2in;
199         unsigned char out2vol;
200         unsigned char out3in;
201         unsigned char out3vol;
202 } AUDChannelCtl = {3,0,0,0,0,0,0,0,0};
203
204 static struct {
205         REQHDR  reqhdr;
206         IOCTL           ioctl;
207 } AUDChannelCtlREQ = {{13,0,12,0,""},{0,0,0,0,0}};
208
209 static struct {
210         unsigned char code;
211         unsigned char out0in;
212         unsigned char out0vol;
213         unsigned char out1in;
214         unsigned char out1vol;
215         unsigned char out2in;
216         unsigned char out2vol;
217         unsigned char out3in;
218         unsigned char out3vol;
219 } AUDChannelInfo = {4,0,0,0,0,0,0,0,0};
220
221 static struct {
222         REQHDR  reqhdr;
223         IOCTL           ioctl;
224 } AUDChannelInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
225
226 static struct {
227         unsigned char code;
228         unsigned char mode;
229         unsigned long headloc;
230 } HeadInfo = {1,MSF_CD_PLAYBACK,0L};
231
232 static struct {
233         REQHDR  reqhdr;
234         IOCTL           ioctl;
235 } HeadInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
236
237 //@@static struct {
238 //@@    ubyte code;
239 //@@    ubyte adr;
240 //@@    ubyte   tno;
241 //@@    ubyte   point;
242 //@@    ubyte   min;
243 //@@    ubyte   sec;
244 //@@    ubyte   frame;
245 //@@    ubyte   zero;
246 //@@    ubyte   pmin;
247 //@@    ubyte   psec;
248 //@@    ubyte   pframe;
249 //@@} QChannelInfo = {12, MSF_CD_PLAYBACK, 2,0,0,0,0,0,0,0,0    };
250 //@@
251 //@@static struct {
252 //@@    REQHDR  reqhdr;
253 //@@    IOCTL           ioctl;
254 //@@} QChannelInfoREQ = {{13, 0, 3, 0, ""}, {0,0,0,0,0}};
255
256
257 //      Translation from RealMode->Protected mode buffer
258
259 typedef struct _REQ_xlatbuf {                   // Buffer for Real Mode Callback
260         REQHDR reqheader;
261         char ioctl[10];
262 } REQ_xlatbuf;
263
264
265
266 //      Other Data ---------------------------------------------------------
267
268 static unsigned char CDDriveLetter;
269 static unsigned long CDNumTracks,CDTrackStart[101];
270 static int RedBookEnabled = 0;
271 static int RedBookPlaybackType = MSF_CD_PLAYBACK;
272 static fix Playback_Start_Time = 0;
273 static fix Playback_Pause_Time = 0;
274 static fix Playback_Length = 0;
275                                                          
276
277 //      Prototypes ---------------------------------------------------------
278
279 int RBSendRequest(char *request, char *xferptr, int xferlen);   
280 unsigned long msf_to_lsn(unsigned long msf);
281 unsigned long lsn_to_msf(unsigned long lsn);
282
283
284 //      --------------------------------------------------------------------
285
286 void RBAInit(ubyte cd_drive_num)        //drive a == 0, drive b == 1
287 {
288         union REGS regs;
289
290 //      Detect presence of CD-ROM
291         regs.x.eax = 0x1500;
292         regs.x.ebx = 0;
293         int386(0x2f, &regs, &regs);
294         
295         if (regs.x.ebx == 0) 
296                 RBADisable();                                           // Disable RedBook
297         //      Error("RBA Error: MSCDEX.EXE compatible driver couldn't be found.");
298         else {
299                 CDDriveLetter = cd_drive_num;
300 //              CDDriveLetter = (unsigned char)regs.x.ecx;
301
302                 RBAEnable();
303                 RBACheckMediaChange();
304
305                 RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
306                 
307         // If Door drive open, or no disc in CD-ROM, then Redbook is Disabled.
308                 if ((DevStat.devstat&2048) || (DevStat.devstat&1) || RBAEnabled() == 0) 
309                         RBADisable();
310
311 //@@            if (DevStat.devstat&4) 
312 //@@                    mprintf((0, "supports cooked and raw reading.\n"));
313 //@@            else 
314 //@@                    mprintf((0, "supports only cooked reading.\n"));
315 //@@
316 //@@            if (DevStat.devstat&256) 
317 //@@                    mprintf((0, "audio channel manipulation.\n"));
318 //@@            else 
319 //@@                    mprintf((0, "no audio channel manipulation.\n"));
320         
321                 if (DevStat.devstat&512) {
322 //                      RedBookPlaybackType = MSF_CD_PLAYBACK;
323                         mprintf((0, "supports HSG and RedBook addressing mode.\n"));
324                 }
325                 else {
326 //                      RedBookPlaybackType = HSG_CD_PLAYBACK;
327                         mprintf((0, "supports HSG addressing only.\n"));
328                 }
329                         
330                 RedBookPlaybackType = MSF_CD_PLAYBACK;
331
332         }
333 }
334
335 //find out how many tracks on the CD, and their starting locations
336 void RBARegisterCD(void)
337 {
338         int i;
339         int error;
340
341         //      Get CD Information First
342         RBACheckMediaChange();
343
344         error = RBSendRequest((char*)&CDInfoREQ, (char*)&CDInfo, sizeof(CDInfo));
345
346         if (error & RBSTAT_ERROR) {             //error!
347                 CDNumTracks = 0;
348                 return;
349         }
350         
351         CDNumTracks = (CDInfo.last-CDInfo.first)+1;
352
353         // Define Track Starts
354         for (i=CDInfo.first; i<=CDNumTracks; i++)
355         {
356                 CDTrackInfo.track = i;
357                 RBSendRequest((char *)&TrackInfoREQ, (char*)&CDTrackInfo, sizeof(CDTrackInfo));
358                 CDTrackStart[i] = CDTrackInfo.start;
359         }
360
361         CDTrackStart[i] = CDInfo.lead_out;
362
363
364
365 long RBAGetDeviceStatus()
366 {
367         RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
368         return (long)DevStat.devstat;
369 }
370
371
372 int RBAGetNumberOfTracks(void)
373 {
374         //      Get CD Information
375         if (RBACheckMediaChange())
376                 RBARegisterCD(); 
377
378         return CDNumTracks;
379 }
380
381
382 int RBAPlayTrack(int track)
383 {
384         unsigned long playlen;
385         int min, sec;
386
387         Playback_Start_Time = 0;
388         Playback_Length = 0;
389
390         if (track < CDInfo.first || track > CDInfo.last) {
391                 mprintf((0,"CD not Redbook Compatible. Will not play track.\n"));
392         }
393 //              Error("RBA Error: Track %d doesn't exist on CD!!!", track);
394         
395         if (RBACheckMediaChange()) {
396                 mprintf((0, "Unable to play track due to CD change.\n"));
397                 return 0;
398         }
399
400         //      Play the track now!!!
401         PlayREQ.mode = RedBookPlaybackType;
402         PlayREQ.playbeg = CDTrackStart[track];
403
404         if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
405                 PlayREQ.playlen = 
406                         msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
407         }
408         else {
409                 mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
410                 Int3();
411                 PlayREQ.playlen = CDTrackStart[track+1] - CDTrackStart[track];
412         }
413         RBSendRequest((char *)&PlayREQ,NULL,0);
414
415         playlen = msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
416         playlen = lsn_to_msf(playlen);
417         min   = (int)((playlen >> 16) & 0xFF);
418         sec   = (int)((playlen >>  8) & 0xFF);
419
420         Playback_Start_Time = timer_get_fixed_seconds();
421         Playback_Length = i2f(min*60+sec);
422
423         mprintf( (0,"Playing Track %d (len: %d secs)\n", track, min*60+sec) );
424
425         return 1;
426 }
427
428 //plays tracks first through last, inclusive
429 int RBAPlayTracks(int first, int last)
430 {
431         unsigned long playlen;
432         int min, sec;
433
434         Playback_Start_Time = 0;
435         Playback_Length = 0;
436
437         if (first < CDInfo.first || last > CDInfo.last) {
438                 mprintf((0,"Invalid start or end track.\n"));
439         }
440 //              Error("RBA Error: Track %d doesn't exist on CD!!!", track);
441         
442         if (RBACheckMediaChange()) {
443                 mprintf((0, "Unable to play track due to CD change.\n"));
444                 return 0;
445         }
446
447         //      Play the track now!!!
448         PlayREQ.mode = RedBookPlaybackType;
449         PlayREQ.playbeg = CDTrackStart[first];
450
451         if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
452                 PlayREQ.playlen = 
453                         msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
454         }
455         else {
456                 mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
457                 Int3();
458                 PlayREQ.playlen = CDTrackStart[last+1] - CDTrackStart[first];
459         }
460         RBSendRequest((char *)&PlayREQ,NULL,0);
461
462         playlen = msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
463         playlen = lsn_to_msf(playlen);
464         min   = (int)((playlen >> 16) & 0xFF);
465         sec   = (int)((playlen >>  8) & 0xFF);
466
467         Playback_Start_Time = timer_get_fixed_seconds();
468         Playback_Length = i2f(min*60+sec);
469
470         mprintf( (0,"Playing Tracks %d-%d (len: %d secs)\n", first,last,min*60+sec) );
471
472         return 1;
473 }
474
475
476 void RBAPause()
477 {
478         RBSendRequest((char *)&StopREQ, NULL, 0);
479         Playback_Pause_Time = timer_get_fixed_seconds();
480 }
481
482
483 int RBAResume()
484 {
485         if (RBACheckMediaChange()) {
486                 RBARegisterCD();
487                 return RBA_MEDIA_CHANGED;
488         }
489         RBSendRequest((char *)&ResumeREQ, NULL, 0);
490
491         Playback_Start_Time += timer_get_fixed_seconds() - Playback_Pause_Time;
492
493         return 1;
494 }
495
496
497 void RBAStop()
498 {
499         if (RBACheckMediaChange())
500                 RBARegisterCD();
501
502         RBSendRequest((char *)&StopREQ,NULL,0);      
503 }
504
505
506 void RBASetStereoAudio(RBACHANNELCTL *channels)
507 {
508         AUDChannelCtl.out0in = channels->out0in;
509         AUDChannelCtl.out0vol = channels->out0vol;
510         AUDChannelCtl.out1in = channels->out1in;
511         AUDChannelCtl.out1vol = channels->out1vol;
512         AUDChannelCtl.out2in = AUDChannelCtl.out2vol = 0;
513         AUDChannelCtl.out3in = AUDChannelCtl.out3vol = 0;
514         
515         RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
516 }
517
518
519 void RBASetQuadAudio(RBACHANNELCTL *channels)
520 {
521         AUDChannelCtl.out0in = (unsigned char)channels->out0in;
522         AUDChannelCtl.out0vol = (unsigned char)channels->out0vol;
523         AUDChannelCtl.out1in = (unsigned char)channels->out1in;
524         AUDChannelCtl.out1vol = (unsigned char)channels->out1vol;
525         AUDChannelCtl.out2in = (unsigned char)channels->out2in;
526         AUDChannelCtl.out2vol = (unsigned char)channels->out2vol;
527         AUDChannelCtl.out3in = (unsigned char)channels->out3in;
528         AUDChannelCtl.out3vol = (unsigned char)channels->out3vol;
529         
530         RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
531 }
532
533
534 void RBAGetAudioInfo(RBACHANNELCTL *channels)
535 {
536         RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
537         
538         channels->out0in = (int)AUDChannelInfo.out0in;
539         channels->out0vol = (int)AUDChannelInfo.out0vol;
540         channels->out1in = (int)AUDChannelInfo.out1in;
541         channels->out1vol = (int)AUDChannelInfo.out1vol;
542         channels->out2in = (int)AUDChannelInfo.out2in;
543         channels->out2vol = (int)AUDChannelInfo.out2vol;
544         channels->out3in = (int)AUDChannelInfo.out3in;
545         channels->out3vol = (int)AUDChannelInfo.out3vol;
546
547 }
548
549
550 void RBASetChannelVolume(int channel, int volume) 
551 {
552         //RBACHANNELCTL channels;
553         
554         RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
555
556         AUDChannelCtl.out0in = AUDChannelInfo.out0in;
557         AUDChannelCtl.out0vol = AUDChannelInfo.out0vol;
558         AUDChannelCtl.out1in = AUDChannelInfo.out1in;
559         AUDChannelCtl.out1vol = AUDChannelInfo.out1vol;
560         AUDChannelCtl.out2in = AUDChannelInfo.out2in;
561         AUDChannelCtl.out2vol = AUDChannelInfo.out2vol;
562         AUDChannelCtl.out3in = AUDChannelInfo.out3in;
563         AUDChannelCtl.out3vol = AUDChannelInfo.out3vol;
564
565         if (channel == 0) AUDChannelCtl.out0vol = (unsigned char)volume;
566         if (channel == 1) AUDChannelCtl.out1vol = (unsigned char)volume;
567         if (channel == 2) AUDChannelCtl.out2vol = (unsigned char)volume;
568         if (channel == 3) AUDChannelCtl.out3vol = (unsigned char)volume;
569         
570         RBSendRequest((char*)&AUDChannelCtlREQ,(char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
571
572 }
573
574
575 void RBASetVolume(int volume)
576 {
577         RBASetChannelVolume(0,volume);
578         RBASetChannelVolume(1,volume);
579 }
580
581
582 long RBAGetHeadLoc(int *min, int *sec, int *frame)
583 {
584         unsigned long loc;
585
586         if (RBACheckMediaChange())
587                 return RBA_MEDIA_CHANGED;
588
589         HeadInfo.mode = RedBookPlaybackType;
590         RBSendRequest((char*)&HeadInfoREQ, (char*)&HeadInfo, sizeof(HeadInfo));
591         
592         if (RedBookPlaybackType == MSF_CD_PLAYBACK)
593                 loc = HeadInfo.headloc;
594         else 
595                 loc = lsn_to_msf(HeadInfo.headloc);
596
597         *min   = (int)((loc >> 16) & 0xFF);
598         *sec   = (int)((loc >>  8) & 0xFF);
599         *frame = (int)((loc >>  0) & 0xFF);
600
601         return loc;
602 }               
603
604
605 int RBAPeekPlayStatus()
606 {
607         if ((timer_get_fixed_seconds()-Playback_Start_Time) > Playback_Length) return 0;
608         else return 1; 
609 }
610         
611
612 int RBAEnabled()
613 {
614         if (RedBookEnabled < 1) return 0;
615         else return 1;
616 }
617
618
619 void RBAEnable()
620 {
621         RedBookEnabled = 1;
622         mprintf((0, "Enabling Redbook...\n"));
623 }
624
625
626 void RBADisable()
627 {
628         RedBookEnabled = 0;
629         mprintf((0, "Disabling Redbook...\n"));
630 }
631
632
633
634 //      RB functions:  Internal to RBA library  -----------------------------
635
636 //returns 1 if media has changed, else 0
637 int RBACheckMediaChange()
638 {
639         RBSendRequest((char *)&MedChgREQ, (char*)&MedChg, sizeof(MedChg));
640
641         if (MedChg.byte == 255 || MedChg.byte == 0) {
642                 // New media in drive (or maybe no media in drive)
643                 mprintf((0,"CD-ROM Media change detected\n"));
644                 return 1;
645         }
646         return 0;
647 }
648
649
650 //      Send Request
651
652 //returns 16-bit value.  Bit 15 means error.
653 //WE NEED SYMBOLOIC CONSTANTS FOR ALL RETURN CODES & STATUS BITS
654 int RBSendRequest(char *request, char *xferptr, int xferlen)
655 {
656         //union REGS regs;
657         dpmi_real_regs rregs;
658
659         IOCTL *ioctl;
660         REQ_xlatbuf *xlat_req;                          // Translated Buffer Request 
661         char *xlat_xferptr;                                     // Translated Buffer Transfer Buffer Ptr
662         
663         unsigned short status;
664         
665         if (!RedBookEnabled) return 0;  // Don't send request if no RBA
666
667         memset(&rregs,0,sizeof(dpmi_real_regs));
668
669 // Get Temporary Real Mode Buffer for request translation
670         xlat_req = (REQ_xlatbuf *)dpmi_get_temp_low_buffer(128+xferlen);
671         memcpy(xlat_req, request, sizeof(REQHDR)+sizeof(IOCTL));
672         ioctl = (IOCTL *)(((char*)xlat_req)+sizeof(REQHDR));
673
674 //      Set Transfer Buffer in IOCTL reqion of 'request'        
675         if (xferlen && xferptr) {
676                 xlat_xferptr = ((char*)xlat_req) + 128;
677                 memcpy(xlat_xferptr, xferptr, xferlen);
678                 
679                 ioctl->buffer_realoff = DPMI_real_offset(xlat_xferptr);
680                 ioctl->buffer_realseg = DPMI_real_segment(xlat_xferptr);
681                 ioctl->xferlen = xferlen;
682         }
683
684 //      Setup and Send Request Packet
685         rregs.eax = 0x1510;
686         rregs.ecx = (unsigned)(CDDriveLetter);
687         rregs.es  = DPMI_real_segment(xlat_req);
688         rregs.ebx = DPMI_real_offset(xlat_req);
689         dpmi_real_int386x(0x2f, &rregs);
690
691 //      Return Translate Buffer to Protected mode 'xferptr'
692         if (xferlen && xferptr) {
693                 memcpy(xferptr, xlat_xferptr, xferlen);
694         }
695         memcpy(request, xlat_req, sizeof(REQHDR)+sizeof(IOCTL));
696         
697 //      Check for Errors.
698         status = ((REQHDR *)request)->status;
699
700         if (status & RBSTAT_ERROR) {
701                 mprintf((0,"Error in SendRequest: %x.\n", status));
702         }
703
704         return status;
705
706                 
707
708 //      Converts Logical Sector Number to Minutes Seconds Frame Format
709
710 unsigned long lsn_to_msf(unsigned long lsn)
711 {
712    unsigned long min,sec,frame;
713    lsn += 150;
714
715         min   =  lsn / (60*75);
716    lsn   =  lsn % (60*75);
717         sec   =  lsn / 75;
718    lsn   =  lsn % 75;
719         frame =  lsn;
720
721         return((min << 16) + (sec << 8) + (frame << 0));
722 }
723
724 // convert minutes seconds frame format to a logical sector number.
725
726 unsigned long msf_to_lsn(unsigned long msf)
727 {
728         unsigned long min,sec,frame;
729
730         min   = (msf >> 16) & 0xFF;
731    sec   = (msf >>  8) & 0xFF;
732    frame = (msf >>  0) & 0xFF;
733
734         return(  (min * 60*75) + (sec * 75) + frame - 150  );
735 }
736