DEFINITION MODULE Devices; (********************************************************) (* *) (* Support for device drivers. *) (* *) (* The aim of this module is to a measure of device *) (* independence in I/O operations. It provides a *) (* uniform I/O interface to all device drivers which *) (* choose to make themselves known to module Devices. *) (* *) (* Programmer: P. Moylan *) (* Last edited: 16 June 1992 *) (* Status: Working *) (* *) (********************************************************) FROM SYSTEM IMPORT (* type *) BYTE, ADDRESS; FROM IOErrorCodes IMPORT (* type *) ErrorCode; FROM Semaphores IMPORT (* type *) Semaphore; (************************************************************************) TYPE BlockNumberType = LONGCARD; (* Any I/O device supported by this module is specified by a pair *) (* of type (device, unit), where the first component has private *) (* type Device, and the second is a unit number (normally zero, but *) (* some device drivers support multi-unit devices). *) Device; (* is private *) (* The I/O operations dealt with by this module. Note that "read" *) (* and "physicalread" have the same meaning for most devices - and *) (* similarly for "write" and "physicalwrite" - but the distinction *) (* is important for hard disks, which can be partitioned into *) (* one or more logical disks. *) OperationType = (verify, read, write, physicalread, physicalwrite, shutdown); (********************************************************************) (* *) (* An I/O operation is specified by the details in a request block *) (* whose fields have the meaning: *) (* *) (* Status to show the result of the operation *) (* (Status = OK if there was no error) *) (* operation the desired I/O operation *) (* device,unit the device to be used *) (* BlockNumber the block number on the medium, used *) (* only for block-oriented devices *) (* ByteCount the number of bytes to transfer *) (* BufferAddress the address of an array which holds the *) (* data to be written, or which will *) (* receive the input data *) (* DoneSemaphorePointer the address of a semaphore on *) (* which the device will perform a Signal *) (* to let the user know that the operation *) (* is complete *) (* *) (* The caller must not modify the contents of the request block *) (* until completion of the I/O operation. Device drivers must *) (* not modify any field except the Status field. *) (* *) (********************************************************************) TYPE RequestBlock = RECORD Status: ErrorCode; operation: OperationType; device: Device; unit: CARDINAL; BlockNumber: BlockNumberType; ByteCount: CARDINAL; BufferAddress: ADDRESS; DoneSemaphorePointer: POINTER TO Semaphore; END (*RECORD*); RequestBlockPointer = POINTER TO RequestBlock; (************************************************************************) (* PROCEDURES CALLED BY THE USER TASKS *) (************************************************************************) PROCEDURE SameDevice (d1, d2: Device): BOOLEAN; (* Tests the condition d1 = d2. *) PROCEDURE NullDevice (): Device; (* Returns the device code which this module uses internally to *) (* mean "nonexistent device" or "unknown device". I/O operations *) (* on this device are of course impossible (if attempted, they will *) (* result in the NoSuchDevice error code), but the device code can *) (* be used by client modules as a marker to indicate that no *) (* genuine device has yet been specified. *) PROCEDURE IdentifyDevice (name: ARRAY OF CHAR; VAR (*OUT*) device: Device; VAR (*OUT*) unitnumber: CARDINAL); (* Given the character string form of a device name, returns the *) (* device code and unit number. *) PROCEDURE GetDefaultDirectory (device: Device; unit: CARDINAL; VAR (*OUT*) DirectoryString: ARRAY OF CHAR); (* Produces a string representing the default directory. The *) (* string includes the character form of the device name. *) PROCEDURE VolumeSize (device: Device; unitnumber: CARDINAL): BlockNumberType; (* Returns the number of sectors on (device, unitnumber). Note *) (* that the result is meaningful only for device drivers which *) (* supply this information (see DeviceName below). *) PROCEDURE IOrequest (VAR (*INOUT*) details: RequestBlock); (* Adds the requested I/O operation to the queue of pending *) (* operations on details.device. The operation might not be done *) (* immediately since the device driver might still be working on an *) (* earlier request. On I/O completion, the device driver performs *) (* a Signal(details.DoneSemaphorePointer^). *) PROCEDURE BlockRead (d: Device; unitnumber: CARDINAL; BlockNumber: BlockNumberType; MemoryAddress: ADDRESS; amount: CARDINAL): ErrorCode; (* Reads "amount" bytes into memory, starting at the *) (* beginning of block number "BlockNumber" on the specified device. *) PROCEDURE BlockWrite (d: Device; unitnumber: CARDINAL; BlockNumber: BlockNumberType; MemoryAddress: ADDRESS; amount: CARDINAL): ErrorCode; (* Writes "amount" bytes from memory, starting at the beginning of *) (* block number "BlockNumber" on the specified device. *) PROCEDURE ReadPhysicalBlock (d: Device; unitnumber: CARDINAL; BlockNo: BlockNumberType; MemoryAddress: ADDRESS): ErrorCode; (* Reads one sector into memory, starting at the beginning of *) (* physical block number "BlockNo" on the specified device. *) (************************************************************************) (* PROCEDURES CALLED BY THE DEVICE DRIVERS *) (************************************************************************) PROCEDURE InstallDeviceDriver (MaxUnitNumber: CARDINAL): Device; (* Called by the device driver as part of its initialization code, *) (* to make the driver known to this module. MaxUnitNumber is the *) (* maximum unit number which this device driver will support (0 for *) (* a single-unit device driver). The value returned is the means *) (* by which the device driver will henceforth identify itself to *) (* this module. *) PROCEDURE DeviceName (device: Device; unit: CARDINAL; name: ARRAY OF CHAR; size: BlockNumberType; DefaultDirString: ARRAY OF CHAR); (* Specifies an external name for a given device and unit number. *) (* Duplicate names are permitted. The size parameter gives the *) (* number of sectors in the partition if this "device" is actually *) (* a partition on a hard disk; but it is not necessarily meaningful *) (* for other device types. (This parameter is supplied only for *) (* the benefit of the file system when it has to deal with the *) (* special case of a large partition.) Device drivers which are *) (* not prepared to specify a meaningful size should supply a value *) (* of 0 for the size. *) (* DefaultDirString specifies the initial default directory. *) PROCEDURE AcceptRequest (device: Device): RequestBlockPointer; (* Returns a pointer to the next request enqueued for this device. *) (* If there is no next request, we wait until one appears. *) END Devices.