'****************************************************************************
' MCDC.BAS - Davey T & Andrew G
' Various CD-ROM routines used by MCD.BAS
' Check out each routine for a description of in and out variables
'****************************************************************************
' NOTE: This can be compiled into a quick library!

DECLARE SUB HSG2Red (min%, Sec%, frm%, HSG&)
DECLARE SUB CDIHead (drive%, sect&)
DECLARE SUB CDRPlay (drive%, startSector&, playSectors&)
DECLARE SUB CDRResume (drive%)
DECLARE SUB CDRStop (drive%)
DECLARE FUNCTION CDGetStatus% ()
DECLARE FUNCTION CDGetVersion% ()
DECLARE FUNCTION CDGetDrives$ ()
DECLARE FUNCTION CDGetError$ (enum%)
DECLARE FUNCTION CDDriveCheck% (drive%)
DECLARE FUNCTION CDctlI$ (drive%, info$)
DECLARE SUB CDIInfo (drive%, low%, high%)
DECLARE SUB CDITrack (drive%, track%, start&, ttype%)
DECLARE SUB CDISize (drive%, lsect&)
DECLARE SUB CDIDoor (drive%, stat%)
DECLARE SUB Red2HSG (HSG&, min%, Sec%, frm%)
DECLARE SUB CDctlO (drive%, info$)
DECLARE SUB CDRequest (drive%, req%, info$)
DECLARE SUB CDOClose (drive%)
DECLARE SUB CDOLock (drive%, locked%)
DECLARE SUB CDOOpen (drive%)

TYPE RegTypeX
 ax AS INTEGER: bx AS INTEGER: cx AS INTEGER: dx AS INTEGER: bp AS INTEGER
 si AS INTEGER: di AS INTEGER: f  AS INTEGER: ds AS INTEGER: es AS INTEGER
END TYPE
DIM SHARED Regs AS RegTypeX, CDRStatus%

FUNCTION CDctlI$ (drive%, info$)
 'CDxtlI               Inputs data from the CD-ROM device driver using IOCTL
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  info$              Data to output
 ' Out:
 '  Returns            Modified info$ string

 io$ = CHR$(0)                                 'Media descriptior (0)
 io$ = io$ + MKI$(SADD(info$))                 'Offset of IOCTL data
 io$ = io$ + MKI$(VARSEG(info$))               'Segment of IOCTL data
 io$ = io$ + MKI$(LEN(info$))                  'Bytes to transfer
 io$ = io$ + MKI$(0)                           'Starting sector number (0)
 io$ = io$ + MKL$(0)                           'Volume ID (0)
 CDRequest drive%, 3, io$                      'Call function 3 (IOCTL read)
 CDctlI$ = info$
END FUNCTION

SUB CDctlO (drive%, info$)
 'CDxtlO               Outputs data to the CD-ROM device driver using IOCTL
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  info$              Data to output

 io$ = CHR$(0)                                 'Media descriptior (0)
 io$ = io$ + MKI$(SADD(info$))                 'Offset of IOCTL data
 io$ = io$ + MKI$(VARSEG(info$))               'Segment of IOCTL data
 io$ = io$ + MKI$(LEN(info$))                  'Bytes to transfer
 io$ = io$ + MKI$(0)                           'Starting sector number (0)
 io$ = io$ + MKL$(0)                           'Volume ID (0)
 CDRequest drive%, 12, io$                     'Call function 14 (IOCTL write)
END SUB

FUNCTION CDDriveCheck% (drive%)
 'CDDriveCheck%        Checks whether a drive is a valid CD-ROM drive or not
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  Returns 0          MSCDEX is installed and this drive is supported
 '  Returns 1          MSCDEX is installed but this drive is not supported
 '  Returns 2          MCCDEX is not installed

 Regs.ax = &H150B                   'Drive Check
 Regs.cx = drive%                   'Drive number (0=A)
 CALL interruptx(&H2F, Regs, Regs)  'Call the interrupt
 IF Regs.bx = &HADAD THEN
  CDDriveCheck% = 0                 'Might be needed
  IF Regs.ax = 0 THEN CDDriveCheck% = 1
 ELSE
  CDDriveCheck% = 2
 END IF
END FUNCTION

FUNCTION CDGetDrives$
 'CDGetDrives$         Find CD-ROM drives
 ' Out:
 '  Returns            String containing the CD-ROM drive list

 Regs.ax = &H1500                   'Installation check
 Regs.bx = 0
 CALL interruptx(&H2F, Regs, Regs)  'Call the interrupt
 list$ = SPACE$(Regs.bx)
 Regs.ax = &H150D                   'Get drive letters
 Regs.es = VARSEG(list$): Regs.bx = SADD(list$)
 CALL interruptx(&H2F, Regs, Regs)  'Call the interrupt
 CDGetDrives$ = list$
END FUNCTION

FUNCTION CDGetError$ (enum%)
 'CDGetError$          Get error from error num
 ' In:
 '  enum%              Specifies the error number (0 to 17)
 ' Out:
 '  Returns            Error text

 SELECT CASE enum%
  CASE 0: e$ = "No error"
  CASE 1: e$ = "Write protect violation"
  CASE 2: e$ = "Unknown unit"
  CASE 3: e$ = "Drive not ready"
  CASE 4: e$ = "Unknown command"
  CASE 5: e$ = "CRC error"
  CASE 6: e$ = "Bad request structure length"
  CASE 7: e$ = "Seek error"
  CASE 8: e$ = "Unknown media"
  CASE 9: e$ = "Sector not found"
  CASE 10: e$ = "Out of paper"
  CASE 11: e$ = "Write fault"
  CASE 12: e$ = "Read fault"
  CASE 13: e$ = "General failure"
  CASE 14, 15: e$ = "Unknown"
  CASE 16: e$ = "Invalid disk change"
  CASE 17: e$ = "Multiple errors has occured"
 END SELECT
 CDGetError$ = e$
END FUNCTION

FUNCTION CDGetStatus%
 'CDGetStatus          Get CD status
 ' Out:
 '  Returns            Status and error code

 'IF INT(TIMER / 4) AND 1 THEN CDRStatus% = CDRStatus% OR 1 'Error check
 CDGetStatus% = CDRStatus%
 CDRStatus% = 0
END FUNCTION

FUNCTION CDGetVersion%
 'CDGetVersion         Checks MSCDEX version
 ' Out:
 '  Returns            MSCDEX version

 Regs.ax = &H150C                   'Version check
 CALL interruptx(&H2F, Regs, Regs)  'Call the interrupt
 CDGetVersion% = (Regs.bx AND 255) + (Regs.bx \ 256) * 100
END FUNCTION

SUB CDIAudio (drive%, chn0%, vol0%, chn1%, vol1%, chn2%, vol2%, chn3%, vol3%)
 'CDIAudio             IOCTL input: get volumes
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  chn0% to chn3%     Returns the in channels for out channel 0 to 3
 '  vol0% to vol3%     Returns the volume for out channel 0 to 3

 ctl$ = CHR$(4)                                'IOCTL function 4 (volume chan)
 ctl$ = ctl$ + SPACE$(8)                       'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)
 chn0% = ASC(MID$(ctl$, 2, 1)): vol0% = ASC(MID$(ctl$, 3, 1))
 chn1% = ASC(MID$(ctl$, 4, 1)): vol1% = ASC(MID$(ctl$, 5, 1))
 chn2% = ASC(MID$(ctl$, 6, 1)): vol2% = ASC(MID$(ctl$, 7, 1))
 chn3% = ASC(MID$(ctl$, 8, 1)): vol3% = ASC(MID$(ctl$, 9, 1))
END SUB

SUB CDIDoor (drive%, state%)
 'CDIDoor              IOCTL input: get door status
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  state% bit 0       0 door closed, 1 door open
 '  state% bit 1       0 door unlocked, 1 door locked

 ctl$ = CHR$(6)                                'IOCTL function 6 (device stat)
 ctl$ = ctl$ + MKL$(0)                         'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)
 state% = (ASC(MID$(ctl$, 2, 1)) AND 3)
 IF (state% AND 1) THEN state% = state% AND 1
END SUB

SUB CDIHead (drive%, sect&)
 'CDIHead              IOCTL input: get curremt head position
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  sect&              Current sector

 ctl$ = CHR$(1)                                'IOCTL function 1  (head loc)
 ctl$ = ctl$ + CHR$(0)
 ctl$ = ctl$ + SPACE$(4)                       'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)                  'Get status get the right bits
 sect& = CVL(MID$(ctl$, 3, 4))
END SUB

SUB CDIInfo (drive%, low%, high%)
 'CDIInfo              IOCTL input: get audio cd info
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  low%               Lowest track number
 '  high%              Highest track number

 ctl$ = CHR$(10)                               'IOCTL function 10 (disk info)
 ctl$ = ctl$ + SPACE$(6)                       'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)
 low% = ASC(MID$(ctl$, 2, 1))                  'Get return info
 high% = ASC(MID$(ctl$, 3, 1))
END SUB

SUB CDISize (drive%, lsect&)
 'CDISize              IOCTL input: get volume size
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  lsect&             Volume size (last sector)

 ctl$ = CHR$(8)                                'IOCTL function 8 (vol size)
 ctl$ = ctl$ + SPACE$(4)                       'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)
 lsect& = CVL(MID$(ctl$, 2, 4)) - 150
END SUB

SUB CDITrack (drive%, track%, start&, ttype%)
 'CDITrack             IOCTL input: get track information
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  track%             Which track to get info from
 ' Out:
 '  start&             Start position of this track
 '  ttype%             0 audio stereo, 1 data, 2 audio surround

 ctl$ = CHR$(11)                               'IOCTL function 11 (track info)
 ctl$ = ctl$ + CHR$(track%)
 ctl$ = ctl$ + SPACE$(5)                       'Space for return info
 ctl$ = CDctlI$(drive%, ctl$)
 Red2HSG start&, ASC(MID$(ctl$, 5, 1)), ASC(MID$(ctl$, 4, 1)), ASC(MID$(ctl$, 3, 1))
' ttype% = (ASC(MID$(ctl$, 7, 1)) AND 192) / 48
ttype% = ASC(MID$(ctl$, 7, 1))
END SUB

SUB CDOAudio (drive%, chn0%, vol0%, chn1%, vol1%, chn2%, vol2%, chn3%, vol3%)
 'CDOAudio             IOCTL output: set volumes
 ' In:
 '  drive%             Specifies the drive number (0=A)
 ' Out:
 '  chn0% to chn3%     Sets the in channels for out channel 0 to 3
 '  vol0% to vol3%     Sets the volume for out channel 0 to 3

 ctl$ = CHR$(3)                                'IOCTL function 4 (volume chan)
 ctl$ = ctl$ + CHR$(chn0%) + CHR$(vol0%)
 ctl$ = ctl$ + CHR$(chn1%) + CHR$(vol1%)
 ctl$ = ctl$ + CHR$(chn2%) + CHR$(vol2%)
 ctl$ = ctl$ + CHR$(chn3%) + CHR$(vol3%)
 CDctlO drive%, ctl$
END SUB

SUB CDOClose (drive%)
 'CDOClose             IOCTL output: close the CD-ROM tray
 ' In:
 '  drive%             Specifies the drive number (0=A)

 CDctlO drive%, CHR$(5)                        'IOCTL function 5 (close tray)
END SUB

SUB CDOLock (drive%, locked%)
 'CDOLock              IOCTL output: lock/unlock the CD-ROM tray
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  locked%            Cero unlocks the tray, noncero locks it

 ctl$ = CHR$(1)                                'IOCTL function 1 (lock door)
 IF locked% THEN ctl$ = ctl$ + CHR$(1) ELSE ctl$ = ctl$ + CHR$(0)
 CDctlO drive%, ctl$
END SUB

SUB CDOOpen (drive%)
 'CDOOpen              IOCTL output: open the CD-ROM tray
 ' In:
 '  drive%             Specifies the drive number (0=A)

 CDctlO drive%, CHR$(0)                        'IOCTL function 0 (open tray)
END SUB

SUB CDRequest (drive%, req%, info$)
 'CDRequest            Makes a request to MSCDEX
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  req%               Request code
 '  info$              Request information

 Regs.ax = &H1510
 Regs.cx = drive%
 request$ = CHR$(13) + CHR$(0) + CHR$(req%) + SPACE$(10) + info$
 Regs.es = VARSEG(request$): Regs.bx = SADD(request$)
 CALL interruptx(&H2F, Regs, Regs)  'Call the interrupt

 stat% = CVI(MID$(request$, 4, 2))
 IF stat% AND -32768 THEN
  IF CDRStatus% AND 255 THEN
   CDRStatus% = 17
  ELSE
   CDRStatus% = (stat% AND 255) + 1
  END IF
 ELSE
  CDRStatus% = 0
 END IF
 CDRStatus% = CDRStatus% + (stat% AND 768)
END SUB

SUB CDRFetch (drive%, ssect&, rsnum%)
 'CDRFetch$            Request: prefetch sectors
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  ssect&             Starting sector
 '  rsnum%             Number of sector to read

 io$ = CHR$(0)                                'Set adressing mode to HSG
 io$ = io$ + MKL$(0)                          'Transfer adress (not used)
 io$ = io$ + MKI$(rsnum%)                     'Number of sectors to prefetch
 io$ = io$ + MKL$(ssect&)                     'Starting sector number
 io$ = io$ + CHR$(1)                          'Set data read mode to raw
 io$ = io$ + CHR$(0)                          'Set interleave size to 0
 io$ = io$ + CHR$(0)                          'Set interleave skip factor to 0
 CDRequest drive%, 130, io$                   'Call function 130 (prefetch)
END SUB

SUB CDRPlay (drive%, startSector&, playSectors&)
 'CDRPlay              Request: play audio
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  startSector&       Where to begin playing
 '  playSectors&       How many sectors to play

 cdr$ = CHR$(0)                                'Set adressing mode to HSG
 cdr$ = cdr$ + MKL$(startSector&)              'Set start sector
 cdr$ = cdr$ + MKL$(playSectors&)              'Set number of sectors to play
 CDRequest drive%, 132, cdr$                   'Call function 132 (play)
END SUB

SUB CDRRead (drive%, ssect&, rsnum%, data$)
 'CDRRead$             Request: read sectors
 ' In:
 '  drive%             Specifies the drive number (0=A)
 '  ssect&             Starting sector
 '  rsnum%             Number of sector to read
 ' Out:
 '  data$              Read sectors

 IF LEN(data$) < 2352 * rsnum% THEN EXIT SUB
 io$ = CHR$(0)                                'Set adressing mode to HSG
 io$ = io$ + MKI$(SADD(data$))                'Offset of sector buffer
 io$ = io$ + MKI$(VARSEG(data$))              'Segment of sector buffer
 io$ = io$ + MKI$(rsnum%)                     'Number of sectors to read
 io$ = io$ + MKL$(ssect&)                     'Starting sector number
 io$ = io$ + CHR$(1)                          'Set data read mode to raw
 io$ = io$ + CHR$(0)                          'Set interleave size to 0
 io$ = io$ + CHR$(0)                          'Set interleave skip factor to 0
 CDRequest drive%, 128, io$                   'Call function 128 (read long)
END SUB

SUB CDRResume (drive%)
 'CDRResume            Request: resume playing audio
 ' In:
 '  drive%             Specifies the drive number (0=A)

 CDRequest drive%, 136, ""                     'Call function 136 (resume)
END SUB

SUB CDRStop (drive%)
 'CDRStop              Request: stop playing audio
 ' In:
 '  drive%             Specifies the drive number (0=A)

 CDRequest drive%, 133, ""                     'Call function 133 (stop)
END SUB

SUB HSG2Red (min%, Sec%, frm%, HSG&)
 IF HSG& <= 445500 AND HSG& >= 0 THEN
  frm% = HSG& MOD 75
  Sec% = (HSG& MOD 4500) \ 75
  min% = HSG& \ 4500
 ELSE
  frm% = -1
 END IF
END SUB

SUB Red2HSG (HSG&, min%, Sec%, frm%)
 HSG& = CDBL(min%) * 4500 + Sec% * 75 + frm% - 150
END SUB

