DISK.ASM
资源名称:drdossrc.zip [点击查看]
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:72k
源码类别:
操作系统开发
开发平台:
Asm
- ; File : $DISK.ASM$
- ;
- ; Description :
- ;
- ; Original Author :
- ;
- ; Last Edited By : $Author: RGROSS$
- ;
- ;-----------------------------------------------------------------------;
- ; Copyright Unpublished Work of Novell, Inc. All Rights Reserved.
- ;
- ; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
- ; PROPRIETARY AND TRADE SECRET INFORMATION OF NOVELL, INC.
- ; ACCESS TO THIS WORK IS RESTRICTED TO (I) NOVELL, INC. EMPLOYEES
- ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
- ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN NOVELL, INC. WHO
- ; HAVE ENTERED INTO APPROPRIATE LICENSE AGREEMENTS. NO PART OF THIS
- ; WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED,
- ; REVISED, MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED,
- ; COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED OR ADAPTED
- ; WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR
- ; EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- ; THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
- ;-----------------------------------------------------------------------;
- ;
- ; *** Current Edit History ***
- ; *** End of Current Edit History ***
- ;
- ; $Log: $
- ; DISK.ASM 1.1 93/11/18 17:20:12 RGROSS
- ;
- ; DISK.ASM 1.41 93/11/18 17:20:25 IJACK
- ;
- ; DISK.ASM 1.40 93/11/10 00:28:12 IJACK
- ; Format changes so you can format your hard disk
- ; DISK.ASM 1.39 93/11/08 21:47:25 IJACK
- ; Add hidden sectors to ioctl format etc of hard disks
- ; DISK.ASM 1.38 93/11/02 16:09:29 IJACK
- ; Always zero BPB_HIDDEN_SECTORS on floppies - problem with PCW free disk which
- ; has garbage in those fields.
- ; DISK.ASM 1.37 93/10/18 17:33:18 IJACK
- ; format c: fix
- ; DISK.ASM 1.36 93/10/11 18:37:24 IJACK
- ; media-change checks serial-numbers for 3.5" disks
- ; DISK.ASM 1.35 93/10/06 22:09:16 IJACK
- ; vec_save extrn replaced by orgInt13 extrn
- ; DISK.ASM 1.34 93/09/03 20:13:32 IJACK
- ; Fix bug in disk formatting
- ; DISK.ASM 1.33 93/09/01 17:40:31 IJACK
- ; update UDSC_TIMER after media check forced by drive change
- ; (DBASE IV slow installation problem)
- ; DISK.ASM 1.32 93/08/12 15:33:07 IJACK
- ; Handle DMA error from multi-track read (ancient PC-XT hard disk)
- ; DISK.ASM 1.31 93/08/03 15:29:01 IJACK
- ; use serial numbers for media change detection
- ; DISK.ASM 1.30 93/08/02 18:44:50 IJACK
- ; don't trust the changeline if switching drives
- ; DISK.ASM 1.29 93/08/02 18:38:19 IJACK
- ;
- ; DISK.ASM 1.28 93/08/02 14:47:38 IJACK
- ;
- ; DISK.ASM 1.27 93/07/29 21:00:24 IJACK
- ; get rid of genpb_ptr and genpb_minor
- ; DISK.ASM 1.26 93/07/26 21:18:25 IJACK
- ; Correctly return UDSC_ root from Int 2F/0803
- ; DISK.ASM 1.25 93/07/26 18:07:21 IJACK
- ; Switch ms-windows to full screen when prompting for disk
- ; DISK.ASM 1.24 93/07/23 17:34:27 IJACK
- ; fix floppy/driver.sys support
- ; DISK.ASM 1.23 93/07/22 20:37:42 IJACK
- ;
- ; DISK.ASM 1.22 93/07/22 19:43:46 IJACK
- ; switch over to REQUEST.EQU
- ; change floppy drive order, add get/set serial number
- ; DISK.ASM 1.21 93/07/19 18:57:21 IJACK
- ; Add header
- ;
- ; ENDLOG
- include BIOSGRPS.EQU
- include DRMACROS.EQU ; standard DR macros
- include IBMROS.EQU ; ROM BIOS equates
- include REQUEST.EQU ; request header equates
- include BPB.EQU ; BIOS parameter block equates
- include UDSC.EQU ; unit descriptor equates
- include DRIVER.EQU ; device driver equates
- int_____DISK_INT macro
- call Int13
- endm
- FASTSETTLE equ FALSE ; disable "head settle == 0 ms"
- RETRY_MAX equ 3 ; do 3 retries if we get an error
- MAX_SPT equ 40 ; maximum sectors per track
- SECSIZE equ 512
- IDOFF equ SECSIZE-2 ; last word in boot sector is ID
- PTOFF equ IDOFF-40h ; 4*16 bytes for partition def's
- DOS20_ID equ 1 ; DOS 2.0 partition, < 4086 clusters
- DOS30_ID equ 4 ; DOS 3.0 partition, < 65536 sectors
- DOSEX_ID equ 5 ; DOS 3.3 extended partition
- DOS331_ID equ 6 ; COMPAQ DOS 3.31 partition > 32 Mb
- ; Now for the secure partition types
- SEC_ID equ 0C0h ; New DR secure partition types
- SEC_ID2 equ 0D0h ; Old DR secure partition types
- page
- CGROUP group CODE, RCODE, ICODE, RESBIOS, IDATA
- CG equ offset CGROUP
- Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
- IVECT segment at 0000h
- org 0013h*4
- i13off dw ?
- i13seg dw ?
- org 001Eh*4
- i1eptr dd ?
- org 002Fh*4
- i2Foff dw ?
- i2Fseg dw ?
- org 0472h
- reset_flag dw ?
- org 0504h
- dual_byte db ? ; multiple drive byte at 50:4
- IVECT ends
- ROS segment at 0F000h
- org 0FFF0h
- reset proc far
- reset endp
- ROS ends
- CODE segment 'CODE'
- extrn endbios:word ; for device driver INIT function
- extrn read_system_ticks:near ; get system tick count in CX/DX
- extrn Int13Trap:near
- extrn Int2FTrap:near
- extrn orgInt13:dword
- extrn i13pointer:dword
- extrn i13off_save:word
- extrn i13seg_save:word
- extrn NumDiskUnits:byte
- extrn DeblockSeg:word
- extrn local_parms:byte
- extrn parms_spt:byte
- extrn parms_gpl:byte
- extrn local_buffer:byte
- extrn local_pt:word
- extrn local_id:word
- extrn layout_table:word
- extrn bpbs:word
- extrn bpb160:byte
- extrn bpb360:byte
- extrn bpb720:byte
- extrn NBPBS:abs
- extrn bpbtbl:word
- extrn req_off:word
- extrn req_seg:word
- udsc_root label dword
- dw -1,-1
- orig_int1e_off dw 522h
- orig_int1e_seg dw 0
- new_int1e_off dw 522h
- new_int1e_seg dw 0
- Public i13_AX
- i13_AX label word
- i13_size db ? ; number of sectors to xfer
- i13_op db ? ; Int13 Operation
- i13_dma_ptr label dword
- i13_dma_off dw ?
- i13_dma_seg dw ?
- activeRosUnit db ? ; currently active ROS unit
- include biosmsgs.def ; Include TFT Header File
- ifdef JAPAN
- extrn disk_msgA_jpn :byte
- extrn disk_msgB_jpn :byte
- endif
- ;disk_msgA db 13,10,'Insert disk for drive '
- ;disk_msgB db ': any press any key when ready ', 0
- page
- Assume DS:nothing, SS:nothing, ES:nothing
- CODE ends
- RCODE segment 'RCODE'
- extrn DataSegment:word
- even
- Int13 proc near
- clc
- push bp
- int DISK_INT
- pop bp
- ret
- Int13 endp
- ros_errors db 03h, 80h, 08h, 10h, 40h, 04h, 06h, 00h
- dos_errors db 00h, 02h, 04h, 04h, 06h, 08h, 0Fh, 0Ch
- NUMROSERR equ dos_errors - ros_errors
- ; The following code is required in order to cope with
- ; application programs invoking Int 13h directly. It
- ; handles applications that format floppies or access the
- ; disk via Int 13h after a floppy disk change.
- Assume CS:CGROUP, DS:Nothing, ES:Nothing, SS:Nothing
- Public Int13Unsure
- ;----------
- Int13Unsure proc far
- ;----------
- sti
- cld
- push ds
- mov ds,cs:DataSegment
- Assume DS:CGROUP
- call i13_unsure ; no longer sure of this drive
- pop ds
- ret
- Int13Unsure endp
- Public Int13Deblock
- ;-----------
- Int13Deblock proc far
- ;-----------
- ; handle user programs formatting the disk
- sti
- cld
- push ds
- mov ds,cs:DataSegment
- Assume DS:CGROUP
- pushx <es, bx, cx, si, di> ; save work registers
- mov i13_dma_off,bx
- mov i13_dma_seg,es
- i13_deblock10:
- pushx <cx, dx>
- mov cl,4
- mov ax,i13_dma_seg ; get transfer address
- shl ax,cl ; get A4..A15 from segment
- add ax,i13_dma_off ; combine with A0..A15 from offset
- not ax ; AX = # of bytes left in 64K bank
- xor dx,dx
- mov cx,SECSIZE
- div cx ; convert this to physical sectors
- mov dl,i13_size ; see if we can xfer amount wanted
- cmp al,dl ; capable of more than requested?
- jb i13_deblock20 ; skip if we can do it all
- xchg ax,dx ; we can do them all
- i13_deblock20:
- les bx,i13_dma_ptr ; do the xfer to here
- popx <dx, cx>
- mov ah,i13_op ; get read/write/verify operation
- test al,al ; if zero length possible
- jz i13_deblock30 ; then deblock
- mov di,es ; get transfer address
- cmp di,DeblockSeg ; is this in high memory ?
- jb i13_deblock50 ; then force through deblock buffer
- i13_deblock30:
- push ds ; if deblocking then we'd better
- pop es ; point at local buffer we
- mov bx,CG:local_buffer ; will be using for actual I/O
- cmp i13_op,ROS_WRITE
- jne i13_deblock40 ; skip data copy if not writing to disk
- push ds
- push cx
- mov di,bx ; ES:DI -> local buffer
- lds si,i13_dma_ptr ; DS:SI -> data to write
- mov cx,SECSIZE/2
- rep movsw ; copy to deblocking buffer
- pop cx
- pop ds
- i13_deblock40:
- mov al,1 ; do a single sector via buffer
- clc
- pushf ; fake an Int
- call i13pointer ; to the track handler
- jc i13_deblock90 ; stop on error
- mov al,1 ; restore AL for buggy bios's
- cmp i13_op,ROS_READ ; if we are reading then we'll
- jne i13_deblock60 ; have to copy data out of
- push cx ; the deblocking buffer
- les di,i13_dma_ptr ; ES:DI -> dest for data
- mov si,CG:local_buffer ; point at local buffer which
- mov cx,SECSIZE/2 ; contains actual data
- rep movsw ; copy from deblocking buffer
- pop cx
- jmps i13_deblock60
- i13_deblock50:
- push ax ; save # sectors in xfer
- clc
- pushf ; fake an Int
- call i13pointer ; do the operation
- pop bx
- mov al,bl ; restore AL for buggy bios's
- jc i13_deblock90 ; stop on error
- i13_deblock60: ; we succeeded in doing AL sectors
- sub i13_size,al ; forget about those we have done
- jbe i13_deblock90 ; and do more if there are any
- push ax
- mov ah,SECSIZE/16
- mul ah ; AX = paras to inc DMA address
- add i13_dma_seg,ax ; up DMA address by this amount
- pop ax
- call i13_point_unit ; ES:DI -> UDSC_
- jc i13_deblock90 ; exit if we can't find it
- mov bx,cx ; get sector/cylinder in BX
- and bx,0003Fh ; BX = sector
- and cx,0FFC0h ; CX = mandled cylinder bits
- add bl,al ; work out new sector
- i13_deblock70:
- mov ax,es:UDSC_BPB+BPB_SPT[di]
- cmp bx,ax ; still on the same track ?
- jbe i13_deblock80 ; easy if no overflow onto next track
- sub bx,ax ; subtract a tracks worth
- inc dh ; and move onto next head
- mov al,dh ; isolate head from cylinder
- and ax,003Fh ; bits 10/11
- cmp ax,es:UDSC_BPB+BPB_HEADS[di]
- jb i13_deblock70 ; onto next track yet ?
- and dh,0C0h ; back to head zero
- add ch,1 ; onto next track (bits 0-7)
- jnc i13_deblock70 ; overflow to bits 8-9 ?
- add cl,040h ; yes, "inc" bits 8/9 of cylinder
- jnc i13_deblock70 ; overflow to bits 10-11 ?
- add dh,040h ; yes, "inc" bits 10/11 of cylinder
- jmps i13_deblock70
- i13_deblock80:
- or cx,bx ; recombine sector/cylinder
- jmp i13_deblock10 ; and do some more
- i13_deblock90:
- popx <di, si, cx, bx, es> ; restore work registers
- pop ds ; recover user DS
- ret 2 ; return to user with result
- i13_point_unit proc near
- ;-------------
- ; On Entry:
- ; DL = ROS unit
- ; On Exit:
- ; ES:DI -> UDSC_ for that unit
- ; All other regs preserved
- ;
- les di,udsc_root ; ES:DI -> 1st es:UDSC_
- i13_point_unit10:
- cmp dl,es:UDSC_RUNIT[di] ; find the physical unit
- je i13_point_unit20
- les di,es:UDSC_NEXT[di]
- cmp di,0FFFFh ; else try the next es:UDSC_
- jne i13_point_unit10
- mov ah,09h ; return DMA error to caller as we
- stc ; don't know about this unit
- i13_point_unit20:
- ret
- i13_point_unit endp
- Int13Deblock endp
- i13_unsure proc near
- ;---------
- ; mark physical drive DL as unsure
- ;
- pushx <ds, si>
- lds si,udsc_root
- i13_unsure10:
- cmp dl,ds:UDSC_RUNIT[si] ; does it match ROS drive?
- jne i13_unsure20 ; skip if not
- or ds:UDSC_FLAGS[si],UDF_UNSURE
- i13_unsure20: ; next drive
- lds si,ds:UDSC_NEXT[si]
- cmp si,0FFFFh
- jne i13_unsure10
- popx <si, ds> ; restore registers
- ret
- i13_unsure endp
- Assume DS:Nothing, SS:Nothing, ES:Nothing
- Public Int2FHandler
- Int2FHandler proc far
- ;-----------
- ; On Entry we have offset/seg of next in chain on the stack
- ; (ie. we can pass on by a RETF)
- ;
- cmp ah,8 ; DRIVER.SYS support
- je i2F_driver
- cmp ah,13h ; int13 intercept
- jne i2F_iret
- ;
- ; Int 13 interception support
- ; ---------------------------
- ;
- ; On Entry:
- ; DS:DX -> New Int 13 vector
- ; ES:BX -> Int 13 vector restored by Int 19
- ;
- ; On Exit:
- ; DS:DX -> Old Int 13 vector
- ; ES:BX -> Old Int 13 vector restored by Int 19
- ;
- i2F_i13_intercept:
- mov ax,ds
- mov ds,cs:DataSegment
- Assume DS:CGROUP
- xchg dx,ds:i13off_save
- xchg ax,ds:i13seg_save
- push ax
- xchg bx,ds:word ptr orgInt13
- mov ax,es
- xchg ax,ds:word ptr orgInt13+2
- mov es,ax
- pop ds
- Assume DS:Nothing
- i2F_iret:
- iret
- ;
- ; DRIVER.SYS support
- ; -------------------
- ;
- ; On Entry:
- ; AX=0800, installation check
- ; AX=0801, add new block device at DS:SI
- ; AX=0802, execute driver request at ES:BX
- ; AX=0803, return address of first es:UDSC_
- ;
- i2F_driver:
- cmp al,1
- jb i2F_driver_check
- je i2F_driver_add
- cmp al,3
- jb i2F_driver_req
- je i2F_driver_point
- iret
- i2F_driver_check:
- ;
- ; Installation check
- ;
- mov al,0ffh ; say we are installed
- iret
- i2F_driver_add:
- ;
- ; Add new block device DS:DI
- ;
- push ds
- push es
- push ds
- pop es ; ES:DI -> unit
- mov ds,cs:DataSegment
- call add_unit
- pop es
- pop ds
- iret
- i2F_driver_point:
- ;
- ; return DS:DI -> first UDSC_
- ;
- mov ds,cs:DataSegment ; DS -> our data
- lds di,ds:udsc_root
- iret
- ;
- ; Execute DRIVER.SYS request ES:BX
- ;
- i2F_driver_req:
- push ds
- mov ds,cs:DataSegment
- Assume DS:CGROUP
- mov ds:req_off,bx ; fill in request pointer
- mov ds:req_seg,es ; as if it was local
- pop ds
- Assume DS:Nothing
- push cs:driverTable ; fiddle the table address
- jmp DriverFunction ; then go to normal handler
- extrn DriverFunction:near
- extrn IntDiskTable:word ; = DiskTable
- driverTable dw CG:IntDiskTable ; push address of table on
- ; stack as DriverFunction
- ; examines it
- Int2FHandler endp
- Assume DS:CGROUP, SS:Nothing, ES:Nothing
- Public DiskTable
- DiskTable label word
- db 24 ; Last supported function
- dw CG:dd_init ; 0-initialize driver
- dw CG:dd_medchk ; 1-media change check
- dw CG:dd_build_bpb ; 2-build BIOS Parameter Block
- dw CG:dd_error ; 3-IOCTL string input
- dw CG:dd_input ; 4-input
- dw CG:dd_error ; 5-nondestructive input (char only)
- dw CG:dd_error ; 6-input status (char only)
- dw CG:dd_error ; 7-input flush
- dw CG:dd_output ; 8-output
- dw CG:dd_output_vfy ; 9-output with verify
- dw CG:dd_error ; 10-output status (char only)
- dw CG:dd_error ; 11-output flush (char only)
- dw CG:dd_error ; 12-IOCTL string output
- dw CG:dd_open ; 13-device open
- dw CG:dd_close ; 14-device close
- dw CG:dd_remchk ; 15-removable media check
- dw CG:dd_error ; 16-n/a
- dw CG:dd_error ; 17-n/a
- dw CG:dd_error ; 18-n/a
- dw CG:dd_genioctl ; 19-generic IOCTL
- dw CG:dd_error ; 20-n/a
- dw CG:dd_error ; 21-n/a
- dw CG:dd_error ; 22-n/a
- dw CG:dd_getdev ; 23-get logical drive
- dw CG:dd_setdev ; 24-set logical drive
- driver proc near
- point_unit: ; get unit descriptor for work drive
- ;----------
- ; On Entry:
- ; ES:BX -> Request Header
- ; On Exit:
- ; AL = logical drive
- ; ES:DI -> es:UDSC_
- ; (All other registers preserved)
- ;
- mov al,es:RH_UNIT[bx] ; get the unit number (0=A:, 1=B:, etc)
- les di,udsc_root ; ES:DI -> 1st es:UDSC_
- point_unit10:
- cmp al,es:UDSC_DRIVE[di] ; stop if the logical drive matches
- je point_unit20
- les di,es:UDSC_NEXT[di]
- cmp di,0FFFFh ; else try the next es:UDSC_
- jne point_unit10
- pop ax ; don't return to the caller
- mov ax,RHS_ERROR+1 ; return "invalid unit" error
- point_unit20:
- ret
- add_unit: ; add a new unit to the list
- ;--------
- ; On Entry:
- ; ES:DI -> UDSC to add
- ; On Exit:
- ; ES:DI preserved
- ;
- mov al,es:UDSC_DRIVE[di] ; get the logical unit
- cmp al,MAXPART ; is it too many ?
- jae add_unit40
- push ds
- mov es:word ptr UDSC_NEXT[di],0FFFFh
- ; make sure it's terminated
- and es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
- lea si,udsc_root ; DS:SI -> [first UDSC_]
- add_unit10:
- cmp ds:word ptr UDSC_NEXT[si],0FFFFh
- je add_unit30
- lds si,ds:UDSC_NEXT[si] ; DS:SI -> UDSC_ we already have
- mov al,es:UDSC_RUNIT[di]
- cmp al,ds:UDSC_RUNIT[si] ; do the logical units match ?
- jne add_unit10
- mov ax,ds:UDSC_FLAGS[si] ; inherit some flags
- push ax
- and ax,UDF_HARD+UDF_CHGLINE
- mov es:UDSC_FLAGS[di],ax ; hard disk/changeline inherited
- pop ax
- test ax,UDF_HARD
- jnz add_unit10 ; skip owner stuff on hard drive
- test ax,UDF_VFLOPPY ; is this a multiple drive anyway ?
- jnz add_unit20
- or ax,UDF_OWNER+UDF_VFLOPPY
- mov ds:UDSC_FLAGS[si],ax ; no, 1st person becomes owner
- add_unit20:
- or es:UDSC_FLAGS[di],UDF_VFLOPPY
- jmps add_unit10 ; go and try the next
- add_unit30:
- mov ds:word ptr UDSC_NEXT[si],di
- mov ds:word ptr UDSC_NEXT+2[si],es
- pop ds
- add_unit40:
- ret
- dd_error: ; 3-IOCTL string input
- ;--------
- mov ax,RHS_ERROR+3 ; "invalid command" error
- ret
- dd_medchk: ; 1-media change check
- ;---------
- ; entry: ES:BX -> request header
- ; exit: RH1_RETURN = 0, 1 or FF
- ; 00 = media may have changed
- ; 01 = media hasn't changed
- ; FF = media has been changed
- call point_unit ; get unit descriptor
- test es:UDSC_FLAGS[di],UDF_HARD
- jnz medchk2 ; "hasn't changed" if hard disk
- call ask_for_disk ; make sure we've got correct floppy
- mov ax,es:UDSC_FLAGS[di] ; get flags
- test ax,UDF_UNSURE ; has format/diskcopy occurred?
- jnz medchk6 ; may have changed to different format
- test ax,UDF_CHGLINE
- jz medchk3 ; skip ROS call if no change line
- mov dl,es:UDSC_RUNIT[di]
- mov al,dl ; don't trust changeline if we are
- xchg al,activeRosUnit ; changing floppies
- cmp al,dl ; return may have changed
- jne medchk3
- mov ah,ROS_DSKCHG ; get disk change status function
- int_____DISK_INT ; AH=0: DC low, AH=6: DC active
- jc medchk5 ; disk change not active?
- medchk2:
- mov al,01h ; disk hasn't changed
- jmps medchk_ret
- medchk3: ; no changeline support, use timer
- call read_system_ticks ; get system tick count in CX/DX
- mov ax,dx
- xchg ax,es:UDSC_TIMER[di] ; get previous time and update
- sub dx,ax
- mov ax,cx
- xchg ax,es:UDSC_TIMER+2[di]
- sbb cx,ax ; CX/DX = # ticks since last access
- jne medchk5 ; media could have changed if > 64k
- cmp dx,18*3 ; more than three seconds expired?
- jb medchk2 ; "not changed" if access too recent
- medchk5:
- mov cx,1 ; read track 0, sector 1 (boot sector)
- call login_read ; to check the builtin BPB
- jc medchk6 ; may have changed if read error
- mov al,local_buffer+11+BPB_FATID
- cmp al,0F0h ; check if we find a BPB
- jb medchk6 ; may have changed if not good BPB
- cmp al,es:UDSC_BPB+BPB_FATID[di]
- jne medchk8 ; has media byte changed ?
- mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
- lodsb ; get extended boot
- sub al,29h ; do we have an extended boot ?
- je medchk7 ; no, test against our dummy value
- push cs
- pop ds ; DS:SI -> our dummy value
- mov si,offset CGROUP:dummyMediaID
- medchk7:
- push di
- lea di,UDSC_SERIAL[di]
- mov cx,2
- repe cmpsw ; is serial number unchanged ?
- pop di
- je medchk6 ; then return may have changed
- medchk8:
- lea ax,UDSC_LABEL[di] ; ES:AX -> ASCII label
- lds bx,REQUEST[bp]
- mov ds:word ptr RH1_VOLID[bx],ax
- mov ds:word ptr RH1_VOLID+2[bx],es
- mov al,0FFH ; return disk changed
- jmps medchk_ret
- medchk6:
- mov al,00h ; disk may have changed
- medchk_ret:
- and es:UDSC_FLAGS[di],not UDF_UNSURE
- les bx,REQUEST[bp]
- mov es:RH1_RETURN[bx],al ; set return value
- sub ax,ax
- ret
- page
- dd_build_bpb: ; 2-build BIOS Parameter Block
- ;------------
- call point_unit ; get unit descriptor
- test es:UDSC_FLAGS[di],UDF_HARD
- jnz bldbpb1 ; BPB doesn't change for hard disks
- call login_media ; try to determine media type (BPB)
- jc bldbpb_err
- bldbpb1:
- mov es:UDSC_OPNCNT[di],0 ; no files open at this time
- and es:UDSC_FLAGS[di],not UDF_UNSURE
- ; media is sure
- lea si,UDSC_BPB[di]
- mov ax,es
- les bx,REQUEST[bp]
- mov es:RH2_BPBOFF[bx],si ; return the current BPB
- mov es:RH2_BPBSEG[bx],ax
- xor ax,ax
- ret
- bldbpb_err:
- jmp xlat_error ; return error code
- ; ret
- login_media: ; determine BPB for new floppy disk
- ;-----------
- push ds
- mov cx,1 ; read track 0, sector 1 (boot)
- call login_read ; to determine media type
- jc login_media_err ; abort if physical error
- cmp local_buffer+11+BPB_FATID,0F0h
- jb login_media10 ; fail unless FATID sensible
- lodsw ; get JMP instruction from boot sector
- xchg ax,bx ; save in BX
- lodsb ; get next 3rd byte in AX
- add si,8 ; skip JMP, OEM name, SI -> BPB
- cmp bl,0E9h ; does it start with a JMP ?
- je login_media40
- cmp bl,069h
- je login_media40
- cmp bl,0EBh ; how about a JMPS ?
- jne login_media10
- cmp al,090h ; then we need a NOP
- je login_media40
- login_media10:
- mov cx,2 ; read track 0, sector 2 (FAT)
- call login_read ; try to read the sector
- jc login_media_err ; abort if physical error
- cmp word ptr 1[si],-1 ; bytes 1, 2 must be 0FFh, 0FFh
- jne login_media30 ; default media if bad FAT
- lodsb ; else get FAT ID byte
- mov si,CG:bpb160 ; look through builtin BPB table
- mov cx,NBPBS ; # of builtin BPBs
- login_media20:
- cmp al,BPB_FATID[si] ; does it match one we know?
- je login_media40 ; yes, use builtin BPB
- add si,BPB_LENGTH ; else move to next BPB
- loop login_media20 ; repeat for all BPBs
- login_media30: ; can't find that FAT ID
- lea si,UDSC_DEVBPB[di] ; use the default type
- push es
- pop ds ; use BPB at DS:SI ->
- login_media40:
- push di
- lea di,UDSC_BPB[di] ; ES:DI -> unit descriptor (UDSC)
- mov cx,UDSC_BPB_LENGTH ; size of a BPB (less reserved stuff)
- rep movsb ; copy into unit descriptor
- pop di
- mov es:UDSC_BPB+BPB_SECSIZ[di],SECSIZE
- ; mov cx,0
- mov es:word ptr (UDSC_BPB+BPB_HIDDEN)[di],cx
- mov es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di],cx
- cmp si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11
- jne login_media50 ; is the BPB from the boot sector ?
- ; mov ax,ds ; if so then check for media id
- ; cmp ax,cs:DataSegment ; seg check redundant as UDSC_DEVBPB
- ; jne login_media50 ; is followed by 7 bytes of zero
- lodsw ; skip 2 bytes
- lodsb ; now get possible boot signature
- cmp al,29h ; is it an extended boot sector ?
- je login_media60 ; yes, use it
- login_media50:
- push cs
- pop ds ; DS:SI -> our dummy value
- mov si,offset CGROUP:dummyMediaID
- login_media60:
- call UpdateMediaID ; update UDSC_ with media info
- clc
- login_media_err:
- pop ds
- ret
- dummyMediaID dd 0 ; serial number 0
- db 'NO NAME '
- db 'FAT12 '
- UpdateMediaID:
- ;-------------
- ; On Entry:
- ; DS:SI -> extended boot record info
- ; ES:DI -> UDSC_ to update
- ; On Exit:
- ; ES:DI preserved
- ;
- push di
- xor ax,ax ; AX = a handy zero
- lea di,UDSC_SERIAL[di]
- movsw
- movsw ; copy serial number
- pop di
- push di
- lea di,UDSC_LABEL[di]
- mov cx,11
- rep movsb ; copy the volume label
- stosb ; zero terminate it
- pop di
- push di
- lea di,UDSC_FSTYPE[di]
- movsw
- movsw
- movsw
- movsw ; copy the file system type
- stosb ; zero terminate it
- pop di
- ret
- login_read:
- ; entry: CH, CL = cylinder/sector to read
- ; exit: CY = 1, AH = status if error
- ; else local_buffer filled in
- mov dl,es:UDSC_RUNIT[di] ; DL = ROS drive
- mov dh,0 ; DH = head number
- login_read_dx: ; read on drive DL, head DH
- ;------------- ; (entry for hard disk login)
- mov P_RETRY[bp],RETRY_MAX ; initialize retry count
- logrd1:
- push es
- mov ax,ROS_READ*256 + 1 ; read one sector from ROS
- push ds
- pop es ; ES = DS = local segment
- mov bx,CG:local_buffer
- int_____DISK_INT ; call the ROM BIOS
- pop es
- jnc logrd3 ; skip if no disk error
- push ax
- ; mov ah,ROS_RESET
- xor ax,ax
- int_____DISK_INT ; reset the drive
- pop ax
- dec P_RETRY[bp]
- jnz logrd1 ; loop back if more retries
- logrd2:
- stc
- logrd3:
- mov si,CG:local_buffer
- ret
- page
- dd_output: ; 8-output
- ;---------
- mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
- jmps io_common
- dd_output_vfy: ; 9-output with verify
- ;-------------
- mov P_ROSCMD[bp],ROS_VERIFY ; write & verify floppy/hard disk
- jmps io_common
- dd_input: ; 4-input
- ;--------
- mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
- ; jmps io_common
- io_common: ; common code for the above three
- call point_unit ; get unit descriptor
- call ask_for_disk ; make sure we've got correct floppy
- call setup_rw ; setup for read/write operation
- jc io_ret ; return if bad parameters
- io_loop:
- call track_rw ; read as much as possible on track
- jc xlat_error ; return if physical disk error
- cmp P_COUNT[bp],0 ; test if any more stuff to read
- jne io_loop ; yes, loop back for more
- mov al,es:UDSC_RUNIT[di] ; remember the drive that is active
- mov activeRosUnit,al
- test es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
- jnz io_exit ; skip timer read for hard/changeline
- call read_system_ticks ; get system tick count in CX/DX
- mov es:UDSC_TIMER[di],dx
- mov es:UDSC_TIMER+2[di],cx ; save time of successful access
- io_exit:
- xor ax,ax ; all done, no error encountered
- io_ret:
- ret
- xlat_error: ; translate ROS error to DOS error
- ;----------
- ; entry: AH = ROS disk error code, CY = 1
- ; exit: AX = status to be returned to BDOS
- pushx <es, di> ; save some registers
- mov al,ah ; AL = ROS error code
- push cs
- pop es
- mov di,CG:ros_errors ; ES:DI -> ROS error code table
- mov cx,NUMROSERR
- repne scasb ; scan for match
- mov ax,RHS_ERROR ; get basic error indication
- or al,cs:(CG:dos_errors-CG:ros_errors-1)[di]
- ; combine with type of error
- popx <di, es>
- stc
- ret
- setup_rw: ; prepare for INPUT, OUTPUT or OUTPUT_VFY
- ;--------
- ; On Entry:
- ; ES:DI -> UDSC
- ; On Exit:
- ; if CY == 0:
- ; P_CYL, P_HEAD, P_SECTOR,
- ; P_DMAOFF, P_DMASEG, P_COUNT initialized
- ; if CY == 1: invalid parameters detected
- ; ES:DI preserved
- push ds
- lds bx,REQUEST[bp]
- mov ax,ds:RH4_BUFOFF[bx] ; get offset of transfer buffer
- mov P_DMAOFF[bp],ax ; set transfer offset
- mov ax,ds:RH4_BUFSEG[bx] ; get segment of transfer buffer
- mov P_DMASEG[bp],ax ; set transfer segment
- mov ax,ds:RH4_COUNT[bx] ; get sector count from request header
- mov P_COUNT[bp],ax ; save it locally for later
- mov ax,ds:RH4_SECTOR[bx] ; get low 16 bit of sector #
- sub dx,dx ; assume value is 16 bit only
- cmp ds:RH_LEN[bx],22 ; check if small request
- je setrw2 ; if so forget the rest
- cmp ds:RH_LEN[bx],24 ; check if large request
- jne setrw1
- mov dx,ds:RH4_SECTOR+2[bx] ; yes, get 32-bit record number
- jmps setrw2
- setrw1:
- cmp ds:RH_LEN[bx],30
- jne setrw2
- cmp ax,-1 ; magic number indicating it's
- jne setrw2 ; a 32-bit record number
- mov ax,ds:RH4_BIGSECTORLO[bx]
- mov dx,ds:RH4_BIGSECTORHI[bx]
- setrw2:
- pop ds
- mov cx,P_COUNT[bp] ; get requested count
- jcxz setrw3 ; invalid count
- dec cx ; CX = count - 1
- cmp es:word ptr (UDSC_BPB+BPB_TOTSEC)[di],0
- jne setrw4 ; skip if < 65536 sectors on disk
- add ax,cx
- adc dx,0 ; AX/DX = # of last sector for I/O
- jc setrw3 ; error if > 32 bits
- cmp dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
- ja setrw3 ; skip if too large
- jb setrw5 ; O.K. if small enough
- cmp ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
- jb setrw5 ; fail if too large
- setrw3:
- mov ax,RHS_ERROR+8 ; return "sector not found"
- stc
- ret
- setrw4: ; less than 65536 records
- add ax,cx ; compute end of transfer
- jc setrw3 ; skip if overflow
- cmp ax,es:UDSC_BPB+BPB_TOTSEC[di]
- jae setrw3 ; skip if too large
- setrw5:
- sub ax,cx
- sbb dx,0 ; add partition address for hard disk
- add ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
- adc dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
- push ax ; AX/DX = 32 bit starting record address
- push dx ; save starting record
- mov ax,es:UDSC_BPB+BPB_SPT[di]
- mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
- mov cx,ax ; CX = sectors per cylinder
- pop dx ; recover 32 bit start block
- pop ax
- div cx ; AX = cylinder #, DX = head/sec offset
- mov P_CYL[bp],ax ; save physical cylinder number
- xor ax,ax ; make remainder 32 bit so
- xchg ax,dx ; DX:AX = (head # * SPT) + sector #
- div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
- mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
- mov P_HEAD[bp],al ; save physical sector/head for later
- clc ; tell them we like the parameters
- ret ; we've figured out starting address
- track_rw:
- ;--------
- ; entry: P_CYL = cylinder for start of transfer
- ; P_HEAD = head # for start of transfer
- ; P_SECTOR = sector # for start of transfer
- ; P_COUNT = remaining sector count
- ; P_DMAOFF = transfer offset
- ; P_DMASEG = transfer segment
- ; ES:DI -> UDSC structure
- ; exit: CY = 0 if no error, P_COUNT = remaining sectors
- ; CY = 1 if error, AH = ROS error code
- call track_setup ; compute size of transfer
- if FASTSETTLE
- call new_settle ; set new head settle delay
- endif
- cmp P_DIRECT[bp],0 ; DMA boundary problem?
- jne trkrw10 ; no, direct transfer performed
- cmp P_ROSCMD[bp],ROS_READ
- je trkrw10 ; skip if not writing to disk
- pushx <ds, es, di>
- mov cx,SECSIZE/2 ; CX = # of word per sector
- push ds
- pop es ; ES:DI -> destination
- mov di,CG:local_buffer
- lds si,P_DMA[bp] ; DS:SI -> source
- rep movsw ; copy from deblocking buffer
- popx <di, es, ds>
- trkrw10:
- mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
- trkrw20: ; loop back here for retries
- mov cx,P_CYL[bp] ; get cylinder #
- xchg cl,ch ; CH = bits 0..7, CL = bits 8..11
- ror cl,1
- ror cl,1 ; cylinder bits 8..9 in bits 6..7
- mov dh,cl ; cylinder bits 10.11 in bits 0..1
- and cl,11000000b ; isolate cylinder bits 8..9
- add cl,P_SECTOR[bp] ; bits 0..5 are sector number
- inc cx ; make it one-relative for ROS
- ror dh,1
- ror dh,1 ; cylinder bits 10..11 in bits 6..7
- and dh,11000000b ; isolate cylinder bits 10..11
- add dh,P_HEAD[bp] ; add physical head number
- mov dl,es:UDSC_RUNIT[di] ; get ROS unit #
- push es
- mov ax,ds
- mov es,ax
- mov bx,CG:local_buffer ; point at our local buffer
- cmp P_DIRECT[bp],0 ; DMA boundary problem?
- je trkrw30 ; no, direct transfer performed
- les bx,P_DMA[bp] ; ES:BX -> transfer address
- trkrw30:
- mov ax,P_MCNT[bp] ; AL = physical sector count
- mov ah,P_ROSCMD[bp] ; AH = ROS read command
- cmp ah,ROS_VERIFY ; write with verify?
- jne trkrw40 ; skip if ROS_READ or ROS_WRITE
- mov ah,ROS_WRITE ; else first perform normal write
- int_____DISK_INT ; call ROS to write to disk
- jc trkrw50 ; skip if any errors occurred
- mov ax,P_MCNT[bp] ; else get sector count
- mov ah,ROS_VERIFY ; verify disk sectors
- trkrw40: ; AH = function, AL = count
- int_____DISK_INT ; read/write/verify via ROM BIOS
- trkrw50: ; CY = 1, AH = error code
- pop es
- jnc trkrw70 ; skip if no errors occurred
- call disk_reset ; reset the hardware
- cmp ah,11h ; ECC corrected data?
- je trkrw60 ; first sector known to be good
- cmp ah,03h ; write protect error
- je trkrw_error ; don't recover, report to user
- dec P_RETRY[bp] ; count # of errors so far
- jnz trkrw20 ; retries done, declare it permanent
- trkrw_error: ; disk error occurred
- if FASTSETTLE
- call old_settle ; restore head settle delay
- endif
- stc ; CY = 1 indicates error, AH = code
- ret
- trkrw60: ; ECC error, only 1st sector OK
- mov P_MCNT[bp],1 ; say we have done one sector
- trkrw70: ; read/write/verify succeeded
- cmp P_DIRECT[bp],0 ; DMA boundary problem?
- jne trkrw80 ; no, direct transfer performed
- cmp P_ROSCMD[bp],ROS_READ
- jne trkrw80 ; skip if not reading from disk
- pushx <di, ds, es>
- mov cx,SECSIZE/2 ; CX = # of word per sector
- mov si,CG:local_buffer
- les di,P_DMA[bp] ; DS:SI -> source, ES:DI -> destination
- rep movsw ; copy from deblocking buffer
- popx <es, ds, di>
- trkrw80:
- mov ax,P_MCNT[bp] ; get physical transfer length
- sub P_COUNT[bp],ax ; subtract from total transfer length
- jz trkrw90 ; exit if none left
- add P_SECTOR[bp],al ; update current sector
- mov ah,SECSIZE/16
- mul ah ; AX = paras to inc DMA address
- add P_DMASEG[bp],ax ; update DMA segment
- xor ax,ax
- mov al,P_SECTOR[bp] ; get current sector
- cmp ax,es:UDSC_BPB+BPB_SPT[di]
- jb trkrw90 ; skip if on same track
- mov P_SECTOR[bp],0 ; else start at beginning of new track
- inc P_HEAD[bp] ; move to the next head
- mov al,P_HEAD[bp] ; get current head
- cmp ax,es:UDSC_BPB+BPB_HEADS[di]
- jb trkrw90 ; did we go over end of cylinder?
- mov P_HEAD[bp],0 ; start with first head...
- inc P_CYL[bp] ; ... on the next cylinder
- trkrw90:
- if FASTSETTLE
- call old_settle ; restore head settle delay
- endif
- clc ; indicate no errors
- ret
- disk_reset:
- ;----------
- ; entry: DL = ROS drive code
- push ax ; save the error status
- ; mov ah,ROS_RESET ; try a restore
- xor ax,ax
- int_____DISK_INT ; might sort things out
- pop ax ; restore error status
- ret
- track_setup: ; prepare for I/O on disk track
- ;-----------
- ; entry: P_CYL = cylinder for start of transfer
- ; P_HEAD = head # for start of transfer
- ; P_SECTOR = sector # for start of transfer
- ; P_COUNT = remaining sector count
- ; P_DMAOFF = transfer offset
- ; P_DMASEG = transfer segment
- ; ES:DI -> UDSC structure
- ; exit: P_DIRECT = 1 if no deblocking
- ; P_MCNT = # of sectors possible in one ROS call
- mov ax,P_DMASEG[bp] ; get transfer address
- cmp ax,DeblockSeg ; is this in high memory ?
- jae trksu20 ; then force through deblock buffer
- mov ax,P_COUNT[bp] ; assume we can transfer all
- mov P_MCNT[bp],ax ; that's requested this time
- mov P_DIRECT[bp],1 ; directly to destination
- test es:UDSC_RUNIT[di],80h ; is it a hard disk transfer ?
- jnz trksu30 ; yes, transfer the lot
- ; floppy transfer, break up into tracks
- mov dx,es:UDSC_BPB+BPB_SPT[di]
- ; DX = sectors per track
- sub dl,P_SECTOR[bp] ; subtract starting sector
- cmp dx,ax ; more than we want?
- jae trksu10 ; no, use this count
- mov P_MCNT[bp],dx ; set count for this pass
- trksu10:
- mov ax,P_DMASEG[bp] ; get transfer address
- mov cl,4
- shl ax,cl ; get A4..A15 from segment
- add ax,P_DMAOFF[bp] ; combine with A0..A15 from offset
- not ax ; AX = # of bytes left in 64K bank
- sub dx,dx
- mov cx,SECSIZE
- div cx ; convert this to physical sectors
- cmp ax,P_MCNT[bp] ; capable of more than requested?
- jae trksu30 ; skip if we can do it all
- mov P_MCNT[bp],ax ; else update possible transfer length
- test ax,ax ; can we transfer anything at all?
- jnz trksu30 ; yes, perform the transfer
- trksu20:
- mov P_MCNT[bp],1 ; single sector transfer via buffer
- mov P_DIRECT[bp],0 ; if DIRECT = 0, deblocked transfer
- trksu30:
- ret
- if FASTSETTLE
- new_settle:
- ;----------
- test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
- jnz new_settle9
- cmp P_ROSCMD[bp],ROS_READ
- jne new_settle9
- push ax
- pushx <bx, ds>
- sub ax,ax
- mov ds,ax
- Assume DS:IVECT
- lds bx,i1eptr
- xchg al,9[bx]
- Assume DS:CGROUP
- popx <ds, bx>
- mov P_SETTLE[bp],al
- pop ax
- new_settle9:
- ret
- old_settle:
- ;----------
- test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
- jnz old_settle9
- cmp P_ROSCMD[bp],ROS_READ
- jne old_settle9
- pushx <ax, bx, ds>
- mov al,P_SETTLE[bp]
- sub bx,bx
- mov ds,bx
- Assume DS:IVECT
- lds bx,i1eptr
- mov 9[bx],al
- Assume DS:CGROUP
- popx <ds, bx, ax>
- old_settle9:
- ret
- endif
- dd_open: ; 13-device open
- ;-------
- call point_unit ; get unit descriptor
- inc es:UDSC_OPNCNT[di] ; increment open count
- sub ax,ax
- ret
- dd_close: ; 14-device close
- ;--------
- call point_unit ; get unit descriptor
- dec es:UDSC_OPNCNT[di] ; decrement open count
- sub ax,ax
- ret
- dd_remchk: ; 15-removable media check
- ;---------
- call point_unit ; get unit descriptor
- sub ax,ax ; assume floppy disk
- test es:UDSC_FLAGS[di],UDF_HARD
- jz remchk1 ; skip if it really is a floppy
- mov ax,RHS_BUSY ; else return "busy" for hard disk
- remchk1:
- ret
- dd_genioctl: ; 19-generic IOCTL
- ;-----------
- mov cx,es:RH19_CATEGORY[bx] ; get major & minor function
- xchg cl,ch ; swap them around
- call point_unit ; get unit descriptor
- cmp ch,8 ; is it the right major category?
- jne ioctl20 ; no, return an error
- or es:UDSC_FLAGS[di],UDF_UNSURE
- ; media unsure after IOCTL
- mov si,offset CGROUP:genioctlTable
- ioctl10:
- lods cs:byte ptr [si] ; get category
- mov ch,al ; keep in CH
- lods cs:word ptr [si] ; AX = function address
- cmp cl,ch ; is it the category we want ?
- je ioctl30 ; yes, go do it
- test ch,ch ; is it the end of the list ?
- jnz ioctl10 ; no, do another one
- ioctl20:
- mov ax,RHS_ERROR+3 ; "unknown command"
- ret
- ioctl30:
- jmp ax ; go do our routine
- genioctlTable label byte
- db RQ19_SET ; set device parameters
- dw offset CGROUP:ioctl_set
- db RQ19_GET ; get device parameters
- dw offset CGROUP:ioctl_get
- db RQ19_WRITE ; write track
- dw offset CGROUP:ioctl_write
- db RQ19_READ ; read track
- dw offset CGROUP:ioctl_read
- db RQ19_FORMAT ; format & verify track
- dw offset CGROUP:ioctl_format
- db RQ19_VERIFY ; verify track
- dw offset CGROUP:ioctl_verify
- db RQ19_GETMEDIA ; get media id
- dw offset CGROUP:ioctl_getmedia
- db RQ19_SETMEDIA ; set media id
- dw offset CGROUP:ioctl_setmedia
- db 0 ; terminate the list
- point_ioctl_packet:
- ;------------------
- ; On Entry:
- ; None
- ; On Exit:
- ; DS:BX -> ioctl request packet
- ; All other regs preserved
- ;
- lds bx,REQUEST[bp]
- lds bx,ds:RH19_GENPB[bx] ; ES:BX -> request packet
- ret
- ioctl_get:
- ;---------
- push ds
- call point_ioctl_packet ; DS:BX -> ioctl packet
- mov al,es:UDSC_TYPE[di] ; get drive type
- mov ds:1[bx],al ; return drive type (0/1/2/5/7)
- mov ax,es:UDSC_FLAGS[di] ; get device attributes
- and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
- mov ds:2[bx],ax ; return device attributes
- mov ax,es:UDSC_NCYL[di] ; get # of cylinders
- mov ds:4[bx],ax ; return # of cylinders
- sub ax,ax ; for now always say "default"
- mov ds:6[bx],al ; return media type
- test ds:byte ptr [bx],1 ; return default BPB?
- pop ds
- lea si,UDSC_DEVBPB[di] ; assume we want device BPB
- jz get1 ; skip if yes
- test es:UDSC_FLAGS[di],UDF_HARD
- jnz get1 ; BPB doesn't change for hard disks
- call ask_for_disk ; make sure we've got correct floppy
- call login_media ; determine floppy disk type
- jc get_err ; abort if can't login disk
- lea si,es:UDSC_BPB[di] ; get current BPB
- get1:
- push ds
- push es
- push di
- push es
- call point_ioctl_packet ; DS:BX -> ioctl packet
- push ds
- pop es
- lea di,7[bx] ; ES:DI -> BPB in parameter block
- pop ds ; DS:SI -> BPB to copy
- mov cx,UDSC_BPB_LENGTH
- rep movsb ; copy the BPB across to user
- pop di
- pop es
- pop ds
- xor ax,ax ; return success
- ret
- get_err:
- jmp xlat_error ; return error code
- ; ret
- ioctl_set: ; set device parameters
- ;---------
- push ds
- push es
- call point_ioctl_packet ; DS:BX -> ioctl packet
- test ds:byte ptr [bx],2 ; ignore all but track layout?
- jnz set2 ; yes, skip BPB stuff
- mov al,ds:1[bx] ; get new drive type (0/1/2/5/7)
- mov es:UDSC_TYPE[di],al ; set drive type
- and es:UDSC_FLAGS[di],not (UDF_HARD+UDF_CHGLINE)
- mov ax,ds:2[bx] ; get new device attributes
- and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
- or es:UDSC_FLAGS[di],ax ; combine the settings
- mov ax,ds:4[bx] ; get new # of cylinders
- mov es:UDSC_NCYL[di],ax ; set # of cylinders
- lea ax,UDSC_BPB[di] ; AX -> media BPB in es:UDSC_
- test ds:byte ptr [bx],1 ; fix BPB for "build BPB" call?
- jnz set1 ; skip if new media BPB only
- lea ax,UDSC_DEVBPB[di] ; AX -> device BPB in es:UDSC_
- set1:
- lea si,7[bx] ; DS:SI -> new BPB from user
- xchg ax,di ; ES:DI -> BPB in es:UDSC_
- mov cx,UDSC_BPB_LENGTH
- rep movsb ; copy BPB into UDSC as new default
- xchg ax,di ; ES:DI -> UDSC_ again
- set2: ; now set track layout
- lea si,BPB_LENGTH+7[bx] ; DS:SI -> new user layout
- mov es,cs:DataSegment
- mov di,CG:layout_table ; ES:DI -> BIOS layout table
- lodsw ; get sector count
- test ax,ax ; make sure this is good value
- jz set6
- cmp ax,MAX_SPT ; make sure this is good value
- ja set6 ; so we don't overflow table
- xchg ax,cx ; CX = sector count
- set3: ; loop here for every sector
- inc di
- inc di
- lodsw ; get sector number
- stosb ; write sector number
- lodsw ; get sector size (0080, 0100, 0200, 0400)
- shl ax,1 ; double it (0100, 0200, 0400, 0800)
- set4:
- shr ah,1 ; halve the sector size until = 128
- jc set5 ; we've shifted out bottom bit
- inc al ; count the # of bits
- jnz set4 ; (this should always jump)
- set5:
- stosb ; store LOG2 (sector size/128)
- loop set3 ; repeat for all sectors
- set6:
- pop es
- pop ds
- xor ax,ax
- ret
- ioctl_read:
- ;----------
- mov P_ROSCMD[bp],ROS_READ ; read physical track
- jmps ioctl_rw_common ; use common code
- ioctl_write:
- ;-----------
- mov P_ROSCMD[bp],ROS_WRITE ; write physical track
- ; jmps ioctl_rw_common ; use common code
- ioctl_rw_common:
- call ask_for_disk ; make sure we've got correct floppy
- push ds
- call point_ioctl_packet ; DS:BX -> ioctl packet
- mov al,ds:5[bx] ; get logical sector (0..SPT-1)
- mov P_SECTOR[bp],al
- mov ax,ds:7[bx] ; get sector count
- mov P_COUNT[bp],ax
- mov ax,ds:9[bx] ; get transfer address
- mov P_DMAOFF[bp],ax
- mov ax,ds:11[bx]
- mov P_DMASEG[bp],ax
- mov ax,ds:1[bx] ; get head number
- mov P_HEAD[bp],al
- mov ax,ds:3[bx] ; get cylinder number
- mov P_CYL[bp],ax
- pop ds
- rw_loop:
- call track_rw ; read as much as possible on track
- jc rw_err ; return if physical disk error
- cmp P_COUNT[bp],0 ; test if any more stuff to read
- jne rw_loop ; yes, loop back for more
- sub ax,ax ; all done, no error encountered
- ret ; return O.K. code
- rw_err:
- jmp xlat_error ; translate ROS code to DOS error
- ; ret
- ioctl_verify:
- ;------------
- ioctl_format:
- ;------------
- call ask_for_disk ; make sure we've got correct floppy
- mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
- format_retry:
- call set_format ; attempt data rate setup
- push ds
- call point_ioctl_packet ; DS:BX -> ioctl packet
- test ds:byte ptr [bx],1 ; are we testing parameters only ?
- jz format10
- mov ds:[bx],al ; return AL
- pop ds
- xor ax,ax ; we succeeded
- ret
- format10:
- mov ax,es:UDSC_BPB+BPB_SPT[di]
- test ds:byte ptr [bx],2 ; is it undocumented "do 2 tracks" bit?
- jz format20
- add ax,ax ; yes, double the count
- format20:
- mov P_COUNT[bp],ax ; save it locally for later
- mov dh,ds:1[bx] ; get head #
- mov cx,ds:3[bx] ; get cylinder #
- ror ch,1
- ror ch,1
- xchg cl,ch
- or cl,1 ; start with sector 1
- mov dl,es:UDSC_RUNIT[di] ; get ROS drive #
- lds bx,REQUEST[bp] ; DS:BX -> Request Header
- mov bx,ds:RH19_CATEGORY[bx] ; get major & minor function
- pop ds
- push es
- xor ax,ax
- mov es,ax
- mov ax,new_int1e_off ; point floppy paramters at local
- xchg ax,es:[4*1Eh]
- mov orig_int1e_off,ax ; save old value
- mov ax,new_int1e_seg
- xchg ax,es:[4*1Eh+2]
- mov orig_int1e_seg,ax
- pop es
- format30:
- cmp bh,RQ19_FORMAT ; skip if verify only
- jne format40
- test es:UDSC_FLAGS[di],UDF_HARD
- jnz format40 ; hard disks are always verify
- mov ax,P_COUNT[bp]
- mov ah,ROS_FORMAT
- push es
- push bx
- push ds
- pop es
- mov bx,CG:layout_table ; ES:BX -> parameter table
- int_____DISK_INT
- pop bx
- pop es
- jc format50
- format40: ; no error on format, try verify
- mov ax,P_COUNT[bp]
- mov ah,ROS_VERIFY
- push es
- push bx
- xor bx,bx
- mov es,bx
- int_____DISK_INT
- pop bx
- pop es
- jc format50
- xor ax,ax ; return success
- format50:
- push es
- push di
- push ax
- mov ax,0
- mov es,ax
- mov di,78h
- mov ax,orig_int1e_off
- stosw
- mov ax,orig_int1e_seg
- stosw
- pop ax
- pop di
- pop es
- jnc format60 ; if no error's just exit
- call xlat_error ; translate to DOS error
- dec P_RETRY[bp] ; any more retries ?
- jz format60 ; no, just exit with error
- ; mov ah,ROS_RESET
- xor ax,ax
- int_____DISK_INT ; reset the drive
- jmp format_retry ; now give it another go
- format60:
- ret
- ; The following table indicates which combinations of drive
- ; types, sectors per track and tracks per disk are O.K. and
- ; which value in AL is required for those combinations for
- ; INT 13h, AH = 17h ("set DASD type for format").
- ; +---------------------- 0 = 360Kb, 1 = 1.2Mb, 2 = 720Kb
- ; | +------------------ # of sectors/track (9, 15, 18)
- ; | | +--------------- # of tracks per disk (40 or 80)
- ; | | | +----------- 1 = 360 Kb in 360 Kb
- ; | | | | 2 = 360 Kb in 1.2 Mb
- ; | | | | 3 = 1.2 Mb in 1.2 Mb
- ; | | | | 4 = 720 Kb in 720 Kb
- ; | | | | +-------- gap length for format
- ; | | | | |
- ; V V V V V
- ok_fmt_table db 0, 9, 40, 1, 50h ; 360 Kb
- db 1, 9, 40, 2, 50h ; 360 Kb in 1.2 Mb
- db 1, 15, 80, 3, 54h ; 1.2 Mb in 1.2 Mb
- db 2, 9, 80, 4, 50h ; 720 Kb in 720 Kb
- db -1 ; end of table
- set_format:
- ;----------
- ; On Entry:
- ; ES:DI -> UDSC_
- ; On Exit:
- ; AL = 0 on success, else value to return in parameter block
- ; ES:DI preserved
- ;
- push ds
- call point_ioctl_packet ; DS:BX -> ioctl packet
- mov dh,ds:1[bx] ; get the head number
- mov cx,ds:3[bx] ; get the cylinder number
- pop ds
- mov si,CG:layout_table ; SI -> track layout table
- mov ax,MAX_SPT ; AX = # of sectors per track
- set_format10:
- mov 0[si],cl ; set cylinder number
- mov 1[si],dh ; set head number
- add si,4 ; next sector entry
- dec ax ; count down # of sectors
- jnz set_format10 ; repeat until all done
- call get_ncyl ; return # of tracks
- dec ax ; AX = max. cylinder #
- ror ah,1
- ror ah,1 ; move bits 8,9 into 6,7
- xchg al,ah
- mov cx,es:UDSC_BPB+BPB_SPT[di]
- ; get desired sectors/track
- or cx,ax ; CL, CH = max. cylinder/max. sector #
- cmp cx,2708h ; check for 40 track, 8 sectors/track
- jne set_format20 ; we convert 160, 320 to 180, 360
- inc cx ; make it 9 sectors per track
- set_format20:
- mov dl,es:UDSC_RUNIT[di] ; get ROS unit number
- pushx <es, di>
- mov ah,ROS_SETMEDIA ; set type for format
- int_____DISK_INT ; check if combination is legal
- mov new_int1e_off,di
- mov new_int1e_seg,es ; ES:DI -> new parameters if legal
- popx <di, es>
- jc set_format40 ; did we succeed ?
- set_format30:
- xor ax,ax ; success, return no errors
- ret
- set_format40:
- ; ROM BIOS has given an error, if the function isn't supported drop
- ; thru' and try the older method's
- ;
- mov al,2 ; assume ROS doesn't support it
- cmp ah,0Ch ; media combination not supported ?
- je set_format80 ; return AL=2
- inc ax ; AL = 3
- cmp ah,80h ; drive not ready ?
- je set_format80 ; return AL=3
- ; Lets look for a match in our tables
- call get_ncyl ; AX = number of cylinders
- mov cx,es:UDSC_BPB+BPB_SPT[di]
- ; CL = sectors per track
- mov ch,al ; CH = tracks per disk
- cmp cx,2808h ; 40 tracks, 8 sectors?
- jne set_format50
- inc cx ; force it to 9 sectors/track
- set_format50:
- mov si,CG:ok_fmt_table-4
- set_format60:
- add si,4 ; next table entry
- lods cs:byte ptr [si] ; get drive type
- cmp al,0FFh ; end of device/media list?
- je set_format70 ; yes, can't handle this combination
- cmp al,es:UDSC_TYPE[di] ; does the drive type match?
- jne set_format60 ; try next one if wrong drive
- cmp cx,cs:[si] ; do tracks/sectors match?
- jne set_format60 ; no, try next one
- mov parms_spt,cl ; set sectors/track
- mov al,cs:3[si] ; get required gap length from table
- mov parms_gpl,al ; set gap length for format
- mov ax,CG:local_parms
- mov new_int1e_off,ax ; use local parameters for formatting
- mov new_int1e_seg,ds ; set new interrupt vector address
- mov dl,es:UDSC_RUNIT[di]
- mov al,cs:2[si] ; get media/drive combination
- mov ah,ROS_SETTYPE ; set the drive type
- int_____DISK_INT
- jnc set_format30 ; return if no errors
- cmp es:UDSC_TYPE[di],0 ; is this a 360 K drive?
- je set_format30 ; go ahead, might be old ROS
- cmp es:UDSC_TYPE[di],2 ; is this a 720 K drive?
- je set_format30 ; go ahead, might be old ROS
- set_format70:
- mov al,1 ; return not supported
- set_format80:
- ret
- get_ncyl:
- ;--------
- mov ax,es:UDSC_BPB+BPB_TOTSEC[di]
- xor dx,dx ; get sectors on disk
- test ax,ax ; zero means we use 32 bit value
- jnz get_ncyl10
- mov ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
- mov dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
- get_ncyl10:
- div es:UDSC_BPB+BPB_SPT[di] ; AX = # of cylinders * heads
- call get_ncyl20 ; round up
- div es:UDSC_BPB+BPB_HEADS[di]; AX = # of cylinders
- get_ncyl20:
- test dx,dx ; do we have overflow ?
- jz get_ncyl30
- inc ax ; round up
- xor dx,dx ; make it a 32 bit value
- get_ncyl30:
- ret
- ioctl_getmedia:
- ;--------------
- mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
- call rw_media ; read the boot sector
- jc getmedia10
- push es
- push di
- push ds
- call point_ioctl_packet ; DS:BX -> ioctl packet
- push ds
- pop es
- lea di,2[bx] ; ES:DI -> skip info word
- pop ds ; DS:SI -> boot sector media id
- mov cx,4+11+8
- rep movsb ; copy the boot sector image
- pop di
- pop es
- xor ax,ax
- getmedia10:
- ret
- ioctl_setmedia:
- ;--------------
- mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
- call rw_media ; read the boot sector
- jc setmedia10
- push ds
- push si
- push es
- push di
- push ds
- push si
- call point_ioctl_packet ; DS:BX -> ioctl packet
- lea si,2[bx] ; DS:SI -> skip info word
- pop di
- pop es ; ES:DI -> boot sector image
- mov cx,4+11+8
- rep movsb ; update the boot sector image
- pop di
- pop es
- pop si
- pop ds
- mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
- jmp rw_media ; write the boot sector
- setmedia10:
- ret
- rw_media:
- ;--------
- ; On Entry:
- ; ES:DI -> UDSC
- ; On Exit:
- ; ES:DI preserved
- ; CY clear, SI -> boot record info
- ; CY set on error, AX = error code
- ;
- ; setup parameters to read/write boot sector to/from local buffer
- ;
- call ask_for_disk ; make sure we've got correct floppy
- mov P_DMAOFF[bp],CG:local_buffer
- mov P_DMASEG[bp],ds ; set transfer address
- mov P_COUNT[bp],1 ; read 1 sector
- mov ax,es:UDSC_BPB+BPB_SPT[di]
- mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
- xchg ax,cx ; CX = sectors per cylinder
- mov ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
- mov dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
- div cx ; AX = cylinder #, DX = head/sec offset
- mov P_CYL[bp],ax ; save physical cylinder number
- xor ax,ax ; make remainder 32 bit so
- xchg ax,dx ; DX:AX = (head # * SPT) + sector #
- div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
- mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
- mov P_HEAD[bp],al ; save physical sector/head for later
- call rw_loop ; read the boot sector
- jc rw_media20
- cmp local_buffer+11+BPB_FATID,0F0h
- jb rw_media10
- mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
- lodsb ; get extended boot
- sub al,29h ; do we have an extended boot ?
- je rw_media20 ; no, well we can't write a new one
- rw_media10:
- mov ax,RHS_ERROR+3 ; "unknown command"
- rw_media20:
- ret
- dd_getdev: ; 23-get logical drive
- ;---------
- ; get logical drive that corresponds to the physical drive
- call point_unit ; get unit descriptor
- call get_owner ; DL = owning drive (zero not owned)
- jmps dd_setdev10 ; return the owner
- dd_setdev: ; 24-set logical drive
- ;---------
- ; set logical drive that corresponds to the physical drive
- ;
- call point_unit ; get unit descriptor
- call set_owner ; set new owner
- dd_setdev10:
- les bx,REQUEST[bp]
- mov es:RH_UNIT[bx],dl ; return current logical drive
- xor ax,ax
- ret
- get_owner:
- ;---------
- ; On Entry:
- ; ES:DI -> UDSC_
- ; On Exit:
- ; DL = owning drive (zero = no owner)
- ;
- xor dx,dx ; assume one unit per physical drive
- mov ax,es:UDSC_FLAGS[di]
- test ax,UDF_HARD
- jnz get_owner40
- test ax,UDF_VFLOPPY
- jz get_owner40
- push ds
- mov ds,dx ; DS -> low memory
- Assume DS:IVECT
- mov dl,dual_byte
- pop ds
- Assume DS:CGROUP
- mov al,es:UDSC_RUNIT[di] ; lets look for this ROS drive
- test al,al ; is it physical unit zero ?
- jz get_owner30 ; yes, return dual_byte
- push ds ; no, search our internal info
- lds si,udsc_root
- Assume DS:Nothing
- get_owner10:
- cmp al,ds:UDSC_RUNIT[si] ; do we use the same drive ?
- jne get_owner20
- test ds:UDSC_FLAGS[si],UDF_OWNER
- jz get_owner20 ; do we own it ?
- mov dl,ds:UDSC_DRIVE[si] ; get the logical drive owner
- get_owner20:
- lds si,ds:UDSC_NEXT[si]
- cmp si,0FFFFh ; try the next drive
- jne get_owner10
- pop ds
- Assume DS:CGROUP
- get_owner30:
- inc dx ; make drive one based
- get_owner40:
- ret
- set_owner:
- ;---------
- ; On Entry:
- ; ES:DI -> UDSC_
- ; On Exit:
- ; ES:DI preserved
- ; DL = owning drive (zero = no owner)
- ;
- xor dx,dx ; assume one unit per physical drive
- mov ax,es:UDSC_FLAGS[di]
- test ax,UDF_HARD
- jnz set_owner40
- test ax,UDF_VFLOPPY
- jz set_owner40
- mov al,es:UDSC_DRIVE[di]
- mov ah,es:UDSC_RUNIT[di] ; get ROS unit
- test ah,ah ; is it unit zero ?
- jnz set_owner10
- push ds
- mov ds,dx ; DS -> low memory
- Assume DS:IVECT
- mov dual_byte,al ; set dual drive support byte
- pop ds
- Assume DS:CGROUP
- set_owner10:
- push ds
- lds si,udsc_root
- Assume DS:Nothing
- set_owner20:
- cmp ah,ds:UDSC_RUNIT[si] ; does this unit use the same drive ?
- jne set_owner30
- or ds:UDSC_FLAGS[si],UDF_UNSURE+UDF_OWNER
- cmp al,ds:UDSC_DRIVE[di]
- je set_owner30
- and ds:UDSC_FLAGS[si],not UDF_OWNER
- set_owner30:
- lds si,ds:UDSC_NEXT[si]
- cmp si,0FFFFh ; end of the line ?
- jne set_owner20
- pop ds
- Assume DS:CGROUP
- xchg ax,dx ; DL = owning drive
- inc dx ; make it one based
- set_owner40:
- ret
- ask_for_disk: ; make sure the right disk is in the floppy drive
- ;------------
- call get_owner ; DL = owning drive
- dec dx ; make DL zero based
- js askfdsk30 ; stop if not a logical drive
- mov dh,es:UDSC_DRIVE[di] ; DH = new drive, DL = old drive
- cmp dl,dh ; do we own the drive ?
- je askfdsk30 ; yes, stop now
- push dx ; save for broadcast
- mov dl,dh ; new owner in DL
- call set_owner ; we are now the owner
- push es
- push di
- push cs
- call FullScreen
- pop di
- pop es
- pop dx
- mov ax,4A00h ; should we prompt ?
- xor cx,cx
- int 2Fh ; lets ask
- inc cx ; CX = FFFF ?
- jcxz askfdsk30 ; then skip prompt
- ifdef JAPAN
- mov ax,5001h ; get adaptor mode
- int VIDEO_INT ; ..
- cmp bx,81 ; japanese mode ?
- mov si,CG:disk_msgA_jpn ; get message to print for Japanese
- je askfdsk10 ; yes
- endif
- mov si,CG:disk_msgA ; get message to print
- askfdsk10:
- call WriteASCIIZ ; output the string
- mov al,es:UDSC_DRIVE[di] ; get drive letter for new drive
- add al,'A'
- dec si ; point to NUL
- call WriteNext ; output char, stop at NUL
- ifdef JAPAN
- mov ax,5001h ; get adaptor mode
- int VIDEO_INT ; ..
- cmp bx,81 ; japanese mode ?
- mov si,CG:disk_msgB_jpn ; get message to print for Japanese
- je askfdsk20 ; yes
- endif
- mov si,CG:disk_msgB ; get message to print
- askfdsk20:
- call WriteASCIIZ ; output the string
- mov ah,0 ; wait for any key to be pressed
- int KEYBOARD_INT ; read one key from keyboard
- askfdsk30:
- ret ; we've got the right drive
- WriteNext:
- int 29h ; output via fastconsole entry
- WriteASCIIZ:
- lods cs:byte ptr [si] ; get next char
- test al,al
- jnz WriteNext ; stop at NUL
- ret
- FullScreen:
- xor di,di
- mov es,di
- mov ax,1684h ; get the entry point
- mov bx,21 ; for DOSMGR
- int 2Fh
- mov bx,es
- or bx,di ; anyone there ?
- jz FullScreen10
- mov ax,1 ; yes, go full screen please
- push es ; fake a JMPF to ES:DI
- push di
- FullScreen10:
- retf
- driver endp
- RCODE ends ; end of device driver code
- page
- ICODE segment 'ICODE' ; initialization code
- Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
- dd_init: ; 0-initialize driver
- ;-------
- call hard_init ; setup hard disk units
- call floppy_init ; setup floppy units
- les bx,REQUEST[bp]
- mov al,nunits ; get # of units installed
- mov es:RH0_NUNITS[bx],al ; return value to the BDOS
- mov NumDiskUnits,al ; also set it in device header
- mov ax,endbios ; get pointer to last resident byte
- mov es:RH0_RESIDENT[bx],ax ; set end of device driver
- mov es:RH0_RESIDENT+2[bx],ds
- mov ax,CG:bpbtbl
- mov es:RH0_BPBOFF[bx],ax ; set BPB table array
- mov es:RH0_BPBSEG[bx],ds
- sub ax,ax ; initialization succeeded
- ret ; (BIOS init always does...)
- floppy_init:
- ;-----------
- mov nunits,0 ; floppies start at drive A:
- mov ah,ROS_RESET ; reset the disk system
- xor dx,dx ; for NEAT hard disk boot bug
- int_____DISK_INT
- int EQUIPMENT_INT ; determine equipment status
- mov cl,6
- shr ax,cl ; shift down floppy bits
- and ax,03h ; mask for floppy
- inc ax ; correct 0 based code
- mov nfloppy,al
- cmp al,1 ; if there is only one floppy
- jne equip_check_des ; then use 2 designators
- inc ax ; this fakes a B: drive
- equip_check_des:
- mov cx,ax ; CX = # of units to set up
- xor dx,dx ; DL = physical drive
- equip_loop:
- push cx
- call new_unit ; ES:DI -> UDSC
- mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
- call floppy_type ; determine type, build default BPB
- cmp nfloppy,1 ; do we only have single drive?
- je equip_single ; yes, use same physical drive for all
- inc dx ; else use new drive for each unit
- equip_single: ; we only have one physical drive
- call add_unit ; add ES:DI to list of UDSC_'s
- pop cx
- loop equip_loop ; repeat for all logical floppies
- pushx <ds, es>
- push ds ; DS -> i13_trap segment
- mov di,ds
- mov es,di
- sub si,si
- mov ds,si
- lds si,78h[si]
- mov di,CG:local_parms ; copy parameters to template
- mov cx,11
- rep movsb
- pop es ; now ES -> i13_trap segment
- Assume ES:CGROUP
- sub ax,ax
- mov ds,ax ; DS -> interrupt vectors
- Assume DS:IVECT
- mov ax,CG:Int2FTrap ; hook Int 2F
- mov i2Foff,ax
- mov i2Fseg,es
- mov ax,CG:Int13Trap ; hook Int 13
- xchg ax,i13off
- mov es:i13off_save,ax
- mov ax,es
- xchg ax,i13seg
- mov es:i13seg_save,ax
- mov di,500h ; dual drive byte & friends live here
- mov cx,20h/2 ; zero some bytes at 50h:0
- sub ax,ax ; get a quick zero
- mov es,ax ; ES:DI -> 0:500h
- rep stosw ; setup dual drive byte & friends
- Assume DS:CGROUP, ES:Nothing
- popx <es, ds>
- ret
- floppy_type:
- ;-----------
- ; entry: DI -> unit descriptor
- mov UDSC_TYPE[di],0 ; assume 360K 5.25" floppy
- mov UDSC_NCYL[di],40 ; 40 tracks only
- mov ah,ROS_GETTYPE ; "Read DASD type"
- int_____DISK_INT ; find out if disk change line available
- jc equip_no_chgline ; skip if function not supported
- cmp ah,2 ; floppy with disk change line?
- jne equip_no_chgline ; no, must be old 360K
- or es:UDSC_FLAGS[di],UDF_CHGLINE
- mov es:UDSC_TYPE[di],1 ; assume 1.2Mb floppy
- mov es:UDSC_NCYL[di],80 ; 80 tracks
- equip_no_chgline:
- pushx <es, di, dx> ; save our registers
- mov ah,ROS_PARAM ; read drive parameters
- int_____DISK_INT ; find out floppy type
- popx <dx, di, es>
- jc equip_no_type ; skip if PC,XT,jr,AT before 10 Jan 84
- dec bx ; make values 0 based
- jns equip_type ; (CMOS invalid - type = 0)
- xor bx,bx ; assume 360K
- cmp ch,4fh ; is it 80 track ?
- jne equip_no_type ; if not forget it
- mov bl,1 ; BL = 1 (ie. 1.2M)
- cmp cl,15 ; 15 spt ?
- je equip_type
- inc bx ; BL = 2 (ie. 720k)
- cmp cl,9 ; 9 spt ?
- je equip_type
- inc bx ; BL = 3 (ie. 1.4M)
- cmp cl,18 ; 18 spt ?
- je equip_type
- inc bx
- inc bx ; BL = 5 (ie. 2.8M)
- cmp cl,36 ; 36 spt ?
- jne equip_no_type ; don't recognise anything
- equip_type:
- cmp bl,3 ; is it 1.44 Mb 3.5" type?
- jb equip_type_ok ; skip if 360K, 1.2Mb, 720K (0, 1, 2)
- mov bl,7 ; use reserved "Other" type
- je equip_type_ok
- inc bx ; else make it 2.88 Mb type 9
- inc bx
- equip_type_ok:
- mov es:UDSC_TYPE[di],bl ; set the default drive type for format
- equip_no_type:
- mov al,es:UDSC_TYPE[di] ; AL = 0, 1, 2 or 7 (360/1.2/720/1.44)
- cbw ; make it a word
- xchg ax,si ; SI = drive type
- shl si,1 ; SI = drive type * 2
- mov si,bpbs[si] ; get default BPB for drive
- cmp si,CG:bpb360 ; is this is a 360 K drive?
- jne equip_360 ; skip if any other type
- mov bpbtbl[bx],CG:bpb720 ; use larger default BPB
- equip_360:
- mov cx,UDSC_BPB_LENGTH ; CX = size of BPB
- pushx <es, di, si, cx>
- lea di,es:UDSC_BPB[di]
- mov ax,ds
- mov es,ax ; ES = DS
- rep movsb ; make default BPB current BPB in UDSC
- popx <cx, si, di, es>
- pushx <es, di>
- lea di,es:UDSC_DEVBPB[di]
- rep movsb ; copy default BPB device BPB in UDSC
- popx <di, es>
- ret
- page
- LOG_PRIM equ 01h ; log in primary partitions
- LOG_EXTD equ 02h ; log in extended partitions
- log_flag dw LOG_PRIM ; scan for primary only initially
- hard_init: ; setup all hard disk units
- ;---------
- ; mov log_flag,LOG_PRIM ; log in primary only initially
- call hardi0 ; C: & D:
- mov log_flag,LOG_EXTD ; log in extended only
- ; call hardi0
- ; ret
- hardi0:
- mov ah,ROS_PARAM ; get hard disk parameters
- mov dl,80h
- int_____DISK_INT ; get # of hard disks we have
- jc hardi9 ; skip if hard disks not supported
- test dl,dl ; test if any hard disks found
- jz hardi9 ; skip if there weren't any
- mov al,dl
- cbw
- xchg ax,cx ; CX = # of hard disks
- mov dl,80h ; start with first hard disk
- hardi1:
- pushx <cx, dx> ; save drive count, physical drive
- call login_hdisk ; find all partitions on hard disk
- popx <dx, cx> ; restore physical drive, drive count
- inc dx ; next physical hard disk
- loop hardi1 ; next physical hard disk
- hardi9: ; all hard disks done
- ret
- login_hdisk: ; find all partitions on a hard disk
- ;-----------
- ; entry: DL = 80h, 81h for 1st/2nd hard disk
- push log_flag ; save state for next drive
- mov p_unit,dl ; save physical drive
- mov cx,0001h ; track 0, sector 1
- mov dh,0 ; partition tables start on head 0
- log_h1:
- mov dl,p_unit ; get physical unit
- call login_read_dx
- jnc log_h1a
- jmp log_h9 ; give up if disk error
- log_h1a:
- push cx
- push dx
- mov ah,ROS_PARAM
- int_____DISK_INT ; return disk drive parameters
- inc dh ; DH = number of heads
- mov nhead,dh ; set # of heads on drive
- and cl,3Fh ; isolate sector count
- mov nsect,cl ; set sectors per track
- pop dx
- pop cx
- ;; cmp local_id,0AA55h
- ;; jne log_h9 ; give up if not initialized
- test log_flag,LOG_PRIM ; scanning for primary?
- jz log_h5 ; no, ignore all primary partitions
- mov si,CG:local_pt ; point to partition table
- log_h2:
- ;** SECURE PARTITIONS **
- mov al,init_runit
- test al,al ; booting from a hard disk ?
- ;** SECURE PARTITIONS **
- mov al,4[si] ; get system ID
- ;** SECURE PARTITIONS **
- jns log_h2a ; booting from a hard disk ?
- mov ah,al ; yes, allow secure partitions
- and ah,0F0h
- cmp ah,SEC_ID
- je log_h02
- cmp ah,SEC_ID2
- jne log_h2a
- log_h02:
- sub al,ah ; turn into a sensible partition ID
- log_h2a:
- ;** SECURE PARTITIONS **
- cmp al,DOS20_ID ; is this a DOS 2.x partition?
- je log_h3 ; yes, try to log it in
- cmp al,DOS30_ID ; is this a DOS 3.0/3.1/3.2 partition?
- je log_h3 ; yes, try to log it in
- cmp al,DOS331_ID ; is this a DOS 3.31/4.0 partition?
- jne log_h4 ; skip if not a good partition
- log_h3:
- push si ; save partition table index
- pushx <cx, dx> ; save partition table address
- call login_primary ; login primary partition
- popx <dx, cx> ; get partition table address
- call login_read_dx ; re-read partition table
- pop si ; get partition table index
- jc log_h9 ; give up if error
- log_h4:
- add si,16 ; next partition table entry
- cmp si,CG:local_id ; all partitions checked?
- jb log_h2 ; loop back if more
- log_h5: ; primary partitions done
- test log_flag,LOG_EXTD ; scanning for extended?
- jz log_h9 ; skip if no extended scan
- or log_flag,LOG_PRIM ; scan for both types now
- mov si,CG:local_pt ; SI -> partition table
- ; RG-01
- log_h6:
- ;** SECURE PARTITIONS **
- mov al,init_runit
- test al,al ; booting from a hard disk ?
- ;** SECURE PARTITIONS **
- mov al,4[si] ; get system ID
- ;** SECURE PARTITIONS **
- jns log_h6a ; booting from a hard disk ?
- mov ah,al ; yes, allow secure partitions
- and ah,0F0h
- cmp ah,SEC_ID
- je log_sec2
- cmp ah,SEC_ID2
- jne log_h6a
- log_sec2:
- sub al,ah
- log_h6a:
- ;** SECURE PARTITIONS **
- cmp al,DOSEX_ID ; DOS 3.3 extended partition found?
- jne log_h7
- log_h6b:
- mov dh,1[si] ; get head # for next table
- mov cx,2[si] ; get cylinder, sector for next table
- jmp log_h1 ; read & scan next partition table
- log_h7: ; entry not an extended partition
- add si,16 ; next partition table entry
- cmp si,CG:local_buffer+IDOFF; all partitions checked?
- jb log_h6 ; loop back if more
- log_h9: ; drive login done
- pop log_flag ; restore state for next drive
- ret
- login_primary:
- ;-------------
- ; entry: SI -> partition table entry
- mov ax,12[si] ; get size of partition (low)
- mov part_size,ax
- mov ax,14[si] ; get size of partition (high)
- mov part_size+2,ax
- mov cl,2
- mov bx,5[si] ; get last head/sector
- and bx,1100000011000000b ; isolate cylinder bits 10..11,8..9
- rol bl,cl ; bits 10..11 from head into position
- or bh,bl ; or in bits 8..9
- rol bh,cl ; bits 8..11 into place
- mov bl,7[si] ; get cylinder bits 0..7
- mov dh,1[si] ; get head of DOS partition
- mov cx,2[si] ; get cylinder, sector of DOS partition
- pushx <bx,cx,dx>
- call login_read_dx ; try to read the partition boot
- popx <dx,cx,bx>
- jc login_p9 ; skip if partition not readable
- ; CX, DX = disk addr of 1st sector
- ; SI -> boot sector
- ; PART_SIZE = 32 bit partition address
- cmp nunits,MAXPART ; do we already have the maximum?
- jb log_p0 ; skip if space for more units
- login_p9:
- ret ; else ignore this partition
- log_p0:
- call new_unit ; ES:DI -> new UDSC
- mov es:UDSC_FLAGS[di],UDF_HARD
- mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
- mov es:UDSC_TYPE[di],5 ; set type = hard disk
- mov al,dh ; copy head byte
- and al,11000000b ; cylinder # bits 10..11 are in 6..7
- rol al,1 ; shift bits to bottom of word
- rol al,1
- mov ah,cl ; cylinder # bits 8..9 are in 6..7
- and ah,11000000b ; strip off non-cylinder # bits
- or ah,al ; combine the bits
- rol ah,1 ; shift the bits into place
- rol ah,1
- mov al,ch ; cylinder # bits 0..7
- sub bx,ax ; bx = # cylinders
- inc bx ; make it inclusive
- mov es:UDSC_NCYL[di],bx ; and save it
- push ax ; save # CYLINDERS
- mov al,nsect
- and dh,00111111b ; DH = head offset
- mul dh ; AX = HEAD_OFF * NSECT
- xchg ax,bx ; keep in BX
- mov al,nsect
- mul nhead ; AX = HEADS * NSECT
- pop dx ; recover # CYLINDERS
- mul dx ; DX:AX = CYLINDERS * HEADS * NSECT
- add ax,bx
- adc dx,0 ; DX:AX = (CYL*HEADS + HEAD_OFF)*NSECT
- and cx,00111111b ; isolate bottom 6 bits (sector #)
- dec cx ; sector numbers are one-relative
- add ax,cx ; add in non-partition sectors
- adc dx,0 ; (usually 2.x partition table)
- lea bx,UDSC_BPB[di] ; BX -> BPB to build
- add si,11 ; skip JMP + OEM name in boot sector
- mov es:word ptr BPB_HIDDEN[bx],ax ; set the partition address
- mov word ptr BPB_HIDDEN+2[bx],dx ; (32 bit sector offset)
- mov ax,part_size
- mov dx,part_size+2
- mov word ptr BPB_SIZE[bx],ax ; set partition size in sectors
- mov word ptr BPB_SIZE+2[bx],dx
- mov BPB_TOTSEC[bx],ax ; set partition size for < 32 Mb
- ; we'll zero this later if > 32 Mb
- push es
- push di
- push ax
- push dx
- push si
- call hd_bpb ; build BPB from scratch
- pop si
- pop dx
- pop ax
- pop di
- pop es
- cmp byte ptr -11[si],0E9h ; look for a jmp
- jz log_p1a
- cmp word ptr -11[si],0EB90h ; look for a nop!jmps
- jz log_p1a
- cmp byte ptr -11[si],0EBh ; look for a jmps
- jnz log_p1 ; at the start of the boot sector.
- cmp byte ptr -9[si],90h ; EJH 7-1-91
- jnz log_p1
- log_p1a:
- test BPB_SECSIZ[si],SECSIZE-1; not a multiple of 512 byte?
- jnz log_p1
- cmp BPB_FATID[si],0F8h ; is this a good hard disk?
- jne log_p1
- cmp BPB_NFATS[si],2 ; too many FATs?
- ja log_p1
- cmp BPB_NFATS[si],1 ; no FATs at all?
- jae log_p2 ; continue if BPB is valid
- ; elsa build new BPB
- log_p1: ; any of the above: BPB invalid
- ; (propably FDISKed, not FORMATted yet)
- jmps log_p9
- log_p2: ; valid BPB for partition, AX/DX = size
- push ax
- mov al,BPB_ALLOCSIZ[si] ; copy a few parameters from the
- mov BPB_ALLOCSIZ[bx],al ; Boot Sector BPB to our new BPB
- mov ax,BPB_DIRMAX[si] ; EJH 7-1-91
- mov BPB_DIRMAX[bx],ax
- mov ax,BPB_FATSEC[si]
- mov BPB_FATSEC[bx],ax
- mov ax,BPB_SECSIZ[si]
- mov BPB_SECSIZ[bx],ax
- mov ax,BPB_FATADD[si]
- mov BPB_FATADD[bx],ax
- mov al,BPB_NFATS[si]
- mov BPB_NFATS[bx],al
- pop ax
- cmp BPB_TOTSEC[bx],0 ; is it an 32 bit sector partition ?
- jne log_p3 ; no, carry on
- test dx,dx ; would it fit in 16 bit sector sizes ?
- jnz log_p3 ; yes, then make BPB_TOTSEC
- mov BPB_TOTSEC[bx],ax ; a valid 16 bit value too
- log_p3: ; valid BPB for partition, AX/DX = size
- cmp BPB_SECSIZ[bx],SECSIZE
- jbe log_p9 ; skip if no large sectors
- shr BPB_SECSIZ[bx],1 ; halve the sector size
- shl BPB_ALLOCSIZ[bx],1 ; double the cluster size
- shl BPB_FATSEC[bx],1 ; double the FAT size
- shl BPB_FATADD[bx],1 ; double the FAT address
- shl BPB_TOTSEC[bx],1 ; double # of sectors
- jnc log_p3 ; skip if still < 65536 sectors
- mov BPB_TOTSEC[bx],0 ; else indicate large partition
- jmps log_p3 ; try again
- ; we've adjusted the sector size
- log_p9:
- pushx <ds, di>
- push es
- pop ds
- lea si,UDSC_BPB[di] ; DS:SI -> new BPB
- lea di,UDSC_DEVBPB[di] ; ES:DI -> fixed BPB
- mov cx,UDSC_BPB_LENGTH
- rep movsb ; make this the fixed BPB
- popx <di, ds>
- call add_unit ; register this DDSC_
- inc nhard ; yet another hard disk
- ret
- hd_bpb:
- ;------
- mov BPB_SECSIZ[bx],SECSIZE ; set standard sector size
- mov BPB_FATADD[bx],1 ; one reserved (boot) sector
- mov BPB_NFATS[bx],2 ; two FAT copies
- mov BPB_DIRMAX[bx],512 ; assume 512 entry root directory
- ; BPB_TOTSEC set up already
- mov BPB_FATID[bx],0F8h ; standard hard disk ID
- mov al,nsect
- mov ah,0
- mov BPB_SPT[bx],ax ; set sectors/track
- mov al,nhead
- mov BPB_HEADS[bx],ax ; set # of heads
- ; determine FAT size:
- mov BPB_ALLOCSIZ[bx],2*2 ; assume 2 K clusters
- mov ax,word ptr BPB_SIZE[bx]; AX/DX = 32 bit sector count
- mov dx,word ptr BPB_SIZE+2[bx]
- test dx,dx ; have we got huge partition (type 6)?
- jnz hd_bpb10 ; yes, it's 16-bit
- cmp ax,7FCEh ; more than 16 Mb?
- jae hd_bpb20 ; yes, use 16 bit FAT
- mov cx,4*2 ; else we've got old 12-bit FAT
- mov BPB_ALLOCSIZ[bx],cl ; we use 4 K clusters
- add ax,cx ; adjust DX:AX for rounding
- dec ax ; when we work out num clusters
- div cx ; AX = # of clusters
- mov cx,ax
- add ax,ax ; * 2
- add ax,cx ; * 3
- shr ax,1 ; AX = num clus * 3/2 = bytes
- adc ax,512-1 ; allow for rounding
- xor dx,dx
- mov cx,512
- div cx ; AX = # fat sectors
- mov BPB_FATSEC[bx],ax ; remember FAT size
- ret
- hd_bpb10:
- mov BPB_TOTSEC[bx],0 ; zero this if BPB_SIZE is required
- cmp dx,2 ; less than 2*65536 sectors (64 Mb)?
- jb hd_bpb20 ; yes, leave cluster size the same
- mov BPB_ALLOCSIZ[bx],4*2 ; use 4 K clusters if 64-128 Mb
- cmp dx,4 ; less than 4*65536 sectors (128 Mb)?
- jb hd_bpb20 ; yes, leave cluster size the same
- mov BPB_ALLOCSIZ[bx],8*2 ; use 8 K clusters if 128-512 Mb
- cmp dx,16 ; less than 16*65536 sectors (512 Mb)?
- jb hd_bpb20 ; yes, leave cluster size the same
- mov BPB_ALLOCSIZ[bx],16*2 ; use 16 K clusters if 512-1024 Mb
- cmp dx,32 ; less than 32*65536 sectors (1 Gb)?
- jb hd_bpb20 ; yes, leave cluster size the same
- mov BPB_ALLOCSIZ[bx],32*2 ; use 32 K clusters if 1-2 Gb
- hd_bpb20: ; cluster size determined
- sub ax,1+(512*32/SECSIZE) ; subtract reserved+root directory
- sbb dx,0 ; (note: 32 bytes per entry)
- xor cx,cx
- mov ch,BPB_ALLOCSIZ[bx] ; CX = (256 * # of clusters on drive)
- dec cx
- add ax,cx ; add in for rounding error
- adc dx,0
- inc cx
- div cx ; AX = # of fat sectors
- mov BPB_FATSEC[bx],ax ; remember FAT size
- mov es:UDSC_FSTYPE+4[di],'6'; change "FAT12" to "FAT16"
- ret
- new_unit:
- push ds
- push ax
- push bx
- push cx
- push dx
- push si
- mov es,cs:DataSegment
- mov di,endbios ; get next unit descriptor
- mov cx,UDSC_LENGTH
- add endbios,cx ; grow the BIOS size
- xor ax,ax
- push di
- rep stosb ; zero the UDSC
- pop di
- xor bx,bx
- mov bl,nunits ; BX = unit we are working on
- mov es:UDSC_DRIVE[di],bl ; make that our logical unit
- shl bx,1 ; make it a BPB index
- lea ax,es:UDSC_DEVBPB[di] ; get storage area for device BPB
- mov bpbtbl[bx],ax ; update entry in BPB table
- shr bx,1 ; get the latest drive
- inc bx ; onto next unit
- cmp bl,2 ; 3rd floppy ?
- jne new_unit10
- add bl,nhard ; yes, skip past hard disks
- new_unit10:
- mov nunits,bl ; store ready for next time
- mov es:UDSC_RUNIT[di],0FFh ; set physical drive (ROS code)
- push cs
- pop ds ; DS:SI -> our dummy value
- mov si,offset CGROUP:dummyMediaID
- call UpdateMediaID ; update UDSC_ with media info
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- pop ds
- ret
- ICODE ends
- RESBIOS segment 'RESBIOS'
- ; NOTE: we extend the resident BIOS size by the amount of
- ; memory required by the disk driver.
- db MAXPART*UDSC_LENGTH dup (?)
- RESBIOS ends
- IDATA segment
- p_unit db ? ; 80h, 81h for hard disks
- nsect db ? ; # of sectors per track
- nhead db ? ; # of heads on disk
- part_size dw 2 dup (?) ; temporary save address for size
- nunits db 2 ; start with driver C:
- nhard db 0 ; # of hard disk partitions
- nfloppy db 0 ; # of floppy drives
- Public init_runit
- init_runit db 0 ; poked with ROS Unit at boot
- IDATA ends
- end