; ============================================================================= ; ; Litos8 system devices ; ; ============================================================================= ; ----------------------------------------------------------------------------- ; Exported user functions (5): ; OpenDevice - open device ; DevCheck - device check ; DevSize - get device media size ; DevRead - device read ; DevWrite - device write ; ----------------------------------------------------------------------------- CODE_SECTION ; ----------------------------------------------------------------------------- ; Open device ; ----------------------------------------------------------------------------- ; INPUT: CL = length of device name ; SI = device name (without ":") ; DI = pointer to destination FILE structure ; OUTPUT: CY = error, invalid device ; ----------------------------------------------------------------------------- ; ------------- push registers OpenDevice: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- One character: system disk mov ch,0 ; CH <- 0 cmp cl,1 ; 1 character jne short OpenDevice1 ; not system disk mov al,[si] ; AL <- load character call UpperCase ; AL <- convert to upper case letter sub al,"A" ; AL <- system disk number cmp al,SDISK_MAX ; check disk number jae short OpenDevice1 ; invalid disk number shl al,1 shl al,1 shl al,1 shl al,1 ; AL <- shift disk index to bit 4 jmp short OpenDevice8 ; set device ; ------------- prepare to find device OpenDevice1: mov bx,DevNameTab ; BX <- device name table OpenDevice2: mov ax,[bx] ; AL <- text length, AH <- device type inc bx ; BX <- skip text length inc bx ; BX <- skip device type cmp al,cl ; check length of device name jne short OpenDevice7 ; not suitable device name ; ------------- push registers 2 push bx ; push BX push cx ; push CX push si ; push SI ; ------------- get one character OpenDevice3: lodsb ; AL <- name call UpperCase ; AL <- convert to upper case letter cmp byte [bx],"?" ; index? jne short OpenDevice4 ; no ; ------------- device index sub al,"1" ; AL <- index cmp al,3 ; check max. index ja short OpenDevice6 ; invalid index (here is NZ) shl al,1 shl al,1 shl al,1 shl al,1 ; AL <- shift device index to bit 4 or ah,al ; AH <- add index jmp short OpenDevice5 ; ------------- check one character OpenDevice4: cmp al,[bx] ; check character jne short OpenDevice6 ; ------------- next character OpenDevice5: inc bx ; increase pattern loop OpenDevice3 ; next character cmp al,al ; set ZY flag ; ------------- pop registers 2 OpenDevice6: pop si ; pop SI pop cx ; pop CX pop bx ; pop BX mov al,ah ; AL <- device type and index je short OpenDevice8 ; device found OK ; ------------- next device OpenDevice7: mov al,[bx-2] ; AL <- text length cbw ; AX <- text length add bx,ax ; BX <- skip device name cmp byte [bx],0 ; end of table? jne short OpenDevice2 ; no, check next device ; ------------- error, device not found stc ; set error flag jmp short OpenDevice9 ; ------------- clear FILE descriptor (AL = device type and index) OpenDevice8: call ClearFileDesc ; clear FILE descriptor ; ------------- set device name push di ; push DI (pointer to FILE structure) rep movsb ; copy device name pop di ; pop DI (pointer to FILE structure) ; ------------- set device parameters mov byte [di+FILE_Attr],DIR_Device ; set device attribute mov byte [di+FILE_DirInx],al ; set device type and index ; ------------- set device size xchg ax,bx ; BL <- device type and index call DevSize ; get device size mov [di+FILE_Size],ax ; device size LOW mov [di+FILE_Size+2],dx ; device size HIGH ; ------------- check device call DevCheck ; check device ; ------------- pop registers OpenDevice9: pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; NUL device check ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; OUTPUT: CY = invalid device ; ----------------------------------------------------------------------------- NULCheck: clc ; clear error flag ret ; ----------------------------------------------------------------------------- ; Read from NUL device ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; CX = number of bytes ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- NULRead: push ax ; push AX push di ; push DI xor ax,ax ; AX <- 0 shr cx,1 ; CX <- number of words rep stosw ; clear buffer in words adc cx,cx ; CX <- last byte rep stosb ; clear last byte pop di ; pop DI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Write to NUL device ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; CX = number of bytes ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- NULWrite: xor cx,cx ; CX <- 0, no data left, clear CF ret ; ----------------------------------------------------------------------------- ; Device check (invalid device) ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; OUTPUT: CY = invalid device ; ----------------------------------------------------------------------------- ; ----------------------------------------------------------------------------- ; Device read (invalid device) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset (only block device) ; BX = device index (0..15) ; CX = number of bytes/sectors ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes/sectors (or CX = 0 if no error NC) ; NOTES: Block device uses 512-byte sectors, char device uses bytes. ; ----------------------------------------------------------------------------- ; ----------------------------------------------------------------------------- ; Device write (invalid device) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset (only block device) ; BX = device index (0..15) ; CX = number of bytes/sectors ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes/sectors (or CX = 0 if no error NC) ; NOTES: Block device uses 512-byte sectors, char device uses bytes. ; ----------------------------------------------------------------------------- ; ----------------------------------------------------------------------------- ; Device size (invalid device) ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid device (DX:AX = 0) ; ----------------------------------------------------------------------------- DevSizeNone: xor ax,ax ; AX <- 0 xor dx,dx ; DX <- 0 DevCheckNone: DevReadNone: DevWriteNone: stc ; set error flag ret ; ----------------------------------------------------------------------------- ; Get device interface ; ----------------------------------------------------------------------------- ; INPUT: BL = bit 0..3: device type (bit 3: 0=block/1=char device) ; bit 4..7: device index (0..15) ; OUTPUT: BX = device index (0..15) ; SI = pointer to device interface DEVINT ; ----------------------------------------------------------------------------- GetDevInt: xchg ax,si ; SI <- push AX mov al,bl ; AL <- device type and index and al,FILEDEV_MASKTYPE ; AL <- device type mov ah,DEVINT_size ; AH <- size of DEVINT descriptor mul ah ; AX <- offset of descriptor add ax,DevIntTab ; AX <- descriptor xchg ax,si ; SI <- descriptor, AX <- pop AX mov bh,0 shr bl,1 shr bl,1 shr bl,1 shr bl,1 ; BL <- device index ret ; ----------------------------------------------------------------------------- ; Device check ; ----------------------------------------------------------------------------- ; INPUT: BL = bit 0..3: device type (bit 3: 0=block/1=char device) ; bit 4..7: device index (0..15) ; OUTPUT: CY = invalid device ; ----------------------------------------------------------------------------- DevCheck: push bx ; push BX push si ; push SI call GetDevInt ; get device interface -> SI call [si+DEVINT_Check] ; device check pop si ; pop SI pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Get device media size ; ----------------------------------------------------------------------------- ; INPUT: BL = bit 0..3: device type (bit 3: 0=block/1=char device) ; bit 4..7: device index (0..15) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid device (or character device, DX:AX = 0 on error) ; ----------------------------------------------------------------------------- DevSize: push bx ; push BX push si ; push SI call GetDevInt ; get device interface -> SI call [si+DEVINT_Size] ; get device size pop si ; pop SI pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Device read ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current byte offset (only block device) ; BL = bit 0..3: device type (bit 3: 0=block/1=char device) ; bit 4..7: device index (0..15) ; CX = number of bytes ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; NOTES: Block device is limited to 4 GB. ; ----------------------------------------------------------------------------- ; ------------- push registers DevRead: push ax ; push AX push bx ; push BX push dx ; push DX push si ; push SI push di ; push DI push bp ; push BP ; ------------- no data required clc ; clear error flag jcxz DevRead1 ; no data required ; ------------- character device test bl,B3 ; character device? jz short DevRead2 ; no, it is block device call GetDevInt ; get device interface -> SI call [si+DEVINT_Read] ; device read DevRead1: jmp DevRead9 ; ------------- get device interface -> SI DevRead2: call GetDevInt ; get device interface -> SI ; ------------- change byte offset to sector offset -> DX:AX mov bp,ax ; BP <- save start offset LOW mov al,ah mov ah,dl mov dl,dh mov dh,0 ; DX:AX <- offset / 256 shr dx,1 rcr ax,1 ; DX:AX <- sector offset ; ------------- unaligned data in first sector? test bp,SECTSIZE-1 ; check data in first sector jz short DevRead6 ; start is aligned OK ; ------------- read first sector push cx ; push CX push di ; push DI xor cx,cx ; CX <- 0 mov [OldSectBDD],cx ; invalid sector buffer inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Read] ; read first sector pop di ; pop DI pop cx ; pop CX jc short DevRead9 ; error ; ------------- increase sector inc ax ; AX <- sector LOW + 1 jnz short DevRead3 ; no carry inc dx ; carry ; ------------- copy data from first sector DevRead3: push si ; push SI mov si,bp ; SI <- byte offset LOW and si,SECTSIZE-1 ; SI <- byte offset in sector add si,SectBuf ; SI <- start address xchg bp,cx ; BP <- total size, CX <- offset LOW neg cx and ch,(SECTSIZE-1)/256 ; CX <- remaining data cmp cx,bp ; check remaining data jb short DevRead4 ; data size is OK mov cx,bp ; CX <- limit remaining data DevRead4: sub bp,cx ; BP <- shift total size shr cx,1 ; CX <- size in words rep movsw ; copy data in words adc cx,cx ; CX <- odd byte rep movsb ; copy odd byte mov cx,bp ; CX <- new total size pop si ; pop SI jcxz DevRead9 ; no data left (here is NC) ; ------------- read full sectors DevRead6: mov bp,cx ; BP <- total size and cx,~(SECTSIZE-1) ; CX <- mask full sectors jz short DevRead8 ; no full sectors push cx ; push CX xchg cl,ch ; CX <- size / 256 shr cx,1 ; CX <- number of sectors push cx ; push CX call [si+DEVINT_Read] ; read sectors pop cx ; pop CX jc short DevRead7 ; error add ax,cx ; AX <- shift sector LOW adc dx,byte 0 ; DX <- carry DevRead7: pop cx ; pop CX jc short DevRead9 ; error add di,cx ; DI <- shift destination address sub bp,cx ; BP <- shift total size DevRead8: mov cx,bp ; CX <- new total size jcxz DevRead9 ; no data left (here is NC) ; ------------- read last sector push cx ; push CX push di ; push DI xor cx,cx ; CX <- 0 mov [OldSectBDD],cx ; invalid sector buffer inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Read] ; read first sector pop di ; pop DI pop cx ; pop CX jc short DevRead9 ; error ; ------------- copy data from last sector mov si,SectBuf ; SI <- start address shr cx,1 ; CX <- size in words rep movsw ; copy data in words adc cx,cx ; CX <- odd byte rep movsb ; copy odd byte ; ------------- pop registers DevRead9: pop bp ; pop BP pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Device write ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current byte offset (only block device) ; BL = bit 0..3: device type (bit 3: 0=block/1=char device) ; bit 4..7: device index (0..15) ; CX = number of bytes ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; NOTES: Block device is limited to 4 GB. ; ----------------------------------------------------------------------------- ; ------------- push registers DevWrite: push ax ; push AX push bx ; push BX push dx ; push DX push si ; push SI push di ; push DI push bp ; push BP ; ------------- no data required clc ; clear error flag jcxz DevWrite1 ; no data required ; ------------- character device test bl,B3 ; character device? jz short DevWrite2 ; no, it is block device call GetDevInt ; get device interface -> SI call [si+DEVINT_Write] ; device write DevWrite1: jmp DevWrite9 ; ------------- get device interface -> SI DevWrite2: call GetDevInt ; get device interface -> SI ; ------------- change byte offset to sector offset -> DX:AX mov bp,ax ; BP <- save start offset LOW mov al,ah mov ah,dl mov dl,dh mov dh,0 ; DX:AX <- offset / 256 shr dx,1 rcr ax,1 ; DX:AX <- sector offset ; ------------- unaligned data in first sector? test bp,SECTSIZE-1 ; check data in first sector jz short DevWrite6 ; start is aligned OK ; ------------- read first sector push cx ; push CX push di ; push DI xor cx,cx ; CX <- 0 mov [OldSectBDD],cx ; invalid sector buffer inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Read] ; read first sector pop di ; pop DI pop cx ; pop CX jc short DevRead9 ; error ; ------------- copy data to first sector push si ; push SI mov si,di ; SI <- source buffer mov di,bp ; DI <- byte offset LOW and di,SECTSIZE-1 ; DI <- byte offset in sector add di,SectBuf ; DI <- start address xchg bp,cx ; BP <- total size, CX <- offset LOW neg cx and ch,(SECTSIZE-1)/256 ; CX <- remaining data cmp cx,bp ; check remaining data jb short DevWrite4 ; data size is OK mov cx,bp ; CX <- limit remaining data DevWrite4: sub bp,cx ; BP <- shift total size shr cx,1 ; CX <- size in words rep movsw ; copy data in words adc cx,cx ; CX <- odd byte rep movsb ; copy odd byte mov di,si ; DI <- new source buffer pop si ; pop SI ; ------------- write first sector push di ; push DI inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Write] ; write first sector mov cx,bp ; CX <- new total size pop di ; pop DI jc short DevWrite9 ; error jcxz DevWrite9 ; no data left ; ------------- increase sector inc ax ; AX <- sector LOW + 1 jnz short DevWrite6 ; no carry inc dx ; carry ; ------------- write full sectors DevWrite6: mov bp,cx ; BP <- total size and cx,~(SECTSIZE-1) ; CX <- mask full sectors jz short DevWrite8 ; no full sectors push cx ; push CX xchg cl,ch ; CX <- size / 256 shr cx,1 ; CX <- number of sectors push cx ; push CX call [si+DEVINT_Write] ; write sectors pop cx ; pop CX jc short DevWrite7 ; error add ax,cx ; AX <- shift sector LOW adc dx,byte 0 ; DX <- carry DevWrite7: pop cx ; pop CX jc short DevWrite9 ; error add di,cx ; DI <- shift destination address sub bp,cx ; BP <- shift total size DevWrite8: mov cx,bp ; CX <- new total size jcxz DevWrite9 ; no data left (here is NC) ; ------------- read last sector push cx ; push CX push di ; push DI xor cx,cx ; CX <- 0 mov [OldSectBDD],cx ; invalid sector buffer inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Read] ; read first sector pop di ; pop DI pop cx ; pop CX jc short DevWrite9 ; error ; ------------- copy data to last sector push cx ; push CX push si ; push SI mov si,di ; SI <- source buffer mov di,SectBuf ; DI <- start address shr cx,1 ; CX <- size in words rep movsw ; copy data in words adc cx,cx ; CX <- odd byte rep movsb ; copy odd byte pop si ; pop SI ; ------------- write last sector inc cx ; CX <- 1 sector mov di,SectBuf ; DI <- sector buffer call [si+DEVINT_Write] ; write last sector pop cx ; pop CX jc short DevWrite9 ; error xor cx,cx ; CX <- 0, no data left ; ------------- pop registers DevWrite9: pop bp ; pop BP pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Constant data ; ----------------------------------------------------------------------------- CONST_SECTION ; ------------- device names (length, type, text; ?=index 1..4) DevNameTab: db 3,FILEDEV_FD,"FD?" db 3,FILEDEV_HD,"HD?" db 3,FILEDEV_RAM,"RAM" db 3,FILEDEV_RD,"RD?" db 3,FILEDEV_NUL,"NUL" db 3,FILEDEV_CON,"CON" db 4,FILEDEV_COM,"COM?" db 3,FILEDEV_COM,"AUX" db 4,FILEDEV_LPT,"LPT?" db 3,FILEDEV_LPT,"PRN" db 0 ; ------------- device interfaces align 2, db 0 DevIntTab: dw SDDCheck,SDDSize,SDDRead,SDDWrite ; 0: A: ... dw FDDCheck,FDDSize,FDDRead,FDDWrite ; 1: FD? dw HDDCheck,HDDSize,HDDRead,HDDWrite ; 2: HD? dw RAMCheck,RAMSize,RAMRead,RAMWrite ; 3: RAM dw RDDCheck,RDDSize,RDDRead,RDDWrite ; 4: RD? dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 5: dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 6: dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 7: dw NULCheck,DevSizeNone,NULRead,NULWrite ; 8: NUL dw CONCheck,DevSizeNone,CONRead,CONWrite ; 9: CON dw COMCheck,DevSizeNone,COMRead,COMWrite ; 10: COM?, AUX dw LPTCheck,DevSizeNone,DevReadNone,LPTWrite ; 11:LPT?,PRN dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 12: dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 13: dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 14: dw DevCheckNone,DevSizeNone,DevReadNone,DevWriteNone ; 15: ; ----------------------------------------------------------------------------- ; Uninitialised data ; ----------------------------------------------------------------------------- DATA_SECTION