page ,132 .lall ; Hard Disk Driver for PC-DOS. ; Created 6-2-85 by Don Tarbell. ; Last changed 10-21-85 by Don Tarbell. cseg segment para public 'code' ; Equates. false equ 0 true equ not false nlu equ 1 ; number of logical units maxsec equ 512 ; maximum sector size. ; ASCII codes. cr equ 0dh ; carriage-return. lf equ 0ah ; line-feed. ; hard disk controller and drive selection. hctlr macro include morhdc.lib ; controller is Morrow. endm ; Device Driver Equ's. ; Static request header equ's. srh equ 0 ; base. srh_len equ 13 ; length. srh_len_fld equ srh ; length field. srh_ucd_fld equ srh+1 ; unit code field. srh_ccd_fld equ srh+2 ; command code field. srh_sta_fld equ srh+3 ; status field. srh_res_fld equ srh+5 ; reserved area field. md equ srh+srh_len ; media descriptor byte. md_len equ 1 ; media descriptor length. dta equ md+md_len ; disk transfer address. dta_len equ 4 ; disk transfer length. count equ dta+dta_len ; byte/sector count. count_len equ 2 ; byte/sector length. ssn equ count+count_len ; starting sector number. ssn_len equ 2 ; starting sector length. ret_byte equ md+md_len ; byte returned address. bpba_ptr equ dta+dta_len ; pointer to bpb. bpba_ptr_len equ 4 ; pointer to bpb length. units equ srh+srh_len ; pointer to number of units. end_ptr_off equ units+1 ; ending adr pointer offset. end_ptr_seg equ end_ptr_off+2 ; ending adr pointer segment. bpb_ptr_off equ end_ptr_seg+2 ; bpb pointer offset. bpb_ptr_seg equ bpb_ptr_off+2 ; bpb pointer segment. hdisk proc far assume cs:cseg,es:cseg,ds:cseg begin: start equ $ ; Device Header. nextdev dd -1 ; pointer to next device. attrib dw 2000h ; block device (non-ibm format) strateg dw devstrat ; pointer to device strategy. interpt dw devint ; pointer to device interrupt handler. devname db 1 ; number of block devices. db 7 dup(?) ; 7 bytes of filler. ; reqhdr label dword rhoff dw ? ; request header offset. rhseg dw ? ; request header segment. ; Bios parameter block. ; These initial values allow first sector to get read. ; (values shown are for cmi-19 and morrow controller) ; The correct block then gets put into here from buffer. bpb equ $ hrdbps dw 512 ; bytes per sector. db 2 ; sectors per allocation unit. dw 66h ; number of reserved sectors. db 2 ; number of file allocation tables. dw 2048 ; number of directory entries. dw 079ech ; total number of sectors. db 0f8h ; media descriptor byte. dw 3dh ; number of sectors for each fat. hrdspt dw 17 ; sectors per track. hrdtpc dw 6 ; number of heads (tracks per cylinder). hidden dw 66h ; number of hidden sectors. ; bios parameter block pointer array (one entry for each device) bpb_ptr dw offset bpb ; bios parameter block offset. ; Function Table. funtab label byte dw init ; initialization. dw media_check ; media check. dw build_bpb ; build bios parameter block. dw ioctl_in ; ioctl input. dw input ; input (read). dw nd_input ; non-desctructive input no wait. dw in_stat ; input status. dw in_flush ; input flush. dw output ; output (write). dw out_verify ; output (write) with verify. dw out_stat ; output status. dw out_flush ; output flush. dw ioctl_out ; ioctl output. ; messages. iemsg db cr,lf,'Initialization',0 inpmsg db cr,lf,'Read',0 outmsg db cr,lf,'Write',0 ermsg db ' error on hard disk:' db cr,lf,'Cylinder ',0 hedmsg db ', head ',0 secmsg db ', sector ',0 statmsg db ', status ',0 ; Common data area. partab equ $ ; parameter table from dos. dtaadr label dword dtaoff dw ? ; transfer address offset. dtaseg dw ? ; transfer address segment. totsec dw ? ; number of sectors to transfer. sector dw ? ; starting sector number. vidoff dw ? ; volume id offset. vidseg dw ? ; volume id segment. bufoff dw ? ; buffer offset (in controller driver). ; Current values. nsects dw ? ; sectors left to transfer on cylinder. verify db 0 ; 0=no verify, 1=verify after write. ercnt db ? ; retry counter. ; Error parameters returned from driver. ercyl dw ? ; cylinder number. erhead db ? ; head number. ersect db ? ; sector number. erstat db ? ; error status. ; Stack Stuff. dw 50 dup(?) ; stack area. stktop equ $ ; stack top. stkoff dw ? ; old stack offset. stkseg dw ? ; old stack segment. ; Device Strategy. devstrat proc far mov cs:rhseg,es ; save segment of request header pointer. mov cs:rhoff,bx ; save offset of request header pointer. ret devstrat endp ; Device Interrupt Handler. devint: ; save registers. cld push ds push es push ax push bx push cx push dx push di push si ; set up local stack. mov stkoff,sp ; save old stack pointer. mov stkseg,ss ; save old stack segment. mov ax,offset stktop ; get local stack pointer. mov sp,ax mov ax,cs ; get local stack segment. mov ss,ax ; es:bx = request header address. mov ax,cs ; ds = cs. mov ds,ax les bx,reqhdr ; es:bx = request header adr. ; jump to selected function. mov al,es:[bx]+2 ; al = function byte. rol al,1 ; al = table offset. lea di,funtab ; di = function table offset. xor ah,ah ; ax = table offset. add di,ax ; di = function table entry offset. jmp word ptr [di] ; jump to select function. ;---------------- ; Initialization. ;---------------- init: mov es:byte ptr units[bx],nlu lea dx,bpb_ptr ; set address of bpb pointer array. mov es:bpb_ptr_off[bx],dx mov es:bpb_ptr_seg[bx],cs mov dx,offset eop mov es:end_ptr_off[bx],dx ; set ending address. mov es:end_ptr_seg[bx],cs mov cl,0 ; cl = drive number. push bx ; save bx, es. push es call mapper ; initialize hard disk controller. pop es ; restore es, bx. pop bx jc initer ; hop if error. or es:word ptr srh_sta_fld[bx],100h ; move bios parameter block from buffer to local storage. ; note: mapper routine returns offset of buffer with bpb in si. mov ax,cs ; es = cs. mov es,ax mov bufoff,si ; save buffer offset. add si,11 ; si = bpb address in buffer. mov di,offset bpb ; di = local bpb address. mov cx,19 ; cx = number of bytes to move. cld ; direction = forward. rep movsb ; now move it. jmp exit initer: mov si,offset iemsg ; print 'Intitialization' jmp errex ; error exit. ;------------- ; Media Check. ;------------- media_check: mov es:byte ptr ret_byte[bx],1 ; return byte = 1. or es:word ptr srh_sta_fld[bx],0100h ; set done bit. jmp exit ; restore registers and return. ;---------------------------- ; Build Bios Parameter Block. ;---------------------------- build_bpb: lea dx,bpb ; dx = bpb pointer. mov es:bpba_ptr[bx],dx ; save ptr to bpb table. mov es:bpba_ptr+2[bx],cs mov dx,bufoff ; dx = buffer address. mov es:dta[bx],dx ; offset of sector buffer. mov es:dta+2[bx],cs or es:word ptr srh_sta_fld[bx],0100h ; status done. jmp exit ; restore registers and return. ;------------------------ ; Non-Supported Commands. ;------------------------ ioctl_in: ioctl_out: nd_input: in_stat: in_flush: out_stat: out_flush: jmp exit ; restore registers & return. ; Get entry parameters. ; Entry: parameters are at es:bx. ; Exit: dtaoff = disk transfer address offset. ; dtaseg = disk transfer address segment. ; nsects = number of sectors to transfer. ; sector = starting sector number. ; vidoff = volume id offset. ; vidseg = volume id segment. getparm proc near ; move parameters into local table. mov ax,es:word ptr dta[bx] ; get disk transfer address. mov cs:dtaoff,ax mov ax,es:word ptr dta+2[bx] mov cs:dtaseg,ax mov ax,es:word ptr count[bx] ; get transfer count. mov totsec,ax mov nsects,ax mov ax,es:word ptr ssn[bx] ; get starting sector number. mov sector,ax ret getparm endp ;----------- ; Disk Read. ;----------- input: call getparm ; get entry parameters. inloop: call setreg ; put parameters into registers. mov ah,1 ; ah = read code. call findalt ; perform the transfer. jc inper ; exit with error if carry. inc sector ; increment sector number. add dtaseg,20h ; add one sector to segment. dec nsects ; decrement number of sectors. jnz inloop ; loop back if not zero. jmp sethdr ; restore registers & return. inper: mov si,offset inpmsg ; print 'Read' jmp errex ; process error and return. ;------------ ; Disk Write. ;------------ output: call getparm ; get entry parameters. outloop: call setreg ; put parameters into registers. mov ah,2 ; ah = write code. call findalt ; perform the transfer. jc outer ; set error flag if carry. inc sector ; increment sector number. add dtaseg,20h ; add one sector to segment. dec nsects ; decrement number of sectors. jnz outloop ; loop back if not zero. sethdr: les bx,reqhdr ; es:bx = request header adr. mov ax,totsec ; ax = original sector count. sub ax,nsects ; ax = sectors actually transfered. mov es:count[bx],ax ; save it for return. or es:word ptr srh_sta_fld[bx],100h ; set status done no error. jmp exit ; restore registers & return. outer: mov si,offset outmsg ; print 'Write' ; process errors and exit. errex: mov ercyl,bx ; save cylinder requested. mov erhead,dh ; save head number. mov ersect,dl ; save sector number. mov erstat,al ; save status code. call prtmsg ; print message at si. les bx,reqhdr ; es:bx = request header adr. mov ax,8004h ; set crc error for now. mov es:srh_sta_fld[bx],ax ; put into header. mov ax,totsec ; ax = original sector count. sub ax,nsects ; ax = sectors actually transferred. mov es:count[bx],ax mov si,offset ermsg ; print ' error on hard disk:' call prtmsg mov cx,ercyl ; print cylinder number. call prtdec mov si,offset hedmsg ; print ', head '. call prtmsg mov ch,0 ; print head number. mov cl,erhead call prtdec mov si,offset secmsg ; print ', sector '. call prtmsg mov ch,0 ; print sector number. mov cl,ersect call prtdec mov si,offset statmsg ; print ', status '. call prtmsg mov ah,erstat ; print status bits. call prtbin jmp exit ; restore registers and return. ;---------------------------- ; Output (Write) with Verify. ;---------------------------- out_verify: mov cs:byte ptr verify,1 ; set the verify flag. jmp output ; do the rest above. hctlr ; print message at cs:si. ; message is terminated by a zero. prtmsg proc near cld ; direction = forward. mov al,[si] ; al = byte. test al,al ; is it end of message? jz prtex ; exit if so. call conout ; print character on screen. inc si ; point si at next character. jmp prtmsg ; loop till string ends. prtex: ret ; exit. prtmsg endp ; print number in cx in decimal form. prtdec proc near push dx ; save on stack. mov dx,-1 ; becomes number / radix. prtsub: sub cx,10 ; subtract 10. inc dx ; increment remainder. jnc prtsub ; loop till carry out. add cx,10 ; add radix back in. xchg dx,cx ; switch new/current. jz prtdon ; hop if conversion complete. call prtdec ; recursive call. prtdon: mov cl,dl ; get bcd value. add cl,'0' ; add ascii bias. mov al,cl ; al = char to print. call conout ; print char on screen. pop dx ret prtdec endp ; print number in ah in binary form. prtbin proc near mov ch,8 ; 8 bits in a byte. prtlop: mov al,'0' ; assume bit is 0. rol ah,1 ; test next bit. jnc prtbit ; it's off, leave 0. inc al ; it's on, make 1. prtbit: call conout ; print the 0 or 1. dec ch ; decrement bit counter. jnz prtlop ; loop til done. ret prtbin endp ; print character in al on screen. conout proc near push ax ; save registers. push cx mov bl,1 ; bl = color. mov ah,14 ; ah = code for tty write. int 10h ; write character on screen. pop cx ; restore registers. pop ax ret conout endp ; Set parameters into registers for transfer. setreg proc near les di,dtaadr ; es:di = transfer address. mov cl,0 ; cl = hard disk drive number. mov ah,byte ptr hrdtpc ; ah = tracks per cylinder (heads). mov al,byte ptr hrdspt ; al = sectors per track. mul ah ; ax = sectors per cylinder. mov bx,ax ; bx = sectors per cylinder. mov ax,sector ; ax = sector to read. mov dx,0 ; numerator is dx and ax. div bx ; dx = sector number. mov bx,ax ; bx = cylinder number. ret setreg endp ; Exit: Restore registers and return. exit: ; restore stack. mov ss,stkseg ; get stack segment back. mov sp,stkoff ; get stack offset back. ; restore rest of registers. pop si pop di pop dx pop cx pop bx pop ax pop es pop ds ret ; return. eop: hdisk endp cseg ends end begin