ST-DOS driver interface Note: The kernel changes the current PSP value to the PSP of the driver program before calling the driver functions, so the driver doesn't need to change the PSP before doing syscalls. A device driver can be a TSR program or a part of the currently running DOS program. The kernel doesn't care, as long as the driver code is in the memory. The driver MUST be unloaded using system call 0x6C before overwriting the driver code from the memory. 1. Device drivers How to write a device driver A driver can have 1 - 65535 device nodes. When a driver is loaded, the kernel treats the name of the driver as a reserved filename. For example, if the name of the driver is COM and a program tries to open a file named COM1, the kernel opens the device 1 from the driver COM to a file handle. The device number is 0 if not specified. To load a device driver you must use syscall 0x6A. Read SYSCALLS.TXT for more information. You must pass a pointer to a table of 32-bit pointers to the kernel. The entries in this table point to the routines that the kernel calls. If the driver wants to call the CTRL+BREAK handler safely, it can do it by calling software interrupt 0x2B. If the driver wants to call the critical error handler safely, it can do it by calling software interrupt 0x2C. Indexes and routines in the function table: 0: READ 1: WRITE 2: SEEK 3: OPEN 4: CLOSE 5: GET_ERROR_CODE 6: SEND_COMMAND 7: IOCTL The driver must supply a full 8 entries long table, but not all listed functions have to be implemented. The table entries for unimplemented functions must be null pointers. All routines must return with RETF. Calling conventions of device driver routines 0. READ Arguments: BX = device number DX:AX = pointer to a buffer CX = count of bytes Return value: AX = count of bytes read Note: This function is called by the syscall 0x3F (read handle). 1. WRITE Arguments: BX = device number DX:AX = pointer to a buffer CX = count of bytes Return value: AX = count of bytes written Note: This function is called by the syscall 0x40 (write handle). 2. SEEK Arguments: BX = device number (0 if not specified) DX:AX = count CX = origin (same as in DOS syscall 0x42) Return value: DX:AX = new offset Note: This function is called by the syscall 0x42 (move file pointer). 3. OPEN Arguments: BX = device number CX = mode (0, 1 or 2, same as in DOS syscall 0x3D) Return value: AX = 0 if no error AX = non-zero if error Note: The kernel always calls the GET_ERROR_CODE routine (if it exists) after every routine. If the OPEN routine returns non-zero, the error code set by the driver is discarded and the kernel sets its own error code. If you want to return your own error code, make the OPEN routine return zero (0) and wait for the kernel to call the GET_ERROR_CODE routine. 4. Close Arguments: BX = device number Return value: AX = 0 if no error AX = non-zero if error Note: This function is called when a file handle that refers to the device is closed and the handle does not have any duplicates left. 5. Get error Arguments: BX = device number Return value: AX = DOS error code Note: This function, if implemented, must return 0 if the last call returned without an error. On error this must return a suitable DOS error code. 6. Send command Arguments: BX = device number DX:AX = pointer to a command string Return value: AX = return code that is passed to the user program Note: This function can be used to send driver-specific control strings to the driver. 7. IOCTL Arguments: BX = device number CX = byte count SI = AX register from DOS syscall 0x44 DX:AX = data or buffer Return value: DX:AX = device status flags as returned by DOS syscall 0x44 (IOCTL) 2. Filesystem drivers To load a filesystem driver you must use the syscall 0x6a with cx==1. Indexes and routines in the function table: 0: CHDIR* 1: GETCWD* 2: FSCHGD* 3: FREESPACE* 4: DIRENTRY* 5: FILEINFO* 6: HANDLESTATINFO* 7: READFILE* 8: RENAME 9: WRITEFILE 10: TRUNCFILE 11: CREATEFILE 12: CREATEDIR 13: UPDATEFILEINFO_NOHDL 14: UPDATEFILEINFO_HDL 15: SETFILEINFO 16: DELETE 17: MOUNT* 18: UNMOUNT* 19: RAWREAD* 20: RAWWRITE 21: GETERROR* Entries marked with "*" are required. Other functions are not required if the filesystem driver is read-only. A "path array" is an array of entries of type dirindex_t. The array is terminated with the value of -1. The array contains the directory indexes of a directory or file path. The path array of the root directory is a single -1. The path array of the third file in a directory that is the tenth directory entry in the root directory would be 10, 3, -1. A "drive path array" is an array of entries of type dirindex_t. Its first entry contains the drive number. Next entries form a "path array". The data type of dirindex_t is currently a 32-bit unsigned int. 0. CHDIR Arguments: BX = drive (A = 0, B = 1 ...) DX:AX = pointer to a path array Changes the current directory of the drive. This function MUST NOT fail. The kernel only uses this function with directories that are known to exist. 1. GETCWD Arguments: BX = drive DX:AX = pointer to a path array. Fills the pointer in DX:AX with the path array of the current working directory. This function MUST NOT fail. 2: FSCHGD Arguments: BX = drive Returns 0 if the media in the drive has been changed. Returns 1 if the media has been changed, and -1 if the media was changed and remounting the filesystem failed. With non-removable filesystems this should always return 0. 3: FREESPACE Arguments: BX = drive DX:AX = pointer to a diskfree struct Returns the filesystem usage stats. See the declaration of the diskfree struct in structs.c. 4: DIRENTRY Arguments: DX:AX = dirindex_t of the requested directory entry in the current directory BL = Drive BH = Count+1 of entries that the kernel is going to request in the next calls DS:CX = Pointer to a 32-bit segment:offset pointer of the destination buffer Returns -1 to AX if the current working directory does not have a directory entry at the requested index. Returns -2 if the requested index is larger than that of the last file in the directory. Returns -3 if an error happened. Normally returns 0 and copies the filename to the destination buffer. 5: FILEINFO Arguments: BX = drive DX:AX = dirindex_t of a file DS:CX = pointer to a file_info struct Returns information about the file. See the declaration of the file_info struct in structs.c. 6: GETHANDLESTATINFO Arguments: BX = drive DX:AX = dirindex_t of a file Return registers: DX:AX The kernel calls this function when a program has opened a file handle. The filesystem driver can use this function to return information that makes accessing the file faster in the future, for example the starting block of the file. The returned information is stored in a file_handle struct to byte offset 4. The first 32-bit dword in a file_handle struct can be used by the filesystem driver to store variable data about the file, for example the block of the current file offset. This value is zeroed by the kernel when the file is seeked to a different offset. The second 32-bit dword in the struct is used to store more persistent data about the file. The offset of the file is stored in the third 32-bit dword. 7: READFILE Arguments: DS:AX = pointer to the file offset as a 32-bit integer DS:BX = pointer to dirindex_t of the file CX = count of bytes to read DS:DX = pointer to a 32-bit segment:offset pointer to the destination buffer SI:0 = pointer to a file_handle struct Reads bytes from the file to the destination buffer. Returns the amount of read bytes to AX. If the value of the SI register is not 0, the file_handle struct contains the value returned earlier by GETHANDLESTATINFO in byte offset 4. If the value is 0, the filesystem driver must recalculate it and save the value to the struct. 8: RENAME Arguments: DX:AX = dirindex_t of a file CX:SI = new filename BX = drive Changes the name of a file. Must return 0 when no error happened, else returns -1. 9: WRITEFILE Arguments: Same as with READFILE Writes data to a file. Returns the count of bytes written. 10: TRUNCFILE Arguments: BX = segment of a file handle struct BX:24 = pointer to a path array BX:16 = less significant doubleword of file offset (BX:20 = more significant doubleword of file offset - not used with this call) Truncates the length of the file to the current offset. Returns -1 if an error happened, else returns 0. 11: CREATEFILE Arguments: BX = drive DX:AX = filename CX = attributes Creates a new file. Returns the dirindex_t of the new file to DX:AX, or -1 if an error happened. 12: CREATEDIR Arguments: BX = drive DX:AX = filename Creates a new directory. Returns nothing, but sets an error code if an error happened. 13: UPDATEFILEINFO_NOHDL Arguments: DX:AX = pointer to a drive path array Sets an ARCHIVE flag or an equivalent flag for the file. Updates the timestamp of the file. Returns 0 if no error happened, else returns -1. 14: UPDATEFILEINFO_HDL Arguments: BX = handle seg BX:8 = less significant doubleword of the current length of the handle (BX:12 = more significant doubleword of the length - not used with this call) BX:CX = time struct, if the timestamp of the time has been changed in the handle - 0 if the time is unchanged BX:DX = date struct, if the timestamp has been changed - else 0 BX:24 = pointer to a drive path array Sets an ARCHIVE flag or an equivalent flag for the file. Updates the length and timestamp information of the file. Returns 0 if no error happened, else returns -1. 15: SETFILEINFO Arguments: SI = drive BX:CX = dirindex_t of the file DX:AX = pointer to a file_info struct Updates file information (attributes and timestamp). 16: DELETE Arguments: DX:AX = dirindex_t of the file BX = drive CX = force Deletes a file. If CX == 0, the filesystem driver may refuse to delete the file if, for example, the file has a "read only" attribute set or the file is a directory. Returns 0 if no error happened, otherwise returns non-zero. 17: MOUNT Arguments: BX = drive DX:AX = pointer to a filename of an image file The kernel calls this function to inform the filesystem driver that the drive number in BX is now using this filesystem driver. If the pointer in DX:AX is not null, the filesystem driver must use the image file as a logical drive of its filesystem. If the pointer is null and the filesystem driver is using a device driver for I/O, this function must return 1 to AX. Else (if the filesystem driver not using an image file or a local partition such as DRV:D, DRV:e ...) this must return 0. 18: UNMOUNT Arguments: BX = drive Unmounts a drive. Returns 0 when successful. 19: RAWREAD Arguments: BX = drive DX:AX = less significant doubleword of the offset DS:SI+0 = pointer to a 32-bit SEGMENT:OFFSET pointer to the destination buffer DS:SI+4 = pointer to the most significant doubleword of the offset CX = count of bytes to read Reads raw bytes from the filesystem. Returns the count of read bytes to AX. 20: RAWWRITE Arguments: Same as with RAWREAD Writes raw bytes to the filesystem. Returns the count of written bytes to AX. 21: GETERROR Arguments: none Returns the error code to AX, or 0 if no error happened during the previous call.