Index: trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc	(revision 593)
@@ -56,11 +56,13 @@
 PIO_6_MIN_ACTIVE_TIME_NS	EQU		55
 
-; PIO Minimum Recovery Times or Inactive Times (t2i) can be calculated
-; from Minimum Cycle Time (t0) - Minimum Active Time (t2) - Address Valid Time (t1).
-; I'm not sure about this calculation so correct me if I'm wrong!
-; Recovery time should be calculated at run time since Cycle Time t0 can be
-; read from ATA information (ATA2+) but most drives just report the
-; Min Cycle Times listed above.
-
+; PIO 0...2 Maximum Addr valid to IOCS16- released (t8)
+PIO_0_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		60
+PIO_1_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		45
+PIO_2_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		30
+
+; PIO DIOR-/DIOW- to address valid hold (t9)
+PIO_0_DIORW_TO_ADDR_VALID_HOLD				EQU		20
+PIO_1_DIORW_TO_ADDR_VALID_HOLD				EQU		15
+PIO_2_DIORW_TO_ADDR_VALID_HOLD				EQU		10
 
 
Index: trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc	(revision 593)
@@ -29,19 +29,4 @@
 BOOT_READ_RETRY_TIMES		EQU		3
 
-; Pre-boot variables. These do not exist after successful boot to OS.
-; Segment is always 0000h, same as BDA segment
-struc BOOTVARS
-						resb	7C00h
-	.rgbAtaInfo:						; 7C00h, ATA Information for drive detection
-	.rgbBootSect		resb 	512		; 7C00h, Boot sector
-						resb	256		; Boot Menu stack
-	.rgbMnuStack:
-	.dwPostStack		resb	4		; POST stack pointer when entering INT 19h
-%ifdef MODULE_HOTKEYS
-	.hotkeyVars			resb	HOTKEYVARS_size
-%endif
-	.rgDrvDetectInfo:					; Array containing DRVDETECTINFO structs
-endstruc
-
 
 %ifdef MODULE_HOTKEYS
@@ -66,4 +51,21 @@
 
 %endif ; MODULE_HOTKEYS
+
+
+; Pre-boot variables. These do not exist after successful boot to OS.
+; Segment is always 0000h, same as BDA segment
+struc BOOTVARS
+						resb	7C00h
+	.rgbAtaInfo:						; 7C00h, ATA Information for drive detection
+	.rgbBootSect		resb 	512		; 7C00h, Boot sector
+						resb	256		; Boot Menu stack
+	.rgbMnuStack:
+	.dwPostStack		resb	4		; POST stack pointer when entering INT 19h
+%ifdef MODULE_HOTKEYS
+	.hotkeyVars			resb	HOTKEYVARS_size	; Must be located just before DRVDETECTINFO structs
+%endif
+	.rgDrvDetectInfo:					; Array containing DRVDETECTINFO structs
+endstruc
+
 
 ; MAX_HARD_DISK_NAME_LENGTH must be defined ahead of the DRVDETECTINFO structure to avoid problems with NASM
Index: trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc	(revision 593)
@@ -23,4 +23,6 @@
 MIN_TIME_TO_DISPLAY_HOTKEY_BAR			EQU	(4000/55)	; 4000 ms
 
+FIRST_FUNCTION_KEY_SCANCODE				EQU	3Bh	; F1 key
+
 ROM_BOOT_HOTKEY_SCANCODE				EQU	42h	; F8
 
Index: trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc	(revision 593)
@@ -29,4 +29,30 @@
 %ifdef MODULE_SERIAL_FLOPPY OR MODULE_DRIVEXLATE
 	%define NEED_XLATEVARS
+%endif
+
+
+%ifdef NEED_XLATEVARS
+; Variables for translating drive numbers.
+	struc XLATEVARS
+	%ifdef MODULE_SERIAL_FLOPPY
+		.bFlopCreateCnt:
+		.bFlopCntAndFirst	resb	1	; Normally, packed starting floppy drive number (high order 7 bits)
+										; and number of drives (low order bit, max 2 drives supported).
+										; During initialization, until the end of DetectDrives_FromAllIDEControllers,
+										; this byte contains the raw number of floppy drives seen
+										; (using .bFlopCreateCnt)
+	%else
+							resb	1	; alignment
+	%endif
+
+	%ifdef MODULE_DRIVEXLATE
+		.bXlatedDrv			resb	1	; Drive number after translation
+		.wFDandHDswap:
+		.bFDSwap			resb	1	; Floppy Drive to swap to 00h and vice versa
+		.bHDSwap			resb	1	; Hard Drive to swap to 80h and vice versa
+	%else
+							resb	1	; alignment
+	%endif
+	endstruc
 %endif
 
@@ -66,29 +92,4 @@
 RAMVARS_DRV_DETECT_SIGNATURE	EQU	5A5Ah	; Signature when BIOS is in drive detection mode
 
-
-%ifdef NEED_XLATEVARS
-; Variables for translating drive numbers.
-	struc XLATEVARS
-	%ifdef MODULE_SERIAL_FLOPPY
-		.bFlopCreateCnt:
-		.bFlopCntAndFirst	resb	1	; Normally, packed starting floppy drive number (high order 7 bits)
-										; and number of drives (low order bit, max 2 drives supported).
-										; During initialization, until the end of DetectDrives_FromAllIDEControllers,
-										; this byte contains the raw number of floppy drives seen
-										; (using .bFlopCreateCnt)
-	%else
-							resb	1	; alignment
-	%endif
-
-	%ifdef MODULE_DRIVEXLATE
-		.bXlatedDrv			resb	1	; Drive number after translation
-		.wFDandHDswap:
-		.bFDSwap			resb	1	; Floppy Drive to swap to 00h and vice versa
-		.bHDSwap			resb	1	; Hard Drive to swap to 80h and vice versa
-	%else
-							resb	1	; alignment
-	%endif
-	endstruc
-%endif
 
 %ifdef MODULE_SERIAL_FLOPPY
Index: trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc	(revision 593)
@@ -22,71 +22,33 @@
 %define ROMVARS_INC
 
-; ROM Variables. Written to the ROM image before flashing.
-struc ROMVARS
-	.wRomSign			resb	2	; ROM Signature (AA55h)
-	.bRomSize			resb	1	; ROM size in 512 byte blocks
-	.rgbJump			resb	3	; First instruction to ROM init (jmp)
-
-	.rgbSign			resb	8	; Signature for XTIDE Configurator Program
-	.szTitle			resb	31	; BIOS title string
-	.szVersion			resb	25	; BIOS version string
-
-	.wFlags				resb	2	; Word for ROM flags
-	.wDisplayMode		resb	2	; Display mode for boot menu
-	.wBootTimeout		resb	2	; Boot Menu selection timeout in system timer ticks
-	.pColorTheme		resb	2	; Ptr to the color attribute struc used by the boot menu and hotkey bar
-	.bIdeCnt			resb	1	; Number of available IDE controllers
-	.bBootDrv			resb	1	; Default drive to boot from
-	.bMinFddCnt			resb	1	; Minimum number of Floppy Drives
-	.bStealSize			resb	1	; Number of 1kB blocks stolen from 640kB base RAM
-	.bIdleTimeout		resb	1	; Standby timer value
-
-	.ideVarsBegin:
-	.ideVars0			resb	IDEVARS_size
-	.ideVars1			resb	IDEVARS_size
-	.ideVars2			resb	IDEVARS_size
-	.ideVars3			resb	IDEVARS_size
-
-%ifdef MODULE_SERIAL
-	.ideVarsSerialAuto	resb	IDEVARS_size
-%endif
-
-	.ideVarsEnd:
+
+; Master/Slave drive specific parameters
+struc DRVPARAMS
+	.wFlags			resb	2	; Drive flags
+	.dwMaximumLBA:				; User specified maximum number of sectors
+	.wCylinders		resb	2	; User specified cylinders (1...16383)
+	.wHeadsAndSectors:
+	.bHeads			resb	1	; User specified Heads (1...16)
+	.bSect			resb	1	; User specified Sectors per track (1...63)
 endstruc
 
-%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
-	%if ROMVARS.ideVarsEnd & 0xff00 <> 0
-		%error ".ideVars structures must fit within the first 256 bytes of the ROM image"
-	%endif
-	%if (ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) = 0
-		%error "there must be at least one .ideVars structure, it would be bizarre if this were not true, but it is assumed in the ah0h reset code."
-	%endif
-%endif
-
-NUMBER_OF_IDEVARS					EQU	((ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) / IDEVARS_size)
-
-; Bit defines for ROMVARS.wFlags
-FLG_ROMVARS_FULLMODE				EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
-FLG_ROMVARS_SERIAL_SCANDETECT 		EQU	(1<<3)	; Scan COM ports at the end of drive detection.  Can also be invoked
-												; by holding down the ALT key at the end of drive detection.
-												; (Conveniently, this is 8, a fact we exploit when testing the bit)
-
-; Here in case the configuration needs to know functionality is present. Note! Changing the order/location of these flags
-; also requires changes elsewhere as they are usually tested using byte-accesses for efficiency.
-FLG_ROMVARS_MODULE_POWER_MANAGEMENT		EQU	(1<<5)
-FLG_ROMVARS_MODULE_8BIT_IDE				EQU	(1<<6)
-FLG_ROMVARS_MODULE_8BIT_IDE_ADVANCED	EQU (1<<7)
-FLG_ROMVARS_MODULE_ADVANCED_ATA			EQU	(1<<8)
-FLG_ROMVARS_MODULE_BOOT_MENU			EQU	(1<<9)
-FLG_ROMVARS_MODULE_EBIOS				EQU	(1<<10)
-FLG_ROMVARS_MODULE_HOTKEYS				EQU	(1<<11)
-FLG_ROMVARS_MODULE_IRQ					EQU	(1<<12)
-FLG_ROMVARS_MODULE_SERIAL				EQU (1<<13)
-FLG_ROMVARS_MODULE_SERIAL_FLOPPY		EQU (1<<14)
-FLG_ROMVARS_MODULE_STRINGS_COMPRESSED	EQU (1<<15)
-
-
-; Boot Menu Display Modes (see Assembly Library Display.inc for standard modes)
-DEFAULT_TEXT_MODE		EQU	4
+; Bit defines for DRVPARAMS.wFlags - these flags are accessed as bytes so changes here might require changes elsewhere
+MASK_DRVPARAMS_WRITECACHE		EQU	(3<<0)	; Bits 0...1, Drive internal write cache settings (must start at bit 0)
+	DEFAULT_WRITE_CACHE				EQU	0	; Must be 0
+	DISABLE_WRITE_CACHE				EQU	1
+	ENABLE_WRITE_CACHE				EQU	2
+MASK_DRVPARAMS_TRANSLATEMODE	EQU	(3<<TRANSLATEMODE_FIELD_POSITION)	; Bits 2...3, Position shared with DPT
+	TRANSLATEMODE_FIELD_POSITION	EQU	2
+	TRANSLATEMODE_NORMAL			EQU	0	; Must be zero
+	TRANSLATEMODE_LARGE				EQU	1
+	TRANSLATEMODE_ASSISTED_LBA		EQU	2	; 28-bit or 48-bit LBA
+	TRANSLATEMODE_AUTO				EQU	3	; Only available in ROMVARS, not in DPTs
+FLG_DRVPARAMS_BLOCKMODE			EQU	(1<<4)	; Enable Block mode transfers
+FLG_DRVPARAMS_USERCHS			EQU	(1<<5)	; User specified P-CHS values
+	MAX_PCHS_CYLINDERS				EQU	16383
+	MAX_PCHS_HEADS					EQU	16
+	MAX_PCHS_SECTORS_PER_TRACK		EQU	63
+	MAX_PCHS_TOTAL_SECTOR_COUNT		EQU	(MAX_PCHS_CYLINDERS * MAX_PCHS_HEADS * MAX_PCHS_SECTORS_PER_TRACK)	; 16,514,064
+FLG_DRVPARAMS_USERLBA			EQU	(1<<6)	; User specified LBA value
 
 
@@ -173,32 +135,79 @@
 XTCF_DEVICE_OFFSET						EQU	FIRST_XTCF_DEVICE						; Used for XT-CF device <--> mode conversion
 
-; Master/Slave drive specific parameters
-struc DRVPARAMS
-	.wFlags			resb	2	; Drive flags
-	.dwMaximumLBA:				; User specified maximum number of sectors
-	.wCylinders		resb	2	; User specified cylinders (1...16383)
-	.wHeadsAndSectors:
-	.bHeads			resb	1	; User specified Heads (1...16)
-	.bSect			resb	1	; User specified Sectors per track (1...63)
+
+; ROM Variables. Written to the ROM image before flashing.
+struc ROMVARS
+	.wRomSign			resb	2	; ROM Signature (AA55h)
+	.bRomSize			resb	1	; ROM size in 512 byte blocks
+	.rgbJump			resb	3	; First instruction to ROM init (jmp)
+
+	.rgbSign			resb	8	; Signature for XTIDE Configurator Program
+	.szTitle			resb	31	; BIOS title string
+	.szVersion			resb	25	; BIOS version string
+
+	.wFlags				resb	2	; Word for ROM flags
+	.wDisplayMode		resb	2	; Display mode for boot menu
+	.wBootTimeout		resb	2	; Boot Menu selection timeout in system timer ticks
+	.pColorTheme		resb	2	; Ptr to the color attribute struc used by the boot menu and hotkey bar
+	.bIdeCnt			resb	1	; Number of available IDE controllers
+	.bBootDrv			resb	1	; Default drive to boot from
+	.bMinFddCnt			resb	1	; Minimum number of Floppy Drives
+	.bStealSize			resb	1	; Number of 1kB blocks stolen from 640kB base RAM
+	.bIdleTimeout		resb	1	; Standby timer value
+
+	.ideVarsBegin:
+	.ideVars0			resb	IDEVARS_size
+	.ideVars1			resb	IDEVARS_size
+	.ideVars2			resb	IDEVARS_size
+	.ideVars3			resb	IDEVARS_size
+
+%ifdef MODULE_SERIAL
+	.ideVarsSerialAuto	resb	IDEVARS_size
+%endif
+
+	.ideVarsEnd:
 endstruc
 
-; Bit defines for DRVPARAMS.wFlags - these flags are accessed as bytes so changes here might require changes elsewhere
-MASK_DRVPARAMS_WRITECACHE		EQU	(3<<0)	; Bits 0...1, Drive internal write cache settings (must start at bit 0)
-	DEFAULT_WRITE_CACHE				EQU	0	; Must be 0
-	DISABLE_WRITE_CACHE				EQU	1
-	ENABLE_WRITE_CACHE				EQU	2
-MASK_DRVPARAMS_TRANSLATEMODE	EQU	(3<<TRANSLATEMODE_FIELD_POSITION)	; Bits 2...3, Position shared with DPT
-	TRANSLATEMODE_FIELD_POSITION	EQU	2
-	TRANSLATEMODE_NORMAL			EQU	0	; Must be zero
-	TRANSLATEMODE_LARGE				EQU	1
-	TRANSLATEMODE_ASSISTED_LBA		EQU	2	; 28-bit or 48-bit LBA
-	TRANSLATEMODE_AUTO				EQU	3	; Only available in ROMVARS, not in DPTs
-FLG_DRVPARAMS_BLOCKMODE			EQU	(1<<4)	; Enable Block mode transfers
-FLG_DRVPARAMS_USERCHS			EQU	(1<<5)	; User specified P-CHS values
-	MAX_PCHS_CYLINDERS				EQU	16383
-	MAX_PCHS_HEADS					EQU	16
-	MAX_PCHS_SECTORS_PER_TRACK		EQU	63
-	MAX_PCHS_TOTAL_SECTOR_COUNT		EQU	(MAX_PCHS_CYLINDERS * MAX_PCHS_HEADS * MAX_PCHS_SECTORS_PER_TRACK)	; 16,514,064
-FLG_DRVPARAMS_USERLBA			EQU	(1<<6)	; User specified LBA value
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if ROMVARS.ideVarsEnd & 0xff00 <> 0
+		%error ".ideVars structures must fit within the first 256 bytes of the ROM image"
+	%endif
+	%if (ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) = 0
+		%error "there must be at least one .ideVars structure, it would be bizarre if this were not true, but it is assumed in the ah0h reset code."
+	%endif
+%endif
+
+NUMBER_OF_IDEVARS					EQU	((ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) / IDEVARS_size)
+
+; Bit defines for ROMVARS.wFlags
+FLG_ROMVARS_FULLMODE					EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
+FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES	EQU	(1<<1)	; Ignores drives configured in motherboard BIOS setup.
+													; For now it is a hack to get Windows 95 IDE drivers working
+													; but it will be needed later when XTUB supports dynamic drive overlay.
+													; Because of that this must be included into AT builds and cannot be a
+													; module (any AT or 386 must be installable to the hard drive so
+													; there won't be need for even more different builds).
+FLG_ROMVARS_SERIAL_SCANDETECT 			EQU	(1<<3)	; Scan COM ports at the end of drive detection.  Can also be invoked
+													; by holding down the ALT key at the end of drive detection.
+													; (Conveniently, this is 8, a fact we exploit when testing the bit)
+
+; Here in case the configuration needs to know functionality is present. Note! Changing the order/location of these flags
+; also requires changes elsewhere as they are usually tested using byte-accesses for efficiency.
+FLG_ROMVARS_MODULE_POWER_MANAGEMENT		EQU	(1<<5)
+FLG_ROMVARS_MODULE_8BIT_IDE				EQU	(1<<6)
+FLG_ROMVARS_MODULE_8BIT_IDE_ADVANCED	EQU (1<<7)
+FLG_ROMVARS_MODULE_ADVANCED_ATA			EQU	(1<<8)
+FLG_ROMVARS_MODULE_BOOT_MENU			EQU	(1<<9)
+FLG_ROMVARS_MODULE_EBIOS				EQU	(1<<10)
+FLG_ROMVARS_MODULE_HOTKEYS				EQU	(1<<11)
+FLG_ROMVARS_MODULE_IRQ					EQU	(1<<12)
+FLG_ROMVARS_MODULE_SERIAL				EQU (1<<13)
+FLG_ROMVARS_MODULE_SERIAL_FLOPPY		EQU (1<<14)
+FLG_ROMVARS_MODULE_STRINGS_COMPRESSED	EQU (1<<15)
+
+
+; Boot Menu Display Modes (see Assembly Library Display.inc for standard modes)
+DEFAULT_TEXT_MODE		EQU	4
+
 
 %endif ; ROMVARS_INC
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm	(revision 593)
@@ -90,9 +90,4 @@
 ;--------------------------------------------------------------------
 .InitializeBiosAndDetectDrives:
-%ifdef MODULE_HOTKEYS
-	call	TimerTicks_ReadFromBdaToAX
-	mov		[es:BOOTVARS.hotkeyVars+HOTKEYVARS.wTimeWhenDisplayed], ax
-%endif
-
 	call	Initialize_AndDetectDrives
 
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm	(revision 593)
@@ -33,7 +33,25 @@
 ;				Cleared if no controller
 ;	Corrupts registers:
-;		BX
+;		BX, CX
 ;--------------------------------------------------------------------
 AdvAtaInit_DetectControllerForIdeBaseInBX:
+	; Detect if system has PCI bus. If it does, we can skip VLB detection. This is
+	; good thing since detecting Vision QD6850 is dangerous since Intel PIIX4 south bridge
+	; mirrors Interrupt Controller registers from Axh to Bxh. This can lead to faulty
+	; detection of QD6850 that will eventually crash the system when ports are written.
+
+	; We should save the 32-bit registers but we don't since system BIOS has stored
+	; them already and we don't use the 32-bit registers ourselves anywhere at the moment.
+	push	bx
+	push	di
+	xor		edi, edi		; Some BIOSes require this to be set to zero
+	mov		ax, PCI_INSTALLATION_CHECK
+	int		BIOS_TIME_PCI_PNP_1Ah
+	pop		di
+	pop		bx
+	test	ah, ah
+	jz		SHORT .ThisSystemHasPCIbus
+
+	; Detect VLB controllers
 	call	Vision_DetectAndReturnIDinAXandPortInDXifControllerPresent
 	jnz		SHORT .NoVisionControllerFound
@@ -51,4 +69,5 @@
 
 .NoAdvancedControllerForPortBX:
+.ThisSystemHasPCIbus:
 	xor		ax, ax		; Clear ID in AX and CF
 	ret
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm	(revision 593)
@@ -41,8 +41,4 @@
 	in		al, QD65XX_BASE_PORT + QD65XX_CONFIG_REGISTER_in
 
-%ifdef DANGEROUS_DETECTION
-	; Checking alternative base port is currently commented away
-	; since Intel PIIX4 south bridge mirrors Interrupt Controller registers
-	; from Axh to Bxh.
 	call	IsConfigRegisterWithIDinAL
 	je		SHORT VisionControllerDetected.Return
@@ -51,5 +47,4 @@
 	mov		dl, QD65XX_ALTERNATIVE_BASE_PORT
 	in		al, QD65XX_ALTERNATIVE_BASE_PORT + QD65XX_CONFIG_REGISTER_in
-%endif ; DANGEROUS_DETECTION
 	; Fall to IsConfigRegisterWithIDinAL
 
@@ -198,5 +193,7 @@
 
 	; Calculate Recovery Time value for QD65xx IDE Timing Register
-	call	AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX
+	xchg	ax, cx
+	eMOVZX	cx, BYTE [cs:bx+.rgbToSubtractFromCycleTimeBasedOnPIOmode]
+	sub		ax, cx
 	mov		bx, bp						; Active Time value now in BL
 	mov		bp, QD65xx_MAX_RECOVERY_TIME_CLOCKS | (QD65xx_MIN_RECOVERY_TIME_CLOCKS << 8)
@@ -209,4 +206,15 @@
 	ret									; Return with CF cleared
 
+.rgbToSubtractFromCycleTimeBasedOnPIOmode:
+	; For PIO 0 to 2 this method (t0 - (t1+t8+t9)) seems to give closest (little less) values to the fixed preset
+	; values used by QDI6580 DOS driver v3.7
+	db		(PIO_0_MIN_ADDRESS_VALID_NS + PIO_0_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_0_DIORW_TO_ADDR_VALID_HOLD)
+	db		(PIO_1_MIN_ADDRESS_VALID_NS + PIO_1_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_1_DIORW_TO_ADDR_VALID_HOLD)
+	db		(PIO_2_MIN_ADDRESS_VALID_NS + PIO_2_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_2_DIORW_TO_ADDR_VALID_HOLD)
+	db		102		; QDI6580 DOS driver v3.7 uses fixed values for PIO 3...
+	db		61		; ...and PIO 4. No idea where these values come from.
+	db		(PIO_5_MIN_CYCLE_TIME_NS / 2) ; PIO 5 and 6 were not available when QD6850 was released. Use values...
+	db		(PIO_6_MIN_CYCLE_TIME_NS / 2) ; ...that resembles those used for PIO 4
+
 
 ;--------------------------------------------------------------------
@@ -226,7 +234,7 @@
 
 	; Get VLB Cycle Time in nanosecs
-	mov		cl, VLB_33MHZ_CYCLE_TIME	; Assume 33 MHz or slower VLB bus
+	mov		cl, VLB_33MHZ_CYCLE_TIME	; Assume 33 MHz or slower VLB bus (30 ns)
 	test	BYTE [di+DPT_ADVANCED_ATA.wControllerID], FLG_QDCONFIG_ID3
-	eCMOVZ	cl, VLB_40MHZ_CYCLE_TIME
+	eCMOVZ	cl, VLB_40MHZ_CYCLE_TIME	; (25 ns)
 
 	; Convert value in AX to VLB ticks
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm	(revision 593)
@@ -211,32 +211,4 @@
 
 ;--------------------------------------------------------------------
-; AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX
-;	Parameters:
-;		BX:		PIO Mode
-;		CX:		PIO Cycle Time in nanosecs
-;	Returns:
-;		AX:		Active Time in nanosecs
-;	Corrupts registers:
-;		BX, CX
-;--------------------------------------------------------------------
-AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX:
-	call	AtaID_GetActiveTimeToAXfromPioModeInBX
-	mov		bl, [cs:bx+.rgbPioModeToAddressValidTimeNs]
-	sub		cx, bx	; Cycle Time (t0) - Address Valid Time (t1)
-	sub		cx, ax	; - Active Time (t2)
-	xchg	ax, cx	; AX = Recovery Time (t2i)
-	ret
-
-.rgbPioModeToAddressValidTimeNs:
-	db		PIO_0_MIN_ADDRESS_VALID_NS
-	db		PIO_1_MIN_ADDRESS_VALID_NS
-	db		PIO_2_MIN_ADDRESS_VALID_NS
-	db		PIO_3_MIN_ADDRESS_VALID_NS
-	db		PIO_4_MIN_ADDRESS_VALID_NS
-	db		PIO_5_MIN_ADDRESS_VALID_NS
-	db		PIO_6_MIN_ADDRESS_VALID_NS
-
-
-;--------------------------------------------------------------------
 ; AtaID_GetActiveTimeToAXfromPioModeInBX
 ;	Parameters:
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm	(revision 593)
@@ -95,4 +95,41 @@
 ; FindDPT_ForDriveNumber will not find any drives that are ours.
 ;
+
+; Here we might want to replace BIOS configured drives with the ones we detected.
+; Primary reason is to support dynamic overlay feature in the future. Second reason
+; is a hack to get Windows 95 load proper IDE drivers.
+; 
+; The Windows hack has two parts. First part is to try to alter CMOS address 12h as that
+; is what Windows 95 driver reads to detect IDE drives. Altering is not possible on all
+; systems since CMOS has a checksum but it's location is not standardized. We will first
+; try to detect valid checksum. If it succeeds, then it is safe to assume this system
+; has compatible CMOS and we can alter it.
+; If verify fails, we do the more dirty hack to zero BDA drive count. Then Windows 95 works
+; as long as user has configured at least one drive in the BIOS setup.
+
+%ifdef USE_AT	; FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES is for AT builds only
+
+	%ifdef MODULE_WIN95_CMOS_HACK
+		mov		dl, HARD_DISK_TYPES
+		call	CMOS_ReadFromIndexInDLtoAL
+		test	al, al
+		jnz		SHORT .ContinueInitialization	; CMOS byte 12h is ready for Windows 95
+		call	CMOS_Verify10hTo2Dh
+		jnz		SHORT .ClearBdaDriveCount		; Unsupported BIOS, use plan B
+	
+		; Now we can alter CMOS location 12h
+		mov		dl, HARD_DISK_TYPES
+		mov		al, 0F0h	; Drive 0 type 16...47 but Windows doesn't care as long as this is not zero
+		call	CMOS_WriteALtoIndexInDL
+		call	CMOS_StoreNewChecksumFor10hto2Dh
+	%endif
+
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES
+	jz		SHORT .ContinueInitialization
+.ClearBdaDriveCount:
+	mov		BYTE [es:BDA.bHDCount], 0	; Set hard disk count to zero
+.ContinueInitialization:
+%endif
+
 	mov		cx, [RAMVARS.wDrvCntAndFlopCnt]		; Our count of hard disks
 	mov		al, [es:BDA.bHDCount]
Index: trunk/XTIDE_Universal_BIOS/Src/Main.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 593)
@@ -77,5 +77,9 @@
 ;---------------------------;
 %ifdef USE_AT
+%ifdef USE_386
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES | MASK_ROMVARS_INCLUDED_MODULES
+%else
 	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | MASK_ROMVARS_INCLUDED_MODULES
+%endif
 	at	ROMVARS.wDisplayMode,	dw	DEFAULT_TEXT_MODE
 %ifdef MODULE_BOOT_MENU
@@ -188,4 +192,7 @@
 
 	%include "AssemblyLibrary.asm"
+%ifdef MODULE_WIN95_CMOS_HACK
+	%include "CMOS.asm"				; This belongs in the Assembly Library
+%endif
 
 	; String compression tables need to come after the AssemblyLibrary (since they depend on addresses
Index: trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm	(revision 593)
@@ -75,4 +75,8 @@
 	mov		cl, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bFddLetter]
 	mov		di, g_szFDD
+
+	; Clear CH if floppy drive is selected for boot
+	mov		ch, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bFlags]
+	;and		ch, FLG_HOTKEY_HD_FIRST		; Needed if more flags are added
 	call	FormatDriveHotkeyString
 
@@ -92,5 +96,7 @@
 	call	BootVars_GetLetterForFirstHardDriveToAX
 	mov		ah, ANGLE_QUOTE_RIGHT
-	mov		cl, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bHddLetter]
+	mov		cx, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bHddLetter]	; Letter to CL, flags to CH
+	;and		ch, FLG_HOTKEY_HD_FIRST		; Needed if more flags are added
+	xor		ch, FLG_HOTKEY_HD_FIRST		; Clear CH if HD is selected for boot, set otherwise
 	mov		di, g_szHDD
 	call	FormatDriveHotkeyString
@@ -182,4 +188,5 @@
 ; FormatDriveHotkeyString
 ;	Parameters:
+;		CH:			Zero if letter in CL is selected for boot
 ;		CL:			Drive letter hotkey from BOOTVARS
 ;		AL:			First character for drive key string
@@ -192,6 +199,16 @@
 ;		AX, CX, DX, SI, DI
 ;--------------------------------------------------------------------
-;; No work to do before going into FormatFunctionHotkeyString
-FormatDriveHotkeyString  equ  GetNonSelectedHotkeyDescriptionAttributeToDX
+FormatDriveHotkeyString:
+	; Invalid scancodes are filtered on HotkeyBar_StoreHotkeyToBootvarsIfValidKeystrokeInAX
+	; so here we have either drive letter or function key pressed. If latter, draw
+	; drive letters as unselected
+	cmp		BYTE [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bScancode], FIRST_FUNCTION_KEY_SCANCODE
+	jae		SHORT GetNonSelectedHotkeyDescriptionAttributeToDX
+
+	; Drive selected to boot from?
+	test	ch, ch
+	jnz		SHORT GetNonSelectedHotkeyDescriptionAttributeToDX
+	jmp		SHORT GetSelectedHotkeyDescriptionAttributeToDX
+
 
 ;--------------------------------------------------------------------
@@ -216,6 +233,7 @@
 %ifdef MODULE_BOOT_MENU
 
+GetSelectedHotkeyDescriptionAttributeToDX:
 	mov		si, ATTRIBUTE_CHARS.cHurryTimeout		; Selected hotkey
-	je		SHORT GetDescriptionAttributeToDX		; From compare with bScancode above
+	je		SHORT GetDescriptionAttributeToDX		; From compare with bScancode above and from FormatDriveHotkeyString
 
 GetNonSelectedHotkeyDescriptionAttributeToDX:
@@ -232,6 +250,7 @@
 %else ; if no MODULE_BOOT_MENU - No boot menu so use simpler attributes
 
+GetSelectedHotkeyDescriptionAttributeToDX:
 	mov		dx, (COLOR_ATTRIBUTE(COLOR_YELLOW, COLOR_CYAN) << 8) | MONO_REVERSE_BLINK
-	je		SHORT SelectAttributeFromDHorDLbasedOnVideoMode		; From compare with bScancode above
+	je		SHORT SelectAttributeFromDHorDLbasedOnVideoMode		; From compare with bScancode above and from FormatDriveHotkeyString
 
 GetNonSelectedHotkeyDescriptionAttributeToDX:
Index: trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm	(revision 593)
@@ -64,5 +64,5 @@
 	mov		al, FLG_DEVCONTROL_nIEN	; Disable IRQ
 .EnableDeviceIrq:
-%else
+%else	; ifndef MODULE_IRQ
 	mov		al, FLG_DEVCONTROL_nIEN	; Disable IRQ
 %endif ; MODULE_IRQ
Index: trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm	(revision 593)
@@ -35,11 +35,19 @@
 	mov		al, DRVDETECTINFO_size
 	mul		BYTE [cs:ROMVARS.bIdeCnt]
-	mov		di, BOOTVARS.rgDrvDetectInfo	; We must not initialize anything before this!
 	xchg	cx, ax
 %ifndef MODULE_HOTKEYS
+	mov		di, BOOTVARS.rgDrvDetectInfo	; We must not initialize anything before this!
 	jmp		Memory_ZeroESDIwithSizeInCX
 
 %else ; if MODULE_HOTKEYS
+	; Also zero HOTKEYVARS located above DRVDETECTINFO structs
+	mov		di, BOOTVARS.hotkeyVars
+	add		cx, BYTE HOTKEYVARS_size
 	call	Memory_ZeroESDIwithSizeInCX
+
+	; Store time when hotkeybar is displayed
+	; (it will be displayed after initialization is complete)
+	call	TimerTicks_ReadFromBdaToAX
+	mov		[es:BOOTVARS.hotkeyVars+HOTKEYVARS.wTimeWhenDisplayed], ax
 
 	; Initialize HOTKEYVARS by storing default drives to boot from
Index: trunk/XTIDE_Universal_BIOS/makefile
===================================================================
--- trunk/XTIDE_Universal_BIOS/makefile	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/makefile	(revision 593)
@@ -29,4 +29,5 @@
 # MODULE_VERY_LATE_INIT       Initialize on INT 13h if our INT 19h handler is not called           #
 # MODULE_POWER_MANAGEMENT     Power Management support                                             #
+# MODULE_WIN95_CMOS_HACK      Hack for Windows 95 compatibility                                    #
 #                                                                                                  #
 # Not modules but these affect the assembly:                                                       #
@@ -34,5 +35,4 @@
 # RELOCATE_INT13H_STACK **    Relocates INT 13h stack to beginning of stolen conventional memory   #
 # RESERVE_DIAGNOSTIC_CYLINDER Reserve one L-CHS cylinder for compatibility with old BIOSes         #
-# DANGEROUS_DETECTION         Scans Advanced Controllers from dangerous ports like mirrored PIC    #
 # NO_ATAID_VALIDATION ***     Excludes code that tries to ensure proper communication with drives  #
 # USE_186                     Use instructions supported by 80188/80186 and V20/V30 and later      #
@@ -41,4 +41,5 @@
 # USE_AT                      Use features supported on AT and later systems (not available on XT) #
 # USE_UNDOC_INTEL             Optimizations for Intel CPU:s - do NOT use on NEC V20/V30/Sony CPU:s #
+# USE_NEC_V                   Optimizations for use with NEC V20/V30 processors only               #
 # CLD_NEEDED                  Only needed for compatibility with buggy software/BIOSes             #
 #                                                                                                  #
@@ -116,8 +117,9 @@
 
 DEFINES_XT_TINY = MODULE_STRINGS_COMPRESSED MODULE_8BIT_IDE NO_ATAID_VALIDATION CLD_NEEDED
-DEFINES_386_8K = $(DEFINES_AT) USE_386 MODULE_ADVANCED_ATA
+DEFINES_386 = $(DEFINES_AT) USE_386 MODULE_ADVANCED_ATA MODULE_WIN95_CMOS_HACK
+DEFINES_386_LARGE = $(DEFINES_AT_LARGE) USE_386 MODULE_ADVANCED_ATA MODULE_WIN95_CMOS_HACK
 
 DEFINES_ALL_FEATURES = MODULE_8BIT_IDE MODULE_8BIT_IDE_ADVANCED MODULE_ADVANCED_ATA MODULE_EBIOS MODULE_BOOT_MENU MODULE_HOTKEYS MODULE_IRQ MODULE_SERIAL MODULE_SERIAL_FLOPPY MODULE_STRINGS_COMPRESSED MODULE_POWER_MANAGEMENT MODULE_COMPATIBLE_TABLES
-DEFINES_ALL_FEATURES += ELIMINATE_CGA_SNOW RELOCATE_INT13H_STACK RESERVE_DIAGNOSTIC_CYLINDER
+DEFINES_ALL_FEATURES += ELIMINATE_CGA_SNOW RELOCATE_INT13H_STACK RESERVE_DIAGNOSTIC_CYLINDER MODULE_WIN95_CMOS_HACK
 
 
@@ -140,5 +142,6 @@
 DEFS_AT_LARGE = $(DEFINES_AT_LARGE:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_LARGE)
 DEFS_XT_TINY = $(DEFINES_XT_TINY:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_TINY)
-DEFS_386_8K = $(DEFINES_386_8K:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_SMALL)
+DEFS_386 = $(DEFINES_386:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_SMALL)
+DEFS_386_LARGE = $(DEFINES_386_LARGE:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_LARGE)
 DEFS_ALL_FEATURES = $(DEFINES_ALL_FEATURES:%=-D%)
 
@@ -181,8 +184,8 @@
 	@echo All done!
 
-small: xt_tiny xt xtplus at 386_8k
+small: xt_tiny xt xtplus at 386
 	@echo All small binaries built!
 
-large: xt_large xtplus_large at_large
+large: xt_large xtplus_large at_large 386_large
 	@echo All large binaries built!
 
@@ -215,7 +218,11 @@
 	@echo * Tiny XT version "$(TARGET)_tiny.bin" built.
 
-386_8k:
-	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386_8K) -l"$(TARGET)_386.lst" -o"$(TARGET)_386.bin"
+386:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386) -l"$(TARGET)_386.lst" -o"$(TARGET)_386.bin"
 	@echo * Small 386 version "$(TARGET)_386.bin" built.
+
+386_large:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386_LARGE) -l"$(TARGET)_386l.lst" -o"$(TARGET)_386l.bin"
+	@echo * Large 386 version "$(TARGET)_386l.bin" built.
 
 strings: src\Strings.asm
@@ -237,4 +244,5 @@
 	@perl ..\Tools\checksum.pl $(TARGET)_atl.bin $(BIOS_SIZE_LARGE)
 	@perl ..\Tools\checksum.pl $(TARGET)_386.bin $(BIOS_SIZE_SMALL)
+	@perl ..\Tools\checksum.pl $(TARGET)_386l.bin $(BIOS_SIZE_LARGE)
 
 unused:
