home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Dos / VARIOS / pascal / SWAG9605.DDD / 0105_Another CDRom Interface.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-05-31  |  15.9 KB  |  416 lines

  1. {==========================================================================}
  2. { CDDrive - an interface to the CD-ROM device driver.                      }
  3. {--------------------------------------------------------------------------}
  4. { Copyright (c) 1996 C.J.Rankin   CJRankin@VossNet.Co.UK                   }
  5. {                                                                          }
  6. { This unit provides an elementary interface for controlling a CD-ROM      }
  7. { in TP6+. It has been left open-ended so that, if you wish, it can be     }
  8. { extended to provide a more comprehensive range of CD-ROM functions.      }
  9. {                                                                          }
  10. { Note that in its current form, it will *only* recognise the first CD-ROM }
  11. { in the system- not a problem for most of us.                             }
  12. {                                                                          }
  13. {--------------------------------------------------------------------------}
  14. {                                                                          }
  15. { Note: Windows 95 uses a protected mode CD-ROM driver and interface       }
  16. {       (MSCDEX v2.95). As a result, the standard way of requesting IOCTL  }
  17. {       functions of opening a file handle to the driver using Assign()    }
  18. {       and Reset() and then calling DOS services AX=$4402/$4403 DOES NOT  }
  19. {       WORK: DOS cannot open the CD-ROM driver in the DOS driver-list and }
  20. {       so opens a new file on the hard disc instead.                      }
  21. {                                                                          }
  22. {==========================================================================}
  23. {$A-,B-,D+,F-,G+,I-,L+,O+,R-,S-,V-,X+}
  24. unit CDDrive;
  25.  
  26. interface
  27.  
  28. const
  29.   ex_CDROMUnknownUnit       =  1;
  30.   ex_CDROMUnready           =  2;
  31.   ex_CDROMUnknownCommand    =  3;
  32.   ex_CDROMCRCError          =  4;
  33.   ex_CDROMBadReqStrucLen    =  5;
  34.   ex_CDROMBadSeek           =  6;
  35.   ex_CDROMUnknownMedia      =  7;
  36.   ex_CDROMUnknownSector     =  8;
  37.   ex_CDROMReadError         = 11;
  38.   ex_CDROMGeneralFailure    = 12;
  39.   ex_CDROMMediaUnavailable  = 14;
  40.   ex_CDROMInvalidDiscChange = 15;
  41.  
  42. const
  43.   MaxCDROM = 26;
  44. type
  45.   TCDROMIndex  = 1..MaxCDROM;
  46.   TCDROMLetter = 0..MaxCDROM-1;
  47.   TCDROMNumber = 0..MaxCDROM;
  48.  
  49. {                                                             }
  50. { These are the explicit CD-ROM services provided by the unit }
  51. {                                                             }
  52. procedure Eject;      (* Eject CD-ROM                                      *)
  53. procedure Close;      (* Close CD-ROM tray                                 *)
  54. procedure Lock;       (* Lock CD-ROM drive                                 *)
  55. procedure Unlock;     (* Unlock CD-ROM drive                               *)
  56. procedure Reset;      (* Reinitialise CD-ROM: i.e. as if disc was changed. *)
  57. function GetNumberOfCDROMDrives: TCDROMNumber;
  58. function GetCDROMVersion: word;
  59.  
  60. {                                                                       }
  61. { Templates for CD-ROM service requests. To implement another device    }
  62. { or IOCTL request, create a descendant object with the requisite extra }
  63. { fields and pass it to the appropriate requestor function.             }
  64. {                                                                       }
  65. type
  66.   PDeviceRequest = ^TDeviceRequest;
  67.   TDeviceRequest = object
  68.                      HeaderLength: byte;
  69.                      SubUnit:      byte;
  70.                      CommandCode:  byte;
  71.                      Status:       word;
  72.                      Reserved:     array[1..8] of byte;
  73.                    end;
  74.  
  75.   PIOCTLRequest = ^TIOCTLRequest;
  76.   TIOCTLRequest = object
  77.                     SubFn: byte;
  78.                   end;
  79.  
  80.   TRequestFunc = function(var Request: TDeviceRequest): word;
  81.  
  82. {                                                                          }
  83. { This constitutes the interface to the driver, enabling further functions }
  84. { to be added if desired. The return value is the driver's Status word:    }
  85. { Status Word:   Bit 15: Error flag. If set then Bits 0-7 are error code   }
  86. {                Bit  8: Request done flag.                                }
  87. {                Bit  9: Device busy flag.                                 }
  88. {                                                                          }
  89. function DriverRequest_v210(var Request: TDeviceRequest): word;
  90. function DriverBasicRequest(var Request: TDeviceRequest): word;
  91. function IOCTLInput(var Request: TIOCTLRequest; ReqLen: word): word;
  92. function IOCTLOutput(var Request: TIOCTLRequest; ReqLen: word): word;
  93.  
  94. {                                                                          }
  95. { Errors are returned in this variable: the values are explained above ... }
  96. {                                                                          }
  97. var CDROMError: byte;
  98.  
  99. {                                                                          }
  100. { DriverRequest_v210 enables CD-ROM driver requests for MSCDEX v2.10+. For }
  101. { earlier versions of MSCDEX, DriverBasicRequest is used instead. The      }
  102. { appropriate function is assigned to the following procedural variable.   }
  103. {                                                                          }
  104. var DriverRequest: TRequestFunc;
  105.  
  106. implementation
  107. uses DOS;
  108.  
  109. type
  110.   TDrvName = array[1..8] of char;
  111.  
  112.   PCDROMDriver = ^TCDROMDriver;
  113.   TCDROMDriver = record
  114.                    NextDriver:         PCDROMDriver;
  115.                    DeviceAttr:         word;
  116.                    StrategyEntryPoint: word;
  117.                    INTEntryPoint:      word;
  118.                    DeviceName:         TDrvName;
  119.                    Reserved:           word;
  120.                    DriveLetter:        TCDROMNumber;
  121.                    Units:              byte
  122.                  end;
  123.  
  124.   TCDROMDriveEntry = record
  125.                        SubUnit:     byte;
  126.                        CDROMDriver: PCDROMDriver
  127.                      end;
  128.  
  129. type
  130.   PDeviceIOCTLRequest = ^TDeviceIOCTLRequest;
  131.   TDeviceIOCTLRequest = object(TDeviceRequest)
  132.                           Media:  byte;
  133.                           BufPtr: pointer;
  134.                           BufLen: byte;
  135.                         end;
  136.  
  137. type
  138.   TCDROMLock = (CDROM_Unlocked, CDROM_Locked);
  139.  
  140.   PCDROMLockRequest = ^TCDROMLockRequest;
  141.   TCDROMLockRequest = object(TIOCTLRequest)
  142.                         LockStatus: TCDROMLock;
  143.                       end;
  144.  
  145. var Regs:                Registers;
  146. var NumberOfCDROMDrives: TCDROMNumber;
  147. var CDROMDriveLetter:    array[TCDROMIndex] of TCDROMLetter;
  148.  
  149. var CDROMDriverStrategyEntryPoint: procedure;
  150. var CDROMDriverINTEntryPoint:      procedure;
  151.  
  152. {                                                                         }
  153. { This is the interface to the CD-ROM driver. The assumption here is that }
  154. { we are only dealing with the first CD-ROM drive in the system- not a    }
  155. { problem to us mere mortals who only HAVE one CD-ROM...                  }
  156. {                                                                         }
  157. function DriverRequest_v210(var Request: TDeviceRequest): word;
  158. begin
  159.   with Regs do
  160.     begin
  161.       ax := $1510;
  162.       es := Seg(Request);
  163.       bx := Ofs(Request);
  164.       cx := CDROMDriveLetter[1]; (* Letter of CD-ROM drive: A=0,B=1,C=2... *)
  165.       Intr($2f,Regs)
  166.     end;
  167.   with Request do
  168.     begin
  169.       if Status and (1 shl 15) <> 0 then (* Check the error flag...*)
  170.         CDROMError := lo(Status)         (* ... return the error   *)
  171.       else
  172.         CDROMError := 0;                 (* ... return `no error'  *)
  173.       DriverRequest_v210 := Status
  174.     end
  175. end;
  176.  
  177. {                                                                     }
  178. { This method of calling CD-ROM driver functions should work for all  }
  179. { versions of MSCDEX. Again, assume that there is only 1 CD-ROM ...   }
  180. {                                                                     }
  181. function DriverBasicRequest(var Request: TDeviceRequest): word;
  182. begin
  183.   with Request do
  184.     begin
  185.       SubUnit := 0; (* Only 1 CD-ROM, so it must be driver sub-unit 0 *)
  186.       asm
  187.         LES BX, [BP+OFFSET Request]
  188.       end;
  189.       CDROMDriverStrategyEntryPoint;
  190.       CDROMDriverINTEntryPoint;
  191.       if Status and (1 shl 15) <> 0 then (* Check the error flag...*)
  192.         CDROMError := lo(Status)         (* ... return the error   *)
  193.       else
  194.         CDROMError := 0;                 (* ... return `no error'  *)
  195.       DriverBasicRequest := Status
  196.     end
  197. end;
  198.  
  199. {                                                                        }
  200. { The CDROM driver can be asked to do LOTS of things; the IOCTL requests }
  201. { are only a very small part. In theory you could descend other buffers  }
  202. { from TDeviceRequest, fill in the HeaderLength, CommandCode and any new }
  203. { fields and send them off to DriverRequest for execution...             }
  204. {                                                                        }
  205. function IOCTLOutput(var Request: TIOCTLRequest; ReqLen: word): word;
  206. var
  207.   DeviceRequestHeader: TDeviceIOCTLRequest;
  208. begin                               (* Descendant of TDeviceRequest *)
  209.   with DeviceRequestHeader do
  210.     begin
  211.       HeaderLength := SizeOf(DeviceRequestHeader);
  212.       CommandCode := $0C;
  213.       BufPtr := @Request.SubFn;  (* These fields added to TDeviceRequest *)
  214.       BufLen := ReqLen           (* for IOCTL commands...                *)
  215.     end;
  216.   IOCTLOutput := DriverRequest(DeviceRequestHeader)
  217. end;
  218.  
  219. function IOCTLInput(var Request: TIOCTLRequest; ReqLen: word): word;
  220. var
  221.   DeviceRequestHeader: TDeviceIOCTLRequest;
  222. begin                               (* Descendant of TDeviceRequest *)
  223.   with DeviceRequestHeader do
  224.     begin
  225.       HeaderLength := SizeOf(DeviceRequestHeader);
  226.       CommandCode := $03;
  227.       BufPtr := @Request.SubFn;  (* These fields added to TDeviceRequest *)
  228.       BufLen := ReqLen           (* for IOCTL commands...                *)
  229.     end;
  230.   IOCTLInput := DriverRequest(DeviceRequestHeader)
  231. end;
  232.  
  233. {                                                                          }
  234. { Yes, I COULD have just put NumberOfCDROMDrives in the interface section, }
  235. { except that this number is important and I don't want users `fiddling'   }
  236. { with it. :-)                                                             }
  237. {                                                                          }
  238. function GetNumberOfCDROMDrives: TCDROMNumber;
  239. begin
  240.   GetNumberOfCDROMDrives := NumberOfCDROMDrives
  241. end;
  242.  
  243. {                                                                     }
  244. { The mechanism used to perform device driver requests depends on the }
  245. { version of MSCDEX, so we need a method of finding this out.         }
  246. {                                                                     }
  247. function GetCDROMVersion: word;
  248. begin
  249.   with Regs do
  250.     begin
  251.       bx := 0;
  252.       ax := $150c;
  253.       Intr($2f,Regs);
  254.       GetCDROMVersion := bx  (* Hi byte = Major version number *)
  255.     end                      (* Lo byte = Minor version number *)
  256. end;
  257.  
  258. procedure Eject;
  259. var
  260.   Request: TIOCTLRequest;
  261. begin
  262.   if NumberOfCDROMDrives > 0 then
  263.     with Request do
  264.       begin
  265.         SubFn := 00;   (* IOCTL command code for Eject... *)
  266.         IOCTLOutput(Request,SizeOf(Request))
  267.       end
  268. end;
  269.  
  270. procedure Reset;
  271. var
  272.   Request: TIOCTLRequest;
  273. begin
  274.   if NumberOfCDROMDrives > 0 then
  275.     with Request do
  276.       begin
  277.         SubFn := 02;   (* IOCTL command code to reset the CD-ROM drive *)
  278.         IOCTLOutput(Request,SizeOf(Request))
  279.       end
  280. end;
  281.  
  282. procedure Close;
  283. var
  284.   Request: TIOCTLRequest;
  285. begin
  286.   if NumberOfCDROMDrives > 0 then
  287.     with Request do
  288.       begin
  289.         SubFn := 05;   (* IOCTL command code to close the CD-ROM drive *)
  290.         IOCTLOutput(Request,SizeOf(Request))
  291.       end
  292. end;
  293.  
  294. {
  295. { This routine seems to require a CD in the drive. Otherwise it returns  }
  296. { CDROMError = 2 (on my machine anyway...)                               }
  297. {                                                                        }
  298. procedure Lock;
  299. var
  300.   Request: TCDROMLockRequest;
  301. begin
  302.   if NumberOfCDROMDrives > 0 then
  303.     with Request do
  304.       begin
  305.         SubFn := 01;   (* ... locking the CDROM... *)
  306.         LockStatus := CDROM_Locked;
  307.         IOCTLOutput(Request,SizeOf(Request))
  308.       end
  309. end;
  310.  
  311. procedure Unlock;
  312. var
  313.   Request: TCDROMLockRequest;
  314. begin
  315.   if NumberOfCDROMDrives > 0 then
  316.     with Request do
  317.       begin
  318.         SubFn := 01;   (* ... and unlocking ... *)
  319.         LockStatus := CDROM_Unlocked;
  320.         IOCTLOutput(Request,SizeOf(Request))
  321.       end
  322. end;
  323.  
  324. {                                                                       }
  325. { Store the Strategy and Interrupt Entry Points for the CD-ROM device   }
  326. { driver... Again, assume that there is only 1 CD-ROM drive, and so     }
  327. { SubUnit will always = 0                                               }
  328. {                                                                       }
  329. procedure SetUpEntryPoints;
  330. var
  331.   CDDriveList: array[TCDROMIndex] of TCDROMDriveEntry;
  332. begin
  333.   with Regs do
  334.     begin
  335.       ax := $1501;
  336.       es := Seg(CDDriveList);
  337.       bx := Ofs(CDDriveList);
  338.       Intr($2f,Regs)
  339.     end;
  340.   with CDDriveList[1] do
  341.     begin
  342.       @CDROMDriverStrategyEntryPoint :=
  343.                   Ptr(Seg(CDROMDriver^),CDROMDriver^.StrategyEntryPoint);
  344.       @CDROMDriverINTEntryPoint :=
  345.                   Ptr(Seg(CDROMDriver^),CDROMDriver^.INTEntryPoint)
  346.  
  347.     end
  348. end;
  349.  
  350. {                                                                          }
  351. { Initialisation code: neither the number of CD-ROM drives nor their drive }
  352. { letters will change during execution, so we shall identify the drives    }
  353. { NOW and not do it again.                                                 }
  354. {                                                                          }
  355. begin
  356. {                                         }
  357. { Get number of CD-ROMs in the system ... }
  358. {                                         }
  359.   with Regs do
  360.     begin
  361.       ax := $1500;
  362.       bx := 0;
  363.       Intr($2f,Regs);
  364.       NumberOfCDROMDrives := bl;
  365. {                                                                         }
  366. { Get the drive-letters for CD-ROMSs... There is an MSCDEX function to do }
  367. { this for v2.00+, viz AX=$150D INT $2F. However we are assuming only one }
  368. { CD-ROM and so the drive letter has already been determined.             }
  369. {                                                                         }
  370.       if NumberOfCDROMDrives > 0 then
  371.         begin
  372.           CDROMDriveLetter[1] := cl;
  373. {                                                                 }
  374. { Determine the entry points for direct device-driver requests... }
  375. {                                                                 }
  376.           SetUpEntryPoints;
  377. {                                                                 }
  378. { Determine which mechanism to use for CD-ROM driver requests ... }
  379. {                                                                 }
  380.           if GetCDROMVersion < 2*256 + 10 then
  381.             DriverRequest := DriverBasicRequest
  382.           else
  383.             DriverRequest := DriverRequest_v210
  384.         end
  385.     end
  386. end.
  387.  
  388. { ----------------------   DEMO PROGRAM ----------------------- }
  389.  
  390. {$A+,B-,D+,E-,F-,G+,I+,L+,N-,O-,R-,S-,V-,X+}
  391. {$M 16384,0,655360}
  392. program CDDemo;
  393. uses CDDrive;
  394.  
  395. var
  396.   Version: word;
  397. begin
  398.   if GetNumberOfCDROMDrives = 0 then
  399.     writeln( 'This machine has no CD-ROM drive.' )
  400.   else
  401.     begin
  402.       Version := GetCDROMVersion;
  403.       writeln( 'MSCDEX v', hi(Version), '.', lo(Version) );
  404.       Lock;
  405.       writeln( 'Lock: Error = ', CDROMError );
  406.       Unlock;
  407.       writeln( 'Unlock: Error = ', CDROMError );
  408.       Eject;
  409.       writeln( 'Eject: Error = ', CDROMError );
  410.       Close;
  411.       writeln( 'Close: Error = ', CDROMError );
  412.       Reset;
  413.       writeln( 'Reset: Error = ', CDROMError )
  414.     end
  415. end.
  416.