; e forproc.sal= @(#)ibmfor.asm 1.28 85/10/15
;	name	OemFormatRoutines
;******************************************************************************
;AN001 - ???
;AN002 - D304 Modify Boot record structure for OS2		  11/09/87 J.K.
;******************************************************************************

%include "forchng.mac"
debug	equ	0
DEBUG	equ	0
;-------------------------------------------------------------------------------
; Public for debugging only

	public	LastChanceToSaveIt
	public	WriteBootSector
	public	OemDone
	public	WriteBogusDos
	public	ConvertToOldDirectoryFormat
	public	SetPartitionTable
	public	ReadSector
	public	WriteSector
	public	SectorIO
	public	GetVolumeId

	public	customBPBs
	public	NotSlashB
	public	NotSingleSided
	public	EndSwitchCheck
	public	WeCanNotIgnoreThisError
	public	HardDisk?
	public	BogusDos
	public	sys_mess_loop
	public	end_sys_loop
	public	DirectoryRead
	public	wrtdir
	public	DirectoryWritten
	public	FCBforVolumeIdSearch
	public	CopyVolumeId
	public	CompareVolumeIds
	public	BadVolumeId

	public	boot2
boot equ BOOT	; NASM port label
	public	boot
	public	scratchBuffer
	public	biosFilename
	public	dosFilename
	public	oldDrive
	public	oldVolumeId
	public	Read_Write_Relative
	public	Serial_Num_Low
	public	Serial_Num_High
	public	SizeMap

	public	ptr_msgWhatIsVolumeId?

	public	trackReadWritePacket

	public	BPB81
	public	BPB82
	public	BPB91
	public	BPB92

;-------------------------------------------------------------------------------

section data public align=16 class=DATA
; (no prior section) ; data	ends

section code public align=16 class=CODE
	assume	cs:code,ds:data

	Public	AccessDisk
	public	LastChanceToSaveIt
	public	OemDone
	public	BiosFile
	public	DosFile

section data
	extrn	AddToSystemSize:near
	extrn	currentCylinder:word
	extrn	currentHead:word
	extrn	deviceParameters:byte
	extrn	drive:byte
	extrn	driveLetter:byte
	extrn	fBigFAT:byte
	extrn	inbuff:byte
	extrn	switchmap:word
	extrn	Old_Dir:byte
	extrn	fLastChance:byte
	extrn	Fatal_Error:Byte
	extrn	Bios:Byte
	extrn	Dos:Byte
	extrn	Command:Byte

	extrn	msgBad_T_N:byte
	extrn	msgBadVolumeId:byte
	extrn	msgBadPartitionTable:byte
	extrn	msgBootWriteError:byte
	extrn	msgDirectoryReadError:byte
	extrn	msgDirectoryWriteError:byte
	extrn	msgInvalidParameter:byte
	extrn	msgIncompatibleParameters:byte
	extrn	msgIncompatibleParametersForHardDisk:byte
	extrn	msgParametersNotSupportedByDrive:byte
	extrn	msgPartitionTableReadError:byte
	extrn	msgPartitionTableWriteError:byte
	extrn	msgWhatIsVolumeId?:byte
	extrn	NumSectors:word, TrackCnt:word

%IF	DEBUG
	extrn	msgFormatBroken:byte
%ENDIF

section code	; data	ends

	extrn	PrintString:near
	extrn	std_printf:near
	extrn	crlf:near
	extrn	user_string:near
	extrn	Read_Disk:near
	extrn	Write_Disk:near


;-------------------------------------------------------------------------------
; Constants

[list -]
%include "dosmac.mac"
%include "formacro.mac"
%include "forequ.mac"
%include "forswtch.mac"

; This defines all the int 21H system calls
%include "syscall.mac"

; Limits

%include "filesize.mac"

;-------------------------------------------------------------------------------
; These are the data structures which we will need

%include "dirent.mac"
%include "ioctl.mac"
%include "version.mac"

[list +]

;-------------------------------------------------------------------------------
; And this is the actual data
section data

Read_Write_Relative: ; NASM structure instance
Relative_Sector_Buffer_size equ Relative_Sector_Buffer_struc_size	; NASM port equate
istruc Relative_Sector_Buffer
iend


	%IF IBMCOPYRIGHT
BiosFile db	"x:\IBMBIO.COM", 0
DosFile db	"x:\IBMDOS.COM", 0
	%ELSE
BiosFile db	"x:\IO.SYS", 0
DosFile db	"x:\MSDOS.SYS", 0
	%ENDIF

Dummy_Label db	"NO NAME    "
Dummy_Label_Size dw  11 			;AN028

Serial_Num_Low dw 0				;				;AN000;
Serial_Num_High dw 0				;				;AN000;

SizeMap db	0				;				;AN000;

trackReadWritePacket: ; NASM structure instance
A_TRACKREADWRITEPACKET_size equ A_TRACKREADWRITEPACKET_struc_size	; NASM port equate
istruc A_TRACKREADWRITEPACKET
iend


; BIOS parameter blocks for various media
customBPBs label byte
BPB92: ; NASM structure instance
A_BPB_size equ A_BPB_struc_size	; NASM port equate
istruc A_BPB
at BPB_BYTESPERSECTOR
	dw 512
at BPB_SECTORSPERCLUSTER
	db 2
at BPB_RESERVEDSECTORS
	dw 1
at BPB_NUMBEROFFATS
	db 2
at BPB_ROOTENTRIES
	dw 112
at BPB_TOTALSECTORS
	dw 2*9*40
at BPB_MEDIADESCRIPTOR
	db 0fdH
at BPB_SECTORSPERFAT
	dw 2
at BPB_SECTORSPERTRACK
	dw 9
at BPB_HEADS
	dw 2
at BPB_HIDDENSECTORS
	dw 0
	dw 0
at BPB_BIGTOTALSECTORS
	dw 0
	dw 0
iend
BPB91: ; NASM structure instance
istruc A_BPB
at BPB_BYTESPERSECTOR
	dw 512
at BPB_SECTORSPERCLUSTER
	db 1
at BPB_RESERVEDSECTORS
	dw 1
at BPB_NUMBEROFFATS
	db 2
at BPB_ROOTENTRIES
	dw 64
at BPB_TOTALSECTORS
	dw 1*9*40
at BPB_MEDIADESCRIPTOR
	db 0fcH
at BPB_SECTORSPERFAT
	dw 2
at BPB_SECTORSPERTRACK
	dw 9
at BPB_HEADS
	dw 1
at BPB_HIDDENSECTORS
	dw 0
	dw 0
at BPB_BIGTOTALSECTORS
	dw 0
	dw 0
iend
BPB82: ; NASM structure instance
istruc A_BPB
at BPB_BYTESPERSECTOR
	dw 512
at BPB_SECTORSPERCLUSTER
	db 2
at BPB_RESERVEDSECTORS
	dw 1
at BPB_NUMBEROFFATS
	db 2
at BPB_ROOTENTRIES
	dw 112
at BPB_TOTALSECTORS
	dw 2*8*40
at BPB_MEDIADESCRIPTOR
	db 0ffH
at BPB_SECTORSPERFAT
	dw 1
at BPB_SECTORSPERTRACK
	dw 8
at BPB_HEADS
	dw 2
at BPB_HIDDENSECTORS
	dw 0
	dw 0
at BPB_BIGTOTALSECTORS
	dw 0
	dw 0
iend
BPB81: ; NASM structure instance
istruc A_BPB
at BPB_BYTESPERSECTOR
	dw 512
at BPB_SECTORSPERCLUSTER
	db 1
at BPB_RESERVEDSECTORS
	dw 1
at BPB_NUMBEROFFATS
	db 2
at BPB_ROOTENTRIES
	dw 64
at BPB_TOTALSECTORS
	dw 1*8*40
at BPB_MEDIADESCRIPTOR
	db 0feH
at BPB_SECTORSPERFAT
	dw 1
at BPB_SECTORSPERTRACK
	dw 8
at BPB_HEADS
	dw 1
at BPB_HIDDENSECTORS
	dw 0
	dw 0
at BPB_BIGTOTALSECTORS
	dw 0
	dw 0
iend
BPB720: ; NASM structure instance
istruc A_BPB
at BPB_BYTESPERSECTOR
	dw 512
at BPB_SECTORSPERCLUSTER
	db 2
at BPB_RESERVEDSECTORS
	dw 1
at BPB_NUMBEROFFATS
	db 2
at BPB_ROOTENTRIES
	dw 112
at BPB_TOTALSECTORS
	dw 2*9*80
at BPB_MEDIADESCRIPTOR
	db 0F9h
at BPB_SECTORSPERFAT
	dw 3
at BPB_SECTORSPERTRACK
	dw 9
at BPB_HEADS
	dw 2
at BPB_HIDDENSECTORS
	dw 0
	dw 0
at BPB_BIGTOTALSECTORS
	dw 0
	dw 0
iend



boot2:
	%include "boot11.mac"
	db	512 - ($ - boot2) dup(?)
REORG2	LABEL	BYTE


%include "bootform.mac"


BOOT	LABEL	BYTE
	%include "boot.mac"

scratchBuffer db 512 dup(?)

ptr_msgWhatIsVolumeId? dw offset msgWhatIsVolumeId?
	dw	offset driveLetter


FAT12_String db "FAT12   "
FAT16_String db "FAT16   "

Media_ID_Buffer: ; NASM structure instance
Media_ID_size equ Media_ID_struc_size	; NASM port equate
istruc Media_ID
at Media_ID_Volume_Label,	times 11 db 32
at Media_ID_File_System,	times 8 db 32
iend


section code	; data	ends
;-------------------------------------------------------------------------------
; AccessDisk:
;    Called whenever a different disk is about to be accessed
;
;    Input:
;	al - drive letter (0=A, 1=B, ...)
;
;    Output:
;	none
AccessDisk proc near

	push	ax				; save drive letter
	mov	bl,al				; Set up GENERIC IOCTL REQUEST preamble
	inc	bl
IOCTL equ IOCtl	; NASM port equate
	mov	ax,(IOCTL << 8) + Set_Drv_Owner ; IOCTL function
	int	21h
	pop	ax
	return

AccessDisk endp

;-------------------------------------------------------------------------------
;    CheckSwitches:
;	Check switches against device parameters
;	Use switches to modify device parameters
;
;    Input:
;	deviceParameters
;
;    Output:
;	deviceParameters may be modified
;	Carry set if error
;
;
;  /B <> /S
;  /B/8 <> /V
;  /1 or /8 <> /T/N
;


CHeckSwitches equ CheckSwitches	; NASM port label
Public	CHeckSwitches
CheckSwitches proc near


; Disallow /C
						;lea	 dx, msgInvalidParameter					 ;AC000;
	test	word [switchmap], SWITCH_C
	jz	CheckExcl
	Message msgInvalidParameter		;AC000;
SwitchError:
						;call	 PrintString							 ;AC000;
	stc
	ret

CheckExcl:

SwitchMap equ switchmap	; NASM port label
Switch_F equ SWITCH_F	; NASM port equate
	test	word [SwitchMap],Switch_F		;Specify size?			;AN001;
;	$IF	NZ				;Yes				;AN001;
	JZ DD_IF1
Switch_1 equ SWITCH_1	; NASM port equate
Switch_8 equ SWITCH_8	; NASM port equate
Switch_4 equ SWITCH_4	; NASM port equate
Switch_N equ SWITCH_N	; NASM port equate
Switch_T equ SWITCH_T	; NASM port equate
	   test    word [SwitchMap],(Switch_1+Switch_8+Switch_4+Switch_N+Switch_T) ;AN001;
;	   $IF	   NZ				;/F replaces above switches	;AN001;
	   JZ DD_IF2
	      Message msgIncompatibleParameters ;Print error			;AN001;
Yes equ YES	; NASM port equate
	      mov     byte [Fatal_Error],Yes		;Force exit			;AN001;
;	   $ELSE				;				;AN001;
	   JMP SHORT DD_EN2
DD_IF2:
	      call    Size_To_Switch		;Go set switches based		;AN001;
;	   $ENDIF				; on the size			;AN001;
DD_EN2:
;	$ENDIF					;				;AN001;
DD_IF1:
	cmp	byte [Fatal_Error],NO			;				;AN007;
;	$IF	E				;				;AN007;
	JNE DD_IF6
	   call    Check_Switch_8_B		;				;ac007
	   call    Check_T_N
;	$ENDIF					;				;AN009;
DD_IF6:
	cmp	byte [Fatal_Error],Yes 		;				;AN007;
	jne	ExclChkDone			;				;AN007;
	stc					;				;AN007;
	ret					;				;AN007;

ExclChkDone:
; Patch the boot sector so that the boot strap loader knows what disk to
; boot from
;	 mov	 Boot.Boot_PhyDrv, 00H		 ;AC000;
Boot equ BOOT	; NASM port label
	mov	byte [Boot + EXT_PHYDRV], 00H		;AN00?;

DP_DeviceType equ DP_DEVICETYPE	; NASM port equate
	cmp	byte [deviceParameters + DP_DeviceType], DEV_HARDDISK
	jne	CheckFor5InchDrives

; Formatting a hard disk so we must repatch the boot sector
;	 mov	 Boot.Boot_PhyDrv, 80H		 ;AC000;
	mov	byte [Boot + EXT_PHYDRV], 80H		;AN00?;
SWITCH_Select equ SWITCH_SELECT	; NASM port equate
Switch_B equ SWITCH_B	; NASM port equate
	test	word [switchmap], ~ (SWITCH_S | SWITCH_V | SWITCH_Select | SWITCH_AUTOTEST | Switch_B) ;AN007;
	jz	SwitchesOkForHardDisk

	Message msgIncompatibleParametersForHardDisk ;			     ;AC000;
	stc
	ret

; Before checking the Volume Id we need to verify that a valid one exists
; We assume that unless a valid boot sector exists on the target disk, no
; valid Volume Id can exist.

SwitchesOkForHardDisk:
	SaveReg <ax,bx,cx,dx,ds>
	mov	al,[drive]
LogBootSect equ LOGBOOTSECT	; NASM port equate
	mov	cx,LogBootSect
	xor	dx,dx
	lea	bx,[scratchBuffer]		; ScratchBuffer := Absolute_Read_Disk(
						;INT	 25h				 ;		      Logical_sec_1 )

						;Assume Dir for vol ID exists in 1st 32mb of partition

	mov	word [Read_Write_Relative + Start_Sector_High],0
	call	Read_Disk			;				;AC000;
						;	on the stack. We throw them away

	jnc	CheckSignature
	stc
	RestoreReg <ds,dx,cx,bx,ax>
	ret

CheckSignature: 				; IF (Boot.Boot_Signature != aa55)

ScratchBuffer equ scratchBuffer	; NASM port label
	mov	ax, word ptr [ScratchBuffer + Boot_Signature] ;AC000;
	cmp	ax, 0aa55h			;Find a valid boot record?
	RestoreReg <ds,dx,cx,bx,ax>
	clc					;No, so no need to check label
;	$IF	Z				;No further checking needed	;AC000;
	JNZ DD_IF8
	   test    word [SwitchMap],(SWITCH_Select | SWITCH_AUTOTEST) ;Should we prompt for vol label?;AN000;
;	   $IF	   Z				;Yes, if /Select not entered	;AN000;
	   JNZ DD_IF9
	      call    CheckVolumeId		;Go ask user for vol label	;     ;
;	   $ELSE				;/Select entered		;AN000;
	   JMP SHORT DD_EN9
DD_IF9:
	      clc				;CLC indicates passed label test;AN000;
;	   $ENDIF				; for the return		;AN000;
DD_EN9:
;	$ENDIF
DD_IF8:
	return

Incomp_Message: 				;an000; fix PTM 809

	Message msgIncompatibleParameters	;an000; print incompatible parms
	stc					;an000; signal error
	return					;an000; return to caller

Print_And_Return:
						;call	 PrintString			 ;				 ;AC000;
	stc
	return


CheckFor5InchDrives:

						;If drive type is anything other than 48 or 96, then only /V/S/H/N/T allowed
	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH96TPI
	je	Got96

	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH
	je	Got48

	xor	ax,ax								;an000; dms;clear reg
Switch_V equ SWITCH_V	; NASM port equate
Switch_S equ SWITCH_S	; NASM port equate
	or	ax,(Switch_V | Switch_S | Switch_N | Switch_T | Switch_B)	;an000; dms;set up switch mask
Switch_Backup equ SWITCH_BACKUP	; NASM port equate
Switch_Select equ SWITCH_SELECT	; NASM port equate
Switch_Autotest equ SWITCH_AUTOTEST	; NASM port equate
	or	ax,(Switch_Backup | Switch_Select | Switch_Autotest)		;an000; dms;
%IF ShipDisk
Switch_Z equ SWITCH_Z	; NASM port equate
	or	ax,Switch_Z							;an000; dms;
%ENDIF
	not	ax								;an000; dms;
	test	[switchmap],ax							;an000; dms;invalid switch?
	jz	Goto_Got_BPB1							;an000;dms;continue format
	Message msgParametersNotSupportedByDrive ;			 ;AC000;
	jmp	short Print_And_Return

Goto_Got_BPB1:
	jmp	Goto_Got_BPB
	nop	; identicalise
						; We have a 96tpi floppy drive
						; /4 allows just about all switches however, /1 requires /4
Got96:
;;;DMS;;test	switchmap, SWITCH_8		;an000; If /8 we have an error
;;;DMS;;jnz	Incomp_message			;an000; tell user error

	test	word [switchmap], SWITCH_4
	jnz	CheckForInterestingSwitches	;If /4 check /N/T/V/S

	test	word [switchmap], SWITCH_1		;If /1 and /4 check others
	jz	Got48

						;If only /1 with no /4, see if /N/T
	test	word [SwitchMap],(Switch_N | Switch_T)
	jnz	CheckForInterestingSwitches

Incomp_message equ Incomp_Message	; NASM port label
	jmp	Incomp_message			;an000; tell user error occurred

Got48:
						;Ignore /4 for non-96tpi 5 1/4" drives
	and	word [switchmap], ~ SWITCH_4

						;Ignore /1 if drive has only one head and not /8
BPB_Heads equ BPB_HEADS	; NASM port equate
	cmp	word [deviceParameters + DP_BPB + BPB_Heads], 1
	ja	CheckForInterestingSwitches
	test	word [switchmap], SWITCH_8
	jz	CheckForInterestingSwitches
	and	word [switchmap], ~ SWITCH_1

						;Are any interesting switches set?
CheckForInterestingSwitches:
	test	word [switchmap], ~ (SWITCH_V | SWITCH_S | Switch_Backup | SWITCH_SELECT | SWITCH_AUTOTEST | Switch_B)
	jz	Goto_EndSwitchCheck		;No, everything ok

						;At this point there are switches other than /v/s/h
	test	word [SwitchMap],(SWITCH_N | SWITCH_T)
	jz	Use_48tpi			;Not /n/t, so must be /b/1/8/4

						;We've got /N/T, see if there are others
	test	word [SwitchMap], ~ (SWITCH_N | SWITCH_T | SWITCH_V | SWITCH_S | Switch_Backup | SWITCH_SELECT | SWITCH_AUTOTEST)
	jz	NT_Compatible			;Nope, all is well

						;If 96tpi drive and /1 exists with /N/T, then okay, otherwise error
	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH96TPI
	jne	Bad_NT_Combo

	test	word [SwitchMap], ~ (SWITCH_1 | SWITCH_N | SWITCH_T | SWITCH_V)
	jnz	Bad_NT_Combo
	test	word [SwitchMap], ~ (SWITCH_S | Switch_Backup | SWITCH_SELECT | Switch_Autotest)
	jz	Goto_Got_BPB

Bad_NT_Combo:
	Message msgIncompatibleParameters	;				;AC000;
	jmp	Print_And_Return

Goto_Got_BPB:
Got_BPB_Ok equ Got_BPB_OK	; NASM port label
	jmp	Got_BPB_Ok			;Sleazy, but je won't reach it
	nop	; identicalise

Goto_EndSwitchCheck:
	jmp	EndSwitchCheck
						;There is a problem with /N/T in that IBMBIO will default to a BPB with the
						;media byte set to F0 (other) if the /N/T combo is used for the format. This
						;will cause problems if we are creating a media that has an assigned media
						;byte, i.e. 160,180,320,360, or 720k media using /N/T. To avoid this problem,
						;if we detect a /N/T combo that would correspond to one of these medias, then
						; we will set things up using the /4/1/8 switches instead of the /N/T
						; MT - 7/17/86 PTR 33D0110

						; Combo's that we look for - 96tpi drive @ /T:40, /N:9
						;			     96tpi drive @ /T:40, /N:8
						;
						; Look for this combo after we set everything up with the /T/N routine
						;			     1.44 drive  @ /T:80, /N:9

NT_Compatible:
	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH96TPI
	jne	Goto_Got_BPB

	cmp	word [TrackCnt],40			;Look for 40 tracks
	jne	Got_BPB_Ok

	cmp	word [NumSectors],9			;9 sectors?
	je	Found_48tpi_Type

	cmp	word [NumSectors],8			;8 sectors?
	jne	Goto_Got_BPB			;Nope, different type, let it go thru

	or	word [SwitchMap],SWITCH_8		;Yes, turn on /8 switch

Found_48tpi_Type:
	and	word [SwitchMap],~ (SWITCH_N | SWITCH_T) ;Turn off /T/N

;******End PTR fix

; if we have a 96 tpi drive then we will be using it in 48 tpi mode
Use_48tpi:
	cmp	byte [deviceParameters + DP_DeviceType], DEV_5INCH96TPI
	jne	Not96tpi

DP_MediaType equ DP_MEDIATYPE	; NASM port equate
	mov	byte [deviceParameters + DP_MediaType], 1
DP_Cylinders equ DP_CYLINDERS	; NASM port equate
	mov	word [deviceParameters + DP_Cylinders], 40
Not96tpi:

; Since we know we are formatting in 48 tpi mode turn on /4 switch
; (We use this info in LastChanceToSaveIt)
	or	word [switchmap], SWITCH_4

; At this point we know that we will require a special BPB
; It will be one of:
;    0) 9 track 2 sides - if no switches
;    1) 9 track 1 side	- if only /1 specified
;    2) 8 track 2 sides - if only /8 specified
;    3) 8 track 1 side	- if /8 and /1 specified
;
Get_BPBs:
; ax is used to keep track of which of the above BPB's we want
	xor	ax, ax

NotSlashB:

	test	word [switchmap], SWITCH_1
	jz	NotSingleSided
	add	ax, 1
NotSingleSided:

	test	word [switchmap], SWITCH_8
	jz	Not8SectorsPerTrack
	add	ax, 2
; /8 implies Old_Dir = TRUE
	mov	byte [Old_Dir],TRUE
Not8SectorsPerTrack:

; Ok now we know which BPB to use so lets move it to the device parameters

a_BPB_struc_size equ A_BPB_struc_size	; NASM port equate
	mov	bx, a_BPB_struc_size
	mul	bx
CustomBPBs equ customBPBs	; NASM port label
	lea	si, [CustomBPBs]
	add	si, ax
	lea	di, [deviceParameters + DP_BPB]
	mov	cx, a_BPB_struc_size
	push	ds
	pop	es
	repnz	movsb

;*****************************************************************
;*  /N/T DCR stuff.  Possible flaw exists if we are dealing with a
;*  HardDisk. If they support the  "custom format" features for
;*  Harddisks too, then CheckForInterestingSwitches should
;*  consider /n/t UNinteresting, and instead of returning
;*  after setting up the custom BPB we fall through and do our
;*  Harddisk Check.
Got_BPB_OK:
	test	word [switchmap],SWITCH_N+SWITCH_T
	jnz	Setup_Stuff
	jmp	EndSwitchCheck
Setup_Stuff:
; Set up NumSectors and SectorsPerTrack entries correctly
	test	word [switchmap],SWITCH_N
	jz	No_Custom_Seclim
	mov	ax,word ptr [NumSectors]
DeviceParameters equ deviceParameters	; NASM port label
BPB_SectorsPerTrack equ BPB_SECTORSPERTRACK	; NASM port equate
	mov	[DeviceParameters + DP_BPB + BPB_SectorsPerTrack],ax
	jmp	short Handle_Cyln
No_Custom_Seclim:
	mov	ax,[deviceParameters + DP_BPB + BPB_SectorsPerTrack]
	mov	[NumSectors],ax

Handle_Cyln:
	test	word [switchmap],SWITCH_T
	jz	No_Custom_Cyln
; Set up TrackCnt and Cylinders entries correctly
	mov	ax,[TrackCnt]
	mov	[DeviceParameters + DP_Cylinders],ax
	jmp	short Check_720
No_Custom_Cyln:
	mov	ax,[DeviceParameters + DP_Cylinders]
	mov	[TrackCnt],ax

;****PTM P868  - Always making 3 1/2 media byte 0F0h. If 720, then set to
;		 0F9h and use the DOS 3.20 BPB. Should check all drives
;		 at this point (Make sure not 5 inch just for future
;		 protection)
;		 We will use the known BPB info for 720 3 1/2 diskettes for
;		 this special case. All other new diskette media will use the
;		 calculations that follow Calc_Total for BPB info.
; Fix MT  11/12/86

Check_720:

	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH96TPI
	je	Calc_Total

	cmp	byte [deviceParameters + DP_DeviceType],DEV_5INCH
	je	Calc_Total

	cmp	word [TrackCnt],80
	jne	Calc_Total

	cmp	word [NumSectors],9
	jne	Calc_Total

; At this point we know we have a 3 1/2 720kb diskette to format. Use the
; built in BPB rather than the one handed to us by DOS, because the DOS one
; will be based on the default for that drive, and it can be different from
; what we used in DOS 3.20 for the 720's. Short sighted on our part to use
; 0F9h as the media byte, should have use 0F0h (OTHER) and then we wouldn't
; have this problem.

	SaveReg <ds,es,si,di,cx>


	mov	cx,data			;Setup seg regs, just in case they ain't!
	mov	ds,cx
	mov	es,cx

	mov	si,offset BPB720		;Copy the BPB!
	mov	di,offset deviceParameters + DP_BPB
	mov	cx,a_BPB_struc_size
	rep	movsb
	RestoreReg <cx,di,si,es,ds>
	jmp	EndSwitchCheck
	nop	; identicalise

;End PTM P868 fix ****************************************

Calc_Total:
	mov	ax,[NumSectors]
	mov	bx,[DeviceParameters + DP_BPB + BPB_Heads]
	mul	bl				; AX = # of sectors * # of heads
	mul	word [TrackCnt]			; DX:AX = Total Sectors
	or	dx,dx
	jnz	Got_BigTotalSectors
BPB_TotalSectors equ BPB_TOTALSECTORS	; NASM port equate
	mov	[DeviceParameters + DP_BPB + BPB_TotalSectors],ax
	jmp	short Set_BPB
Got_BigTotalSectors:
BPB_BigTotalSectors equ BPB_BIGTOTALSECTORS	; NASM port equate
	mov	[DeviceParameters + DP_BPB + BPB_BigTotalSectors],ax
	mov	[DeviceParameters + DP_BPB + BPB_BigTotalSectors+2],dx
	push	dx				; preserve dx for further use
	xor	dx,dx
	mov	[DeviceParameters + DP_BPB + BPB_TotalSectors],dx
	pop	dx

Set_BPB:
; We calculate the number of sectors required in a FAT. This is done as:
; # of FAT Sectors = TotalSectors / SectorsPerCluster * # of bytes in FAT to
; represent one cluster (i.e. 3/2) / BytesPerSector (i.e. 512)
	xor	bx,bx
BPB_SectorsPerCluster equ BPB_SECTORSPERCLUSTER	; NASM port equate
	mov	bl,[DeviceParameters + DP_BPB + BPB_SectorsPerCluster]
	div	bx				; DX:AX contains # of clusters
; now multiply by 3/2
	mov	bx,3
	mul	bx
	mov	bx,2
	div	bx
	xor	dx,dx				; throw away modulo
; now divide by 512
	mov	bx,512
	div	bx
; dx:ax contains number of FAT sectors necessary
	inc	ax				; Go one higher
BPB_SectorsPerFAT equ BPB_SECTORSPERFAT	; NASM port equate
	mov	[DeviceParameters + DP_BPB + BPB_SectorsPerFAT],ax
	mov	byte [DeviceParameters + DP_MediaType],0
BPB_MediaDescriptor equ BPB_MEDIADESCRIPTOR	; NASM port equate
	mov	byte [DeviceParameters + DP_BPB + BPB_MediaDescriptor],Custom_Media


EndSwitchCheck:
	clc
	return

CheckSwitches endp

;*****************************************************************************
;Routine name: Size_To_Switch
;*****************************************************************************
;
;Description: Given the SizeMap field as input indicating the SIZE= value
;	      entered, validate that the specified size is valid for the
;	      drive, and if so, turn on the appropriate data fields and
;	      switches that would be turned on by the equivilent command line
;	      using only switchs. All defined DOS 4.00 sizes are hardcoded,
;	      in case a drive type of other is encountered that doesn't
;	      qualify as a DOS 4.00 defined drive. Exit with error message if
;	      unsupported drive. The switches will be setup for the CheckSwitches
;	      routine to sort out, using existing switch matrix logic.
;
;Called Procedures: Low_Density_Drive
;		    High_Capacity_Drive
;		    720k_Drives
;		    Other_Drives
;
;Change History: Created	8/1/87	       MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 SwitchMap = appropriate Switch_?? values turned on
;	 TrackCnt, NumSectors set if Switch_T,Switch_N turned on
;*****************************************************************************


Procedure Size_To_Switch

	cmp	byte [SizeMap],0			;Are there sizes entered?	 ;AN001;
;	$IF	NE				;Yes				;AN001;
	JE DD_IF13
	   cmp	   byte [deviceParameters + DP_DeviceType],DEV_HARDDISK ;AN000;		;AN001;
;	   $IF	   E				;No size for fixed disk 	;AN001;
	   JNE DD_IF14
	      Message msgIncompatibleParametersForHardDisk ;			;AN001;
;	   $ELSE				;Diskette, see what type	;AN001;
	   JMP SHORT DD_EN14
DD_IF14:
	      cmp     byte [deviceParameters + DP_DeviceType],DEV_5INCH ;	;AN001;
;	      $IF     E 			;Found 180/360k drive		;AN001;
	      JNE DD_IF16
		 call	 Low_Density_Drive	;Go set switches		;AN001;
;	      $ELSE				;Check for 96TPI		;AN001;
	      JMP SHORT DD_EN16
DD_IF16:
		 cmp	 byte [deviceParameters + DP_DeviceType],DEV_5INCH96TPI ;AN001; ;
;		 $IF	 E			;Found it			;AN001;
		 JNE DD_IF18
		    call    High_Capacity_Drive ;				;AN001;
;		 $ELSE				;				;AN001;
		 JMP SHORT DD_EN18
DD_IF18:
		    cmp     byte [deviceParameters + DP_DeviceType],DEV_3INCH720KB ;AN0001;
;		    $IF     E			;Found 720k drive		;AN001;
		    JNE DD_IF20
		       call    Small_Drives	;				;AN001;
;		    $ELSE			;				;AN001;
		    JMP SHORT DD_EN20
DD_IF20:
		       cmp     byte [deviceParameters + DP_DeviceType],DEV_OTHER ;AN001;
;		       $IF     E		;Must be 1.44mb 		;AN001;
		       JNE DD_IF22
			  call	  Other_Drives	;				;AN001;
;		       $ELSE			;				;AN001;
		       JMP SHORT DD_EN22
DD_IF22:
			  Message msgParametersNotSupportedByDrive ;		;AN001;
			  mov	  byte [Fatal_Error],Yes ;				;AN001;
;		       $ENDIF			;				;AN001;
DD_EN22:
;		    $ENDIF			;				;AN001;
DD_EN20:
;		 $ENDIF 			;				;AN001;
DD_EN18:
;	      $ENDIF				;				;AN001;
DD_EN16:
;	   $ENDIF				;				;AN001;
DD_EN14:
;	$ENDIF					;				;AN001;
DD_IF13:
	cmp	byte [Fatal_Error],Yes 		;				;AN001;
;	$IF	E				;				;AN001;
	JNE DD_IF30
	   Message msgIncompatibleParameters	;				;AN001;
;	$ENDIF					;				;AN001;
DD_IF30:

	cmp	byte [deviceParameters + DP_DeviceType],DEV_HARDDISK			;an001;
;	$if	e								;an001;
	JNE DD_IF32
		mov	byte [Fatal_Error],Yes 					;an001;
;	$endif									;an001;
DD_IF32:

	and	word [SwitchMap],~ Switch_F		;Turn off /F so doesn't effect  ;AN001;
	ret					; following logic		;AN001;

Size_To_Switch endp

;*****************************************************************************
;Routine name: High_Capacity_Drive
;*****************************************************************************
;
;Description: See if 1.2mb diskette, or one of the other 5 1/4 sizes. Turn
;	      on /4 if 360k or lower
;
;Called Procedures: Low_Density_Drive
;
;Change History: Created	8/1/87	       MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 SwitchMap = Switch_4 if 360k or lowere
;*****************************************************************************

Procedure High_Capacity_Drive			;

	test	byte [SizeMap],Size_1200		;1.2mb diskette?		 ;AN001;
;	$IF	Z				;Nope				;AN001;
	JNZ DD_IF34
	   call    Low_Density_Drive		;Check for /4 valid types	;AN001;
No equ NO	; NASM port equate
	   cmp	   byte [Fatal_Error], No		;Find 160/180/320/360k? 	;AN001;
;	   $IF	   E				;Yes				;AN001;
	   JNE DD_IF35
	      or      word [SwitchMap],Switch_4	;Turn on /4 switch		;AN001;
;	   $ELSE				;Did not find valid size	;AN001;
	   JMP SHORT DD_EN35
DD_IF35:
	      mov     byte [Fatal_Error],Yes		;Indicate invalid device	;AN001;
;	   $ENDIF				;				;AN001;
DD_EN35:
;	$ENDIF					;				;AN001;
DD_IF34:
	ret					;				;AN001;

High_Capacity_Drive endp

;*****************************************************************************
;Routine name: Low_Density_Drive
;*****************************************************************************
;
;Description: See if 360k diskete or one of the other 5 1/4 sizes. Turn
;	      on the /1/8 switch to match sizes
;
;Called Procedures: Low_Density_Drive
;
;Change History: Created	8/1/87	       MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 SwitchMap = Switch_1, Switch_8 to define size
;
;	360k = No switch
;	320k = Switch_8
;	180k = Switch_1
;	160k = Switch_1 + Switch_8
;*****************************************************************************


Procedure Low_Density_Drive			;				;AN000;
						;
	test	byte [SizeMap],Size_160		;				 ;AN001;
;	$IF	NZ				;				;AN001;
	JZ DD_IF39
	   or	   word [SwitchMap],Switch_1+Switch_8	;				;AN001;
;	$ELSE					;				;AN001;
	JMP SHORT DD_EN39
DD_IF39:
	   test    byte [SizeMap],Size_180		;				 ;AN001;
;	   $IF	   NZ				;				;AN001;
	   JZ DD_IF41
	      or      word [SwitchMap],Switch_1	;				;AN001;
;	   $ELSE				;				;AN001;
	   JMP SHORT DD_EN41
DD_IF41:
	      test    byte [SizeMap],Size_320		;				 ;AN001;
;	      $IF     NZ			;				;AN001;
	      JZ DD_IF43
		 or	 word [SwitchMap],Switch_8	;				;AN001;
;	      $ELSE				;				;AN001;
	      JMP SHORT DD_EN43
DD_IF43:
		 test	 byte [SizeMap],Size_360	;				 ;AN001;
;		 $IF	 Z			;None of the above, not valid	;AN001;
		 JNZ DD_IF45
		    mov     byte [Fatal_Error],Yes	;				;AN001;
;		 $ENDIF 			;				;AN001;
DD_IF45:
;	      $ENDIF				;				;AN001;
DD_EN43:
;	   $ENDIF				;				;AN001;
DD_EN41:
;	$ENDIF					;				;AN001;
DD_EN39:
	ret					;				;AN001;

Low_Density_Drive endp

;*****************************************************************************
;Routine name: Small_Drives
;*****************************************************************************
;
;Description: See if 720k media in 720 drive, set up /T/N if so, otherwise
;	      error
;
;Called Procedures: None
;
;Change History: Created	8/1/87	       MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 SwitchMap
;	 TrackCnt
;	 NumSectors
;	720k = /T:80 /N:9
;*****************************************************************************

Procedure Small_Drives				;				;AN000;

	test	byte [SizeMap],Size_720		;Ask for 720k?			 ;AN001;
;	$IF	Z				;Nope, thats all drive can do	;AN001;
	JNZ DD_IF50
	   mov	   byte [Fatal_Error],Yes		;Indicate error 		;AN001;
;	$ENDIF					;				;AN001;
DD_IF50:
	ret					;				;AN001;

Small_Drives endp


;*****************************************************************************
;Routine name: Other_Drives
;*****************************************************************************
;
;Description: See if 1.44 media or 720k media, setup /t/n, otherwise error
;
;Called Procedures: Small_Drives
;
;Change History: Created	8/1/87	       MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 SwitchMap
;	 TrackCnt
;	 NumSectors
;	720k = /T:80 /N:9
;*****************************************************************************

Procedure Other_Drives				;				;AN001;

	test	byte [SizeMap],Size_1440		;Ask for 1.44mb diskette?	 ;AN001;
;	$IF	Z				;Nope				;AN001;
	JNZ DD_IF52
	   call    Small_Drives 		;See if 720k		       ;AN001;
	   cmp	   byte [Fatal_Error],No		;Fatal_error=Yes if not 	;AN001;
;	   $IF	   E				;Got 720k			;AN001;
	   JNE DD_IF53
	      or      word [SwitchMap],Switch_T+Switch_N ;Turn on /T:80 /N:9		;AN001;
	      mov     word [TrackCnt],80		;				;AN001;
	      mov     word [NumSectors],9		;				;AN001;
;	   $ENDIF				;				;AN001;
DD_IF53:
;	$ELSE					;Asked for 1.44mb		;AN001;
	JMP SHORT DD_EN52
DD_IF52:
	   or	   word [SwitchMap],Switch_T+Switch_N	;Turn on /T:80 /N:18;		;AN001;
	   mov	   word [TrackCnt],80			;This will protect SIZE=1440	;AN001;
	   mov	   word [NumSectors],18		; from non-standard drives with ;AN001;
;	$ENDIF					; type of 'other'		;AN001;
DD_EN52:
	ret					;				;AN001;

Other_Drives endp


;*****************************************************************************
;Routine name:Check_T_N
;*****************************************************************************
;
;Description: Make sure than if /T is entered, /N is also entered
;
;Called Procedures:  None
;
;Change History: Created	8/23/87  MT
;
;Input: SizeMap
;	Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;*****************************************************************************

Procedure Check_T_N

	test	word [SwitchMap],Switch_N		;Make sure /T entered if /N	;AN009;
;	$IF	NZ,AND				;				;AN009;
	JZ DD_IF57
	test	word [SwitchMap],Switch_T		;				;AN009;
;	$IF	Z				;				;AN009;
	JNZ DD_IF57
	   Message msgBad_T_N			;It wasn't, so barf             ;AN009;
	   mov	   byte [Fatal_Error],Yes		;Indicate error 		;AN009;
;	$ELSE					;				;AN009;
	JMP SHORT DD_EN57
DD_IF57:
	   test    word [SwitchMap],Switch_T		;Make sure /N entered if /T	;AN009;
;	   $IF	   NZ,AND			;				;AN009;
	   JZ DD_IF59
	   test    word [SwitchMap],Switch_N		;				;AN009;
;	   $IF	   Z				;It wasn't, so also barf        ;AN009;
	   JNZ DD_IF59
	      Message msgBad_T_N		;				;AN009;
	      mov     byte [Fatal_Error],Yes		;Indicate error 		;AN009;
;	   $ENDIF				;				;AN009;
DD_IF59:
;	$ENDIF					;				;AN009;
DD_EN57:
	ret

Check_T_N endp



;-------------------------------------------------------------------------------
;    LastChanceToSaveIt:
;	This routine is called when an error is detected in DiskFormat.
;	If it returns with carry not set then DiskFormat is restarted.
;	It gives the oem one last chance to try formatting differently.
;	fLastChance gets set Then to prevent multiple prompts from being
;	issued for the same diskette.
;
;	Algorithm:
;		IF (error_loc == Track_0_Head_1) &
;			  ( Device_type < 96TPI )
;		   THEN
;			fLastChance  := TRUE
;			try formatting 48TPI_Single_Sided
;		   ELSE return ERROR
;
LastChanceToSaveIt proc near

	cmp	word [currentCylinder], 0
	jne	WeCanNotIgnoreThisError
	cmp	word [currentHead], 1
	jne	WeCanNotIgnoreThisError

	cmp	byte [deviceParameters + DP_DeviceType], DEV_5INCH
	ja	WeCanNotIgnoreThisError

	mov	byte [fLastChance], TRUE

	or	word [switchmap], SWITCH_1
	call	CheckSwitches
	clc
	ret

WeCanNotIgnoreThisError:
	stc
	ret

LastChanceToSaveIt endp

;-------------------------------------------------------------------------------


;*****************************************************************************
;Routine name WriteBootSector
;*****************************************************************************
;
;DescriptioN: Copy EBPB information to boot record provided by Get recommended
;	      BPB, write out boot record, error
;	      if can write it, then fill in new fields (id, etc..). The volume
;	      label will not be added at this time, but will be set by the
;	      create volume label call later.
;
;Called Procedures: Message (macro)
;
;Change History: Created	4/20/87 	MT
;
;Input: DeviceParameters.DP_BPB
;
;Output: CY clear if ok
;	 CY set if error writing boot or media_id info
;
;Psuedocode
;----------
;
;	Copy recommended EBPB information to canned boot record
;	Write boot record out (INT 26h)
;	IF error
;	   Display boot error message
;	   stc
;	ELSE
;	   Compute serial id and put into field (CALL Create_Serial_ID)
;	   Point at 'FAT_12' string for file system type
;	   IF fBIGFat	 ;16 bit FAT
;	      Point at 'FAT_16' for file system type
;	   ENDIF
;	   Copy file system string into media_id field
;	   Write info to boot (INT 21h AX=440Dh, CX=0843h SET MEDIA_ID)
;	   IF error (CY set)
;	      Display boot error message
;	      stc
;	   ELSE
;	      clc
;	   ENDIF
;	ENDIF
;	ret
;*****************************************************************************

Procedure WriteBootSector			;				;AN000;

	lea	si, [deviceParameters + DP_BPB]	;Copy EBPB to the boot record	;
	lea	di, [Boot + EXT_BOOT_BPB]		;  "  " 	"  "		;AC000:
	mov	cx, EXT_BPB_INFO_struc_size		;  "  " 	"  "		;AC000:
	push	ds				;Set ES=DS (data segment)	;     ;
	pop	es				;  "  " 	"  "		;     ;
	repnz	movsb				;Do the copy			;     ;
						;Write out the boot record	;     ;
	mov	al, [drive]			;Get drive letter		;     ;
	mov	cx, 1				;Specify 1 sector		;     ;
	xor	dx, dx				;Logical sector 0		;     ;
	lea	bx, [boot]			;Point at boot record		;     ;
;Boot record in 1st 32mb of partition
	mov	word [Read_Write_Relative + Start_Sector_High],0 ;			;AN000;
	call	Write_Disk			;				;AC000;
;	$IF	C				;Error on write 		;AC000;
	JNC DD_IF62
	   Message msgBootWriteError		;Print error			;     ;
	   stc					;CY=1 means error		;     ;
;	$ELSE					;Good write of boot record!	;AN000;
	JMP SHORT DD_EN62
DD_IF62:
	   mov	   cx,[Dummy_Label_Size]		;Put in dummy volume label size ;ac026;ac028;
	   lea	   si,[Dummy_Label]		;  "  "       "  "		;AN000;
	   lea	   di,[Media_ID_Buffer + Media_ID_Volume_Label]  ;	"  "	   "  " ;AN000;
	   rep	   movsb			;  "  "       "  "		;AN000;
	   call    Create_Serial_ID		;Go create unique ID number	;AN000;
	   lea	   si,[FAT12_String]		;Assume 12 bit FAT		;AN000;
	   cmp	   byte [fBigFAT],TRUE 		;Is it? 			;AN000;
;	   $IF	   E				;Not if fBigFat is set....	;AN000;
	   JNE DD_IF64
	      lea     si,[FAT16_String]		;Got 16 bit FAT 		;AN000;
;	   $ENDIF				;				;AN000;
DD_IF64:
						;Copy file system string	;     ;
	   mov	   cx,8 			; to buffer			;AN000;
	   lea	   di,[Media_ID_Buffer + Media_ID_File_System] ;	 "  "		;AN000;
	   repnz   movsb			;    "   "	  "  "		;AN000;
Generic_IOCtl equ GENERIC_IOCTL	; NASM port equate
	   mov	   al,Generic_IOCtl		;Generic IOCtl call		;AN000;
Drive equ drive	; NASM port label
	   mov	   bl,[Drive]			;Get drive			;AN000;
	   inc	   bl				;Make it 1 based		;AN000;
	   xor	   bh,bh			;Set bh=0			;AN000;
RawIO equ RAWIO	; NASM port equate
	   mov	   ch,RawIO			;Set Media ID call		;AN000;
Set_Media_ID equ SET_MEDIA_ID	; NASM port equate
	   mov	   cl,Set_Media_ID
	   mov	   dx,offset Media_ID_Buffer	;Point at buffer		;AN000;
	   DOS_Call IOCtl			;Do function call		;AN000;
;	   $IF	   C				;Error ? (Write or old boot rec);AN000;
	   JNC DD_IF66
	      Message msgBootWriteError 	;Indicate we couldn't write it  ;AN000;
	      stc				;CY=1 for error return		;AN000;
;	   $ELSE				;Set Media ID okay		;AN000;
	   JMP SHORT DD_EN66
DD_IF66:
	      clc				;CY=0 for good return		;AN000;
;	   $ENDIF				;				;AN000;
DD_EN66:
;	$ENDIF					;				;AN000;
DD_EN62:
	ret					;				;AN000;

WriteBootSector endp				;				;AN000;


;*****************************************************************************
;Routine name Create_Serial_ID
;*****************************************************************************
;
;DescriptioN&gml Create unique 32 bit serial number by getting current date and
;	      time and then scrambling it around.
;
;Called Procedures: Message (macro)
;
;Change History&gml Created	   4/20/87	   MT
;
;Input&gml None
;
;Output&gml Media_ID_Buffer.Serial_Number = set
;	    AX,CX,DX destroyed
;	    Serial_Num_Low/High = Serial number generated
;
;Psuedocode
;----------
;
;	Get date (INT 21h, AH=2Bh)
;	Get time (INT 21h, AH=2Ch)
;	Serial_ID+0 = DX reg date + DX reg time
;	Serial_ID+2 = CX reg date + CX reg time
;	Serial_Num_Low = Serial_ID+2
;	Serial_Num_High = Serial_ID+0
;	ret
;*****************************************************************************

Procedure Create_Serial_ID			;				;AN000;

	DOS_Call Get_Date			;Get date from DOS		;AN000;
	push	cx				;Save results			;AN000;
	push	dx				;				;AN000;
	DOS_Call Get_Time			;Get_Time			;AN000;
	mov	ax,dx				;Scramble it			;AN000;
	pop	dx				;				;AN000;
	add	ax,dx				;				;AN000;
	mov	word ptr [Media_ID_Buffer + Media_ID_Serial_Number+2],ax ;		;AC004;
	mov	[Serial_Num_Low],ax		;				;AN000;
	mov	ax,cx				;				;AN000;
	pop	cx				;				;AN000;
	add	ax,cx				;				;AN000;
	mov	word ptr [Media_ID_Buffer + Media_ID_Serial_Number],ax ;		;AC004;
	mov	[Serial_Num_High],ax		;				;AN000;
	ret					;				;AN000;

Create_Serial_ID endp				;				;AN000;

;-------------------------------------------------------------------------------

; OemDone:
;
OemDone proc	near

; if /b write out a fake dos & bios
	test	word [switchmap], SWITCH_B
	jz	Switch8?
	call	WriteBogusDos
	retc

Switch8?:
	test	word [switchmap], SWITCH_8
	jz	HardDisk?
	call	ConvertToOldDirectoryFormat
	retc

HardDisk?:
	cmp	byte [deviceParameters + DP_DeviceType], DEV_HARDDISK
	clc
	retnz
	call	SetPartitionTable

	return

OemDone endp

;------------------------------------------------------------------------------

section data

	%if IBMCOPYRIGHT
biosFilename db "x:\ibmbio.com",0
dosFilename db	"x:\ibmdos.com",0
	%else
biosFilename db "x:\io.sys",0
dosFilename db	"x:\msdos.sys",0
	%endif

section code	; data	ends

; simple code to stuff bogus dos in old-style diskette.

BogusDos:
	push	cs
	pop	ds
	mov	al,20h
	out	20h,al				; turn on the timer so the disk motor
	mov	si,mesofs			; shuts off
	nop	; identicalise
sys_mess_loop:
	lodsb
%if IBMCOPYRIGHT
end_sys_loop:
%endif
	or	al,al
	jz	end_sys_loop
	mov	ah,14
	mov	bx,7
	int	16
	jmp	sys_mess_loop
%ifn IBMCOPYRIGHT
end_sys_loop:
	xor	ah, ah				; get next char function
	int	16h				; call keyboard services
	int	19h				; reboot
%endif

;=== Push trace listing source: boot.cl1
	%include "boot.cl1" ; NASM included file
;=== Pop trace listing source
sysmsg equ SYSMSG	; NASM port label
mesofs	equ	sysmsg - BogusDos

WriteBogusDos proc near

	mov	al,[driveLetter]
	mov	[biosFilename],al
	mov	[dosFilename],al
ATTR_HIDDEN equ attr_hidden	; NASM port equate
ATTR_SYSTEM equ attr_system	; NASM port equate
	mov	cx, ATTR_HIDDEN | ATTR_SYSTEM
	lea	dx, [biosFilename]
CREAT equ Creat	; NASM port equate
	mov	ah,CREAT
	int	21h
	mov	bx,ax
	mov	cx, BIOS_SIZE
	push	ds
	push	cs
	pop	ds
	assume	ds:code
	lea	dx, [BogusDos]
WRITE equ Write	; NASM port equate
	mov	ah,WRITE
	int	21h
	pop	ds
	assume	ds:data
CLOSE equ Close	; NASM port equate
	mov	ah,CLOSE
	int	21h
	mov	cx, ATTR_HIDDEN | ATTR_SYSTEM
	lea	dx, [dosFilename]
	mov	ah,CREAT
	int	21h
	mov	bx,ax
	mov	cx, DOS_SIZE
	lea	dx, [BogusDos]
	mov	ah,WRITE
	int	21h
	mov	ah,CLOSE
	int	21h
; Comunicate system size to the main format program
DOS equ Dos	; NASM port label
FileSizeInBytes equ fileSizeInBytes	; NASM port equate
	mov	word [DOS + FileSizeInBytes],DOS_SIZE				;an000; dms;get size of DOS
	mov	word [DOS + FileSizeInBytes+2],00h				;an000; dms;

	xor	dx,dx
	mov	ax,DOS_SIZE
	call	AddToSystemSize

	mov	word [Bios + FileSizeInBytes],BIOS_SIZE 			;an000; dms;get size of BIOS
	mov	word [Bios + FileSizeInBytes+2],00h				;an000; dms;

	xor	dx,dx
	mov	ax,BIOS_SIZE
	call	AddToSystemSize

	clc
	return

WriteBogusDos endp

;-------------------------------------------------------------------------------

ConvertToOldDirectoryFormat proc near

;
; convert to 1.1 directory
;
	mov	al,[drive]			; Get 1st sector of directory
	mov	cx,1				; 1.1 directory always starts on
	mov	dx,3				; sector 3
	lea	bx,[scratchBuffer]
;Root Directory always in 1st 32mb of partition
	mov	word [Read_Write_Relative + Start_Sector_High],0 ;		       ;AN000;
	call	Read_Disk			;				;AC000;
	jnc	DirectoryRead
	Message msgDirectoryReadError		;				;AC000;
	stc
	ret
DirectoryRead:

; fix attribute of ibmbio and ibmdos
	lea	bx,[scratchBuffer]
	mov	byte ptr [bx + dir_attr], ATTR_HIDDEN | ATTR_SYSTEM
	add	bx, dir_entry_struc_size
	mov	byte ptr [bx + dir_attr], ATTR_HIDDEN | ATTR_SYSTEM

wrtdir:
	mov	al,[drive]			; write out the directory
	cbw
	mov	cx,1
	mov	dx,3
	lea	bx,[scratchBuffer]
;Root Directory always in 1st 32mb of partition
	mov	word [Read_Write_Relative + Start_Sector_High],0 ;		       ;AN000;
	call	Write_Disk			;				;AC000;
	jnc	DirectoryWritten
	Message msgDirectoryWriteError		;				;AC000;
	stc
	ret
DirectoryWritten:

	test	word [switchmap], SWITCH_S		; Was system requested?
	retnz					; yes, don't write old boot sector
	mov	al,[drive]
	cbw
	mov	bx,offset boot2 		; no,  write old boot sector
	cmp	word [deviceParameters + DP_BPB + BPB_Heads], 1
	je	bootset8
	mov	word ptr [bx+3],0103h		; start address for double sided drives
bootset8:
	mov	cx,1
	xor	dx,dx
;Boot record in 1st 32mb of partition
	mov	word [Read_Write_Relative + Start_Sector_High],0 ;		       ;AN000;
	call	Write_Disk			;				;AC000;
	retnc

	Message msgBootWriteError		;				;AC000;
	stc
	ret

ConvertToOldDirectoryFormat endp

;-------------------------------------------------------------------------------

a_PartitionTableEntry struc
BootInd db	?
BegHead db	?
BegSector db	?
BegCylinder db	?
SysInd	db	?
EndHead db	?
EndSector db	?
EndCylinder db	?
RelSec	dd	?
CSec	dd	?
a_PartitionTableEntry ends

; structure of the IBM hard disk boot sector:
IBMBoot STRUC
	db	512 - (4*a_PartitionTableEntry_struc_size + 2) dup(?)
PartitionTable db 4*a_PartitionTableEntry_struc_size dup(?)
Signature dw	?
IBMBoot ENDS


;*****************************************************************************
;Routine name: SetPartitionTable
;*****************************************************************************
;
;Description: Find location for DOS partition in partition table, get the
;	      correct system indicator byte, and write it out. If can not
;	      read/write boot record or can't find DOS partition, display
;	      error
;
;Called Procedures: Message (macro)
;		    Determine_Partition_Type
;		    ReadSector
;		    WriteSector
;
;Change History: Created	4/20/87 	MT
;
;Input: None
;
;Output: CY set if error
;
;Psuedocode
;----------
;
;	Read the partition table (Call ReadSector)
;	IF ok
;	   IF boot signature of 55AAh
;	       Point at system partition table
;	       SEARCH
;		  Assume DOS found
;		  IF System_Indicator <> 1,AND
;		  IF System_Indicator <> 4,AND
;		  IF System_Indicator <> 6
;		    STC   (DOS not found)
;		  ELSE
;		    CLC
;		  ENDIF
;	       EXITIF DOS found (CLC)
;		  CALL Determine_Partition_Type
;		  Write the partition table (CALL WriteSector)
;		  IF error
;		     Display boot write error message
;		     stc
;		  ELSE
;		     clc
;		  ENDIF
;	       ORELSE
;		  Point at next partition entry (add 16 to partition table ptr)
;	       ENDLOOP if checked all 4 partition entries
;		  Display Bad partition table message
;		  stc
;	       ENDSRCH
;	   ELSE invalid boot record
;	      Display Bad partition table message
;	      stc
;	   ENDIF
;	ELSE error
;	   Display Partition table error
;	   stc
;	ENDIF
;	ret
;*****************************************************************************

Procedure SetPartitionTable			;				;AN000;

	xor	ax, ax				;Head				;AC000;
	xor	bx, bx				;Cylinder			;AC000;
	xor	cx, cx				;Sector 			;AC000;
	lea	dx, [boot2]			;Never use 1.x boot on hardfile,;     ;
	call	ReadSector			;this will use space as buffer	;     ;
;	$IF	NC				;If read okay			;AN000;
	JC DD_IF70
Boot2 equ boot2	; NASM port label
	   cmp	   word [Boot2 + Boot_Signature],Boot_ID ;				;AC000;
;	   $IF	   E				;Does signature match?		;AN000;
	   JNE DD_IF71
	      lea     bx, [boot2 + PartitionTable]	;Yes, point at partition table	;AN000;
;	      $SEARCH				;Look for DOS partition 	;AN000;
DD_DO72:
sysind equ SysInd	; NASM port equate
		 cmp	 byte [bx + sysind],FAT12_File_System ;			;AC000;
;		 $IF	 NE,AND 		;				;AN000;
		 JE DD_IF73
		 cmp	 byte [bx + sysind],FAT16_File_System ;		     ;AC000;
;		 $IF	 NE,AND 		;				;AN000;
		 JE DD_IF73
		 cmp	 byte [bx + sysind],New_File_System ;			  ;AC000;
;		 $IF	 NE			;				;AN000;
		 JE DD_IF73
		    stc 			;We didn't find partition       ;AN000;
;		 $ELSE				;				;AN000;
		 JMP SHORT DD_EN73
DD_IF73:
		    clc 			;Indicate found partition	;AN000;
;		 $ENDIF 			;				;AN000;
DD_EN73:
;	      $EXITIF NC			;Get correct id for it		;AN000;
	      JC DD_IF72
		 CALL	 Determine_Partition_Type ;				;AN000;
		 mov	 ax, 0			;Head				;     ;
		 mov	 bx, 0			;Cylinder			;     ;
		 mov	 cx, 0			;Sector 			;     ;
		 lea	 dx, [boot2]		;				;     ;
		 call	 WriteSector		;Write out partition table	;     ;
;		 $IF	 C			;Error writing boot record	;AN000;
		 JNC DD_IF77
		    MESSAGE msgPartitionTableWriteError ;			;AC000;
		    stc 			;Set CY to indicate error	;     ;
;		 $ELSE				;				;AN000;
		 JMP SHORT DD_EN77
DD_IF77:
		    clc 			;No error means no CY		;     ;
;		 $ENDIF 			;				;AN000;
DD_EN77:
;	      $ORELSE				;				;AN000;
	      JMP SHORT DD_SR72
DD_IF72:
		 add	 bx,a_PartitionTableEntry_struc_size ;			;     ;
		 cmp	 bx,(offset Boot2 + PartitionTable)+4*a_PartitionTableEntry_struc_size ;     ;
;	      $ENDLOOP				;Checked all 4 partition entries;AN000;
	      JMP SHORT DD_DO72
		 MESSAGE msgBadPartitionTable	;Tell user bad table		;AC000;
		 stc				;Set CY for exit		;     ;
;	      $ENDSRCH				;				;AN000;
DD_SR72:
;	   $ELSE				;Invalid boot record		;AN000;
	   JMP SHORT DD_EN71
DD_IF71:
	      MESSAGE msgBadPartitionTable	;				;AC000;
	      stc				;Set CY for error return	;     ;
;	   $ENDIF				;				;AN000;
DD_EN71:
;	$ELSE					;Couldn't read boot record      ;AN000;
	JMP SHORT DD_EN70
DD_IF70:
	   MESSAGE msgPartitionTableReadError	;				;AC000;
	   stc					;Set CY for error return	;     ;
;	$ENDIF					;				;AN000;
DD_EN70:
	ret					;				;     ;

SetPartitionTable endp				;				;AN000;

;*****************************************************************************
;Routine name: Determine_Partition_Type
;*****************************************************************************
;
;DescriptioN: Set the system indicator field to its correct value as
;	      determined by the following rules:
;
;	     - Set SysInd = 01h if partition or logical drive size is < 10mb
;	       and completely contained within the first 32mb of DASD.
;	     - Set SysInd = 04h if partition or logical drive size is >10mb,
;	       <32mb, and completely contained within the first 32mb of DASD
;	     - Set SysInd to 06h if partition or logical drive size is > 32mb,
;
;Called Procedures: Message (macro)
;
;Change History: Created	3/18/87 	MT
;
;Input: BX has offset of partition table entry
;	fBigFAT = TRUE if 16bit FAT
;
;Output: BX.SysInd = correct partition system indicator value (1,4,6)
;
;Psuedocode
;----------
;	Add partition start location to length of partition
;	IF end > 32mb
;	   BX.SysInd = 6
;	ELSE
;	   IF fBigFat
;	      BX.SysInd = 4
;	   ELSE
;	      BX.SysInd = 1
;	   ENDIF
;	ret
;*****************************************************************************

Procedure Determine_Partition_Type						;AN000;

Csec equ CSec	; NASM port equate
	mov	dx,word ptr [bx + Csec + 2] 					;an000; dms;Get high word of sector count
	cmp	dx,0								;AN000;    ;> 32Mb?
;	$IF	NE								;AN000;    ;yes
	JE DD_IF87
		mov	byte [BX + SysInd],New_File_System				;AN000;    ;type 6
;	$ELSE									;AN000;
	JMP SHORT DD_EN87
DD_IF87:
		call	Calc_Total_Sectors_For_Partition			;an000; dms;returns DX:AX total sectors
BPB_HiddenSectors equ BPB_HIDDENSECTORS	; NASM port equate
		cmp	word [DeviceParameters + DP_BPB + BPB_HiddenSectors + +2],0 	;an000; dms;> 32Mb?
;		$if	ne							;an000; dms;yes
		JE DD_IF89
			mov	byte [bx + SysInd],New_File_System			;an000; dms; type 6
;		$else								;an000; dms;
		JMP SHORT DD_EN89
DD_IF89:
			cmp	dx,0						;an000; dms; partition > 32 Mb?
;			$if	ne						;an000; dms; yes
			JE DD_IF91
				mov  byte [bx + SysInd],New_File_System		;an000; dms; type 6
;			$else							;an000; dms; < 32 Mb partition
			JMP SHORT DD_EN91
DD_IF91:
fBigFat equ fBigFAT	; NASM port label
True equ TRUE	; NASM port equate
				cmp	byte [fBigFat],True				;an000;    ;16 bit FAT
;				$IF	E					;AC000;    ;yes
				JNE DD_IF93
					mov	byte [BX + SysInd],FAT16_File_System	;an000;    ;type 4
;				$ELSE						;an000;    ;12 bit FAT
				JMP SHORT DD_EN93
DD_IF93:
					mov	byte [bx + SysInd],FAT12_File_System	;an000;    ;type 1
;				$ENDIF						;AN000;
DD_EN93:
;			$ENDIF							;an000;
DD_EN91:
;		$ENDIF								;an000;
DD_EN89:
;	$endif									;an000;
DD_EN87:
	ret									;an000;

Determine_Partition_Type endp			;				;AN000;


;=========================================================================
; Calc_Total_Sectors_For_Partition	: This routine determines the
;					  total number of sectors within
;					  this partition.
;
;	Inputs	: DeviceParameters
;
;	Outputs : DX:AX - Double word partition size
;=========================================================================

Procedure Calc_Total_Sectors_For_Partition					;an000; dms;

	mov	ax,word ptr [DeviceParameters + DP_BPB + BPB_HiddenSectors + +0]	;an000; dms; low word
	mov	dx,word ptr [DeviceParameters + DP_BPB + BPB_HiddenSectors + +2]	;an000; dms; high word
	cmp	word [DeviceParameters + DP_BPB + BPB_TotalSectors],0			;an000; dms; extended BPB?
;	$if	e								;an000; dms; yes
	JNE DD_IF99
		add	ax,word ptr [DeviceParameters + DP_BPB + BPB_BigTotalSectors + +0]   ;an000; dms; add in low word
		adc	dx,0							;an000; dms; pick up carry if any
		add	dx,word ptr [DeviceParameters + DP_BPB + BPB_BigTotalSectors + +2]   ;an000; dms; add in high word
;	$else									;an000; dms; standard BPB
	JMP SHORT DD_EN99
DD_IF99:
		add	ax,word ptr [DeviceParameters + DP_BPB + BPB_TotalSectors]	;an000; dms; add in total sector count
		adc	dx,0							;an000; dms; pick up carry if any
;	$endif									;an000; dms;
DD_EN99:

	ret

Calc_Total_Sectors_For_Partition	endp


;-------------------------------------------------------------------------------
; ReadSector:
;    Read one sector
;
;    Input:
;	ax - head
;	bx - cylinder
;	cx - sector
;	dx - transfer address

ReadSector proc near

TrackReadWritePacket equ trackReadWritePacket	; NASM port label
TRWP_FirstSector equ TRWP_FIRSTSECTOR	; NASM port equate
	mov	[TrackReadWritePacket + TRWP_FirstSector], cx
	mov	cx,(RAWIO << 8) | READ_TRACK
	call	SectorIO
	return

ReadSector endp

;-------------------------------------------------------------------------------
; WriteSector:
;    Write one sector
;
;    Input:
;	ax - head
;	bx - cylinder
;	cx - sector
;	dx - transfer address

WriteSector proc near

	mov	[TrackReadWritePacket + TRWP_FirstSector], cx
	mov	cx,(RAWIO << 8) | WRITE_TRACK
	call	SectorIO
	return

WriteSector endp

;-------------------------------------------------------------------------------
; SectorIO:
;    Read/Write one sector
;
;    Input:
;	ax - head
;	bx - cylinder
;	cx - (RAWIO shl 8) or READ_TRACK
;	   - (RAWIO shl 8) or WRITE_TRACK
;	dx - transfer address

SectorIO proc	near

TRWP_Head equ TRWP_HEAD	; NASM port equate
	mov	[TrackReadWritePacket + TRWP_Head], ax
TRWP_Cylinder equ TRWP_CYLINDER	; NASM port equate
	mov	[TrackReadWritePacket + TRWP_Cylinder], bx
TRWP_TransferAddress equ TRWP_TRANSFERADDRESS	; NASM port equate
	mov	WORD PTR [TrackReadWritePacket + TRWP_TransferAddress], dx
	mov	WORD PTR [TrackReadWritePacket + TRWP_TransferAddress + 2], ds
TRWP_SectorsToReadWrite equ TRWP_SECTORSTOREADWRITE	; NASM port equate
	mov	word [TrackReadWritePacket + TRWP_SectorsToReadWrite], 1

	mov	bl, [drive]
	inc	bl
	mov	ax, (IOCTL << 8) | GENERIC_IOCTL
	lea	dx, [trackReadWritePacket]
	int	21H
	return

SectorIO endp

;-------------------------------------------------------------------------------

section data

oldDrive db	?

FCBforVolumeIdSearch db 0ffH
	db	5 dup(0)
	db	08H
	db	0
	db	"???????????"
	db	40 DUP(0)

section code	; data	ends

GetVolumeId proc near
; Input:
;    dl = drive
;    di = name buffer

; Save current drive
	mov	ah,19H
	int	21H
	mov	[oldDrive], al

; Change current drive to the drive that has the volume id we want
	mov	ah, 0eH
	int	21H

; Search for the volume id
	mov	ah, 11H
	lea	dx, [FCBforVolumeIdSearch]
	int	21H
	push	ax

; Restore current drive
	mov	ah, 0eH
	mov	dl,[oldDrive]
	int	21H

; Did the search succeed?
	pop	ax
	or	al,al
	jz	CopyVolumeId
	stc
	ret

CopyVolumeId:
; Find out where the FCB for the located volume id was put
	mov	ah,2fH
	int	21H

; Copy the Volume Id
	mov	si, bx
	add	si, 8
	push	es
	push	ds
	pop	es
	pop	ds
	mov	cx, 11
	rep	movsb
	push	es
	pop	ds

	clc
	ret

GetVolumeId endp

section data
oldVolumeId db	11 dup(0)
section code	; data	ends

CheckVolumeId proc near

; Get the volume id that's on the disk
	lea	di, [oldVolumeId]
	mov	dl, [drive]
	call	GetVolumeId
	jnc	Ask_User			;Did we find one?
	clc					;No, return with no error
	ret

; Ask the user to enter the volume id that he/she thinks is on the disk
; (first blank out the input buffer)
Ask_User:

	Message msgWhatIsVolumeId?		;				;AC000;
						;lea	 dx, ptr_msgWhatIsVolumeId?
						;call	 std_printf
	call	user_string
	call	crlf

; If the user just pressed ENTER, then there must be no label
	cmp	byte [inbuff+1], 0
	jne	CompareVolumeIds
	cmp	byte [oldVolumeId], 0
	jne	BadVolumeId
	ret

CompareVolumeIds:
; pad the reponse with blanks
; The buffer is big enough so just add 11 blanks to what the user typed in
	push	ds
	pop	es
	mov	cx, Label_Length		;AC000;
	xor	bx,bx
	mov	bl, [inbuff + 1]
	lea	di, [inbuff + 2]
	add	di, bx
	mov	al, ' '
	rep	stosb
; Make the reply all uppercase
Inbuff equ inbuff	; NASM port label
ASCIIZ_End equ Asciiz_End	; NASM port equate
	mov	byte [Inbuff+2+Label_Length],ASCIIZ_End ;Make string ASCIIZ	 ;AN000;
	mov	dx, offset inbuff + 2		;Start of buffer		;AC000;
	mov	al,22h				;Capitalize asciiz		;AC000;
	DOS_Call GetExtCntry			;Do it				;AC000;

; Now compare what the user specified with what is really out there
	mov	cx, Label_Length		;				;AC000;
	lea	si, [inbuff + 2]
	lea	di, [oldVolumeId]
	repe	cmpsb
	jne	BadVolumeId
	ret

BadVolumeId:
msgBadVolumeID equ msgBadVolumeId	; NASM port label
	Message msgBadVolumeID			;				;AC000;
	stc
	ret

CheckVolumeId endp


Check_Switch_8_B	proc	near

	   test    word [SwitchMap], SWITCH_B		;/8/B <> /V because		;AC007;
;	   $IF	   NZ,AND			; old directory type		;AC007;
	   JZ DD_IF102
	   test    word [SwitchMap], Switch_8		; used which didn't support     ;AC007;
;	   $IF	   NZ,AND			; volume labels.		;AC007;
	   JZ DD_IF102
	   test    word [SwitchMap], SWITCH_V		;				;AC007;
;	   $IF	   NZ				;				;AC007;
	   JZ DD_IF102
	      Message msgIncompatibleParameters ;Tell user			;AC007;
	      mov     byte [Fatal_Error],Yes		;Bad stuff			;AC007;
;	   $ELSE				;No problem so far		;AC007;
	   JMP SHORT DD_EN102
DD_IF102:
	      test    word [SwitchMap], Switch_B	;Can't reserve space and        ;AC007;
;	      $IF     NZ,AND			; install sys files at the	;AC007;
	      JZ DD_IF104
	      test    word [SwitchMap], Switch_S	; same time.			;AC007;
;	      $IF     NZ			; No /S/B			;AC007;
	      JZ DD_IF104
		 Message msgIncompatibleParameters ;Tell user			;AC007;
		 mov	 byte [Fatal_Error],Yes	;Bad stuff			;AC007;
;	       $ELSE				 ;Still okay			 ;AC007;
	       JMP SHORT DD_EN104
DD_IF104:
		  test	  word [SwitchMap],Switch_1	 ;/1/8/4 not okay with /N/T	 ;AC007;
;		  $IF	  NZ,OR 		 ;				 ;AC007;
		  JNZ DD_LL106
		  test	  word [SwitchMap],Switch_8	 ;				 ;AC007;
;		  $IF	  NZ,OR 		 ;				 ;AC007;
		  JNZ DD_LL106
		  test	  word [SwitchMap],Switch_4	 ;				 ;AC007;
;		  $IF	  NZ			 ;				 ;AC007;
		  JZ DD_IF106
DD_LL106:
		     test    word [SwitchMap],(Switch_T | Switch_N) ; 		 ;AC007;
;		     $IF     NZ 		 ;Found /T/N <> /1/8		 ;AC007;
		     JZ DD_IF107
			Message msgIncompatibleParameters ;Tell user		 ;AC007;
			mov	byte [Fatal_Error],Yes  ;Bad stuff			 ;AC007;
;		     $ELSE			 ;				 ;ac007;
		     JMP SHORT DD_EN107
DD_IF107:
			test	word [SwitchMap],Switch_V				 ;ac007;
;			$IF	NZ,AND						 ;ac007;
			JZ DD_IF109
			test	word [SwitchMap],Switch_8				 ;ac007;
;			$IF	NZ						 ;ac007;
			JZ DD_IF109
				Message msgIncompatibleParameters		 ;ac007;
				mov	byte [Fatal_Error],Yes 			 ;ac007;
;			$ENDIF							 ;ac007;
DD_IF109:
;		     $ENDIF			 ;				 ;AC007;
DD_EN107:
;		  $ENDIF			 ;				 ;AC007;
DD_IF106:
;	       $ENDIF				 ;				 ;AC007;
DD_EN104:
;	    $ENDIF				 ;				 ;AC007;
DD_EN102:
	    ret

Check_Switch_8_B	endp


; (no prior section) ; code	ends
	end

