PAGE 64,132 ; ; SCCSID = @(#)driver.asm 4.13 85/10/15 ; SCCSID = @(#)driver.asm 4.13 85/10/15 ; ; External block device driver ; Hooks into existing routines in IBMBIO block driver via Int 2F mpx # 8. ; This technique minimizes the size of the driver. ; ; Revised Try_h: to test for flagheads as msg was being displayed on FormFactor ; this caused the FormFactor to be set in the Head ; Revised the # of sectors/cluster for F0h to 1 ;============================================================================== ;REVISION HISTORY: ;AN000 - New for DOS Version 4.00 - J.K. ;AC000 - Changed for DOS Version 4.00 - J.K. ;AN00x - PTM number for DOS Version 4.00 - J.K. ;============================================================================== ;AN001 - d55 Unable the fixed disk accessibility of DRIVER.SYS. 7/7/87 J.K. ;AN002 - p196 Driver.sys does not signal init. failure 8/17/87 J.K. ;AN003 - p267 "No driver letter..." message 8/19/87 J.K. ;AN004 - p268 "Too many parameter..." message 8/20/87 J.K. ;AN005 - p300 "Bad 1.44MB BPB information..." 8/20/87 J.K. ;AN006 - p490 Driver should reject identical parms 8/28/87 J.K. ;AN007 - p921 Parser.ASM problem 9/18/87 J.K. ;AN008 - d493 New init request structure 2/25/88 J.K. ;============================================================================== code segment byte public assume cs:code,ds:code,es:code ;AN000; .xlist include SYSMSG.INC ;equates and macros .list MSG_UTILNAME iTEST = 0 ;--------------------------------------------------- ; ; Device entry point ; DSKDEV LABEL WORD DW -1,-1 ; link to next device DW 0000100001000000B ; bit 6 indicates DOS 3.20 driver DW STRATEGY DW DSK$IN DRVMAX DB 1 ; ; Various equates ; CMDLEN equ 0 ;LENGTH OF THIS COMMAND UNIT equ 1 ;SUB UNIT SPECIFIER CMD equ 2 ;COMMAND CODE STATUS equ 3 ;STATUS MEDIA equ 13 ;MEDIA DESCRIPTOR TRANS equ 14 ;TRANSFER ADDRESS COUNT equ 18 ;COUNT OF BLOCKS OR CHARACTERS START equ 20 ;FIRST BLOCK TO TRANSFER EXTRA equ 22 ;Usually a pointer to Vol Id for error 15 CONFIG_ERRMSG equ 23 ;AN009; To set this field to Non-zero ; to display "Error in CONFIG.SYS..." PTRSAV DD 0 STRATP PROC FAR STRATEGY: MOV WORD PTR CS:[PTRSAV],BX MOV WORD PTR CS:[PTRSAV+2],ES RET STRATP ENDP DSK$IN: push es push bx push ax les bx,cs:[ptrsav] cmp byte ptr es:[bx].cmd,0 jnz Not_Init jmp DSK$INIT not_init: ; Because we are passing the call onto the block driver in IBMBIO, we need to ; ensure that the unit number corresponds to the logical (DOS) unit number, as ; opposed to the one that is relevant to this device driver. mov al,byte ptr cs:[DOS_Drive_Letter] mov byte ptr es:[bx].UNIT,al mov ax,0802H int 2fH ; ; We need to preserve the flags that are returned by IBMBIO. YUK!!!!! ; pushf pop bx add sp,2 push bx popf exitp proc far DOS_Exit: pop ax POP BX POP ES RET ;RESTORE REGS AND RETURN EXITP ENDP include msbds.inc ; include BDS structures ;include versiona.inc BDS DW -1 ;Link to next structure DW -1 DB 1 ;Int 13 Drive Number DB 3 ;Logical Drive Letter FDRIVE: DW 512 ;Physical sector size in bytes DB -1 ;Sectors/allocation unit DW 1 ;Reserved sectors for DOS DB 2 ;No. allocation tables DW 64 ;Number directory entries DW 9*40 ;Number sectors (at 512 bytes ea.) DB 00000000B ;Media descriptor, initially 00H. DW 2 ;Number of FAT sectors DW 9 ;Sector limit DW 1 ;Head limit DW 0 ;Hidden sector count dw 0 ;AN000; Hidden sector count (High) dw 0 ;AN000; Number sectors (low) dw 0 ;AN000; Number sectors (high) DB 0 ; TRUE => Large fats OPCNT1 DW 0 ;Open Ref. Count DB 2 ;Form factor FLAGS1 DW 0020H ;Various flags DW 80 ;Number of cylinders in device RecBPB1 DW 512 ; default is that of 3.5" disk DB 2 DW 1 DB 2 DW 70h DW 2*9*80 DB 0F9H DW 3 DW 9 DW 2 DW 0 dw 0 ;AN000; dw 0 ;AN000; dw 0 ;AN000; db 6 dup (0) ;AC000; TRACK1 DB -1 ;Last track accessed on this drive TIM_LO1 DW -1 ;Keep these two contiguous (?) TIM_HI1 DW -1 VOLID1 DB "NO NAME ",0 ;Volume ID for this disk VOLSER dd 0 ;AN000; FILE_ID db "FAT12 ",0 ;AN000; DOS_Drive_Letter db ? ; Logical drive associated with this unit ENDCODE LABEL WORD ; Everything below this is thrown away ; after initialisation. DskDrv dw offset FDRIVE ; "array" of BPBs ;AN000; For system parser; FarSW equ 0 ; Near call expected DateSW equ 0 ; Check date format TimeSW equ 0 ; Check time format FileSW equ 0 ; Check file specification CAPSW equ 0 ; Perform CAPS if specified CmpxSW equ 0 ; Check complex list NumSW equ 1 ; Check numeric value KeySW equ 0 ; Support keywords SwSW equ 1 ; Support switches Val1SW equ 1 ; Support value definition 1 Val2SW equ 1 ; Support value definition 2 Val3SW equ 0 ; Support value definition 3 DrvSW equ 0 ; Support drive only format QusSW equ 0 ; Support quoted string format ;--------------------------------------------------- ;.xlist assume ds:nothing ;AN007;!!!Parse.ASM sometimes assumes DS ; to access its own variable!!! include PARSE.ASM ;together with PSDATA.INC assume ds:code ;AN007; ;.list ;Control block definitions for PARSER. ;--------------------------------------------------- Parms label byte dw Parmsx ;AN000; db 0 ;AN000;No extras Parmsx label byte ;AN000; db 0,0 ;AN000;No positionals db 5 ;AN000;5 switch control definitions dw D_Control ;AN000;/D dw T_Control ;AN000;/T dw HS_Control ;AN000;/H, /S dw CN_Control ;AN000;/C, /N dw F_Control ;AN000;/F db 0 ;AN000;no keywords D_Control label word ;AN000; dw 8000h ;AN000;numeric value dw 0 ;AN000;no functions dw Result_Val ;AN000;result buffer dw D_Val ;AN000;value defintions db 1 ;AN000;# of switch in the following list Switch_D label byte ;AN000; db '/D',0 ;AN000; D_Val label byte ;AN000; db 1 ;AN000;# of value defintions db 1 ;AN000;# of ranges db 1 ;AN000;Tag value when match ; dd 0,255 ;AN000; dd 0,127 ;AN001;Do not allow a Fixed disk. Result_Val label byte ;AN000; db ? ;AN000; Item_Tag label byte ;AN000; db ? ;AN000; Synonym_ptr label word ;AN000; dw ? ;AN000;es:offset -> found Synonym RV_Byte label byte ;AN000; RV_Word label word ;AN000; RV_Dword label dword ;AN000; dd ? ;AN000;value if number, or seg:off to string T_Control label word ;AN000; dw 8000h ;AN000;numeric value dw 0 ;AN000;no functions dw Result_Val ;AN000;result buffer dw T_Val ;AN000;value defintions db 1 ;AN000;# of switch in the following list Switch_T label byte ;AN000; db '/T',0 ;AN000; T_Val label byte ;AN000; db 1 ;AN000;# of value defintions db 1 ;AN000;# of ranges db 1 ;AN000;Tag value when match dd 1,999 ;AN000; HS_Control label word ;AN000; dw 8000h ;AN000;numeric value dw 0 ;AN000;no function flag dw Result_Val ;AN000;Result_buffer dw HS_VAL ;AN000;value definition db 2 ;AN000;# of switch in following list Switch_H label byte ;AN000; db '/H',0 ;AN000; Switch_S label byte ;AN000; db '/S',0 ;AN000; HS_Val label byte ;AN000; db 1 ;AN000;# of value defintions db 1 ;AN000;# of ranges db 1 ;AN000;Tag value when match dd 1,99 ;AN000; CN_Control label word ;AN000; dw 0 ;AN000;no match flags dw 0 ;AN000;no function flag dw Result_Val ;AN000;no values returned dw NoVal ;AN000;no value definition ; db 2 ;AN000;# of switch in following list db 1 ;AN001; Switch_C label byte ;AN000; db '/C',0 ;AN000; ;Switch_N label byte ;AN000; ; db '/N',0 ;AN000; Noval db 0 ;AN000; F_Control label word ;AN000; dw 8000h ;AN000;numeric value dw 0 ;AN000;no function flag dw Result_Val ;AN000;Result_buffer dw F_VAL ;AN000;value definition db 1 ;AN000;# of switch in following list Switch_F label byte ;AN000; db '/F',0 ;AN000; F_Val label byte ;AN000; db 2 ;AN000;# of value definitions (Order dependent) db 0 ;AN000;no ranges db 4 ;AN000;# of numeric choices F_Choices label byte ;AN000; db 1 ;AN000;1st choice (item tag) dd 0 ;AN000;0 db 2 ;AN000;2nd choice dd 1 ;AN000;1 db 3 ;AN000;3rd choice dd 2 ;AN000;2 db 4 ;AN000;4th choice dd 7 ;AN000;7 ;AN000;System messages handler data ;AN000;Put the data here .sall MSG_SERVICES ;AN000;Place the messages here MSG_SERVICES ;AN000;Put messages handler code here. MSG_SERVICES .xall ; ; Sets ds:di -> BDS for this drive ; SetDrive: push cs pop ds mov di,offset BDS ret ; ; Place for DSK$INIT to exit ; ERR$EXIT: MOV AH,10000001B ;MARK ERROR RETURN lds bx, cs:[ptrsav] mov byte ptr ds:[bx.MEDIA], 0 ;AN002; # of units mov word ptr ds:[bx.CONFIG_ERRMSG], -1 ;AN009;Show IBMBIO error message too. JMP SHORT ERR1 Public EXIT EXIT: MOV AH,00000001B ERR1: LDS BX,CS:[PTRSAV] MOV WORD PTR [BX].STATUS,AX ;MARK OPERATION COMPLETE RestoreRegsAndReturn: POP DS POP BP POP DI POP DX POP CX POP AX POP SI jmp dos_exit drivenumb db 5 cyln dw 80 heads dw 2 ffactor db 2 slim dw 9 Switches dw 0 Drive_Let_Sublist label dword db 11 ;AN000;length of this table db 0 ;AN000;reserved dw D_Letter;AN000; D_Seg dw ? ;AN000;Segment value. Should be CS db 1 ;AN000;DRIVER.SYS has only %1 db 00000000b ;AN000;left align(in fact, Don't care), a character. db 1 ;AN000;max field width 1 db 1 ;AN000;min field width 1 db ' ' ;AN000;character for pad field (Don't care). D_Letter db "A" if iTEST Message: push ax push ds push cs pop ds mov ah,9 int 21h pop ds pop ax ret extrn nodrive:byte,loadokmsg:byte,letter:byte, badvermsg:byte endif if iTEST %OUT Testing On initmsg db "Initializing device driver",13,10,"$" stratmsg db "In strategy of driver",10,13,"$" dskinmsg db "In DSKIN part of driver",10,13,"$" outinitmsg db "Out of init code ",10,13,"$" exitmsg db "Exiting from driver",10,13,"$" parsemsg db "Parsing switches",10,13,"$" errmsg db "Error occurred",10,13,"$" linemsg db "Parsed line",10,13,"$" int2fokmsg db "****************Int2f loaded**************",10,13,"$" mediamsg db "Media check ok",10,13,"$" getbpbmsg db "getbpb ok",10,13,"$" iookmsg db "Successful I/O",10,13,"$" parseokmsg db "Parsing done fine",10,13,"$" nummsg db "Number read is " number db "00 ",10,13,"$" drvmsg db "Process drive " driven db "0",10,13,"$" cylnmsg db "Process cylinder ",10,13,"$" slimmsg db "Process sec/trk ",10,13,"$" hdmsg db "Process head " hdnum db "0",10,13,"$" ffmsg db "Process form factor " ffnum db "0",10,13,"$" nxtmsg db "Next switch ",10,13,"$" msg48tpi db "Got a 48 tpi drive",10,13,"$" ENDIF DSK$INIT: PUSH SI PUSH AX PUSH CX PUSH DX PUSH DI PUSH BP PUSH DS LDS BX,CS:[PTRSAV] ;GET POINTER TO I/O PACKET MOV AL,BYTE PTR DS:[BX].UNIT ;AL = UNIT CODE MOV AH,BYTE PTR DS:[BX].MEDIA ;AH = MEDIA DESCRIP MOV CX,WORD PTR DS:[BX].COUNT ;CX = COUNT MOV DX,WORD PTR DS:[BX].START ;DX = START SECTOR LES DI,DWORD PTR DS:[BX].TRANS PUSH CS POP DS ASSUME DS:CODE cld push cs ;AN000; Initialize Segment of Sub list. pop [D_Seg] ;AN000; call SYSLOADMSG ;AN000; linitialize message handler jnc GoodVer ;AN000; Error. Do not install driver. mov cx, 0 ;AN000; No substitution mov dh, -1 ;AN000; Utility message call Show_Message ;AN000; Show message jmp err$exitj2 ;AN000; and exit ;; check for correct DOS version ; mov ah,30h ; int 21H ; cmp ax,expected_version ; je GoodVer ; cmp al,DOSVER_HI ; jnz BadDOSVer ; cmp ah,DOSVER_LO ; jz GoodVer ;BadDOSVer: ; Mov dx,offset BadVerMsg ; call message ; jmp err$exitj2 ; do not install driver GoodVer: mov ax,0800H int 2fH ; see if installed cmp al,0FFH jnz err$exitj2 ; do not install driver if not present lds bx,[ptrsav] mov si,word ptr [bx].count ; get pointer to line to be parsed mov ax,word ptr [bx].count+2 mov ds,ax call Skip_Over_Name ; skip over file name of driver mov di,offset BDS ; point to BDS for drive push cs pop es ; es:di -> BDS Call ParseLine jc err$exitj2 LDS BX,cs:[PTRSAV] mov al,byte ptr [bx].extra ; get DOS drive letter mov byte ptr es:[di].DriveLet,al mov cs:[DOS_Drive_Letter],al add al,"A" ; mov cs:[letter],al ; set up for printing final message mov cs:[D_Letter], al ;AN000; call SetDrvParms ; Set up BDS according to switches jc err$exitj2 mov ah,8 ; Int 2f multiplex number mov al,1 ; install the BDS into the list push cs pop ds ; ds:di -> BDS for drive mov di,offset BDS int 2FH lds bx,dword ptr cs:[ptrsav] mov ah,1 mov cs:[DRVMAX],ah mov byte ptr [bx].media,ah mov ax,offset ENDCODE mov word ptr [bx].TRANS,AX ; set address of end of code mov word ptr [bx].TRANS+2,CS mov word ptr [bx].count,offset DskDrv mov word ptr [bx].count+2,cs push dx push cs pop ds mov si, offset Drive_Let_SubList ;AC000; mov ax, LOADOK_MSG_NUM ;load ok message mov cx, 1 ;AN000; 1 substitution mov dh, -1 ;AN000; utility message call Show_Message ; mov dx,offset loadokmsg ; call message pop dx jmp EXIT err$exitj2: stc jmp err$exit ; ; Skips over characters at ds:si until it hits a `/` which indicates a switch ; J.K. If it hits 0Ah or 0Dh, then will return with SI points to that character. Skip_Over_Name: call scanblanks loop_name: lodsb cmp al,CR ;AN003; je End_SkipName ;AN003; cmp al,LF ;AN003; je End_SkipName ;AN003; cmp al,'/' jnz loop_name End_SkipName: ;AN003; dec si ; go back one character RET ;ParseLine: ; push di ; push ds ; push si ; push es ;Next_Swt: ;IF iTEST ; mov dx,offset nxtmsg ; call message ;ENDIF ; call ScanBlanks ; lodsb ; cmp al,'/' ; jz getparm ; cmp al,13 ; carriage return ; jz done_line ; CMP AL,10 ; line feed ; jz done_line ; cmp al,0 ; null string ; jz done_line ; mov ax,-2 ; mark error invalid-character-in-input ; stc ; jmp short exitparse ; ;getparm: ; call Check_Switch ; mov cs:Switches,BX ; save switches read so far ; jnc Next_Swt ; cmp ax,-1 ; mark error number-too-large ; stc ; jz exitparse ; mov ax,-2 ; mark invalid parameter ; stc ; jmp short exitparse ; ;done_line: ; test cs:Switches,flagdrive ; see if drive specified ; jnz okay ; push dx ; mov ax, 2 ; call Show_Message ; mov dx,offset nodrive ; call message ; pop dx ; mov ax,-3 ; mark error no-drive-specified ; stc ; jmp short exitparse ; ;okay: ; call SetDrive ; ds:di points to BDS now. ; mov ax,cs:Switches ; and ax,fChangeline+fNon_Removable ; get switches for Non_Removable and Changeline ; or ds:[di].flags,ax ; xor ax,ax ; everything is fine ; ;; ;; Can detect status of parsing by examining value in AX. ;; 0 ==> Successful ;; -1 ==> Number too large ;; -2 ==> Invalid character in input ;; -3 ==> No drive specified ; ; clc ;exitparse: ; pop es ; pop si ; pop ds ; pop di ; ret ParseLine proc near ;In) DS:SI -> Input string ; ES = CS ; ES:DI -> BDS table inside this program ; ;Out) ; if successfule, then { AX will be set according to the switch ; flag value. BDS.Flag, Drivenumb, cylin, ; slim, heads ffactor are set } ; else ; { ; If (no drive specified) then { display messages }; ; Set carry; ; } ; ;Subroutine to be called: ; SYSPARSE:NEAR, SHOW_MESSAGE:NEAR, GET_RESULT:NEAR ; ;Logic: ;{ While (Not end_of_Line) ; { ; SYSPARSE (); ; if (no error) then ; GET_RESULT () ; else ; Set carry; ; }; ; ; if (carry set) then Exit; /* Initialization failed */ ; if (No drive number entered) /* Drive number is a requirement */ ; then { Show_Message (); ; exit; ; }; ; assume ds:nothing ;AN000;make sure push di ;AN000;save BDS pointer mov di, offset PARMS ;AN000;now, es:di -> parse control definition SysP_While: ;AN000; xor cx, cx ;AN004; I don't have positionals. xor dx, dx ;AN000; call SYSPARSE ;AN000; cmp ax, $P_RC_EOL ;AN000;end of line? je SysP_End ;AN000; cmp ax, $P_NO_ERROR ;AN000;no error? jne SysP_Fail ;AN000; call Get_Result ;AN000; jmp SysP_While ;AN000; SysP_End: ;AN000; test Switches, FLAGDRIVE ;AN000;drive number specified? jnz SysP_Ok ;AN000;Drive number is a requirement push ds ;AN000; mov ax, NODRIVE_MSG_NUM ;AN000;no drive specification mov cx, 0 ;AN000;no substitutions mov dh, -1 ;AN000;utility message call Show_Message ;AN000; pop ds ;AN000; jmp short SysP_Err ;AN003; SysP_Fail: ;AN000; mov dh, 2 ;AN000; parse error mov cx, 0 ;AN000; call Show_Message ;AN000; Show parse error SysP_Err: ;AN003; stc ;AN000; jmp short PL_Ret ;AN000; SysP_Ok: ;AN000; clc ;AN000; PL_Ret: ;AN000; pop di ;AN000;restore BDS pointer ret ;AN000; ParseLine endp ; Get_Result proc near ;In) A successful result of SYSPARSE in Result_Val ; es = cs, ds = command line segment ;Out) ; Switches set according to the user option. ; Drivenumb, Cyln, Heads, Slim, ffactor set if specified. ;Logic) ; Switch (Synonym_Ptr) ; { case Switch_D: Switches = Switches | FLAGDRIVE; /* Set switches */ ; Drivenumb = Reg_DX.Value_L; ; break; ; ; case Switch_T: Switches = Switches | Flagcyln; ; Cyln = Reg_DX.Value_L; ; break; ; ; case Switch_H: Switches = Switches | Flagheads; ; Heads = Reg_DX.Value_L; ; break; ; ; case Switch_S: Switches = Switches | FlagSecLim; ; Slim = Reg_DX.Value_L; ; break; ; ; case Switch_C: Switches = Switches | fChangeline; ; break; ; ;; case Switch_N: Switches = Switches | fNon_Removable; ;; break; ; ; case Switch_F: Switches = Switches | Flagff; ; Reg_DX = (Reg_DX.ITEM_Tag - 1)*5;/*Get the offset of ; /*the choice. ; ffactor = byte ptr (F_Choices + DX + 1); ; /*Get the value of it */ ; break; ; ; } ; mov ax, Synonym_Ptr ;AN000; push ax ;AN006; save Synonym_ptr cmp ax, offset Switch_D ;AN000; jne Stch_T ;AN000; or Switches, FLAGDRIVE ;AN000; mov al, RV_Byte ;AN000; mov Drivenumb, al ;AN000; jmp GR_Ret ;AN000; Stch_T: ;AN000; cmp ax, offset Switch_T ;AN000; jne Stch_H ;AN000; or Switches, FLAGCYLN ;AN000; mov ax, RV_Word ;AN000; mov Cyln, ax ;AN000; jmp GR_Ret ;AN000; Stch_H: ;AN000; cmp ax, offset Switch_H ;AN000; jne Stch_S ;AN000; or Switches, FLAGHEADS ;AN000; mov ax, RV_Word ;AN000; mov Heads, ax ;AN000; jmp GR_Ret ;AN000; Stch_S: ;AN000; cmp ax, offset Switch_S ;AN000; jne Stch_C ;AN000; or Switches, FLAGSECLIM ;AN000; mov ax, RV_Word ;AN000; mov Slim, ax ;AN000; jmp GR_Ret ;AN000; Stch_C: ;AN000; cmp ax, offset Switch_C ;AN000; ; jne Stch_N ;AN000; jne Stch_F ;AN001; or Switches, fCHANGELINE ;AN000; jmp GR_Ret ;AN000; ;Stch_N: ;AN000; ; cmp ax, offset Switch_N ;AN000; ; jne Stch_F ;AN000; ; or Switches, fNON_REMOVABLE ;AN000; ; jmp GR_Ret ;AN000; Stch_F: ;AN000; cmp ax, offset Switch_F ;AN000; jne GR_Not_Found_Ret ;AN000;error in SYSPARSE or Switches, FLAGFF ;AN000; push si ;AN004; mov si, offset F_Choices ;AN000; xor ax, ax ;AN000; mov al, Item_Tag ;AN000; dec al ;AN000; mov cl, 5 ;AN000; mul cl ;AN000; add si, ax ;AN000; mov al, byte ptr es:[si+1] ;AN000;get the result of choices mov ffactor, al ;AN000;set form factor pop si ;AN004; GR_Ret: ;AN000; pop ax ;AN006; Restore Synonym ptr push di ;AN006; Save di push ax ;AN006; pop di ;AN006; mov byte ptr es:[di], ' ' ;AN006;We don't have this switch any more. pop di ;AN006; jmp short Gr_Done_Ret ;AN006; GR_Not_Found_Ret: pop ax ;AN006;adjust stack GR_Done_Ret: ret ;AN000; Get_Result endp ; ; Scans an input line for blank or tab characters. On return, the line pointer ; will be pointing to the next non-blank character. ; ScanBlanks: lodsb cmp al,' ' jz ScanBlanks cmp al,9 ; Tab character jz ScanBlanks dec si ret ; ; Gets a number from the input stream, reading it as a string of characters. ; It returns the number in AX. It assumes the end of the number in the input ; stream when the first non-numeric character is read. It is considered an error ; if the number is too large to be held in a 16 bit register. In this case, AX ; contains -1 on return. ; ;GetNum: ; push bx ; push dx ; xor ax,ax ; xor bx,bx ; xor dx,dx ; ;next_char: ; lodsb ; cmp al,'0' ; check for valid numeric input ; jb num_ret ; cmp al,'9' ; ja num_ret ; sub al,'0' ; xchg ax,bx ; save intermediate value ; push bx ; mov bx,10 ; mul bx ; pop bx ; add al,bl ; adc ah,0 ; xchg ax,bx ; stash total ; jc got_large ; cmp dx,0 ; jz next_char ;got_large: ; mov ax,-1 ; jmp short get_ret ; ;num_ret: ; mov ax,bx ; dec si ; put last character back into buffer ; ;get_ret: ; pop dx ; pop bx ; ret ; ; Processes a switch in the input. It ensures that the switch is valid, and ; gets the number, if any required, following the switch. The switch and the ; number *must* be separated by a colon. Carry is set if there is any kind of ; error. ; ;Check_Switch: ; lodsb ; and al,0DFH ; convert it to upper case ; cmp al,'A' ; jb err_swtch ; cmp al,'Z' ; ja err_swtch ; mov cl,cs:switchlist ; get number of valid switches ; mov ch,0 ; push es ; push cs ; pop es ; set es:di -> switches ; push di ; mov di,1+offset switchlist ; point to string of valid switches ; repne scasb ; pop di ; pop es ; jnz err_swtch ; mov ax,1 ; shl ax,cl ; set bit to indicate switch ; mov bx,cs:switches ; or bx,ax ; save this with other switches ; mov cx,ax ; test ax,7cH ; test against switches that require number to follow ; jz done_swtch ; lodsb ; cmp al,':' ; jnz reset_swtch ; call ScanBlanks ; call GetNum ; cmp ax,-1 ; was number too large? ; jz reset_swtch ;IF iTEST ; push ax ; add al,'0' ; add ah,'0' ; mov cs:number,ah ; mov cs:number+1,al ; mov dx,offset nummsg ; call message ; pop ax ;ENDIF ; call Process_Num ; ;done_swtch: ; ret ; ;reset_swtch: ; xor bx,cx ; remove this switch from the records ;err_swtch: ; stc ; jmp short done_swtch ; ; This routine takes the switch just input, and the number following (if any), ; and sets the value in the appropriate variable. If the number input is zero ; then it does nothing - it assumes the default value that is present in the ; variable at the beginning. ; ;Process_Num: ; push ds ; push cs ; pop ds ; test Switches,cx ; if this switch has been done before, ; jnz done_ret ; ignore this one. ; test cx,flagdrive ; jz try_f ; mov drivenumb,al ;IF iTEST ; add al,"0" ; mov driven,al ; mov dx,offset drvmsg ; call message ;ENDIF ; jmp short done_ret ; ;try_f: ; test cx,flagff ; jz try_t ; mov ffactor,al ;IF iTEST ; add al,"0" ; mov ffnum,al ; mov dx,offset ffmsg ; call message ;ENDIF ; ;try_t: ; cmp ax,0 ; jz done_ret ; if number entered was 0, assume default value ; test cx,flagcyln ; jz try_s ; mov cyln,ax ;IF iTEST ; mov dx,offset cylnmsg ; call message ;ENDIF ; jmp short done_ret ; ;try_s: ; test cx,flagseclim ; jz try_h ; mov slim,ax ;IF iTEST ; mov dx,offset slimmsg ; call message ;ENDIF ; jmp short done_ret ; ;; Switch must be one for number of Heads. ;try_h: ; test cx,flagheads ; jz done_ret ; mov heads,ax ;IF iTEST ; add al,"0" ; mov hdnum,al ; mov dx,offset hdmsg ; call message ;ENDIF ; ;done_ret: ; pop ds ; ret ; ; SetDrvParms sets up the recommended BPB in each BDS in the system based on ; the form factor. It is assumed that the BPBs for the various form factors ; are present in the BPBTable. For hard files, the Recommended BPB is the same ; as the BPB on the drive. ; No attempt is made to preserve registers since we are going to jump to ; SYSINIT straight after this routine. ; SetDrvParms: push cs pop es xor bx,bx call SetDrive ; ds:di -> BDS ;test cs:switches,flagff ; has formfactor been specified? ;jz formfcont mov bl,cs:[ffactor] mov byte ptr [di].formfactor,bl ; replace with new value formfcont: mov bl,[di].FormFactor ;AC000; The followings are redundanat since there is no input specified for Hard file. ; cmp bl,ffHardFile ; jnz NotHardFF ; mov ax,[di].DrvLim ; cmp ax, 0 ;AN000;32 bit sector number? ; push ax ; mov ax,word ptr [di].hdlim ; mul word ptr [di].seclim ; mov cx,ax ; cx has # sectors per cylinder ; pop ax ; xor dx,dx ; set up for div ; div cx ; div #sec by sec/cyl to get # cyl ; or dx,dx ; jz No_Cyl_Rnd ; came out even ; inc ax ; round up ;No_Cyl_Rnd: ; mov cs:[cyln],ax ; mov si,di ; add si,BytePerSec ; ds:si -> BPB for hard file ; jmp short Set_RecBPB ;NotHardFF: ;AC000; End of deletion. cmp bl,ff48tpi jnz Got_80_cyln IF iTEST mov dx,offset msg48tpi call message ENDIF mov cx,40 mov cs:[cyln],cx Got_80_cyln: shl bx,1 ; bx is word index into table of BPBs mov si,offset BPBTable mov si,word ptr [si+bx] ; get address of BPB Set_RecBPB: add di,RBytePerSec ; es:di -> Recommended BPB mov cx,BPBSIZ cld repe movsb ; move BPBSIZ bytes call Handle_Switches ; replace with 'new' values as ; specified in switches. ; ; We need to set the media byte and the total number of sectors to reflect the ; number of heads. We do this by multiplying the number of heads by the number ; of 'sectors per head'. This is not a fool-proof scheme!! ; mov ax,[di].Rdrvlim ; this is OK for two heads sar ax,1 ; ax contains # of sectors/head mov cx,[di].Rhdlim dec cl ; get it 0-based sal ax,cl jc Set_All_Done_BRG ; We have too many sectors - overflow!! mov [di].Rdrvlim,ax cmp cl,1 ; We use media descriptor byte F0H for any type of medium that is not currently ; defined i.e. one that does not fall into the categories defined by media ; bytes F8H, F9H, FCH-FFH. JE HEAD_2_DRV MOV AL, 1 ;1 sector/cluster MOV BL, BYTE PTR [DI].Rmediad CMP BYTE PTR [DI].FormFactor, ffOther JE GOT_CORRECT_MEDIAD MOV CH, BYTE PTR [DI].FormFactor CMP CH, ff48tpi JE SINGLE_MEDIAD MOV BL, 0F0h JMP GOT_CORRECT_MEDIAD Set_All_Done_BRG:jmp Set_All_Done SINGLE_MEDIAD: CMP WORD PTR [DI].RSecLim, 8 ;8 SEC/TRACK? JNE SINGLE_9_SEC MOV BL, 0FEh JMP GOT_CORRECT_MEDIAD SINGLE_9_SEC: MOV BL, 0FCh JMP GOT_CORRECT_MEDIAD HEAD_2_DRV: MOV BL, 0F0h ;default 0F0h MOV AL, 1 ;1 sec/cluster CMP BYTE PTR [DI].FormFactor, ffOther JE GOT_CORRECT_MEDIAD CMP BYTE PTR [DI].FormFactor, ff48tpi JNE NOT_48TPI MOV AL, 2 CMP WORD PTR [DI].RSecLim, 8 ;8 SEC/TRACK? JNE DOUBLE_9_SEC MOV BL, 0FFh JMP GOT_CORRECT_MEDIAD DOUBLE_9_SEC: MOV BL, 0FDh JMP GOT_CORRECT_MEDIAD NOT_48TPI: CMP BYTE PTR [DI].FormFactor, ff96tpi JNE NOT_96TPI MOV AL, 1 ;1 sec/cluster MOV BL, 0F9h JMP GOT_CORRECT_MEDIAD NOT_96TPI: CMP BYTE PTR [DI].FormFactor, ffSmall ;3-1/2, 720kb JNE GOT_CORRECT_MEDIAD ;Not ffSmall. Strange Media device. MOV AL, 2 ;2 sec/cluster MOV BL, 0F9h ;J.K. 12/9/86 THE ABOVE IS A QUICK FIX FOR 3.3 DRIVER.SYS PROB. OLD LOGIC IS COMMENTED OUT. ; mov bl,0F0H ; assume strange media ; mov al,1 ; AL is sectors/cluster - match 3.3 bio dcl. 6/27/86 ; ja Got_Correct_Mediad ;; We check to see if the form factor specified was "other" ; cmp byte ptr [di].FormFactor,ffOther ; jz Got_Correct_Mediad ;; We must have 1 or 2 heads (0 is ignored) ; mov bl,byte ptr [di].Rmediad ; cmp cl,1 ; jz Got_Correct_Mediad ;; We must have one head - OK for 48tpi media ; mov al,1 ; AL is sectors/cluster ; mov ch,byte ptr [di].FormFactor ; cmp ch,ff48tpi ; jz Dec_Mediad ; mov bl,0F0H ; jmp short Got_Correct_Mediad ;Dec_Mediad: ; dec bl ; adjust for one head ;J.K. END OF OLD LOGIC Got_Correct_Mediad: mov byte ptr [di].RSecPerClus,al mov byte ptr [di].Rmediad,bl ; Calculate the correct number of Total Sectors on medium mov ax,word ptr [di].Ccyln mov bx,word ptr [di].RHdLim mul bx mov bx,word ptr [di].RSecLim mul bx ; AX contains the total number of sectors on the disk mov word ptr [di].RDrvLim,ax ;J.K. For ffOther type of media, we should set Sec/FAT, and # of Root directory ;J.K. accordingly. cmp byte ptr [di].FormFactor, ffOther ;AN005; jne Set_All_Ok ;AN005; xor dx, dx ;AN005; dec ax ;AN005; DrvLim - 1. mov bx, 3 ;AN005; Assume 12 bit fat. mul bx ;AN005; = 1.5 byte mov bx, 2 ;AN005; div bx ;AN005; xor dx, dx ;AN005; mov bx, 512 ;AN005; div bx ;AN005; inc ax ;AN005; mov [di].RCSecFat, ax ;AN005; mov [di].RCDir, 0E0h ;AN005; directory entry # = 224 Set_All_Ok: ;AN005; clc Set_All_Done: RET ; ; Handle_Switches replaces the values that were entered on the command line in ; config.sys into the recommended BPB area in the BDS. ; NOTE: ; No checking is done for a valid BPB here. ; Handle_Switches: call setdrive ; ds:di -> BDS test cs:switches,flagdrive jz done_handle ; if drive not specified, exit mov al,cs:[drivenumb] mov byte ptr [di].DriveNum,al ; test cs:switches,flagcyln ; jz no_cyln mov ax,cs:[cyln] mov word ptr [di].cCyln,ax no_cyln: test cs:switches,flagseclim jz no_seclim mov ax,cs:[slim] mov word ptr [di].RSeclim,ax no_seclim: test cs:switches,flagheads jz done_handle mov ax,cs:[heads] mov word ptr [di].RHdlim,ax done_handle: RET Show_Message proc near ;In) AX = message number ; DS:SI -> Substitution list if necessary. ; CX = 0 or n depending on the substitution number ; DH = -1 FOR UTILITY MSG CLASS, 2 FOR PARSE ERROR ;Out) Message displayed using DOS function 9 with no keyboard input. push cs ;AN000; pop ds ;AN000; mov bx, -1 ;AN000; mov dl, 0 ;AN000;no input call SYSDISPMSG ;AN000; ret ;AN000; Show_Message endp ; ; The following are the recommended BPBs for the media that we know of so ; far. ; 48 tpi diskettes BPB48T DW 512 DB 2 DW 1 DB 2 DW 112 DW 2*9*40 DB 0FDH DW 2 DW 9 DW 2 DW 0 ; 96tpi diskettes BPB96T DW 512 DB 1 DW 1 DB 2 DW 224 DW 2*15*80 DB 0F9H DW 7 DW 15 DW 2 DW 0 BPBSIZ = $-BPB96T ; 3 1/2 inch diskette BPB BPB35 DW 512 DB 2 DW 1 ; Double sided with 9 sec/trk DB 2 DW 70h DW 2*9*80 DB 0F9H DW 3 DW 9 DW 2 DW 0 BPBTable dw BPB48T ; 48tpi drives dw BPB96T ; 96tpi drives dw BPB35 ; 3.5" drives ; The following are not supported, so we default to 3.5" layout dw BPB35 ; Not used - 8" drives dw BPB35 ; Not Used - 8" drives dw BPB35 ; Not Used - hard files dw BPB35 ; Not Used - tape drives dw BPB35 ; Not Used - Other switchlist db 7,"FHSTDCN" ; Preserve the positions of N and C. ; The following depend on the positions of the various letters in SwitchList flagdrive equ 0004H flagcyln equ 0008H flagseclim equ 0010H flagheads equ 0020H flagff equ 0040H ;AN000; ;Equates for message number NODRIVE_MSG_NUM equ 2 LOADOK_MSG_NUM equ 3 code ends end