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