Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

IO.ASM

Interface ovladačů zařízení

IO.ASM obsahuje záhlaví zařízení a interface pro přístup k zařízením. Instalovatelný ovladač zařízení systému DOS obsahuje standardní záhlaví popsané strukturami DevCharHeader (pro znaková zařízení) a DevDiskHeader (pro bloková zařízení). Jednotlivá zařízení jsou spolu provázána ukazatelem na další zařízení devch_next nebo devd_next (segment:offset) do řetězce zařízení. Systém má uschovaný ukazatel na první zařízení. Ukazatel v posledním zařízení je nastaven na hodnotu -1 (tj. 0FFFF:FFFFh), čímž je označen konec řetězců zařízení.

Druhou položkou záhlaví zařízení jsou atributy devch_attr resp. devd_attr. Nejvyšší bit slouží k rozlišení, zda se jedná o znakové nebo blokové zařízení.

Další 2 položky záhlaví obsahují offset (ne segment) funkce pro nastavení strategie zařízení, která do zařízení nastaví adresu paketu požadavku, a offset funkce pro zpracování paketu požadavku.

Poslední položkou záhlaví znakového zařízení je jméno zařízení. Zařízení lze tímto jménem otevřít jako běžný soubor a provádět operace čtení a zápisu jako u souboru. Blokové zařízení namísto jména obsahuje bajt udávající počet diskových jednotek, které toto blokové zařízení obsluhuje.


; ============================================================================
;
;                              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)

Záhlaví standardních zařízení, která jsou součástí systému, jsou nadepsána jako "Device parameter blocks". Jsou zde znaková zařízení CON (konzola), AUX (standardní sériový port), COM1COM4 (sériové porty 1 až 4), PRN (standardní tiskové zařízení), LPT1LPT3 (paralelní porty 1 až 3), CLOCK$ (hodiny) a zařízení pro ovládání standardních disků.

Při volání obsluhy strategie je volána pro všechna zařízení stejná funkce SetStrat, která pouze uloží adresu požadavku na zařízení do proměnné Strat.

Obsluhy přerušení využívají společnou funkci DevInt, na jejímž vstupu je funkci předáno číslo tabulky obsluhy funkcí zařízení (podle FNCTab) a číslo portu, obsluhuje-li zařízení více portů. Funkce zkontroluje podle tabulky platnost čísla povelu, připraví nejčastěji používané registry a předá obsluhu funkci zařízení. Po návratu z funkce uloží do paketu požadavku výstupní kód.

Zpět na stránku systému LT-DOS