// Routines to make calls to the real-mode CDROM driver from protected-mode Windows, // Using GlobalDOSAlloc and DPMI's int86x service. // These are allocated in real-mode DOS memory: DWORD cmdbuf=0, // Buffer for commands, device driver request headers, etc... databuf=0, // Buffer for actual data buf[MAXNBUF], // Buffer for reading audio data prev_end=0; // Buffer for synchronization WORD cmdbufseg,cmdbufsel, databufseg,databufsel, // The same as above, but split into SEG/SEL pairs bufseg[MAXNBUF],bufsel[MAXNBUF], prev_endseg, prev_endsel; BYTE *pcmdbuf=0, // Pointers the program can use to access above memory areas *pdatabuf=0, *pprev_end=0, *pbuf[MAXNBUF]; // Set things up to interact with the CDROM driver. Returns 0:Failure, 1:Success int startinterfacing(void) { int i; memset(buf,0,sizeof(buf)); // zap buffer pointers cmdbuf=GlobalDosAlloc(32); // 32 bytes for command buffer (BTW, is at most 26 bytes) cmdbufseg=HIWORD(cmdbuf); cmdbufsel=LOWORD(cmdbuf); pcmdbuf=MK_FP(cmdbufsel,0); if (!cmdbuf) goto Allocerror; databuf=GlobalDosAlloc(4096); // general purpose data buffer databufseg=HIWORD(databuf); databufsel=LOWORD(databuf); pdatabuf=MK_FP(databufsel,0); if (!databuf) goto Allocerror; prev_end=GlobalDosAlloc((long)FRAME_SIZE * NBLOCK); prev_endseg=HIWORD(prev_end); prev_endsel=LOWORD(prev_end); pprev_end=MK_FP(prev_endsel,0); if (!prev_end) goto Allocerror; // Try to allocate as much data buffers if possible, up to MAXNBUF nbuf=0; for (i=0;iflags & 1) { mb("INT2F returned error"); return 1; // Interrupt in error? Test for carry, exit if 1 } memcpy(out,r,sizeof(struct realregs)); // Get result registers back return 0; } // Is MSCDEX installed? (No need for DPMI using this call) int CheckMscdex(void) { union REGS reg; reg.x.ax=0x1500; // MSCDEX - Get number of CDROM drives reg.x.bx=0; int86(0x2f,®,®); if (!reg.x.bx) return 0; // Nr. of CDROM drives in bx CDROM=reg.x.cx; // CX=first CDROM drive (A==0, B==1, etc) return 1; } // Is Smartdrv (v4.1+ or compaitble cache) installed? int CheckSmartdrv(void) { union REGS reg; reg.x.ax=0x4A10; reg.x.bx=0; reg.x.cx=0xEBAB; int86(0x2f,®,®); if (reg.x.ax==0xBABE) return 1; else return 0; } // Does Smartdrv caches the CDROM ? int CheckCDROMCached(void) { struct REGPACK r; r.r_ax=0x4A10; r.r_bx=3; r.r_bp=CDROM; r.r_dx=0; intr(0x2f,&r); if (r.r_ax!=0xBABE) { mb("Smartdrv status call error"); return 0; // error in call } if (r.r_dx&0x0080) return 0; // BL bit 7 set? not cached! return 1; } // Call CDROM device driver; command-buffer (at pcmdbuf) must be filled by caller void CallDriver(void) { struct realregs r; // Prepare registers memset(&r,0,sizeof(r)); r.eax=0x1510; // Function: CDROM device driver request r.es=cmdbufseg; r.ebx=0; // Address of request structure r.ecx=CDROM; // Drive number of CDROM dpmint86(0x2f,&r,&r); } // Get CDROM disk information int GetDiskInfo(void) { struct IOCTLI *pcmd=(struct IOCTLI *)pcmdbuf; struct DiskInfo *pdi=(struct DiskInfo *)pdatabuf; pcmd->req.len=26; pcmd->req.unit=0; pcmd->req.command=3; pcmd->descriptor=0; pcmd->address=MK_FP(databufseg,0); pcmd->len=7; pcmd->secnum=0; pcmd->ptr=0; pdi ->control=10; CallDriver(); lowest =pdi->lowest; highest=pdi->highest; total_time=pdi->total; return pcmd->req.status; } // Read one or more raw audio sectors int ReadLong(DWORD loc, WORD secnum,WORD bufseg) { struct ReadL *pcmd=(struct ReadL *)pcmdbuf; pcmd->req.len=sizeof(struct ReadL); pcmd->req.unit=0; pcmd->req.command=128; pcmd->mode=0; pcmd->address=MK_FP(bufseg,0); pcmd->secnum=secnum; pcmd->loc=loc; pcmd->readmode=RAW_MODE; pcmd->skip[0]=pcmd->skip[1]=0; CallDriver(); return pcmd->req.status; } // Convert sector number to printable MM:SS:FF string, for durations. char *Sector2MSF(DWORD sector) { static char s[20]; long min,sec,frames; frames=sector%75; sec=sector/75; min=sec/60; sec=sec%60; sprintf(s,"%02ldm %02lds %02ldf",min,sec,frames); return s; } // Convert Sierra sector number to redbook DWORD Sierra2Red(DWORD sierra) { DWORD min,sec,frame,loc; sierra+=150; /// ???????????? frame=sierra%75; sec=sierra/75; min=sec/60; sec=sec%60; loc=(BYTE)min; loc<<=8; loc|=(BYTE)sec; loc<<=8; loc|=(BYTE)frame; return loc; } // Convert redbood time location to Sierra sector DWORD Red2Sierra(DWORD loc) { BYTE min,sec,frame; min=(loc>>16)&0xff; sec=(loc>>8)&0xff; frame=loc&0xff; return (DWORD)min*75*60+(DWORD)sec*75+(DWORD)frame-150; } // Convert redbook time location to printable string char *Red2MSF(DWORD loc) { static char s[20]; BYTE min,sec,frame; min=(loc>>16)&0xff; sec=(loc>>8)&0xff; frame=loc&0xff; sprintf(s,"%02um %02us %02uf",min,sec,frame); return s; } // Convert redbook time location to minute, second, frame, and Sierra sector void Red2MSFC(DWORD loc,WORD *min,WORD *sec,WORD *frame,DWORD *sector) { *frame=loc&0xff; loc>>=8; *sec=loc&0xff; loc>>=8; *min=loc&0xff; *sector=((DWORD)*min)*75*60+((DWORD)*sec)*75+((DWORD)*frame)-150; } // Convert minute, second, frame to redbook timecode and Sierra sector void MSF2Red(WORD min,WORD sec,WORD frame,DWORD *red,DWORD *sector) { DWORD loc=0; *sector=(DWORD)min*75*60+(DWORD)sec*75+(DWORD)frame-150; loc|=min; loc<<=8; loc|=sec; loc<<=8; loc|=frame; *red=loc; } // Ask the CDROM device driver information about a track. // Given the track number, find out at which sector it starts int GetTrackInfo(int track,DWORD *loc) { struct IOCTLI *pcmd=(struct IOCTLI *)pcmdbuf; struct TrackInfo *pbuf=(struct TrackInfo *)pdatabuf; pcmd->req.len=26; pcmd->req.unit=0; pcmd->req.command=3; pcmd->descriptor=0; pcmd->address=MK_FP(databufseg,0); pcmd->len=7; pcmd->secnum=0; pcmd->ptr=0; pbuf->control=11; pbuf->track=track; CallDriver(); *loc=pbuf->loc; return pcmd->req.status; } // Stop playing of current audio piece int StopAudio(void) { struct ReqHdr *pcmd=(struct ReqHdr *)pcmdbuf; pcmd->len=13; pcmd->unit=0; pcmd->command=133; CallDriver(); return pcmd->status; } // Play an piece of audio int PlayAudio(DWORD loc, DWORD num) { struct PlayReq *pcmd=(struct PlayReq *)pcmdbuf; pcmd->req.len=22; pcmd->req.unit=0; pcmd->req.command=132; pcmd->mode=1; pcmd->loc=loc; pcmd->secnum=num; CallDriver(); return pcmd->req.status; }