; ============================================================================
;
; LT-DOS - Devices
;
; ============================================================================
; ------------- Device Driver Header, DDH
struc DDH
DDH_next: resw 1 ; 0: offset of next DDH (-1 = last driver)
resw 1 ; 2: segment of next DDH
DDH_attr: resw 1 ; 4: device attributes (see below)
DDH_strat: resw 1 ; 6: offset of device strategy entry point
DDH_inter: resw 1 ; 8: offset of device interrupt entry point
; --- character device
DDH_name: ; 10: (8) blank-padded device name
; --- block device
DDH_units: ; 10: (1) number of subunits (drives)
resb 8
endstruc
DDH_SIZE EQU DDH_size
; ------------- Device attributes
; character devices:
DEV_STDIN EQU B0 ; B0 1=STDIN device
DEV_STDOUT EQU B1 ; B1 1=STDOUT device
DEV_NUL EQU B2 ; B2 1=NUL device
DEV_CLOCK EQU B3 ; B3 1=CLOCK$ device
DEV_FAST EQU B4 ; B4 1=use fast screen int 29h,
; else use STDIN/STDOUT file mode
DEV_IOCALL EQU B6 ; B6 1=supports IOCTL call (command 19)
DEV_IOCHECK EQU B7 ; B7 1=supports IOCTL check (command 25)
DEV_CHANGE EQU B11 ; B11 1=supports removable media
DEV_OUTBUSY EQU B13 ; B13 1=supports output until busy
DEV_IOCTL EQU B14 ; B14 1=supports IOCTL (DOS function 44h)
DEV_CHAR EQU B15 ; B15 1=character device, 0=block device
; block devices:
DEV_32BIT EQU B1 ; B1 1=supports 32-bit sector addressing
;DEV_IOCALL EQU B6 ; B6 1=supports IOCTL call (command 19)
;DEV_IOCHECK EQU B7 ; B7 1=supports IOCTL check (command 29)
DEV_RAW EQU B10 ; B10 1=?????????????????????????????????
;DEV_CHANGE EQU B11 ; B11 1=supports removable media
DEV_REMOTE EQU B12 ; B12 1=network (remote) device
DEV_NOFAT EQU B13 ; B13 1=non-IBM format (non FAT)
;DEV_IOCTL EQU B14 ; B14 1=supports IOCTL (DOS function 44h)
;DEV_CHAR EQU B15 ; B15 1=character device, 0=block device
; ------------- Device Driver Request, DDR
struc DDR
DDR_len: resb 1 ; 0: length of this header (in bytes)
DDR_unit: resb 1 ; 1: subunit number (block device only)
DDR_cmd: resb 1 ; 2: command code (see below)
DDR_errorstatus: ; (3: error code + status)
DDR_error: resb 1 ; 3: error code (if S_ERROR of status is set)
DDR_status: resb 1 ; 4: device request status (see below)
DDR_res: resd 1 ; 5: ... reserved
DDR_next: resd 1 ; 9: pointer to next DDR
DDR_ext: ; --- 13: extensions...
DDR_media: resb 1 ; 13: media descriptor
DDR_trans: resd 1 ; 14: transfer address
DDR_count: resw 1 ; 18: byte count or sector count
DDR_start: resw 1 ; 20: starting sector number (FFFF=use 32-bit)
DDR_volID: resd 1 ; 22: pointer to volume ID
DDR_start2: resd 1 ; 26: 32-bit starting sector number
endstruc
; ------------- Device driver command codes
CMD_INIT EQU 0 ; init
CMD_CHECK EQU 1 ; media check (block devices)
CMD_BUILD EQU 2 ; build BPB (block devices)
CMD_IOIN EQU 3 ; IOCTL input
CMD_IN EQU 4 ; input
CMD_INTEST EQU 5 ; nondestructive input (character devices)
CMD_INSTAT EQU 6 ; input status (character devices)
CMD_INFLUSH EQU 7 ; input flush (character devices)
CMD_OUT EQU 8 ; output
CMD_OUTVER EQU 9 ; output with verify
CMD_OUTSTAT EQU 10 ; output status (character devices)
CMD_OUTFLUSH EQU 11 ; output flush (character devices)
CMD_IOOUT EQU 12 ; IOCTL output
CMD_OPEN EQU 13 ; device open
CMD_CLOSE EQU 14 ; device close
CMD_XCHANGE EQU 15 ; removable media (block devices)
CMD_OUTWAIT EQU 16 ; output until busy (character devices)
CMD_OUTSTOP EQU 17 ; stop output (console screen drivers)
COM_OUTRES EQU 18 ; restart output (console screen drivers)
CMD_IOCTL EQU 19 ; generic IOCTL request
CMD_RESTORE EQU 20 ; device restore (character devices)
CMD_RESFLAG EQU 21 ; reset uncertain media flag
CMD_20 EQU 22 ; ... reserved
CMD_GETDEV EQU 23 ; get logical device
CMD_SETDEV EQU 24 ; set logical device
CMD_CHECKIO EQU 25 ; check generic IOCTL support
; ------------- Device driver error codes
ERR_PROT EQU 0 ; write-protect violation
ERR_UNIT EQU 1 ; unknown unit
ERR_READY EQU 2 ; device not ready
ERR_COMMAND EQU 3 ; unknown command
ERR_CRC EQU 4 ; CRC failure
ERR_LENGTH EQU 5 ; bad drive request structure length
ERR_SEEK EQU 6 ; seek failure
ERR_MEDIA EQU 7 ; unknown media
ERR_SECTOR EQU 8 ; sector not found
ERR_PAPER EQU 9 ; printer out of paper
ERR_WRITE EQU 10 ; write fault
ERR_READ EQU 11 ; read fault
ERR_GENERAL EQU 12 ; general failure
ERR_CHANGE EQU 15 ; ivalid disk change
; ------------- Device driver status
S_DONE EQU B0 ; 01h: done (completed)
S_BUSY EQU B1 ; 02h: busy
S_ERROR EQU B7 ; 80h: error (DDR_error is valid)
; ------------- Command extensions to DDR
; Command code 0 (init):
; 13: (1) out: number of units (block devices)
; 18: (4) in: pointer to commandline arguments
; out: pointer to BPB array (block devices)
;
; Command code 1 (media check, block devices)
; 13: (1) media descriptor (block devices)
; 14: (1) out: media change status (see below)
; 15: (4) out: pointer to new volume disk label (only if meda changed)
;
; Command code 2 (build BPB, block devices)
; 13: (1) out: media descriptor (block devices)
; 14: (4) in: transfer address (contains media descriptor)
; 18: (4) out: pointer to BPB
;
; Command code 3, 12 (IOCTL input, IOCTL output)
; 13: (1) media descriptor (block devices)
; 14: (4) transfer address
; 18: (2) in: number of bytes to read/write
; out: actual number of bytes read or written
;
; Command code 4, 8, 9 (input, output)
; 13: (1) media descriptor (block devices)
; 14: (4) transfer address
; 18: (2) byte count (char.dev.) or sector count (block dev.)
; 20: (2) starting sector number (block devices, 0FFFFh use 32-bit)
; 22: (4) pointer to volume ID if error 15 returned
; 26: (4) 32-bit starting sector number (block devices), if bit 1
; of device attributes is set, sectors > 0FFFFh)
;
; Command code 5 (nondestructive input, character devices)
; 13: (1) out: byte read from device if bit 1 (busy) clear on return
;
; Command code 16 (output until busy)
; 14: (4) transfer address
; 18: (2) in: number of bytes to write
; out: actual number of bytes written
;
; Command code 19. 25 (generic IOCTL request, check generic IOCTL support)
; 13: (1) category code
; 00h: unknown
; 01h: COM
; 02h: terminal
; 03h: CON
; 04h: keyboard
; 05h: LPT
; 07h: mouse
; 08h: disk
; 48h: FAT32 disk control
; 14: (1) command
; 15: (2) copy of DS at time of IOCTL call
; 17: (2) offset of device driver header
; 19: (4) pointer to parameter block
; ------------- Media change status
CHANGE_UNKNOWN EQU 0 ; media change unknown
CHANGE_NO EQU 1 ; media hat not been changed
CHANGE_YES EQU -1 ; media has been changed
; ----------------------------------------------------------------------------
; Device parameter blocks
; ----------------------------------------------------------------------------
DPBCON: dw DPBAUX,BOOTSEG ; pointer to next device
dw B15+B4+B1+B0 ; attributes (stdin, stdout, char)
dw SetStrat ; device strategy
dw CONInt ; device interrupt
db 'CON ' ; device name
DPBAUX: dw DPBPRN,BOOTSEG ; pointer to next device
dw B15 ; attributes (char)
dw SetStrat ; device strategy
dw COM1Int ; device interrupt
db 'AUX ' ; device name
DPBPRN: dw DPBCLOCK,BOOTSEG; pointer to next device
dw B15+B13+B6 ; attributes (print, char)
dw SetStrat ; device strategy
dw LPT1Int ; device interrupt
db 'PRN ' ; device name
DPBCLOCK: dw DPBDISK,BOOTSEG ; pointer to next device
dw B15+B3 ; attributes (clock, char)
dw SetStrat ; device strategy
dw CLKInt ; device interrupt
db 'CLOCK$ ' ; device name
DPBDISK: dw DPBCOM1,BOOTSEG ; pointer to next device
dw B11+B7+B6+B1 ; attributes (xchange, logical, block)
dw SetStrat ; device strategy
dw DSKInt ; device interrupt
db 4 ; number of devices
times 7 db 0
DPBCOM1: dw DPBLPT1,BOOTSEG ; pointer to next device
dw B15 ; attributes (char)
dw SetStrat ; device strategy
dw COM1Int ; device interrupt
db 'COM1 ' ; device name
DPBLPT1: dw DPBLPT2,BOOTSEG ; pointer to next device
dw B15+B13+B6 ; attributes (print, char)
dw SetStrat ; device strategy
dw LPT1Int ; device interrupt
db 'LPT1 ' ; device name
DPBLPT2: dw DPBLPT3,BOOTSEG ; pointer to next device
dw B15+B13+B6 ; attributes (print, char)
dw SetStrat ; device strategy
dw LPT2Int ; device interrupt
db 'LPT2 ' ; device name
DPBLPT3: dw DPBCOM2,BOOTSEG ; pointer to next device
dw B15+B13+B6 ; attributes (print, char)
dw SetStrat ; device strategy
dw LPT3Int ; device interrupt
db 'LPT3 ' ; device name
DPBCOM2: dw DPBCOM3,BOOTSEG ; pointer to next device
dw B15 ; attributes (char)
dw SetStrat ; device strategy
dw COM2Int ; device interrupt
db 'COM2 ' ; device name
DPBCOM3: dw DPBCOM4,BOOTSEG ; pointer to next device
dw B15 ; attributes (char)
dw SetStrat ; device strategy
dw COM3Int ; device interrupt
db 'COM3 ' ; device name
DPBCOM4: dw -1,-1 ; pointer to next device
dw B15 ; attributes (char)
dw SetStrat ; device strategy
dw COM4Int ; device interrupt
db 'COM4 ' ; device name
; ----------------------------------------------------------------------------
; Set device strategy address
; ----------------------------------------------------------------------------
; INPUT: ES:BX = device strategy address
; ----------------------------------------------------------------------------
SetStrat: mov [cs:Strat],bx ; set strategy address LOW
mov [cs:Strat+2],es ; set strategy address HIGH
retf
; ----------------------------------------------------------------------------
; Addresses of device service tables
; ----------------------------------------------------------------------------
FNCTab: dw FNCCON ; CON service table
dw FNCCLK ; CLK service table
dw FNCDSK ; DSK service table
dw FNCCOM ; COM service table
dw FNCLPT ; LPT service table
; ------------- Type of devices
DEVCON EQU 0 ; console
DEVCLK EQU 1 ; clock
DEVDSK EQU 2 ; disk
DEVCOM EQU 3 ; COM port
DEVLPT EQU 4 ; LPT port
; ----------------------------------------------------------------------------
; Device interrupt routines
; ----------------------------------------------------------------------------
%macro DEVPAR1 1 ; parameter: device type
push ax ; push AX
mov al,%1*2 ; AL<-device type*2
%endmacro
%macro DEVPAR2 2 ; parameters: type, device index
push ax ; push AX
mov ax,%2*256+%1*2 ; AL<-device type*2, AH<-device index
%endmacro
; ------------- CON interrupt routine
CONInt: DEVPAR1 DEVCON ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- AUX interrupt routine
AUXInt: DEVPAR2 DEVCOM,0 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- PRN interrupt routine
PRNInt: DEVPAR2 DEVLPT,0 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- CLOCK$ interrupt routine
CLKInt: DEVPAR1 DEVCLK ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- DISK interrupt routine
DSKInt: DEVPAR1 DEVDSK ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- COM1 interrupt routine
COM1Int: DEVPAR2 DEVCOM,0 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- LPT1 interrupt routine
LPT1Int: DEVPAR2 DEVLPT,0 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- LPT2 interrupt routine
LPT2Int: DEVPAR2 DEVLPT,1 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- LPT3 interrupt routine
LPT3Int: DEVPAR2 DEVLPT,2 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- COM2 interrupt routine
COM2Int: DEVPAR2 DEVCOM,1 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- COM3 interrupt routine
COM3Int: DEVPAR2 DEVCOM,2 ; device parameters
jmp short DevInt ; jump to interrupt routine
; ------------- COM4 interrupt routine
COM4Int: DEVPAR2 DEVCOM,3 ; device parameters
; ------------- Push registers (AH=device index, AL=device type*2)
DevInt: push bx ; push BX
push cx ; push CX
push dx ; push DX
push si ; push SI
push di ; push DI
push bp ; push BP
push ds ; push DS
push es ; push ES
pushf ; push FLAGS
; ------------- Store device index (number of COM or LPT)
push cs ; push CS
pop ds ; DS <- CS
mov [DevInx],ah ; store device index
; ------------- Prepare device service table (-> SI)
cbw ; AH <- 0
xchg ax,si ; SI <- offset of table address
mov si,[si+FNCTab] ; SI <- address of service table
; ------------- Check command
lds bx,[Strat] ; DS:BX <- strategy address
mov al,[bx+DDR_cmd] ; AL <- command
cmp al,[cs:si] ; check command
jb DevInt2 ; command is OK
call DevIntInv2 ; invalid command
jmp short DevInt8 ; set output status
; ------------- Prepare parameters from device request
DevInt2: mov cx,[bx+DDR_count]; CX <- number of bytes/sectors
les di,[bx+DDR_trans]; ES:DI <- transfer address
mov dl,[bx+DDR_unit]; DL <- subunit number
mov dh,[bx+DDR_media]; DH <- media descriptor
push cs ; push CS
pop ds ; DS <- CS
; ------------- Jump to service routine
cbw ; AX = command
shl ax,1 ; AX = offset in service table
inc si ; skip max. number of function
add si,ax ; SI <- jump address
xchg ax,dx ; AL <- disk, AH <- count of units
call [si] ; call service routine
; On call:
; AL = subunit number (parameter DDR_unit)
; AH = media descriptor (parameter DDR_media)
; CX = number of bytes/sectors (parameter DDR_count]
; ES:DI = transfer address (data buffer) (parameter DDR_trans)
; DS = data segment
; ------------- Set status word AX
lds bx,[cs:Strat] ; DS:SI <- strategy address
DevInt8: or ah,ah ; is result OK?
js DevInt9 ; it is error
mov al,0 ; no error
DevInt9: mov [bx+DDR_error],ax ; store status word
; ------------- Pop registers
popf ; pop FLAGS
pop es ; pop ES
pop ds ; pop DS
pop bp ; pop BP
pop di ; pop DI
pop si ; pop SI
pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
retf
; ----------------------------------------------------------------------------
; NUL device interrupt routine
; ----------------------------------------------------------------------------
NULInt: pushf ; push flags
push bx ; push BX
push ds ; push DS
lds bx,[cs:Strat] ; DS:SI <- strategy address
mov word [bx+DDR_error],100h ; set status OK
pop ds ; pop DS
pop bx ; pop BX
popf ; pop flags
retf
; ----------------------------------------------------------------------------
; Device interrupt service - invalid command
; ----------------------------------------------------------------------------
DevIntInv: lds bx,[cs:Strat] ; DS:SI <- strategy address
DevIntInv2: mov word [bx+DDR_count],0; set number of bytes/sectors to 0
mov ax,(S_ERROR+S_DONE)*256+ERR_COMMAND ; invalid command
ret
; ----------------------------------------------------------------------------
; Device interrupt service - unknown unit
; ----------------------------------------------------------------------------
DevIntUnit: lds bx,[cs:Strat] ; DS:SI <- strategy address
mov word [bx+DDR_count],0; set number of bytes/sectors to 0
mov ax,(S_ERROR+S_DONE)*256+ERR_UNIT ; invalid unit
ret
; ----------------------------------------------------------------------------
; Device interrupt service - all ok
; ----------------------------------------------------------------------------
DevIntOK: mov ah,S_DONE ; status code OK
ret
; ----------------------------------------------------------------------------
; Device interrupt service - device not ready
; ----------------------------------------------------------------------------
DevIntBusy: mov ah,S_DONE+S_BUSY ; device not ready
ret
; ----------------------------------------------------------------------------
; Device interrupt service - read/write error
; ----------------------------------------------------------------------------
; INPUT: CX = number of remaining bytes/sectors
; AL = error code
; OUTPUT: AX = error status
; DESTROYS: DS,BX
; ----------------------------------------------------------------------------
DevIntError: mov ah,S_ERROR+S_DONE ; error occurs
DevIntError2: lds bx,[cs:Strat] ; DS:BX <- strategy address
sub [bx+DDR_count],cx; decrease processed characters
ret
LPTRData: mov ah,S_DONE ; status code OK
jmp short DevIntError2 ; clear data
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
Strat: dd 0 ; device strategy address
DevInx: dw 0 ; device index (index of COM or LPT)
|