Index: tags/XTIDE_Universal_BIOS_v1.1.4/Doc/changes.txt
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Doc/changes.txt	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Doc/changes.txt	(revision 37)
@@ -0,0 +1,94 @@
+XTIDE Universal BIOS v1.1.4 (24 August 2010)
+  * Correct number of drives is now returned from AH=08h when it is redirected to foreign BIOS.
+  * Interrupt controllers are now unmasked during drive reset.
+  * OS hooks are now enabled for all builds. IRQ waiting no longer uses HLT instruction to fix some EMM386 and VCPI issues.
+  * XT+ build is no more since it would now be the same as AT build
+
+
+XTIDE Universal BIOS v1.1.3 (1 August 2010)
+  * v1.1.1 broke booting from foreign drives, it is now fixed.
+  * Improved error handling a bit.
+  * Longer DRQ and IRQ timeouts to minimize write timouts with some (bad) CF cards.
+  * Default boot menu drive should now be properly selected.
+
+
+XTIDE Universal BIOS v1.1.2 (26 July 2010, no public release)
+  * Fixed a bug where Disk Parameter Table was accessed with wrong pointer register after writing last block.
+  * Cleaned AH=00h, Disk Controller Reset a bit.
+
+
+XTIDE Universal BIOS v1.1.1 (19 July 2010)
+*Booting is now possible from hard disks if floppy controller reset fails
+ since AH=00h, Disk Controller Reset now returns error code for the
+ requested drive only.
+*Now assembles with Yasm.
+
+
+XTIDE Universal BIOS v1.1.0 (first stable release, 2 May 2010)
+*Lite and full operating modes
+*Diagnostic cylinder no longer has to be reserved
+*Slave drives again work without master present
+*32-bit transfers for VLB and PCI IDE controllers
+*16- and 32-bit transfers are enabled on all builds
+*Boot menu hotkeys for all drives
+*Drive swapping is handled separately for floppy and hard disk drives so it
+ is now possible to install DOS to any hard disk from any floppy drive
+*INT 13h,AH=15h return value in DL now longer gets corrupted by drive swapping
+*Rewritten drive detection and lots of code cleaning
+*Longer timeout when detecting first drive
+*Minimum number of floppy drives can be specified if autodetection fails
+*Maybe other changes that i have forgotten
+
+XTIDE Universal BIOS v1.1.0 configuration and flashing program (idecfg.com)
+*Now works as a generic EEPROM flasher
+*Improvements to configuration menus
+*SDP can be completely disabled
+
+
+XTIDE Universal BIOS v1.0.0_RC2
+*No more boot menu slowdown when no XTIDE Universal BIOS
+ controlled drives present
+*Hard disks are now reset properly.
+ This fixes some Block Mode related bugs.
+*Major improvements for error handling
+*Small improvements for interrupt handling
+
+
+XTIDE Universal BIOS v1.0.0_RC1
+*Fixed 386+ stack exception bug
+*Stack is relocated for boot menu even if DPTs are not stored to 30:0h
+*Strings and boot menu are displayed properly on BIOSes that corrupts
+ AH when returning from INT 10h/AH=Eh
+*L-CHS addressing is now used for <=504MiB drives even if LBA is supported
+
+
+XTIDE Universal BIOS v1.0.0_b4
+*Boot menu with drive swapping
+*Block mode transfers
+*Cylinder limiting
+*Drive detection read errors are now properly detected
+*A little longer timeout value when detecting drives
+*Minor optimizations to save some bytes
+
+
+XTIDE Universal BIOS beta3
+*BIOS configuration and flashing program finally available
+*No more conflicts with other hard disk BIOSes
+*Slave drives should now be detected without master
+*Timeouts now use system timer
+*Variables can now be located to top of base memory
+*Completely rewritten interrupt handling
+*Minor optimizations to 8-bit transfers
+*CTRL can be held down to skip initialization
+*Late initialization to fix compatibility issues with old systems
+
+
+XTIDE Universal BIOS beta2
+*AT build and support for 16-bit IDE Controllers
+*XT+ build for 188/186/V20/V30/286 XTs
+*Auto detection for timeout values (AT+)
+*Minor optimizations
+
+
+XTIDE Universal BIOS beta1
+*Initial release
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Doc/readme.txt
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Doc/readme.txt	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Doc/readme.txt	(revision 37)
@@ -0,0 +1,5 @@
+See XTIDE Universal BIOS wiki pages for manual and other information:
+http://code.google.com/p/xtideuniversalbios/w/list
+
+XTIDE Universal BIOS discussion can be found at:
+http://www.vintage-computer.com/vcforum/showthread.php?17986-XTIDE-Universal-BIOS
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/ATA_ID.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/ATA_ID.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/ATA_ID.inc	(revision 37)
@@ -0,0 +1,418 @@
+; File name		:	ATA_ID.inc
+; Project name	:	IDE BIOS
+; Created date	:	30.10.2009
+; Last update	:	12.3.2010
+; Author		:	Tomi Tilli
+; Description	:	ATA Identify Drive information.
+%ifndef ATA_ID_INC
+%define ATA_ID_INC
+
+; ATA-1 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA1
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+	.wCylCnt	resw 1	; 1F, Number of cylinders
+				resw 1	; 2R
+	.wHeadCnt	resw 1	; 3F, Number of heads
+	.wBpTrck	resw 1	; 4F, Number of unformatted bytes per track
+	.wBpSect	resw 1	; 5F, Number of unformatted bytes per sector
+	.wSPT		resw 1	; 6F, Number of sectors per track 
+				resw 3	; 7...9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+	.wBuffType	resw 1	; 20F, Buffer type
+	.wBuffSize	resw 1	; 21F, Buffer size in 512 byte increments (0000h=not specified)
+	.wEccCnt	resw 1	; 22F, # of ECC bytes avail on read/write long cmds (0000h=not spec'd)
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;          per interrupt on read and write multiple commands
+						;		   (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]X
+	.wDWIO		resw 1	; 48F, Can perform doubleword I/O (boolean)
+	.wCaps		resw 1	; 49FRX, Capabilities
+				resw 1	; 50R
+				resb 1	; 51[0-7]X
+	.bPIOTiming	resb 1	; 51[8-15]F, PIO data transfer cycle timing mode
+				resb 1	; 52[0-7]X
+	.bDMATiming	resb 1	; 52[8-15]F, DMA data transfer cycle timing mode
+	.wFields	resw 1	; 53FVR, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+	.wCurCyls	resw 1	; 54V, Number of current cylinders
+	.wCurHeads	resw 1	; 55V, Number of current heads
+	.wCurSPT	resw 1	; 56V, Number of current sectors per track
+	.dwCurSCnt	resd 1	; 57...58V, Current capacity in sectors
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA mode only)
+	.bSDMASupp	resb 1	; 62[0-7]F, Single word DMA transfer modes supported
+	.bSDMAAct	resb 1	; 62[8-15]V, Single word DMA transfer mode active
+	.bMDMASupp	resb 1	; 63[0-7]F, Multiword DMA transfer modes supported
+	.bMDMAAct	resb 1	; 63[8-15]V, Multiword DMA transfer mode active
+endstruc
+
+; ATA-1 Word 0, General configuration
+A1_wGenCfg_NONMAG		EQU	(1<<15)	; Reserved for non-magnetic drives
+A1_wGenCfg_FGAPREQ		EQU	(1<<14)	; Format speed tolerance gap required
+A1_wGenCfg_TRCKOFF		EQU	(1<<13)	; Track offset option available
+A1_wGenCfg_DATAOFF		EQU	(1<<12)	; Data strobe offset option available
+A1_wGenCfg_ROTTOL		EQU	(1<<11)	; Rotational speed tolerance is > 0,5%
+A1_wGenCfg_XFERFAST		EQU (1<<10)	; Disk transfer rate > 10 Mbs
+A1_wGenCfg_XFERMED		EQU	(1<<9)	; Disk transfer rate > 5Mbs but <= 10Mbs
+A1_wGenCfg_XFERSLOW		EQU (1<<8)	; Disk transfer rate <= 5Mbs
+A1_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable cartridge drive
+A1_wGenCfg_FIXED		EQU	(1<<6)	; Fixed drive
+A1_wGenCfg_MOTCTRL		EQU	(1<<5)	; Spindle motor control option implemented
+A1_wGenCfg_HEADSLOW		EQU	(1<<4)	; Head switch time > 15 usec
+A1_wGenCfg_NOTMFM		EQU	(1<<3)	; Not MFM encoded
+A1_wGenCfg_SOFTSECT		EQU	(1<<2)	; Soft sectored
+A1_wGenCfg_HARDSECT		EQU	(1<<1)	; Hard sectored
+
+; ATA-1 Word 49, Capabilities
+A1_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A1_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-1 Word 53, Fields
+A1_wFields_54to58		EQU	(1<<0)	; The fields reported in words 54-58 are valid
+
+; ATA-1 Word 59 high byte, Block mode flags
+A1_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; ATA-2 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA2
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+	.wCylCnt	resw 1	; 1F, Number of logical cylinders
+				resw 1	; 2R
+	.wHeadCnt	resw 1	; 3F, Number of logical heads
+				resw 1	; 4X
+				resw 1	; 5X
+	.wSPT		resw 1	; 6F, Number of logical sectors per track 
+				resw 3	; 7...9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+				resw 1	; 20X
+				resw 1	; 21X
+	.wEccCnt	resw 1	; 22F, # of ECC bytes avail on read/write long cmds (0000h=not spec'd)
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;          per interrupt on read and write multiple commands
+						;		   (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]X
+				resw 1	; 48R
+	.wCaps		resw 1	; 49FRX, Capabilities
+				resw 1	; 50R
+				resb 1	; 51[0-7]X
+	.bPIOTiming	resb 1	; 51[8-15]F, PIO data transfer cycle timing mode
+				resb 1	; 52[0-7]X
+	.bDMATiming	resb 1	; 52[8-15]F, DMA data transfer cycle timing mode
+	.wFields	resw 1	; 53FVR, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+	.wCurCyls	resw 1	; 54V, Number of current logical cylinders
+	.wCurHeads	resw 1	; 55V, Number of current logical heads
+	.wCurSPT	resw 1	; 56V, Number of current logical sectors per track
+	.dwCurSCnt	resd 1	; 57...58V, Current capacity in sectors
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid	
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA mode only)
+	.bSDMASupp	resb 1	; 62[0-7]F, Single word DMA transfer modes supported
+	.bSDMAAct	resb 1	; 62[8-15]V, Single word DMA transfer mode active
+	.bMDMASupp	resb 1	; 63[0-7]F, Multiword DMA transfer modes supported
+	.bMDMAAct	resb 1	; 63[8-15]V, Multiword DMA transfer mode active
+	
+	; Words 64-70 are valid only if bit1 is set in .wFields (ATA2+)
+	.bPIOSupp	resb 1	; 64[0-7]F, Advanced PIO Transfer Modes Supported
+				resb 1	; 64[8-15]R
+	.wMDMAMinCy	resw 1	; 65F, Minimum Multiword DMA Transfer Cycle Time Per Word
+	.wMDMARecCy	resw 1	; 66F, Manufacturers Recommended Multiword DMA Transfer Cycle Time
+	.wPIOMinCy	resw 1	; 67F, Minimum PIO Transfer Cycle Time Without Flow Control
+	.wPIOMinCyF	resw 1	; 68F, Minimum PIO Transfer Cycle Time With IORDY Flow Control
+endstruc
+
+; ATA-2 Word 0, General configuration
+A2_wGenCfg_NONMAG		EQU	(1<<15)	; Reserved for non-magnetic drives
+A2_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable media device
+A2_wGenCfg_FIXED		EQU	(1<<6)	; Not removable controller and/or device
+
+; ATA-1 Word 49, Capabilities
+A2_wCaps_TIMER			EQU	(1<<13)	; Standby timer values as specified in this standard are supported
+A2_wCaps_IORDY			EQU	(1<<11)	; IORDY supported
+A2_wCaps_CANDISIORDY	EQU	(1<<10)	; IORDY can be disabled
+A2_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A2_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-2 Word 53, Fields
+A2_wFields_54to58		EQU	(1<<0)	; The fields reported in words 54-58 are valid
+A2_wFields_64to70		EQU	(1<<1)	; The fields reported in words 64-70 are valid
+
+; ATA-2 Word 59 high byte, Block mode flags
+A2_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; ATA-6 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA6
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+				resw 1	; 1X, Obsolete (Number of logical cylinders)
+				resw 1	; 2V, Specific configuration
+				resw 1	; 3X, Obsolete (Number of logical heads)
+				resw 1	; 4X
+				resw 1	; 5X
+				resw 1	; 6X, Obsolete (Number of logical sectors per track) 
+				resw 2	; 7...8V, Reserved for assignment by the CompactFlash Association
+				resw 1	; 9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+				resw 1	; 20X
+				resw 1	; 21X
+				resw 1	; 22X, Obsolete (# of ECC bytes avail on read/write long cmds (0000h=not spec'd))
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;           per interrupt on read and write multiple commands
+						;		    (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]F, 80h
+				resw 1	; 48R
+	.wCaps		resw 1	; 49FX, Capabilities
+	.wCapsHigh	resw 1	; 50FX, Capabilities 2
+				resw 1	; 51X, Obsolete (PIO data transfer cycle timing mode)
+				resw 1	; 52X, Obsolete (DMA data transfer cycle timing mode)
+	.wFields	resw 1	; 53FX, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+				resw 1	; 54X, Obsolete (Number of current logical cylinders)
+				resw 1	; 55X, Obsolete (Number of current logical heads)
+				resw 1	; 56X, Obsolete (Number of current logical sectors per track)
+				resd 1	; 57...58X, Obsolete (Current capacity in sectors)
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA-28)
+				resb 1	; 62[0-7]X, Obsolete (Single word DMA transfer modes supported)
+				resb 1	; 62[8-15]X, Obsolete (Single word DMA transfer mode active)
+	.wMDMA		resw 1	; 63FV, Multiword DMA transfer modes supported and active
+
+	; Words 64-70 are valid only if bit1 is set in .wFields (ATA2+)
+	.bPIOSupp	resb 1	; 64[0-7]F, Advanced PIO Transfer Modes Supported
+				resb 1	; 64[8-15]R
+	.wMDMAMinCy	resw 1	; 65F, Minimum Multiword DMA Transfer Cycle Time Per Word
+	.wMDMARecCy	resw 1	; 66F, Manufacturers Recommended Multiword DMA Transfer Cycle Time
+	.wPIOMinCy	resw 1	; 67F, Minimum PIO Transfer Cycle Time Without Flow Control
+	.wPIOMinCyF	resw 1	; 68F, Minimum PIO Transfer Cycle Time With IORDY Flow Control
+				resw 71-69	; 69...70R
+
+	; Words 71...74 are reserved for IDENTIFY PACKET DEVICE command
+				resw 75-71	; 71...74R
+
+	.wQueue		resw 1	; 75[0-4]F, Maximum queue depth - 1
+				resw 80-76	; 76...79R
+
+	.wMajorVer	resw 1	; 80F, Major Version Number
+	.wMinorVer	resw 1	; 81F, Minor Version Number
+	.wSetSup82	resw 1	; 82F, Command set supported
+	.wSetSup83	resw 1	; 83F, Command sets supported
+	.wSetSup84	resw 1	; 84F, Command set / Feature supported extension
+	.wEnFor82	resw 1	; 85FV, Command set / feature enabled (for word 82)
+	.wEnFor83	resw 1	; 86FV, Command set / feature enabled (for word 83)
+	.wEnFor84	resw 1	; 87FV, Command set / feature enabled (for word 84)
+
+	; Word 88 is valid only if bit2 is set in .wFields (word 53)
+	.wUDMA		resw 1	; 88FV, Ultra DMA Mode support
+
+	.wEraseTime	resw 1	; 89F, Time required for security erase unit completion
+	.wEnhErTime	resw 1	; 90F, Time required for Enhanced security erase completion
+	.wCurPower	resw 1	; 91V, Current advanced power management value
+	.wPWRev		resw 1	; 92V, Master Password Revision Code
+	.wReset		resw 1	; 93FV, Hardware reset result
+	.bCurAcous	resb 1	; 94[0-7]V, Current automatic acoustic management value
+	.bRecAcous	resb 1	; 94[8-15]V, Vendors recommended acoustic management value
+				resw 100-95		; 95...99R
+	.qwLBACnt	resb 8	; 100...103V, Total number of user addressable sectors (LBA48)
+				resw 127-104	; 104...126R
+	.wRMSN		resw 1	; 127F, Removable Media Status Notification feature set support
+	.wSecurity	resw 1	; 128FV, Security Status
+				resw 160-129	; 129...159X
+	.wCFAPower	resw 1	; 160FV, CFA Power Mode 1
+				resw 176-161	; 161...175R, Reserved for assignment by the CompactFlash Association
+	.strMediaSr	resw 206-176	; 176...205V, Current media serial number
+				resw 255-206	; 206...254R
+	.bSignature	resb 1	; 255[0-7]X, Signature
+	.bChecksum	resb 1	; 255[8-15]X, Checksum
+endstruc
+
+; ATA-6 Word 0, General configuration
+A6_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable media device
+A6_wGenCfg_INCOMPLETE	EQU	(1<<2)	; Response incomplete
+
+; ATA-6 Word 49, Capabilities
+A6_wCaps_TIMER			EQU	(1<<13)	; Standby timer values as specified in this standard are supported
+A6_wCaps_IORDY			EQU	(1<<11)	; IORDY supported
+A6_wCaps_CANDISIORDY	EQU	(1<<10)	; IORDY can be disabled
+A6_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A6_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-6 Word 53, Fields
+A6_wFields_88			EQU	(1<<2)	; The fields reported in word 88 are valid
+A6_wFields_64to70		EQU	(1<<1)	; The fields reported in words 64-70 are valid
+
+; ATA-6 Word 59 high byte, Block mode flags
+A6_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+; ATA-6 Word 63, Multiword DMA Mode
+A6_wMDMA_MODE2_SELECTED	EQU	(1<<10)	; Multiword DMA mode 2 is selected
+A6_wMDMA_MODE1_SELECTED	EQU	(1<<9)	; Multiword DMA mode 1 is selected
+A6_wMDMA_MODE0_SELECTED	EQU	(1<<8)	; Multiword DMA mode 0 is selected
+A6_wMDMA_MODE2_SUPRTD	EQU	(1<<2)	; Multiword DMA mode 2 and below are supported
+A6_wMDMA_MODE1_SUPRTD	EQU	(1<<1)	; Multiword DMA mode 1 and below are supported
+A6_wMDMA_MODE0_SUPRTD	EQU	(1<<0)	; Multiword DMA mode 0 is supported
+
+; ATA-6 Word 80, Major version number
+A6_wMajorVer_ATA6		EQU	(1<<6)
+A6_wMajorVer_ATA5		EQU	(1<<5)
+A6_wMajorVer_ATA4		EQU	(1<<4)
+A6_wMajorVer_ATA3		EQU	(1<<3)
+
+; ATA-6 Word 82, Command set supported
+A6_wSetSup82_NOP		EQU	(1<<14)	; NOP command supported
+A6_wSetSup82_RDBUFF		EQU	(1<<13)	; READ BUFFER command supported
+A6_wSetSup82_WRBUFF		EQU	(1<<12)	; WRITE BUFFER command supported
+A6_wSetSup82_PROT_AREA	EQU	(1<<10)	; Host Protected Area feature set supported
+A6_wSetSup82_DEV_RESET	EQU	(1<<9)	; DEVICE RESET command supported
+A6_wSetSup82_SERVICE	EQU	(1<<8)	; SERVICE interrupt supported
+A6_wSetSup82_RELEASE	EQU	(1<<7)	; Release interrupt supported
+A6_wSetSup82_LOOKAHEAD	EQU	(1<<6)	; Look-ahead supported
+A6_wSetSup82_WRCACHE	EQU	(1<<5)	; Write cache supported
+A6_wSetSup82_POWERMAN	EQU	(1<<3)	; Power Management feature set supported
+A6_wSetSup82_REM_MEDIA	EQU	(1<<2)	; Removable Media feature set supported
+A6_wSetSup82_SECURITY	EQU	(1<<1)	; Security Mode feature set supported
+A6_wSetSup82_SMART		EQU	(1<<0)	; SMART feature set supported
+
+; ATA-6 Word 83, Command sets supported
+A6_wSetSup83_FLUSH_EXT	EQU	(1<<13)	; FLUSH CACHE EXT command supported
+A6_wSetSup83_FLUSH		EQU	(1<<12)	; FLUSH CACHE command supported
+A6_wSetSup83_CFG		EQU	(1<<11)	; Device Configuration Overlay feature set supported
+A6_wSetSup83_LBA48		EQU	(1<<10)	; 48-bit LBA feature set supported
+A6_wSetSup83_ACOUSTIC	EQU	(1<<9)	; Automatic Acoustic Management feature set supported
+A6_wSetSup83_SET_MAX	EQU	(1<<8)	; SET MAX security extension supported
+A6_wSetSup83_FEATURES	EQU	(1<<6)	; SET FEATURES subcommand required to spinup after power-up
+A6_wSetSup83_POWERUP	EQU	(1<<5)	; Power-Up In Standby feature set supported
+A6_wSetSup83_RMSN		EQU	(1<<4)	; Removable Media Status Notification feature set supported
+A6_wSetSup83_APM		EQU	(1<<3)	; Advanced Power Management feature set supported
+A6_wSetSup83_CFA		EQU	(1<<2)	; CFA feature set supported
+A6_wSetSup83_DMAQUEUED	EQU	(1<<1)	; READ/WRITE DMA QUEUED supported
+A6_wSetSup83_MICROCODE	EQU	(1<<0)	; DOWNLOAD MICROCODE command supported
+
+; ATA-6 Word 84, Command set/feature supported extension
+A6_wSetSup84_GENLOG		EQU	(1<<5)	; General Purpose Logging feature set supported
+A6_wSetSup84_MEDIAPASS	EQU	(1<<3)	; Media Card Pass Through Command feature set supported
+A6_wSetSup84_MEDIASER	EQU	(1<<2)	; Media serial number supported
+A6_wSetSup84_SMARTTEST	EQU	(1<<1)	; SMART self-test supported
+A6_wSetSup84_SMARTLOG	EQU	(1<<0)	; SMART error logging supported
+
+; ATA-6 Word 85, Command set/feature enabled (supported by word 82)
+A6_wEnFor82_NOP			EQU	(1<<14)	; NOP command enabled
+A6_wEnFor82_RDBUFF		EQU	(1<<13)	; READ BUFFER command enabled
+A6_wEnFor82_WRBUFF		EQU	(1<<12)	; WRITE BUFFER command enabled
+A6_wEnFor82_PROT_AREA	EQU	(1<<10)	; Host Protected Area feature set enabled
+A6_wEnFor82_DEV_RESET	EQU	(1<<9)	; DEVICE RESET command enabled
+A6_wEnFor82_SERVICE		EQU	(1<<8)	; SERVICE interrupt enabled
+A6_wEnFor82_RELEASE		EQU	(1<<7)	; Release interrupt enabled
+A6_wEnFor82_LOOKAHEAD	EQU	(1<<6)	; Look-ahead enabled
+A6_wEnFor82_WRCACHE		EQU	(1<<5)	; Write cache enabled
+A6_wEnFor82_POWERMAN	EQU	(1<<3)	; Power Management feature set enabled
+A6_wEnFor82_REM_MEDIA	EQU	(1<<2)	; Removable Media feature set enabled
+A6_wEnFor82_SECURITY	EQU	(1<<1)	; Security Mode feature set enabled
+A6_wEnFor82_SMART		EQU	(1<<0)	; SMART feature set enabled
+
+; ATA-6 Word 86, Command set/feature enabled (supported by word 83)
+A6_wEnFor83_FLUSH_EXT	EQU	(1<<13)	; FLUSH CACHE EXT command supported
+A6_wEnFor83_FLUSH		EQU	(1<<12)	; FLUSH CACHE command supported
+A6_wEnFor83_CFG			EQU	(1<<11)	; Device Configuration Overlay supported
+A6_wEnFor83_LBA48		EQU	(1<<10)	; 48-bit LBA feature set supported
+A6_wEnFor83_ACOUSTIC	EQU	(1<<9)	; Automatic Acoustic Management feature set enabled
+A6_wEnFor83_SET_MAX		EQU	(1<<8)	; SET MAX security extension enabled by SET MAX SET PASSWORD
+A6_wEnFor83_FEATURES	EQU	(1<<6)	; SET FEATURES subcommand required to spinup after power-up
+A6_wEnFor83_POWERUP		EQU	(1<<5)	; Power-Up In Standby feature set enabled
+A6_wEnFor83_RMSN		EQU	(1<<4)	; Removable Media Status Notification feature set enabled
+A6_wEnFor83_APM			EQU	(1<<3)	; Advanced Power Management feature set enabled
+A6_wEnFor83_CFA			EQU	(1<<2)	; CFA feature set enabled
+A6_wEnFor83_DMAQUEUED	EQU	(1<<1)	; READ/WRITE DMA QUEUED supported
+A6_wEnFor83_MICROCODE	EQU	(1<<0)	; DOWNLOAD MICROCODE command supported
+
+; ATA-6 Word 87, Command set/feature default
+A6_wEnFor84_GENLOG		EQU	(1<<5)	; General Purpose Logging feature set supported
+A6_wEnFor84_MEDIAPASS	EQU	(1<<3)	; Media Card Pass Through Command feature set enabled
+A6_wEnFor84_MEDIASER	EQU	(1<<2)	; Media serial number is valid
+A6_wEnFor84_SMARTTEST	EQU	(1<<1)	; SMART self-test supported
+A6_wEnFor84_SMARTLOG	EQU	(1<<0)	; SMART error logging supported
+
+; ATA-6 Word 88, Ultra DMA Mode
+A6_wUDMA_MODE5_SELECTED	EQU	(1<<13)	; Ultra DMA mode 5 is selected
+A6_wUDMA_MODE4_SELECTED	EQU	(1<<12)	; Ultra DMA mode 4 is selected
+A6_wUDMA_MODE3_SELECTED	EQU	(1<<11)	; Ultra DMA mode 3 is selected
+A6_wUDMA_MODE2_SELECTED	EQU	(1<<10)	; Ultra DMA mode 2 is selected
+A6_wUDMA_MODE1_SELECTED	EQU	(1<<9)	; Ultra DMA mode 1 is selected
+A6_wUDMA_MODE0_SELECTED	EQU	(1<<8)	; Ultra DMA mode 0 is selected
+A6_wUDMA_MODE5_SUPRTD	EQU	(1<<5)	; Ultra DMA mode 5 and below are supported
+A6_wUDMA_MODE4_SUPRTD	EQU	(1<<4)	; Ultra DMA mode 4 and below are supported
+A6_wUDMA_MODE3_SUPRTD	EQU	(1<<3)	; Ultra DMA mode 3 and below are supported
+A6_wUDMA_MODE2_SUPRTD	EQU	(1<<2)	; Ultra DMA mode 2 and below are supported
+A6_wUDMA_MODE1_SUPRTD	EQU	(1<<1)	; Ultra DMA mode 1 and below are supported
+A6_wUDMA_MODE0_SUPRTD	EQU	(1<<0)	; Ultra DMA mode 0 is supported
+
+; ATA-6 Word 93, Hardware reset result
+A6_wReset_CBLID_BELOW	EQU	(1<<13)	; Device detected CBLID- above ViH
+A6_wReset_DEV1_PDIAG	EQU	(1<<11)	; Device 1 asserted PDIAG-
+A6_wReset_DEV0_RESP_D1	EQU	(1<<6)	; Device 0 responds when Device 1 is selected
+A6_wReset_DEV0_DASP		EQU	(1<<5)	; Device 0 detected the assertion of DASP-
+A6_wReset_DEV0_PDIAG	EQU	(1<<4)	; Device 0 detected the assertion of PDIAG
+A6_wReset_DEV0_PASSED	EQU	(1<<3)	; Device 0 passed diagnostics
+A6_wReset_MASK_DEV1_DETERMINE	EQU ((1<<10)|(1<<9))	; These bits indicate how Device 1 determined the device number
+A6_wReset_MASK_DEV0_DETERMINE	EQU ((1<<2)|(1<<1))		; These bits indicate how Device 0 determined the device number:
+A6_wReset_RESERVED		EQU	00b
+A6_wReset_JUMPER		EQU	01b		; a jumper was used
+A6_wReset_CSEL			EQU	10b		; the CSEL signal was used
+A6_wReset_UNKNOWN		EQU	11b		; some other method was used or the method is unknown
+
+; ATA-6 Word 127, Removable Media Status Notification feature set support
+A6_wRMSN_SUPPORTED		EQU	(1<<0)	; Removable Media Status Notification feature supported
+
+; ATA-6 Word 128, Security status
+A6_wSecurity_MAX		EQU	(1<<8)	; Security level 0 = High, 1 = Maximum
+A6_wSecurity_ENH_ERASE	EQU	(1<<5)	; Enhanced security erase supported
+A6_wSecurity_EXPIRED	EQU	(1<<4)	; Security count expired
+A6_wSecurity_FROZEN		EQU	(1<<3)	; Security frozen
+A6_wSecurity_LOCKED		EQU	(1<<2)	; Security locked
+A6_wSecurity_ENABLED	EQU	(1<<1)	; Security enabled
+A6_wSecurity_SUPPORTED	EQU	(1<<0)	; Security supported
+
+; ATA-6 Word 160, CFA Power Mode 1
+A6_wCFAPower_WORDSUPP	EQU	(1<<15)	; Word 160 supported
+A6_wCFAPower_REQUIRED	EQU	(1<<13)	; CFA power mode 1 is required for one or more commands implemented by the device
+A6_wCFAPower_DISABLED	EQU	(1<<12)	; CFA power mode 1 disabled
+A6_wCFAPower_MASK_mA	EQU	0FFFh	; Maximum current in mA
+
+
+%endif ; ATA_ID_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BiosData.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BiosData.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BiosData.inc	(revision 37)
@@ -0,0 +1,150 @@
+; File name		:	BiosData.inc
+; Project name	:	IDE BIOS
+; Created date	:	28.7.2007
+; Last update	:	23.3.2010
+; Author		:	Tomi Tilli
+; Description	:	Equates for BIOS Data Area.
+%ifndef BIOSDATA_INC
+%define BIOSDATA_INC
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; BIOS DATA AREA VARIABLES ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; BIOS Data Area (related to floppy drives and hard disks)
+struc BDA
+					resb	400h	; 40:0h, Start of BDA
+	.wCOM1			resb	2		; 0:400h, Serial I/O Address, Port 1
+	.wCOM2			resb	2		; 0:402h, Serial I/O Address, Port 2
+	.wCOM3			resb	2		; 0:404h, Serial I/O Address, Port 3
+	.wCOM4			resb	2		; 0:406h, Serial I/O Address, Port 4
+	.wLPT1			resb	2		; 0:408h, Parallel I/O Address, Port 1
+	.wLPT2			resb	2		; 0:40Ah, Parallel I/O Address, Port 2
+	.wLPT3			resb	2		; 0:40Ch, Parallel I/O Address, Port 3					
+	.wLPT4:							; 0:40Eh, Parallel I/O Address, Port 4 (PC/XT)
+	.wSegEBDA		resb	2		; 0:40Eh, Extended BIOS Data Area segment (AT+)
+	
+	.wEquipment		resb	2		; 0:410h, Equipment Word
+	.bTest			resb	1		; 0:412h, Manufacturing test
+	.wBaseMem		resb	2		; 0:413h, Base Memory Size in kB
+	.wAdptrMem:						; 0:415h, Adapter Memory Size (PC/XT)
+	.wError			resb	2		; 0:415h, Error Codes (AT+)
+	.bKBFlgs1		resb	1		; 0:417h, Keyboard, Shift Flags, Set 1
+	.bKBFlgs2		resb	1		; 0:418h, Keyboard, Shift Flags, Set 2
+	.bKBNumpad		resb	1		; 0:419h, Keyboard, ALT+Numpad work area
+	.wKBHead		resb	2		; 0:41Ah, Keyboard, Head of buffer pointer
+	.wKBTail		resb	2		; 0:41Ch, Keyboard, Tail of buffer pointer
+	.rgwKBBuff		resb	32		; 0:41Eh, Keyboard, 16-word buffer
+	
+	.bFDRecal		resb	1		; 0:43Eh, Diskette, Recalibrate status
+	.bFDMotor		resb	1		; 0:43Fh, Diskette, Motor status
+	
+	.bFDMotTime		resb	1		; 0:440h, Diskette, Motor timeout counter
+	.bFDRetST		resb	1		; 0:441h, Diskette, Controller status return code
+	.rgbFDStatus	resb	7		; 0:442h, Diskette, Diskette and Disk Controller status bytes
+	.bVidMode		resb	1		; 0:449h, Video, Mode
+	.wVidColumns	resb	2		; 0:44Ah, Video, Number of columns
+	.wVidBpP		resb	2		; 0:44Ch, Video, Total number of bytes per page
+	.wVidPageOff	resb	2		; 0:44Eh, Video, Current page offset
+	
+	.rgwVidCurPos	resb	16		; 0:450h, Video, Cursor position, pages 0...7
+	
+	.wVidCurShape	resb	2		; 0:460h, Video, Cursor shape
+	.bVidPageIdx	resb	1		; 0:462h, Video, Active display page
+	.wVidPort		resb	2		; 0:463h, Video, I/O Port number base
+	.bVidModeReg	resb	1		; 0:465h, Video, Internal mode register
+	.bVidPalette	resb	1		; 0:466h, Video, Color palette
+	.wCasTimeCnt:					; 0:467h, Cassette, Time count at data edge (PC)
+	.wGenOff		resb	2		; 0:467h, General use offset (XT+)
+	.wCasCRC:						; 0:469h, Cassette, CRC register (PC)
+	.wGenSeg		resb	2		; 0:469h, General use segment (XT+)
+	.bCasLast:						; 0:46Bh, Cassette, Last value read
+	.bLastIRQ		resb	1		; 0:46Bh, Last interrupt that occurred (XT+)
+	.dwTimerTicks	resb	4		; 0:46Ch, Timer ticks count
+	
+	.bTimer24h		resb	1		; 0:470h, Timer ticks rollover flag
+	.bKBCtrlBrk		resb	1		; 0:471h, Keyboard, Ctrl+Break flag
+	.wBoot			resb	2		; 0:472h, Warm boot flag
+	.bHDLastSt		resb	1		; 0:474h, Hard Disk, Status of Last Operation (XT+)
+	.bHDCount		resb	1		; 0:475h, Hard Disk, Number of HDs Attached (XT+)
+	.bHDCtrl		resb	1		; 0:476h, Hard Disk, Control Byte (temp, XT+) 
+	.bHDPortOff		resb	1		; 0:477h, Hard Disk, Port Offset (XT)
+	.bLPT1Timeout	resb	1		; 0:478h, Parallel Printer 1, Timeout (XT+)
+	.bLPT2Timeout	resb	1		; 0:479h, Parallel Printer 2, Timeout (XT+)
+	.bLPT3Timeout	resb	1		; 0:47Ah, Parallel Printer 3, Timeout (XT+)
+	.bLPT4Timeout	resb	1		; 0:47Bh, Parallel Printer 4, Timeout (XT+)
+	.bCOM1Timeout	resb	1		; 0:47Ch, Serial 1, Timeout (XT+)
+	.bCOM2Timeout	resb	1		; 0:47Dh, Serial 2, Timeout (XT+)
+	.bCOM3Timeout	resb	1		; 0:47Eh, Serial 3, Timeout (XT+)
+	.bCOM4Timeout	resb	1		; 0:47Fh, Serial 4, Timeout (XT+)
+	
+	.wKBPtrStart	resb	2		; 0:480h, Keyboard, Pointer to start of buffer (XT+)
+	.wKBPtrEnd		resb	2		; 0:482h, Keyboard, Pointer to end of buffer (XT+)
+	.bVidRows		resb	1		; 0:484h, Video, Number of rows (EGA+)
+	.wVidPpC		resb	2		; 0:485h, Video, Pixels per character (EGA+)
+	.bVidOptns		resb	1		; 0:487h, Video, Options (EGA+)
+	.bVidSwitches	resb	1		; 0:488h, Video, Switches (EGA+)
+	.bVidSave1		resb	1		; 0:489h, Video, Save area 1 (VGA+)
+	.bVidSave2		resb	1		; 0:48Ah, Video, Save area 2 (VGA+)
+	.bFDCfgData		resb	1		; 0:48Bh, Diskette, Configuration data (AT+)
+	.bHDStatus		resb	1		; 0:48Ch, Hard Disk, Status Register (AT+)
+	.bHDError		resb	1		; 0:48Dh, Hard Disk, Error Register (AT+)
+	.bHDTaskFlg		resb	1		; 0:48Eh, Hard Disk, Task Complete Flag (AT+)
+	.bFDCtrlInfo	resb	1		; 0:48Fh, Diskette, Controller information (AT+)
+	
+	.bFDMedia0		resb	1		; 0:490h, Diskette 0, Media state (AT+)
+	.bFDMedia1		resb	1		; 0:491h, Diskette 1, Media state (AT+)
+	.bFDOpStart0	resb	1		; 0:492h, Diskette 0, Operational starting state (AT+)
+	.bFDOpStart1	resb	1		; 0:493h, Diskette 1, Operational starting state (AT+)
+	.bFDCurCyl0		resb	1		; 0:494h, Diskette 0, Current cylinder (AT+)
+	.bFDCurCyl1		resb	1		; 0:495h, Diskette 1, Current cylinder (AT+)
+	.bKBFlgs3		resb	1		; 0:496h, Keyboard, Status flags 3 (AT+)
+	.bKBFlgs4		resb	1		; 0:497h, Keyboard, Status flags 4 (AT+)
+	.dwWaitPtr		resb	4		; 0:498h, User's wait flag pointer (AT+)
+	.dwWaitCnt		resb	4		; 0:49Ch, User's wait count (AT+)
+	
+	.bWaitFlg		resb	1		; 0:4A0h, Wait flag (AT+)
+	.rgbLAN			resb	7		; 0:4A1h, Local Area Network (AT+)
+	.dwVidPtr		resb	4		; 0:4A8h, Video, Parameter Control Block Pointer (EGA+)
+					resb	22h		; Reserved from 0:4ACh...0:4CDh
+
+	.dwDays			resb	4		; 0:4CEh, Clock, Days since 1980 (some BIOSes, AT+)
+					resb	2Eh		; Reserved from 0:4D2h...0:4FFh
+
+	.bPrntScrn		resb	1		; 0:500, Print screen status
+endstruc
+
+; BDA struct with only Hard Disk related locations
+struc HDBDA
+					resb	474h
+	.bHDLastSt		resb	1		; 0:474h, Status of Last Operation (XT+)
+	.bHDCount		resb	1		; 0:475h, Number of HDs Attached (XT+)
+	.bHDCtrl		resb	1		; 0:476h, Control Byte (temp, XT+)
+	.bHDPortOff		resb	1		; 0:477h, Port Offset (XT)
+					resb	15h
+	.bHDStatus:						; 0:48Ch, Status Register (AT+)
+	.bHDError:						; 0:48Dh, Error Register (AT+)
+	.wHDStAndErr	resb	2
+	.bHDTaskFlg		resb	1		; 0:48Eh, Task Complete Flag (AT+)
+endstruc
+
+
+;--------------------------------------------------------------------
+; Load BDA (Bios Data Area) segment to wanted segment register.
+;
+; LOAD_BDA_SEGMENT_TO
+;	Parameters:
+;		%1:		Destination Segment Register
+;		%2:		Temporary WORD Register
+;	Returns:
+;		%1:		BDA segment (zero)
+;	Corrupts registers:
+;		%2
+;--------------------------------------------------------------------
+%macro LOAD_BDA_SEGMENT_TO 2
+	xor		%2, %2
+	mov		%1, %2
+%endmacro
+
+
+%endif ; BIOSDATA_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootMenu.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootMenu.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootMenu.inc	(revision 37)
@@ -0,0 +1,21 @@
+; File name		:	BootMenu.inc
+; Project name	:	IDE BIOS
+; Created date	:	26.3.2010
+; Last update	:	26.3.2010
+; Author		:	Tomi Tilli
+; Description	:	Equates used in Boot Menu.
+%ifndef BOOTMENU_INC
+%define BOOTMENU_INC
+
+; Boot menu sizes
+MENU_TITLE_LINE_CNT		EQU	3		; Number of title lines
+MENU_INFO_LINE_CNT		EQU	3		; Number of info lines
+MENU_WIDTH_IN_CHARS		EQU	38		; Menu width in characters
+MENU_HEIGHT_IN_CHARS_WITH_INFO		EQU	(MENU_TITLE_LINE_CNT + MENU_INFO_LINE_CNT + 4)
+MENU_HEIGHT_IN_CHARS_WITHOUT_INFO	EQU	(MENU_TITLE_LINE_CNT + 3)
+
+; Function IDs
+ID_BOOTFUNC_ROMBOOT		EQU	0		; ROM boot
+
+
+%endif ; BOOTMENU_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootVars.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootVars.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/BootVars.inc	(revision 37)
@@ -0,0 +1,37 @@
+; File name		:	BootVars.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Defines for BOOTVARS struct used by boot menu
+;					and drive initialization.
+%ifndef BOOTVARS_INC
+%define BOOTVARS_INC
+
+
+; Boot Menu Information Table. These are generated for all XTIDE Universal
+; BIOS drives. Available only until boot is successfull.
+LEN_BOOTNFO_DRV		EQU		26		; Bytes reserved for drive name
+struc BOOTNFO
+	.twSectCnt		resb	6		; Total user addressable sectors
+	.szDrvName		resb	LEN_BOOTNFO_DRV+1	; Drive name
+					resb	1		; Alignment
+endstruc
+
+
+; Pre-boot variables. These do not exist after successfull boot to OS.
+; Segment is always 0000h, same as BDA segment
+struc BOOTVARS
+					resb	800h
+	.dwSys18h		resb	4		;  800h, System INT 18h handler (Diskless boot, Boot failure)
+	.dwPostStack	resb	4		;  804h, POST stack when entering INT 19h
+	.bMenuHotkey	resb	1		;  808h, Boot Menu hotkey, zero if none pressed
+					resb	3
+	.rgBootNfo		resb	73F4h	;  80Ch, Array containing BOOTNFO structs
+	.rgbMnuStack:					; 7C00h and below, Boot Menu stack
+	.rgbAtaInfo:					; 7C00h, ATA Information for drive detection
+	.rgbBootSect	resb 	512		; 7C00h, Boot sector
+endstruc
+
+
+%endif ; BOOTVARS_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CompatibleDPT.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CompatibleDPT.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CompatibleDPT.inc	(revision 37)
@@ -0,0 +1,46 @@
+; File name		:	CompatibleDPT.inc
+; Project name	:	IDE BIOS
+; Created date	:	6.4.2010
+; Last update	:	6.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Structs for standard DPTs used for software
+;					compatibility.
+%ifndef COMPATIBLEDPT_INC
+%define COMPATIBLEDPT_INC
+
+; Fixed Disk Parameter table used for drives with capacity up to 504 MiB
+struc COMPATIBLE_FDPT
+	.wCyls			resb	2	; 0, Maximum number of cylinders
+	.bHeads			resb	1	; 2, Maximum number of heads
+	.wRedWrCyl		resb	2	; 3, Starting cylinder for reduced write current (MFM)
+	.wWrPreCmpCyl	resb	2	; 5, Starting write precompensation cylinder (MFM)
+	.bMaxECCLen		resb	1	; 7, Maximum ECC data burst length (MFM)
+	.bDrvCtrl		resb	1	; 8, Control Byte
+	.bNormTimeout	resb	1	; 9, Normal timeout value
+	.bFormatTimeout	resb	1	; 10, Timeout value for format disk drive
+	.bCheckTimeout	resb	1	; 11, Timeout value for check disk drive
+	.wLZoneCyl		resb	2	; 12, Landing zone cylinder
+	.bSectPerTrack	resb	1	; 14, Number of sectors per track
+					resb	1	; 15, unused
+endstruc
+
+
+; Fixed Disk Parameter table used for drives with P-CHS or LBA addressing
+struc COMPATIBLE_EDPT
+	.wLCyls			resb	2	; 0, L-CHS cylinders (1...1024)
+	.bLHeads		resb	1	; 2, L-CHS heads (1...255)
+	.bSignature		resb	1	; 3, EDPT signature (A0h)
+	.bPSect			resb	1	; 4, P-CHS sectors per track (1...63)
+					resb	3	; 5...7, unused
+	.bDrvCtrl		resb	1	; 8, Control Byte
+	.wPCyls			resb	2	; 9, P-CHS cylinders (1...16383)
+	.bPHeads		resb	1	; 11, P-CHS heads (1...16)
+					resb	2	; 12...13, unused
+	.bLSect			resb	1	; 14, L-CHS sectors per track (1...63)
+	.bChecksum		resb	1	; 15, Checksum of bytes 0 to 14		
+endstruc
+
+COMPATIBLE_EDPT_SIGNATURE	EQU		0A0h
+
+
+%endif ; COMPATIBLEDPT_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CustomDPT.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CustomDPT.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/CustomDPT.inc	(revision 37)
@@ -0,0 +1,79 @@
+; File name		:	CustomDPT.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	10.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Defines for DPT structs containing custom
+;					Disk Parameter Table used by this BIOS.
+%ifndef CUSTOMDPT_INC
+%define CUSTOMDPT_INC
+
+
+; Base Disk Parameter Table for all hard disk drives.
+; DPT might have extensions for specific functions.
+struc DPT
+	; General Disk Parameter Table related
+	.bSize		resb	1	; Size of DPT (with extensions) in bytes
+	.bDrvNum	resb	1	; Drive number
+	.bFlags		resb	1	; DPT and Drive related flags
+	.bReset		resb	1	; Drive reset status (for debugging)
+	.bIdeOff	resb	1	; Offset to IDEVARS for this drive
+
+	; Lookup values for L-CHS to P-CHS and L-CHS to LBA28 conversions
+	.bShLtoP	resb	1	; Bit shift count for L-CHS to P-CHS conversion
+	.wLHeads	resb	2	; Number of L-CHS Heads (1...256)
+
+	; IDE related
+	.wPCyls		resb	2	; Number of P-CHS (IDE) Cylinders (1...16383)
+	.bPHeads	resb	1	; Number of P-CHS (IDE) Heads (1...16)
+	.bPSect		resb	1	; Number of P-CHS (IDE) Sectors per Track (1...63)
+	.bDrvSel	resb	1	; Drive Selection byte for Device/Head Register
+	.bDrvCtrl	resb	1	; Drive Control byte for Device Control Register
+
+	; Related to Block Mode transfers.
+	; Block size is specified in sectors (1, 2, 4, 8, 16, 32, 64 or 128).
+	.wSetAndMaxBlock:
+	.bSetBlock	resb	1	; Currect block size (at least 1)
+	.bMaxBlock	resb	1	; Maximum block size, 0 = block mode not supported
+endstruc
+
+; Bit definitions for DPT.bFlags
+MASK_DPT_ADDR		EQU		110b	; Bits 1..2, Addressing Mode
+FLG_DPT_EBIOS		EQU		(1<<0)	; EBIOS functions supported for this drive
+FLG_DPT_FIRSTPART	EQU		(1<<3)	; First BIOS Partition of the drive (drive reset allowed)
+FLG_DPT_PARTITION	EQU		(1<<4)	; BIOS Partition
+FLG_DPT_USERCHS		EQU		(1<<5)	; User has specified P-CHS parameters
+
+; Values for different addressing modes (MASK_DPT_ADDR for DPT.bFlags)
+ADDR_DPT_LCHS		EQU		0		; L-CHS Addressing Mode (NORMAL in many other BIOSes)
+ADDR_DPT_PCHS		EQU		1		; P-CHS Addressing Mode (LARGE in many other BIOSes)
+ADDR_DPT_LBA28		EQU		2		; 28-bit LBA Addressing Mode
+ADDR_DPT_LBA48		EQU		3		; 48-bit LBA Addressing Mode
+
+; Bit definitions for DPT.bReset (inverted)
+FLG_RESET_nDRDY			EQU		(1<<0)	; Drive ready to accept commands
+FLG_RESET_nINITPRMS		EQU		(1<<1)	; Initialize Device Parameters successfull
+FLG_RESET_nRECALIBRATE	EQU		(1<<2)	; Recalibrate successfull
+FLG_RESET_nSETBLOCK		EQU		(1<<3)	; Initialize Block Mode successfull
+MASK_RESET_ALL			EQU		(FLG_RESET_nDRDY | FLG_RESET_nINITPRMS | FLG_RESET_nRECALIBRATE | FLG_RESET_nSETBLOCK)
+
+
+; Extended DPT for XTIDE Universal BIOS partitioned drive.
+; This struct cannot exist with EDPT (EBIOS support).
+struc PART_DPT
+	.dpt		resb	DPT_size
+	.dwStartLBA:
+	.twStartLBA	resb	6	; Starting 28- or 48-bit LBA for BIOS partition
+endstruc
+
+
+; Extended DPT for EBIOS support.
+; This struct cannot exist with PDPT (XTIDE Universal BIOS partitioned drive).
+struc EBDPT
+	.dpt		resb	DPT_size
+	.dwCapacity:
+	.twCapacity	resb	6	; Total drive capacity in sectors
+endstruc
+
+
+%endif ; CUSTOMDPT_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IDE_8bit.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IDE_8bit.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IDE_8bit.inc	(revision 37)
@@ -0,0 +1,205 @@
+; File name		:	IDE_8bit.inc
+; Project name	:	IDE BIOS
+; Created date	:	4.4.2010
+; Last update	:	13.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Macros for accessing data port(s) on 8-bit
+;					IDE controllers.
+%ifndef IDE_8BIT_INC
+%define IDE_8BIT_INC
+
+;--------------------------------------------------------------------
+; Emulates REP INSW for XTIDE dual (8-bit) data port.
+;
+; eREP_DUAL_BYTE_PORT_INSW
+;	Parameters:
+;		CX:		Loop count
+;		DX:		Port address (must be IDE Data Register)
+;		ES:DI:	Ptr to destination buffer
+;	Returns:
+;		CX:		Zero
+;		DI:		Incremented/decremented
+;	Corrupts registers:
+;		AX, FLAGS
+;--------------------------------------------------------------------
+%macro eREP_DUAL_BYTE_PORT_INSW 0
+	push	bx
+	times 2	shr	cx, 1			; Loop unrolling
+	mov		bx, 8				; Bit mask for toggling data low/high reg
+ALIGN JUMP_ALIGN
+%%InswLoop:
+	eDUAL_BYTE_PORT_INSW
+	eDUAL_BYTE_PORT_INSW
+	eDUAL_BYTE_PORT_INSW
+	eDUAL_BYTE_PORT_INSW
+	loop	%%InswLoop
+	pop		bx
+%endmacro
+
+;--------------------------------------------------------------------
+; Emulates INSW for XTIDE dual (8-bit) data port.
+;
+; eDUAL_BYTE_PORT_INSW
+;	Parameters:
+;		BX:		Bit mask for toggling XTIDE data low/high reg
+;		DX:		Port address (must be IDE Data Register)
+;		ES:DI:	Ptr to destination buffer
+;	Returns:
+;		ES:DI:	Incremented/decremented for next word
+;	Corrupts registers:
+;		AL, FLAGS
+;--------------------------------------------------------------------
+%macro eDUAL_BYTE_PORT_INSW 0
+%ifdef USE_186	; INS instruction available
+	insb						; Load low byte from port DX to [ES:DI]
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	insb						; Load high byte from port DX to [ES:DI]
+	xor		dx, bx				; Restore to IDE Data Register
+%else	; If 8088/8086
+	in		al, dx				; Load low byte from port
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	stosb						; Store byte to [ES:DI]
+	in		al, dx				; Load high byte from port
+	xor		dx, bx				; Restore to IDE Data Register
+	stosb						; Store byte to [ES:DI]
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates REP OUTSW for XTIDE dual (8-bit) data port.
+;
+; eREP_DUAL_BYTE_PORT_OUTSW
+;	Parameters:
+;		CX:		Loop count
+;		DX:		Port address (must be IDE Data Register)
+;		ES:SI:	Ptr to source buffer
+;	Returns:
+;		SI:		Incremented/decremented
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+%macro eREP_DUAL_BYTE_PORT_OUTSW 0
+	push	ds
+	push	bx
+	times 2	shr	cx, 1			; Loop unrolling
+	mov		bx, 8				; Bit mask for toggling data low/high reg
+	push	es					; Copy ES...
+	pop		ds					; ...to DS
+ALIGN JUMP_ALIGN
+%%OutswLoop:
+	eDUAL_BYTE_PORT_OUTSW
+	eDUAL_BYTE_PORT_OUTSW
+	eDUAL_BYTE_PORT_OUTSW
+	eDUAL_BYTE_PORT_OUTSW
+	loop	%%OutswLoop
+	pop		bx
+	pop		ds
+%endmacro
+
+;--------------------------------------------------------------------
+; Emulates OUTSW for XTIDE dual (8-bit) data port.
+;
+; eDUAL_BYTE_PORT_OUTSW
+;	Parameters:
+;		BX:		Bit mask for toggling XTIDE data low/high reg
+;		DX:		Port address (must be IDE Data Register)
+;		DS:SI:	Ptr to source buffer
+;	Returns:
+;		SI:		Incremented/decremented for next word
+;	Corrupts registers:
+;		AX, FLAGS
+;--------------------------------------------------------------------
+%macro eDUAL_BYTE_PORT_OUTSW 0
+%ifdef USE_186	; OUTS instruction available
+	lodsb						; Load low byte from [DS:SI] to AL
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	outsb						; Output high byte from [DS:SI]
+	xor		dx, bx				; IDE Data Reg to XTIDE Data Low Reg
+	out		dx, al				; Output low byte from AL
+%else	; If 8088/8086
+	lodsw						; Load word from [DS:SI]
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	xchg	al, ah				; => AL=high byte, AH=low byte
+	out		dx, al				; Output high byte
+	xor		dx, bx				; XTIDE Data High Reg to IDE Data Reg
+	mov		al, ah				; Copy low byte to AL
+	out		dx, al				; Output low byte
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates REP INSW for IDE controllers with single 8-bit Data Port.
+;
+; eREP_SINGLE_BYTE_PORT_INSW
+;	Parameters:
+;		CX:		Number of WORDs to transfer
+;		DX:		IDE Data Port address
+;		ES:DI:	Ptr to destination buffer
+;	Returns:
+;		DI:		Incremented/decremented
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+%macro eREP_SINGLE_BYTE_PORT_INSW 0
+%ifdef USE_186	; INS instruction available
+	shl		cx, 1				; WORD count to BYTE count
+	rep insb
+%else			; If 8088/8086
+	shr		cx, 1				; WORD count to DWORD count
+ALIGN JUMP_ALIGN
+%%InsdLoop:
+	in		al, dx
+	stosb						; Store to [ES:DI]
+	in		al, dx
+	stosb
+	in		al, dx
+	stosb
+	in		al, dx
+	stosb
+	loop	%%InsdLoop
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates REP OUTSW for IDE controllers with single 8-bit Data Port.
+;
+; eREP_SINGLE_BYTE_PORT_OUTSW
+;	Parameters:
+;		CX:		Number of WORDs to transfer
+;		DX:		IDE Data Port address
+;		ES:SI:	Ptr to source buffer
+;	Returns:
+;		SI:		Incremented/decremented
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+%macro eREP_SINGLE_BYTE_PORT_OUTSW 0
+%ifdef USE_186	; OUTS instruction available
+	shl		cx, 1				; WORD count to BYTE count
+	eSEG	es					; Source is ES segment
+	rep outsb
+%else			; If 8088/8086
+	shr		cx, 1				; WORD count to DWORD count
+	push	ds					; Store DS
+	push	es					; Copy ES...
+	pop		ds					; ...to DS
+ALIGN JUMP_ALIGN
+%%OutsdLoop:
+	lodsb						; Load from [DS:SI] to AL
+	out		dx, al
+	lodsb
+	out		dx, al
+	lodsb
+	out		dx, al
+	lodsb
+	out		dx, al
+	loop	%%OutsdLoop
+	pop		ds					; Restore DS
+%endif
+%endmacro
+
+
+%endif ; IDE_8BIT_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IdeRegisters.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IdeRegisters.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/IdeRegisters.inc	(revision 37)
@@ -0,0 +1,86 @@
+; File name		:	IdeRegisters.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	23.3.2010
+; Author		:	Tomi Tilli
+; Description	:	Equates for IDE registers, flags and commands.
+%ifndef IDEREGISTERS_INC
+%define IDEREGISTERS_INC
+
+; IDE Register offsets from Command Block base port
+REG_IDE_DATA			EQU		0		; Data Register
+REGR_IDE_ERROR			EQU		1		; Error Register
+REGW_IDE_FEAT			EQU		1		; Features Register (ATA1+)
+;REGW_IDE_WRPC			EQU		1		; Write Precompensation Register (obsolete on ATA1+)
+REG_IDE_CNT				EQU		2		; Sector Count Register
+REG_IDE_SECT			EQU		3		; Sector Number Register (LBA 7...0)
+REG_IDE_LBA_LOW			EQU		3		; LBA Low Register
+REG_IDE_LOCYL			EQU		4		; Low Cylinder Register (LBA 15...8)
+REG_IDE_LBA_MID			EQU		4		; LBA Mid Register
+REG_IDE_HICYL			EQU		5		; High Cylinder Register (LBA 23...16)
+REG_IDE_LBA_HIGH		EQU		5		; LBA High Register
+REG_IDE_DRVHD			EQU		6		; Drive and Head Register (LBA 27...24)
+REGR_IDE_ST				EQU		7		; Status Register
+REGW_IDE_CMD			EQU		7		; Command Register
+REG_IDE_HIDATA			EQU		8		; XTIDE Data High Register (actually first Control Block reg)
+
+; IDE Register offsets from Control Block base port
+; (usually Command Block base port + 200h)
+REGR_IDEC_AST			EQU		6		; Alternate Status Register
+REGW_IDEC_CTRL			EQU		6		; Device Control Register
+;REGR_IDEC_ADDR			EQU		7		; Drive Address Register (obsolete on ATA2+)
+
+
+; Bit definitions for IDE Error Register
+FLG_IDE_ERR_BBK			EQU		(1<<7)	; Bad Block Detected (reserved on ATA2+, command dependent on ATA4+)
+FLG_IDE_ERR_UNC			EQU		(1<<6)	; Uncorrectable Data Error (command dependent on ATA4+)
+FLG_IDE_ERR_MC			EQU		(1<<5)	; Media Changed (command dependent on ATA4+)
+FLG_IDE_ERR_IDNF		EQU		(1<<4)	; ID Not Found (command dependent on ATA4+)
+FLG_IDE_ERR_MCR			EQU		(1<<3)	; Media Change Request (command dependent on ATA4+)
+FLG_IDE_ERR_ABRT		EQU		(1<<2)	; Command Aborted
+FLG_IDE_ERR_TK0NF		EQU		(1<<1)	; Track 0 Not Found (command dependent on ATA4+)
+FLG_IDE_ERR_AMNF		EQU		(1<<0)	; Address Mark Not Found (command dependent on ATA4+)
+
+; Bit definitions for IDE Drive and Head Select Register
+FLG_IDE_DRVHD_LBA		EQU		(1<<6)	; LBA Addressing enabled (instead of CHS)
+FLG_IDE_DRVHD_DRV		EQU		(1<<4)	; Drive Select (0=Master, 1=Slave)
+MASK_IDE_DRVHD_HEAD		EQU		0Fh		; Head select bits (bits 0...3)
+MASK_IDE_DRVHD_SET		EQU		0A0h	; Bits that must be set to 1 on ATA1 (reserved on ATA2+)
+
+; Bit definitions for IDE Status Register
+FLG_IDE_ST_BSY			EQU		(1<<7)	; Busy (other flags undefined when set)
+FLG_IDE_ST_DRDY			EQU		(1<<6)	; Device Ready
+FLG_IDE_ST_DF			EQU		(1<<5)	; Device Fault (command dependent on ATA4+)
+FLG_IDE_ST_DSC			EQU		(1<<4)	; Device Seek Complete (command dependent on ATA4+)
+FLG_IDE_ST_DRQ			EQU		(1<<3)	; Data Request
+FLG_IDE_ST_CORR			EQU		(1<<2)	; Corrected Data (obsolete on ATA4+)
+FLG_IDE_ST_IDX			EQU		(1<<1)	; Index (vendor specific on ATA2+, obsolete on ATA4+)
+FLG_IDE_ST_ERR			EQU		(1<<0)	; Error
+
+; Bit definitions for IDE Device Control Register
+; Bit 0 must be zero, unlisted bits are reserved.
+FLG_IDE_CTRL_O8H		EQU		(1<<3)	; Drive has more than 8 heads (pre-ATA only, 1 on ATA1, reserved on ATA2+)
+FLG_IDE_CTRL_SRST		EQU		(1<<2)	; Software Reset
+FLG_IDE_CTRL_nIEN		EQU		(1<<1)	; Negated Interrupt Enable (IRQ disabled when set)
+
+
+; Commands for IDE Controller
+;HCMD_RECALIBRATE		EQU		10h		; Recalibrate
+HCMD_READ_SECT			EQU		20h		; Read Sectors (with retries)
+HCMD_WRITE_SECT			EQU		30h		; Write Sectors (with retries)
+HCMD_VERIFY_SECT		EQU		40h		; Read Verify Sectors (with retries)
+;HCMD_FORMAT			EQU		50h		; Format track
+HCMD_SEEK				EQU		70h		; Seek
+;HCMD_DIAGNOSTIC		EQU		90h		; Execute Device Diagnostic
+HCMD_INIT_DEV			EQU		91h		; Initialize Device Parameters
+HCMD_READ_MUL			EQU		0C4h	; Read Multiple (=block)
+HCMD_WRITE_MUL			EQU		0C5h	; Write Multiple (=block)
+HCMD_SET_MUL			EQU		0C6h	; Set Multiple Mode (=block size)
+HCMD_ID_DEV				EQU		0ECh	; Identify Device
+HCMD_SET_FEAT			EQU		0EFh	; Set Features
+
+; Set Features subcommands
+HFEAT_SET_XFER_MODE		EQU		03h		; Set transfer mode based on value in Sector Count register
+
+
+%endif ; IDEREGISTERS_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Int13h.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Int13h.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Int13h.inc	(revision 37)
@@ -0,0 +1,61 @@
+; File name		:	Int13h.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	29.7.2010
+; Author		:	Tomi Tilli
+; Description	:	Equates used in INT 13h functions.
+%ifndef INT13H_INC
+%define INT13H_INC
+
+; Hard Disk function (INT 13h) return status codes in AH
+RET_HD_SUCCESS			EQU		0h		; Operation succesfull, no error occurred
+RET_HD_INVALID			EQU		1h		; Invalid value passed or unsupported func
+RET_HD_ADDRMARK			EQU		2h		; Missing address mark
+RET_HD_WRITEPROT		EQU		3h		; Removable media is write protected
+RET_HD_NOT_FOUND		EQU		4h		; Requested sector not found
+RET_HD_RESETFAIL		EQU		5h		; Reset failed
+RET_HD_CHANGED			EQU		6h		; Media changed
+RET_HD_PARAMACT			EQU		7h		; Drive parameter activity failed
+RET_HD_OVERRUN			EQU		8h		; DMA overrun
+RET_HD_BOUNDARY			EQU		9h		; Data boundary error
+RET_HD_BADSECTOR		EQU		0Ah		; Bad sector detected
+RET_HD_BADTRACK			EQU		0Bh		; Bad track detected
+RET_HD_UNCORRECC		EQU		10h		; Uncorrectable ECC error
+RET_HD_ECC				EQU		11h		; Corrected ECC error
+RET_HD_CONTROLLER		EQU		20h		; Hard disk controller or drive problem
+RET_HD_NOMEDIA			EQU		31h		; No media in removable media drive
+RET_HD_SEEK_FAIL		EQU		40h		; Seek operation failed
+RET_HD_TIMEOUT			EQU		80h		; Drive failed to respond
+RET_HD_NOTREADY			EQU		0AAh	; Drive is not ready or is not selected
+RET_HD_NOTLOCKED		EQU		0B0h	; Volume not locked in drive
+RET_HD_LOCKED			EQU		0B1h	; Volume locked in drive
+RET_HD_NOTREMOVABLE		EQU		0B2h	; Volume not removable
+RET_HD_INUSE			EQU		0B3h	; Volume in use
+RET_HD_LOCKEXCEEDED		EQU		0B4h	; Lock count exceeded
+RET_HD_EJECTFAIL		EQU		0B5h	; Valid eject request failed
+RET_HD_UNDEFINED		EQU		0BBh	; Undefined error occurred
+RET_HD_WRFAULT			EQU		0CCh	; Write fault on selected drive
+RET_HD_STATUSERR		EQU		0E0h	; Status error without error
+RET_HD_SENSEFAIL		EQU		0FFh	; Sense operation failed
+
+
+; Timeout values for IDE controller timeout
+; 255 is the maximum value. Zero means immediate timeout.
+B_TIMEOUT_BSY			EQU		(1000/55)	; 1000 ms
+B_TIMEOUT_RDY			EQU		(1000/55)	; 1000 ms
+B_TIMEOUT_DRQ			EQU		255			;   14 s (some CF cards occasionally have long write delays)
+B_TIMEOUT_DRVINFO		EQU		(500/55)	;  500 ms
+B_TIMEOUT_RESET			EQU		255			;   14 s
+
+
+
+; Floppy Drive types returned by INT 13h, AH=08h
+FLOPPY_TYPE_525_OR_35_DD	EQU	0
+FLOPPY_TYPE_525_DD			EQU	1
+FLOPPY_TYPE_525_HD			EQU	2
+FLOPPY_TYPE_35_DD			EQU	3
+FLOPPY_TYPE_35_HD			EQU	4
+FLOPPY_TYPE_35_ED			EQU	6
+
+
+%endif ; INT13H_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Interrupts.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Interrupts.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/Interrupts.inc	(revision 37)
@@ -0,0 +1,91 @@
+; File name		:	Interrupts.inc
+; Project name	:	IDE BIOS
+; Created date	:	29.7.2007
+; Last update	:	6.11.2009
+; Author		:	Tomi Tilli
+; Description	:	Equates for Interrupts.
+%ifndef INTERRUPTS_INC
+%define INTERRUPTS_INC
+
+; 8259 Master and Slave Interrupt Controller Ports
+RPORT_8259MA_IRR_ISR		EQU		20h		; Master 8259 Read IRR / ISR
+WPORT_8259MA_COMMAND		EQU		20h		; Master 8259 Write command
+WPORT_8259MA_INIT			EQU		21h		; Master 8259 Write Init command
+PORT_8259MA_IMR				EQU		21h		; Master 8259 IMR
+RPORT_8259SL_IRR_ISR		EQU		0A0h	; Slave 8259 Read IRR / ISR
+WPORT_8259SL_COMMAND		EQU		0A0h	; Slave 8259 Write command
+WPORT_8259SL_INIT			EQU		0A1h	; Slave 8259 Write Init command
+PORT_8259SL_IMR				EQU		0A1h	; Slave 8259 IMR
+
+; Valid commands to port 20h (master, WPORT_8259MA_COMMAND) 
+; and A0h (slave, WPORT_8259SL_COMMAND)
+CMD_ROT_IN_AUTO_EOI_MODE_CLEAR	EQU		000h
+CMD_READ_IRR					EQU		00Ah
+CMD_READ_ISR					EQU		00Bh
+CMD_END_OF_INTERRUPT			EQU		020h
+CMD_NO_OPERATION				EQU		040h
+CMD_CLEAR_SPECIAL_MASK_MODE		EQU		048h
+CMD_SPEC_EOI_IRQ0				EQU		060h
+CMD_SPEC_EOI_IRQ1				EQU		061h
+CMD_SPEC_EOI_IRQ2				EQU		062h
+CMD_SPEC_EOI_IRQ3				EQU		063h
+CMD_SPEC_EOI_IRQ4				EQU		064h
+CMD_SPEC_EOI_IRQ5				EQU		065h
+CMD_SPEC_EOI_IRQ6				EQU		066h
+CMD_SPEC_EOI_IRQ7				EQU		067h
+CMD_SET_SPECIAL_MASK_MODE		EQU		068h
+CMD_ROT_IN_AUTO_EOI_MODE_SET	EQU		080h
+CMD_ROT_ON_NONSPEC_EOI			EQU		0A0h
+CMD_IRQ0_LOWST_PRIO				EQU		0C0h
+CMD_IRQ1_LOWST_PRIO				EQU		0C1h
+CMD_IRQ2_LOWST_PRIO				EQU		0C2h
+CMD_IRQ3_LOWST_PRIO				EQU		0C3h
+CMD_IRQ4_LOWST_PRIO				EQU		0C4h
+CMD_IRQ5_LOWST_PRIO				EQU		0C5h
+CMD_IRQ6_LOWST_PRIO				EQU		0C6h
+CMD_IRQ7_LOWST_PRIO				EQU		0C7h
+CMD_EOI_AND_IRQ0_LOWST_PRIO		EQU		0E0h
+CMD_EOI_AND_IRQ1_LOWST_PRIO		EQU		0E1h
+CMD_EOI_AND_IRQ2_LOWST_PRIO		EQU		0E2h
+CMD_EOI_AND_IRQ3_LOWST_PRIO		EQU		0E3h
+CMD_EOI_AND_IRQ4_LOWST_PRIO		EQU		0E4h
+CMD_EOI_AND_IRQ5_LOWST_PRIO		EQU		0E5h
+CMD_EOI_AND_IRQ6_LOWST_PRIO		EQU		0E6h
+CMD_EOI_AND_IRQ7_LOWST_PRIO		EQU		0E7h
+
+
+; Interrupt Vector Table
+INTV_IRQ0						EQU		08h		; System timer
+INTV_IRQ1						EQU		09h		; Keyboard
+INTV_IRQ2						EQU		0Ah
+INTV_IRQ3						EQU		0Bh
+INTV_IRQ4						EQU		0Ch
+INTV_IRQ5						EQU		0Dh
+INTV_IRQ6						EQU		0Eh
+INTV_IRQ7						EQU		0Fh
+INTV_EQUIPMENT_CONF				EQU		11h		; Equipment configuration
+INTV_MEMORY_SIZE				EQU		12h		; Base memory size
+INTV_DISK_FUNC					EQU		13h		; Disk functions
+INTV_SYSTEM_SERVICES			EQU		15h		; Different system functions
+INTV_KEYBOARD_FUNC				EQU		16h		; Keyboard functions
+INTV_BOOT_FAILURE				EQU		18h		; Process Boot Failure
+INTV_BOOTSTRAP					EQU		19h		; Boot Strap Loader
+INTV_TIME_OF_DAY				EQU		1Ah		; Time of day functions
+INTV_KEYB_BREAK					EQU		1Bh		; Keyboard break
+INTV_USER_TIMER_TICK			EQU		1Ch		; User timer tick
+INTV_DPT						EQU		1Eh		; Diskette Parameter Table
+INTV_FLOPPY_FUNC				EQU		40h		; Floppy functions
+INTV_HD0DPT						EQU		41h		; Ptr to HD0 Disk Parameter Table
+INTV_HD1DPT						EQU		46h		; Ptr to HD1 Disk Parameter Table
+INTV_USERS_ALARM				EQU		4Ah		; Users alarm
+INTV_IRQ8						EQU		70h
+INTV_IRQ9						EQU		71h
+INTV_IRQ10						EQU		72h
+INTV_IRQ11						EQU		73h
+INTV_IRQ12						EQU		74h
+INTV_IRQ13						EQU		75h
+INTV_IRQ14						EQU		76h
+INTV_IRQ15						EQU		77h
+
+
+%endif ; INTERRUPTS_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RamVars.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RamVars.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RamVars.inc	(revision 37)
@@ -0,0 +1,55 @@
+; File name		:	RamVars.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	8.4.2010
+; Author		:	Tomi Tilli
+; Description	:	RAMVARS struct containing BIOS variables stored in RAM.
+%ifndef RAMVARS_INC
+%define RAMVARS_INC
+
+; Segment when RAMVARS is stored to top of interrupt vectors.
+SEGMENT_RAMVARS_TOP_OF_INTERRUPT_VECTORS		EQU		30h
+
+
+; Variables for translating drive numbers.
+struc XLATEVARS
+	.bFDSwap		resb	1	; Floppy Drive to swap to 00h and vice versa
+	.bHDSwap		resb	1	; Hard Drive to swap to 80h and vice versa
+	.bRecurCnt		resb	1	; INT 13h recursion counter for drive translation
+					resb	1	; For WORD alignment
+endstruc
+
+; RAM Variables.
+; Variables should be kept to minimum since they might be located
+; at the top of interrupt vectors.
+struc RAMVARS
+	.fpOldI13h		resb	4	; Far pointer to old INT 13h handler
+
+	.dwI13DIDS:					; Temporary DI and DS storages when calling...
+	.wI13hDI:					; ...previous INT 13h handler
+	.wIdeBase		resb	2	; Base port address for currently handled controller
+
+	.wI13hDS:
+	.bEndTime		resb	1	; Timeout ending time
+					resb	1	; Alignment
+
+	.wDrvCntAndFirst:
+	.bDrvCnt		resb	1	; Number of drives handled by this BIOS
+	.bFirstDrv		resb	1	; Number of first drive for this BIOS
+
+	; Variables for drive number translation
+	.xlateVars		resb	XLATEVARS_size
+endstruc
+
+; Full mode RAM variables.
+struc FULLRAMVARS
+	.ramVars		resb	RAMVARS_size
+	.wSign			resb	2			; FULLRAMVARS signature for finding segment
+	.drv80hCompDPT	resb	COMPATIBLE_FDPT_size
+	.drv81hCompDPT	resb	COMPATIBLE_FDPT_size
+endstruc
+
+W_SIGN_FULLRAMVARS		EQU	"fR"		; FULLRAMVARS signature
+
+
+%endif ; RAMVARS_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RomVars.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RomVars.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/RomVars.inc	(revision 37)
@@ -0,0 +1,88 @@
+; File name		:	RomVars.inc
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	1.5.2010
+; Author		:	Tomi Tilli
+; Description	:	Defines for ROMVARS struct containing variables stored
+;					in BIOS ROM.
+%ifndef ROMVARS_INC
+%define ROMVARS_INC
+
+; ROM Variables. There are written to ROM image before flashing.
+struc ROMVARS
+	.wRomSign		resb	2	; ROM Signature (AA55h)
+	.bRomSize		resb	1	; ROM size in 512 byte blocks
+	.rgbJump		resb	5	; First instruction to ROM init (jmp)
+	; Offset 8 (8h) starts here
+	.rgbDate		resb	8	; BIOS build date string (mm/dd/yy)
+	; Offset 16 (10h) starts here
+	.rgbSign		resb	8	; Signature for XTIDE Configurator Program
+	.szTitle		resb	31	; BIOS title string
+	.szVersion		resb	25	; BIOS version string
+	; Offset 80 (50h) starts here
+	.wFlags			resb	2	; Word for ROM flags
+	.bIdeCnt		resb	1	; Number of supported IDE controllers
+	.bBootDrv		resb	1	; Boot Menu default drive
+	.bBootMnuH		resb	1	; Boot Menu maximum height
+	.bBootDelay		resb	1	; Boot Menu selection delay in seconds
+	.bBootLdrType	resb	1	; Boot Loader type
+	.bMinFddCnt		resb	1	; Minimum number of Floppy Drives
+	.bStealSize		resb	1	; Number of 1kB blocks stolen from 640kB base RAM
+					resb	7
+	; Offset 96 (60h) starts here
+	; Last IDEVARS must not start after offset FFh.
+	.ideVars0		resb	IDEVARS_size
+	.ideVars1		resb	IDEVARS_size
+	.ideVars2		resb	IDEVARS_size
+	.ideVars3		resb	IDEVARS_size
+	.ideVars4		resb	IDEVARS_size
+endstruc
+
+; Bit defines for ROMVARS.wFlags
+FLG_ROMVARS_FULLMODE	EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
+FLG_ROMVARS_LATE		EQU	(1<<1)	; Late initialization
+FLG_ROMVARS_DRVXLAT		EQU	(1<<2)	; Enable drive number translation
+FLG_ROMVARS_ROMBOOT		EQU	(1<<3)	; Include ROMBOOT to boot menu
+FLG_ROMVARS_DRVNFO		EQU	(1<<4)	; Display drive info on boot menu
+FLG_ROMVARS_MAXSIZE		EQU	(1<<5)	; Maximize size by sacrificing compatibility with some old BIOSes
+
+; Bootloader types for ROMVARS.bBootLdrType
+BOOTLOADER_TYPE_MENU	EQU	(0<<1)	; Display boot menu on boot loader
+BOOTLOADER_TYPE_SIMPLE	EQU	(1<<1)	; Simple bootloader without menu
+BOOTLOADER_TYPE_NONE	EQU	(3<<1)	; Do not install boot loader
+
+
+; Controller specific variables
+struc IDEVARS
+	.wPort				resb	2	; IDE Base Port for Command Block (usual) Registers
+	.wPortCtrl			resb	2	; IDE Base Port for Control Block Registers
+	.bBusType			resb	1	; Bus type
+	.bIRQ				resb	1	; Interrupt Request Number
+						resb	4	; Reserved
+	.drvParamsMaster	resb	DRVPARAMS_size
+	.drvParamsSlave		resb	DRVPARAMS_size
+endstruc
+
+; Bus types for IDEVARS.bBusType
+BUS_TYPE_8_DUAL			EQU	(0<<1)	; XTIDE transfers with two 8-bit data ports
+BUS_TYPE_16				EQU	(1<<1)	; Normal 16-bit AT-IDE transfers
+BUS_TYPE_32				EQU	(2<<1)	; 32-bit VLB and PCI transfers
+BUS_TYPE_8_SINGLE		EQU	(3<<1)	; 8-bit transfers with single 8-bit data port
+
+
+; Master/Slave drive specific parameters
+struc DRVPARAMS
+	.wFlags			resb	2	; Drive flags
+					resb	2	; Reserved
+	.wCylinders		resb	2	; User specified cylinders (1...16383)
+	.wSectAndHeads:
+	.bSect			resb	1	; User specified Sectors per track (1...63)
+	.bHeads			resb	1	; User specified Heads (1...16)
+endstruc
+
+; Bit defines for DRVPARAMS.wFlags
+FLG_DRVPARAMS_USERCHS	EQU	(1<<0)	; User specified P-CHS values
+FLG_DRVPARAMS_BLOCKMODE	EQU	(1<<1)	; Enable Block mode transfers
+
+
+%endif ; ROMVARS_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Inc/emulate.inc
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Inc/emulate.inc	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Inc/emulate.inc	(revision 37)
@@ -0,0 +1,477 @@
+; File name		:	emulate.inc
+; Project name	:	Emulation library
+; Created date	:	21.10.2009
+; Last update	:	4.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Macros for emulating later x86 instruction with older
+;					processors.
+;					Macros are used so optimized builds could be done
+;					easily for different processors.
+;
+;					This file must be first to be included to
+;					any source file.
+%ifndef EMULATE_INC
+%define EMULATE_INC
+
+; Defines for processor support. Unsupported instructions will be
+; emulated using macros.
+; If using 286, define USE_186 and USE_286
+; If using 386, define USE_186, USE_286 and USE_386
+; If AT class PC is used (instead of XT), define USE_AT
+;%define USE_186				; Define to use 18x/V20/V30 instructions
+;%define USE_286				; Define to use 286 instructions
+;%define USE_386				; Define to use 386 instructions
+;%define USE_AT					; Define for AT class machine
+; Above defines should be set on makefile!
+
+CPU 8086						; Allow 8088/8086 instructions only
+%ifdef USE_186
+CPU 186							; Allow instructions up to 188/186/V20/V30
+%elifdef USE_286
+CPU 286							; Allow instructions up to 286
+%elifdef USE_386
+CPU 386							; Allow instructions up to 386
+%endif
+BITS 16							; Set 16 bit code generation
+
+; Alignments for jump targets.
+; Following values are optimal for different processor types:
+; 286 and 386SX			WORD (16-bit, 2 bytes)
+; 386DX and 486			DWORD (32-bit, 4 bytes)
+; Pentium and later		QWORD (64-bit, 8 bytes)
+%ifdef USE_AT
+	%ifdef USE_386
+		JUMP_ALIGN		EQU		4
+		WORD_ALIGN		EQU		2
+	%else ; USE_286
+		JUMP_ALIGN		EQU		2
+		WORD_ALIGN		EQU		2
+	%endif
+%else ; XT
+	JUMP_ALIGN		EQU		1
+	WORD_ALIGN		EQU		1
+%endif
+
+;==========================================================================
+
+;--------------------------------------------------------------------
+; Emulates BSF (Bit Scan Forward) instruction when necessary.
+; BSF is used to find index of least significant bit.
+;
+; eBSF
+;	Parameters:
+;		%1:		Destination WORD Register for bit index (not CX or same as %2!)
+;		%2:		Source WORD operand where to search bit (not CX or same as %1!)
+;	Returns:
+;		%1:		Index of highest order bit from %2
+;		ZF:		Set if %2 is zero
+;				Cleared if %2 is non-zero
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eBSF 2
+%ifndef USE_386
+	push	cx
+	cmp		WORD %2, BYTE 0		; Source operand is zero?
+	je		SHORT %%Return		;  If so, return with ZF set
+
+	; Set destination to zero and load mask for bit 0
+	xor		%1, %1
+	mov		cx, 1
+
+ALIGN JUMP_ALIGN
+%%BitLoop:
+	test	%2, cx				; Bit set?
+	jnz		SHORT %%Return		;  If so, return with ZF cleared
+	shl		cx, 1				; Prepare to test next bit
+	inc		%1					; Increment bit index
+	jmp		SHORT %%BitLoop		; Loop until bit found
+%%Return:
+	pop		cx
+;-----------------------------------
+%else
+	bsf		%1, %2
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates BSR (Bit Scan Reverse) instruction when necessary.
+; BSR is used to find index of most significant bit.
+;
+; eBSR
+;	Parameters:
+;		%1:		Destination WORD Register for bit index (not CX or same as %2!)
+;		%2:		Source WORD operand where to search bit (not CX or same as %1!)
+;	Returns:
+;		%1:		Index of highest order bit from %2
+;		ZF:		Set if %2 is zero
+;				Cleared if %2 is non-zero
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eBSR 2
+%ifndef USE_386
+	push	cx
+	cmp		WORD %2, BYTE 0		; Source operand is zero?
+	je		SHORT %%Return		;  If so, return with ZF set
+
+	; Load mask for highest order bit
+	mov		cx, 1<<15
+	mov		%1, 15
+
+ALIGN JUMP_ALIGN
+%%BitLoop:
+	test	%2, cx				; Bit set?
+	jnz		SHORT %%Return		;  If so, return with ZF cleared
+	shr		cx, 1				; Prepare to test next bit
+	dec		%1					; Decrement bit index
+	jmp		SHORT %%BitLoop		; Loop until bit found
+%%Return:
+	pop		cx
+;-----------------------------------
+%else
+	bsr		%1, %2
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Moves byte with zero-extending to any Register.
+;
+; eMOVZX
+;	Parameters:
+;		%1:		Destination Register (SP not supported)
+;		%2:		Byte register or byte address
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		FLAGS
+;--------------------------------------------------------------------
+%macro eMOVZX 2
+%ifndef USE_386
+	%ifidni %1, ax
+		mov		al, %2
+		xor		ah, ah
+	%elifidni %1, bx
+		mov		bl, %2
+		xor		bh, bh		; %2 may use BX in effective address
+	%elifidni %1, cx
+		mov		cl, %2
+		xor		ch, ch
+	%elifidni %1, dx
+		mov		dl, %2
+		xor		dh, dh
+	%else	; SI, DI, BP (all may be used in effective address)
+		push	ax
+		mov		al, %2
+		xor		ah, ah
+		xchg	ax, %1
+		pop		ax
+	%endif
+;-----------------------------------
+%else
+	movzx	%1, %2
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates PUSHA instruction when necessary.
+;
+; ePUSHA
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro ePUSHA 0
+%ifndef USE_186
+	push	ax
+	push	cx
+	push	dx
+	push	bx
+	; SP before first push should be pushed here
+	push	bp
+	push	si
+	push	di
+;-----------------------------------
+%else
+	pusha
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates POPA instruction when necessary.
+;
+; ePOPA
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro ePOPA 0
+%ifndef USE_186
+	pop		di
+	pop		si
+	pop		bp
+	; Old SP should be skipped here
+	pop		bx
+	pop		dx
+	pop		cx
+	pop		ax
+;-----------------------------------
+%else
+	popa
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates ENTER instruction when necessary.
+;
+; eENTER
+;	Parameters:
+;		%1:		Number of bytes to reserve from stack
+;		%2:		The lexical nesting level (not emulated)
+;	Returns:
+;		SS:BP:	Ptr to old BP
+;				([bp-2] points to highest local stack frame word)
+;	Corrupts registers:
+;		FLAGS
+;--------------------------------------------------------------------
+%macro eENTER 2
+%ifndef USE_186
+	push	bp
+	mov		bp, sp
+	sub		sp, %1
+;-----------------------------------
+%else
+	enter	%1, %2
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates LEAVE instruction when necessary.
+;
+; eLEAVE
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eLEAVE 0
+%ifndef USE_186
+	mov		sp, bp
+	pop		bp
+;-----------------------------------
+%else
+	leave
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates LSS instruction when necessary.
+;
+; eLSS
+;	Parameters:
+;		%1:		Destination register
+;		%2:		Source memory address without brackets
+;	Returns:
+;		IF:		0 (interrupts disabled)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eLSS 2
+%ifndef USE_386
+	cli							; Disable interrupts
+	mov		%1, [%2]			; Load offset
+	mov		ss, [%2+2]			; Load segment
+;-----------------------------------
+%else
+	lss		%1, [%2]
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Segment override prefix instruction.
+;
+; eSEG
+;	Parameters:
+;		%1:		Name of the segment (ES, CS, SS, DS, FS or GS)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eSEG 1
+	%ifidni %1, es
+		db	00100110b
+	%elifidni %1, cs
+		db	00101110b
+	%elifidni %1, ss
+		db	00110110b
+	%elifidni %1, ds
+		db	00111110b
+	%elifidni %1, fs
+		db	01100100b
+	%elifidni %1, gs
+		db	01100101b
+	%else
+		%error "Invalid segment overried passed to eSEG!"
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Repeats string instruction with segment override.
+; This macro prevents 8088/8086 restart bug.
+;
+; eSEG_STR
+;	Parameters:
+;		%1:		REP/REPNE or REPE prefix
+;		%2:		Source segment override (destination is always ES)
+;		%3:		String instruction
+;		CX:		Repeat count
+;	Returns:
+;		FLAGS for cmps and scas only
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eSEG_STR 3
+%ifndef USE_186	; 8088/8086 has string instruction restart bug when more than one prefix
+	 %%Loop:
+	 	%1						; REP is the prefix that can be lost
+	 	eSEG	%2				; SEG is the prefix that won't be lost
+	 	%3						; String instruction
+	 	jcxz	%%End			; Jump to end if no repeats left (preserves FLAGS)
+	 	jmp		SHORT %%Loop	; Loop while repeats left
+	 %%End:
+%else	; No bug on V20/V30 and later, don't know about 188/186
+	eSEG	%2
+	%1		%3
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Bit shifts and rotates with immediate.
+;
+; eSHIFT_IM
+;	Parameters:
+;		%1:		Shift target
+;		%2:		Number of bits to shift
+;		%3:		Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
+;	Returns:
+;		FLAGS
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eSHIFT_IM 3
+%ifndef USE_186
+	%ifidni %1, cl
+		times %2	%3		%1, 1
+	%elifidni %1, ch
+		times %2	%3		%1, 1
+	%elifidni %1, cx
+		times %2	%3		%1, 1
+	%else
+		%if %2 > 7
+			push	cx
+			mov		cl, %2
+			%3		%1, cl
+			pop		cx
+		%else
+			times %2	%3		%1, 1
+		%endif
+	%endif
+;-----------------------------------
+%else
+	%3		%1, %2
+%endif
+%endmacro
+%macro eSHR_IM 2
+	eSHIFT_IM	%1, %2, shr
+%endmacro
+%macro eSHL_IM 2
+	eSHIFT_IM	%1, %2, shl
+%endmacro
+%macro eROR_IM 2
+	eSHIFT_IM	%1, %2, ror
+%endmacro
+%macro eROL_IM 2
+	eSHIFT_IM	%1, %2, rol
+%endmacro
+%macro eRCR_IM 2
+	eSHIFT_IM	%1, %2, rcr
+%endmacro
+%macro eRCL_IM 2
+	eSHIFT_IM	%1, %2, rcl
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates PUSH imm instruction when necessary.
+;
+; ePUSH_I
+;	Parameters:
+;		%1:		Immediate to push
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro ePUSH_I 1
+%ifndef USE_186
+	push	bp					; Immediate goes here
+	push	bp
+	mov		bp, sp
+	mov		WORD [bp+2], %1
+	pop		bp
+;-----------------------------------
+%else
+	push	%1
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates PUSH imm instruction when necessary.
+; ePUSH_T uses temporary register for faster performance
+; and smaller code size than ePUSH_I.
+;
+; ePUSH_T
+;	Parameters:
+;		%1:		Temporary Register
+;		%2:		Immediate to push
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		%1
+;--------------------------------------------------------------------
+%macro ePUSH_T 2
+%ifndef USE_186
+	%ifidni %2, 0
+		xor		%1, %1
+	%else
+		mov		%1, %2
+	%endif
+	push	%1
+;-----------------------------------
+%else
+	push	%2
+%endif
+%endmacro
+
+
+%endif ; EMULATE_INC
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootInfo.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootInfo.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootInfo.asm	(revision 37)
@@ -0,0 +1,198 @@
+; File name		:	BootInfo.asm
+; Project name	:	IDE BIOS
+; Created date	:	16.3.2010
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for generating and accessing drive
+;					information to be displayed on boot menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Creates new BOOTNFO struct for detected hard disk.
+;
+; BootInfo_CreateForHardDisk
+;	Parameters:
+;		DL:		Drive number
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		ES:BX:	Ptr to BOOTNFO (if successful)
+;		CF:		Cleared if BOOTNFO created succesfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_CreateForHardDisk:
+	call	BootInfo_GetOffsetToBX		; ES:BX now points to new BOOTNFO
+	call	BootInfo_StoreSectorCount
+	jmp		SHORT BootInfo_StoreDriveName
+
+
+;--------------------------------------------------------------------
+; Returns offset to BOOTNFO for wanted drive.
+;
+; BootInfo_GetOffsetToBX
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		BX:		Offset to BOOTNFO struct
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_GetOffsetToBX:
+	mov		bl, dl						; Copy drive number to BL
+	mov		al, BOOTNFO_size			; Size of struct
+	sub		bl, [RAMVARS.bFirstDrv]		; Drive number to index
+	mul		bl							; AX = Offset inside BOOTNFO array
+	mov		bx, ax						; Copy offset to BX
+	add		bx, BOOTVARS.rgBootNfo		; Add offset to BOOTNFO array
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores total sector count to BOOTNFO.
+;
+; BootInfo_StoreSectorCount
+;	Parameters:
+;		ES:BX:	Ptr to BOOTNFO
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		CF:		Cleared if variables stored succesfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_StoreSectorCount:
+	push	bx
+	call	AtaID_GetTotalSectorCount		; Get to BX:DX:AX
+	mov		cx, bx							; Now in CX:DX:AX
+	pop		bx
+	mov		[es:bx+BOOTNFO.twSectCnt], ax
+	mov		[es:bx+BOOTNFO.twSectCnt+2], dx
+	mov		[es:bx+BOOTNFO.twSectCnt+4], cx
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores drive name to BOOTNFO.
+;
+; BootInfo_StoreDriveName
+;	Parameters:
+;		ES:BX:	Ptr to BOOTNFO
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		CF:		Cleared if variables stored succesfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_StoreDriveName:
+	push	ds
+	push	si
+	push	di
+
+	; DS:SI to ATA source string
+	push	es
+	pop		ds
+	add		si, BYTE ATA1.strModel
+
+	; ES:DI to BOOTNFO destination string
+	lea		di, [bx+BOOTNFO.szDrvName]
+
+	; Read string
+	mov		cx, LEN_BOOTNFO_DRV>>1
+	call	BootInfo_StoreAtaString
+	pop		di
+	pop		si
+	pop		ds
+	clc
+	ret
+
+;--------------------------------------------------------------------
+; Stores ATA string.
+; Byte ordering will be corrected and string will be STOP terminated.
+;
+; BootInfo_StoreAtaString
+;	Parameters:
+;		CX:		Maximum number of WORDs to copy (without STOP)
+;		DS:SI:	Ptr to ATA string
+;		ES:DI:	Ptr to destination string
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_StoreAtaString:
+	lodsw							; Load WORD from DS:SI to AX
+	xchg	al, ah					; Change byte order
+	call	BootInfo_StoreAtaChar
+	jc		SHORT .Return			; Return if invalid character
+	mov		al, ah					; Write next char
+	call	BootInfo_StoreAtaChar
+	jc		SHORT .Return			; Return if invalid character
+	loop	BootInfo_StoreAtaString	; Loop while words left
+.Return:
+	mov		al, STOP				; End string with STOP
+	stosb
+	ret
+
+;--------------------------------------------------------------------
+; Stores ATA character.
+;
+; BootInfo_StoreAtaChar
+;	Parameters:
+;		AL:		Character to store
+;		ES:DI:	Ptr to destination character
+;	Returns:
+;		DI:		Incremented to next character
+;		CF:		Set if non writable ASCII character
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootInfo_StoreAtaChar:
+	cmp		al, 20h					; First allowed ASCII char?
+	jb		SHORT .SkipStoring		;  If below, end string
+	cmp		al, 7Eh					; Last allowed ASCII char?
+	ja		SHORT .SkipStoring		;  If above, end string
+	stosb							; Store character
+	clc								; Clear CF to continue with next char
+	ret
+.SkipStoring:
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; Finds BOOTNFO for drive and return total sector count.
+;
+; BootInfo_GetTotalSectorCount
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+BootInfo_GetTotalSectorCount:
+	push	ds
+	call	BootInfo_GetOffsetToBX
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	mov		ax, [bx+BOOTNFO.twSectCnt]
+	mov		dx, [bx+BOOTNFO.twSectCnt+2]
+	mov		bx, [bx+BOOTNFO.twSectCnt+4]
+	pop		ds
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenu.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenu.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenu.asm	(revision 37)
@@ -0,0 +1,341 @@
+; File name		:	BootMenu.asm
+; Project name	:	IDE BIOS
+; Created date	:	25.3.2010
+; Last update	:	3.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Displays Boot Menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Displays Boot Menu and returns Drive or Function number.
+;
+; BootMenu_DisplayAndReturnSelection
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DX:		Untranslated drive number to be used for booting (if CF cleared)
+;				Function number (if CF set)
+;		CF:		Cleared if drive selected
+;				Set if function selected
+;	Corrupts registers:
+;		All General Purpose Registers
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_DisplayAndReturnSelection:
+	call	DriveXlate_Reset
+	call	BootMenuPrint_TheBottomOfScreen
+	call	BootMenu_GetMenuitemCount
+	mov		di, BootMenuEvent_Handler
+	call	BootMenu_Enter			; Get selected menuitem index to CX
+	call	BootMenuPrint_ClearScreen
+	cmp		cx, BYTE 0				; -1 if nothing selected (ESC pressed)
+	jl		SHORT BootMenu_DisplayAndReturnSelection
+	call	BootMenu_CheckAndConvertHotkeyToMenuitem
+	jc		SHORT .SetDriveTranslationForHotkey
+	jmp		BootMenu_ConvertMenuitemToDriveOrFunction
+ALIGN JUMP_ALIGN
+.SetDriveTranslationForHotkey:
+	call	BootMenu_ConvertMenuitemToDriveOrFunction
+	call	DriveXlate_SetDriveToSwap
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns number of menuitems in Boot Menu.
+;
+; BootMenu_GetMenuitemCount
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		CX:		Number of boot menu items
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetMenuitemCount:
+	call	RamVars_GetHardDiskCountFromBDAtoCX
+	xchg	ax, cx
+	call	FloppyDrive_GetCount
+	add		ax, cx
+	call	BootMenu_GetMenuFunctionCount
+	add		cx, ax
+	ret
+
+;--------------------------------------------------------------------
+; Returns number of functions displayed in Boot Menu.
+;
+; BootMenu_GetMenuFunctionCount
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Number of boot menu functions
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetMenuFunctionCount:
+	xor		cx, cx
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_ROMBOOT
+	jz		SHORT .DontIncludeRomBoot
+	inc		cx
+ALIGN JUMP_ALIGN
+.DontIncludeRomBoot:
+	ret
+
+
+;--------------------------------------------------------------------
+; Enters Boot Menu or submenu.
+;
+; BootMenu_Enter
+;	Parameters:
+;		CX:		Number of menuitems in menu
+;		DS:SI:	User specific far pointer
+;		CS:DI:	Pointer to menu event handler function
+;	Returns:
+;		CX:		Index of last pointed Menuitem (not necessary selected with ENTER)
+;				FFFFh if cancelled with ESC
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_Enter:
+	call	BootMenu_GetSelectionTimeout
+	call	BootMenu_GetSize
+	MIN_U	ah, [cs:ROMVARS.bBootMnuH]		; Limit to max height
+	jmp		Menu_Enter
+
+;--------------------------------------------------------------------
+; Returns Boot Menu selection timeout in milliseconds.
+;
+; BootMenu_GetSelectionTimeout
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DX:		Selection timeout in millisecs
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetSelectionTimeout:
+	mov		ax, 1000			; Seconds to milliseconds
+	eMOVZX	dx, BYTE [cs:ROMVARS.bBootDelay]
+	mul		dx					; AX = seconds * milliseconds_per_second
+	xchg	ax, dx				; DX = Timeout in millisecs
+	ret
+
+;--------------------------------------------------------------------
+; Returns Boot Menu size.
+;
+; BootMenu_GetSize
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		Menu width with borders included (characters)
+;		AH:		Menu height with borders included (characters)
+;		BL:		Title line count
+;		BH:		Info line count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetSize:
+	mov		al, MENU_WIDTH_IN_CHARS
+	mov		ah, cl						; Copy menuitem count to AH
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_DRVNFO
+	jz		SHORT .GetHeightWithoutInfoArea
+;.GetHeightWithInfoArea:
+	add		ah, MENU_HEIGHT_IN_CHARS_WITH_INFO
+	mov		bx, (MENU_INFO_LINE_CNT<<8) | MENU_TITLE_LINE_CNT
+	ret
+ALIGN JUMP_ALIGN
+.GetHeightWithoutInfoArea:
+	add		ah, MENU_HEIGHT_IN_CHARS_WITHOUT_INFO
+	mov		bx, MENU_TITLE_LINE_CNT
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks if hotkey has been pressed on Boot Menu.
+; If it has been, it will be converted to menuitem index.
+;
+; BootMenu_CheckAndConvertHotkeyToMenuitem
+;	Parameters:
+;		CX:		Menuitem index (if no hotkey)
+;	Returns:
+;		CX:		Menuitem index
+;		CF:		Set if hotkey has been pressed
+;				Cleared if no hotkey selection
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_CheckAndConvertHotkeyToMenuitem:
+	push	es
+	LOAD_BDA_SEGMENT_TO	es, ax				; Zero AX
+	xchg	al, [es:BOOTVARS.bMenuHotkey]	; Load and clear hotkey
+	test	al, al							; No hotkey? (clears CF)
+	jz		SHORT .Return
+	call	BootMenu_ConvertHotkeyToMenuitem
+	stc
+ALIGN JUMP_ALIGN
+.Return:
+	pop		es
+	ret
+
+;--------------------------------------------------------------------
+; Converts any hotkey to Boot Menu menuitem index.
+;
+; BootMenu_ConvertHotkeyToMenuitem
+;	Parameters:
+;		AX:		ASCII hotkey starting from upper case 'A'
+;	Returns:
+;		CX:		Menuitem index
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_ConvertHotkeyToMenuitem:
+	call	BootMenu_GetLetterForFirstHardDisk
+	cmp		al, cl						; Letter is for Hard Disk?
+	jae		SHORT .StartFromHardDiskLetter
+	sub		al, 'A'						; Letter to Floppy Drive menuitem
+	xchg	ax, cx						; Menuitem index to CX
+	ret
+ALIGN JUMP_ALIGN
+.StartFromHardDiskLetter:
+	sub		al, cl						; Hard Disk index
+	call	FloppyDrive_GetCount
+	add		cx, ax						; Menuitem index
+	ret
+
+;--------------------------------------------------------------------
+; Returns letter for first hard disk. Usually it will be 'c' but it
+; can be higher if more than two floppy drives are found.
+;
+; BootMenu_GetLetterForFirstHardDisk
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CL:		Upper case letter for first hard disk
+;	Corrupts registers:
+;		CH
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetLetterForFirstHardDisk:
+	call	FloppyDrive_GetCount
+	add		cl, 'A'
+	MAX_U	cl, 'C'
+	ret
+
+
+;--------------------------------------------------------------------
+; Converts selected menuitem index to drive number or function ID.
+;
+; BootMenu_ConvertMenuitemToDriveOrFunction
+;	Parameters:
+;		CX:		Index of menuitem selected from Boot Menu
+;		DS:		RAMVARS segment
+;	Returns:
+;		DX:		Drive number to be used for booting (if CF cleared)
+;				Function ID (if CF set)
+;		CF:		Cleared if drive selected
+;				Set if function selected
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_ConvertMenuitemToDriveOrFunction:
+	mov		dx, cx					; Copy menuitem index to DX
+	call	FloppyDrive_GetCount
+	cmp		dx, cx					; Floppy drive?
+	jb		SHORT .ReturnFloppyDriveInDX
+	sub		dx, cx					; Remove floppy drives from index
+	call	RamVars_GetHardDiskCountFromBDAtoCX
+	cmp		dx, cx					; Hard disk?
+	jb		SHORT .ReturnHardDiskInDX
+	sub		dx, cx					; Remove hard disks from index
+	jmp		SHORT BootMenu_ConvertFunctionIndexToID
+ALIGN JUMP_ALIGN
+.ReturnHardDiskInDX:
+	or		dl, 80h
+ALIGN JUMP_ALIGN
+.ReturnFloppyDriveInDX:
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Converts selected menuitem index to drive number or function ID.
+;
+; BootMenu_ConvertFunctionIndexToID
+;	Parameters:
+;		CX:		Menuitem index
+;		DX:		Function index (Menuitem index - floppy count - HD count)
+;	Returns:
+;		DX:		Function ID
+;		CF:		Set to indicate function
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_ConvertFunctionIndexToID:
+	mov		dx, ID_BOOTFUNC_ROMBOOT
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; Converts Floppy or Hard Disk Drive number to menuitem index.
+; This function does not check does the drive really exists.
+;
+; BootMenu_ConvertDriveToMenuitem
+;	Parameters:
+;		DL:		Drive number
+;	Returns:
+;		CX:		Menuitem index (assuming drive is available)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_ConvertDriveToMenuitem:
+	test	dl, 80h					; Floppy drive?
+	jz		SHORT .ReturnFloppyMenuitem
+	call	FloppyDrive_GetCount
+	mov		ax, 7Fh					; Load mask to clear floppy bit
+	and		ax, dx					; AX = Hard Disk index
+	add		cx, ax					; Add hard disk index to floppy drive count
+	ret
+ALIGN JUMP_ALIGN
+.ReturnFloppyMenuitem:
+	eMOVZX	cx, dl					; Drive number and item index are equal
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks is drive number valid for this system.
+;
+; BootMenu_IsDriveInSystem
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set if drive number is valid
+;				Clear if drive is not present in system
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_IsDriveInSystem:
+	test	dl, 80h								; Floppy drive?
+	jz		SHORT .IsFloppyDriveIsInSystem
+	call	RamVars_GetHardDiskCountFromBDAtoCX	; Hard Disk count to CX
+	or		cl, 80h								; Set Hard Disk bit to CX
+	jmp		SHORT .CompareDriveNumberToDriveCount
+.IsFloppyDriveIsInSystem:
+	call	FloppyDrive_GetCount				; Floppy Drive count to CX
+.CompareDriveNumberToDriveCount:
+	cmp		dl, cl
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuEvent.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuEvent.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuEvent.asm	(revision 37)
@@ -0,0 +1,293 @@
+; File name		:	BootMenuEvent.asm
+; Project name	:	IDE BIOS
+; Created date	:	26.3.2010
+; Last update	:	1.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Boot Menu event handler for menu library callbacks.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+;
+; BootMenuEvent_Handler
+;	Parameters:
+;		BX:		Callback event
+;		CX:		Menuitem index (usually index of selected Menuitem)
+;		DX:		Event parameter (event specific)
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AH:		Event specific or unused. Set to 0 if unused.
+;		AL:		1=Event processed
+;				0=Event not processed (default action if any)
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_Handler:
+	push	es
+	push	ds
+	push	di
+	push	si
+
+	xor		ax, ax									; Event not processed
+	cmp		bx, BYTE EVNT_MNU_GETDEF				; Event in jump table?
+	ja		SHORT .Return
+	shl		bx, 1
+	call	[cs:bx+.rgwEventJmp]
+.Return:
+	pop		si
+	pop		di
+	pop		ds
+	pop		es
+	ret
+ALIGN WORD_ALIGN
+.rgwEventJmp:
+	dw		BootMenuEvent_Exit						; 0, EVNT_MNU_EXIT (Menu will quit)
+	dw		BootMenuEvent_EventItemSelectionChanged	; 1, EVNT_MMU_SELCHG (Menuitem selection changed (with arrows))
+	dw		BootMenuEvent_EventItemSelected			; 2, EVNT_MNU_SELSET (Menuitem selected (with Enter))
+	dw		BootMenuEvent_EventKeyPressed			; 3, EVNT_MNU_KEY (Keyboard key pressed)
+	dw		BootMenuEvent_EventMenuDraw				; 4, EVNT_MNU_UPD (Menu needs to be updated)
+	dw		BootMenuEvent_EventGetDefaultMenuitem	; 5, EVNT_MNU_GETDEF (Request menuitem to be selected by default)
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Menu Exit notification (EVNT_MNU_EXIT).
+;
+; BootMenuEvent_Exit
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AH:		1 to cancel exit
+;				0 to allow menu exit
+;		AL:		1 = Event processed
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_Exit:
+	mov		ax, 1					; Event handled
+	ret
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Menuitem Selection Changed notification (EVNT_MMU_SELCHG).
+;
+; BootMenuEvent_EventItemSelectionChanged
+;	Parameters:
+;		CX:		Index of selected Menuitem
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		1 = Event processed
+;	Corrupts registers:
+;		BX, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_EventItemSelectionChanged:
+	call	RamVars_GetSegmentToDS
+	call	DriveXlate_Reset
+	call	BootMenu_ConvertMenuitemToDriveOrFunction
+	jc		SHORT BootMenuEvent_UpdateAllMenuitems	; Selection changed to a function
+	call	DriveXlate_SetDriveToSwap
+	; Fall to BootMenuEvent_UpdateAllMenuitems
+
+;--------------------------------------------------------------------
+; Redraws all menuitems.
+;
+; BootMenuEvent_UpdateAllMenuitems
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		1 = Event processed
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_UpdateAllMenuitems:
+	mov		cx, -1					; Update all items
+	mov		dl, MFL_UPD_ITEM | MFL_UPD_NFO | MFL_UPD_NOCLEAR
+	call	Menu_Invalidate
+	mov		ax, 1					; Event handled
+	ret
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Menuitem Selected notification (EVNT_MNU_SELSET).
+;
+; BootMenuEvent_EventItemSelected
+;	Parameters:
+;		CX:		Index of selected Menuitem
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		1 = Event processed
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_EventItemSelected:
+	call	Menu_Exit				; Exit from menu
+	mov		ax, 1					; Event handled
+	ret
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Key pressed notification (EVNT_MNU_KEY).
+;
+; BootMenuEvent_EventKeyPressed
+;	Parameters:
+;		CX:		Index of currently selected Menuitem
+;		DL:		ASCII character
+;		DH:		BIOS Scan Code
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		1 = Event processed
+;	Corrupts registers:
+;		BX, CX, DX, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_EventKeyPressed:
+	mov		al, dl					; Copy ASCII char to AL
+	sub		al, 'a'-'A'				; To upper case character
+	cmp		al, 'A'					; First possible drive letter?
+	jb		SHORT .Return			;  If below, return
+	cmp		al, 'Z'					; Last possible drive letter?
+	ja		SHORT .Return			;  If above, return
+	LOAD_BDA_SEGMENT_TO	ds, dx
+	mov		[BOOTVARS.bMenuHotkey], al
+	jmp		SHORT BootMenuEvent_EventItemSelected
+.Return:
+	mov		ax, 1
+	ret
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Menu Update notification (EVNT_MNU_UPD).
+;
+; BootMenuEvent_EventMenuDraw
+;	Parameters:
+;		CX: 	Index of Menuitem to update (if MFL_UPD_ITEM set)
+;		DL:		Update flag (only one):
+;					MFL_UPD_TITLE	Update Menu Title string(s)
+;					MFL_UPD_NFO		Update Menu Info string(s)
+;					MFL_UPD_ITEM	Update Menuitem string
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		Was event processed
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_EventMenuDraw:
+	test	dl, MFL_UPD_ITEM		; Need to update Menuitem?
+	jnz		SHORT BootMenuEvent_DrawMenuitem
+	test	dl, MFL_UPD_NFO			; Need to update Info String(s)?
+	jnz		SHORT BootMenuEvent_DrawInfo
+	test	dl, MFL_UPD_TITLE		; Need to update Title String(s)?
+	jnz		SHORT BootMenuEvent_DrawTitle
+	xor		ax, ax
+	ret
+
+;--------------------------------------------------------------------
+; Draws Menuitem string. Cursor is set to a menuitem location.
+;
+; BootMenuEvent_DrawMenuitem
+;	Parameters:
+;		CX: 	Index of Menuitem to draw
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		Was event processed
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, DS, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_DrawMenuitem:
+	call	RamVars_GetSegmentToDS
+	call	BootMenu_ConvertMenuitemToDriveOrFunction
+	jc		SHORT .DrawFunctionItem
+	call	BootMenuPrint_TranslatedDriveNumber
+	test	dl, 80h					; Floppy drive?
+	jz		SHORT .DrawFloppyDriveItem
+	jmp		BootMenuPrint_HardDiskMenuitem
+ALIGN JUMP_ALIGN
+.DrawFunctionItem:
+	jmp		BootMenuPrint_FunctionMenuitem
+ALIGN JUMP_ALIGN
+.DrawFloppyDriveItem:
+	jmp		BootMenuPrint_FloppyMenuitem
+
+;--------------------------------------------------------------------
+; Draws information strings. Cursor is set to a first information line.
+;
+; BootMenuEvent_DrawInfo
+;	Parameters:
+;		CX: 	Index of selected menuitem
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		Was event processed
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, DS, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_DrawInfo:
+	call	RamVars_GetSegmentToDS
+	call	BootMenu_ConvertMenuitemToDriveOrFunction
+	jc		SHORT .DrawFunctionInfo
+	test	dl, 80h					; Floppy drive?
+	jz		SHORT .DrawFloppyDriveInfo
+	jmp		BootMenuPrint_HardDiskMenuitemInformation
+ALIGN JUMP_ALIGN
+.DrawFunctionInfo:
+	jmp		BootMenuPrint_FunctionMenuitemInformation
+ALIGN JUMP_ALIGN
+.DrawFloppyDriveInfo:
+	jmp		BootMenuPrint_FloppyMenuitemInformation
+
+;--------------------------------------------------------------------
+; Draws title strings. Cursor is set to a first title line.
+;
+; BootMenuEvent_DrawTitle
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		Was event processed
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_DrawTitle:
+	jmp		BootMenuPrint_TitleStrings
+
+
+;--------------------------------------------------------------------
+; Boot Menu event handler.
+; Handles Get Default Menuitem notification (EVNT_MNU_GETDEF).
+;
+; BootMenuEvent_EventGetDefaultMenuitem
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AX:		Was event processed
+;		CX:		Index of menuitem to set selected
+;	Corrupts registers:
+;		BX, CX, DX, DI, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_EventGetDefaultMenuitem:
+	call	RamVars_GetSegmentToDS
+	mov		dl, [cs:ROMVARS.bBootDrv]	; Default boot drive
+	call	BootMenu_IsDriveInSystem
+	jnc		SHORT .DoNotSetDefaultMenuitem
+	call	DriveXlate_SetDriveToSwap
+	call	BootMenu_ConvertDriveToMenuitem
+	mov		ax, 1
+	ret
+ALIGN JUMP_ALIGN
+.DoNotSetDefaultMenuitem:
+	xor		ax, ax
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrint.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrint.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrint.asm	(revision 37)
@@ -0,0 +1,562 @@
+; File name		:	BootMenuPrint.asm
+; Project name	:	IDE BIOS
+; Created date	:	26.3.2010
+; Last update	:	3.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for printing boot menu strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints information strings to the bottom of the screen.
+;
+; BootMenuPrint_TheBottomOfScreen
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_TheBottomOfScreen:
+	call	FloppyDrive_GetCount
+	mov		bl, cl					; Floppy Drive count to BL
+	call	RamVars_GetHardDiskCountFromBDAtoCX
+	mov		bh, cl					; Hard Disk count to BH
+	call	BootMenuPrint_GetCoordinatesForBottomStrings
+	call	BootMenuPrint_SetCursorPosition
+	call	BootMenuPrint_FloppyHotkeyString
+	jmp		BootMenuPrint_HardDiskHotkeyString
+
+
+;--------------------------------------------------------------------
+; Returns coordinates for bottom strings.
+;
+; BootMenuPrint_GetCoordinatesForBottomStrings
+;	Parameters:
+;		BL:		Number of floppy drives in system
+;		BH:		Number of hard disks in system
+;	Returns:
+;		DL:		Cursor X coordinate
+;		DH:		Cursor Y coordinate
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_GetCoordinatesForBottomStrings:
+	mov		dx, 1800h				; (0, 24)
+	xor		ax, ax					; Zero AX
+	sub		al, bl					; Set CF if any floppy drives
+	sbb		dh, 0					; Decrement Y-coordinate if necessary
+	sub		ah, bh					; Set CF if any hard disks
+	sbb		dh, 0					; Decrement Y-coordinate if necessary
+	ret
+
+
+;--------------------------------------------------------------------
+; Sets cursor to wanted screen coordinates.
+;
+; BootMenuPrint_SetCursorPosition
+;	Parameters:
+;		DL:		Cursor X coordinate
+;		DH:		Cursor Y coordinate
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_SetCursorPosition:
+	push	bx
+	call	MenuCrsr_SetCursor
+	pop		bx
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints Floppy Drive hotkey string.
+;
+; BootMenuPrint_FloppyHotkeyString
+;	Parameters:
+;		BL:		Number of floppy drives in system
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FloppyHotkeyString:
+	test	bl, bl					; Any floppy drives?
+	jz		.Return
+	ePUSH_T	ax, g_szHDD
+	ePUSH_T	ax, g_szFDD
+	mov		ax, 'A'-1
+	add		al, bl					; Last Floppy Drive letter
+	push	ax
+	ePUSH_T	ax, 'A'
+	jmp		SHORT BootMenuPrint_HotkeyString
+.Return:
+	ret
+
+;--------------------------------------------------------------------
+; Prints Floppy Drive or Hard Disk hotkey string when
+; parameters are pushed to stack.
+;
+; BootMenuPrint_HotkeyString
+;	Parameters:
+;		Stack:	String formatting parameters
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HotkeyString:
+	mov		si, g_szBottomScrn
+	mov		dh, 8					; 8 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Prints Hard Disk hotkey string.
+;
+; BootMenuPrint_FloppyHotkeyString
+;	Parameters:
+;		BH:		Number of hard disks in system
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskHotkeyString:
+	test	bh, bh					; Any hard disks?
+	jz		.Return
+	ePUSH_T	ax, g_szFDD
+	ePUSH_T	ax, g_szHDD
+	call	BootMenu_GetLetterForFirstHardDisk
+	eMOVZX	ax, bh					; Hard disk count to AX
+	add		ax, cx					; One past last hard disk letter
+	dec		ax						; Last hard disk letter
+	push	ax
+	push	cx
+	jmp		SHORT BootMenuPrint_HotkeyString
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Clears screen.
+;
+; BootMenuPrint_ClearScreen
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_ClearScreen:
+	push	cx
+	call	MenuDraw_ClrScr
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Translates and prints drive number.
+;
+; BootMenuPrint_TranslatedDriveNumber
+;	Parameters:
+;		DL:		Untranslated drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_TranslatedDriveNumber:
+	push	dx
+	call	DriveXlate_ToOrBack
+	mov		al, dl						; Drive number to AL
+	call	Print_IntHexB
+	mov		dl, ' '
+	PRINT_CHAR							; Print space
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints Floppy Drive Menuitem string.
+;
+; BootMenuPrint_FloppyMenuitem
+;	Parameters:
+;		DL:		Untranslated Floppy Drive number
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FloppyMenuitem:
+	ePUSH_T	ax, BootMenuPrint_HardDiskPrinted	; Return address
+	add		dl, 'A'				; Number to letter
+	push	dx
+	ePUSH_T	ax, g_szFloppyDrv
+	mov		si, g_szFDLetter
+	mov		dh, 4				; 4 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem string.
+;
+; BootMenuPrint_HardDiskMenuitem
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		CX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitem:
+	ePUSH_T	ax, BootMenuPrint_HardDiskPrinted
+	call	FindDPT_ForDriveNumber		; DS:DI to point DPT
+	jnc		SHORT BootMenuPrint_HardDiskMenuitemForForeignDrive
+	jmp		SHORT BootMenuPrint_HardDiskMenuitemForOurDrive
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskPrinted:
+	mov		ax, 1
+	ret
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem string for drive that is handled by
+; some another BIOS.
+;
+; BootMenuPrint_HardDiskMenuitemForForeignDrive
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitemForForeignDrive:
+	mov		si, g_szforeignHD
+	jmp		PrintString_FromCS
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem string for drive that is handled by our BIOS.
+;
+; BootMenuPrint_HardDiskMenuitemForOurDrive
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		CX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitemForOurDrive:
+	call	BootInfo_GetOffsetToBX
+	LOAD_BDA_SEGMENT_TO	es, ax
+	lea		si, [bx+BOOTNFO.szDrvName]
+	jmp		PrintString_FromES
+
+
+;--------------------------------------------------------------------
+; Prints Function Menuitem string.
+;
+; BootMenuPrint_FunctionMenuitem
+;	Parameters:
+;		DX:		Function ID
+;	Returns:
+;		AX:		1 if function ID was valid
+;				0 if function ID was invalid
+;	Corrupts registers:
+;		DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FunctionMenuitem:
+	test	dx, dx					; ID_BOOTFUNC_ROMBOOT
+	jz		SHORT .PrintRomBootMenuitem
+	xor		ax, ax					; Event not processed
+	ret
+
+ALIGN JUMP_ALIGN
+.PrintRomBootMenuitem:
+	mov		si, g_szRomBoot
+	; Fall to .PrintAndReturn
+
+ALIGN JUMP_ALIGN
+.PrintAndReturn:
+	call	PrintString_FromCS
+	mov		ax, 1					; Event processed
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints Floppy Drive Menuitem information strings.
+;
+; BootMenuPrint_FloppyMenuitemInformation
+;	Parameters:
+;		DL:		Untranslated Floppy Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FloppyMenuitemInformation:
+	call	FloppyDrive_GetType						; Get Floppy Drive type to BX
+	ePUSH_T	ax, BootMenuPrint_ClearThreeInfoLines	; New return address
+	test	bx, bx									; Two possibilities? (FLOPPY_TYPE_525_OR_35_DD)
+	jz		SHORT BootMenuPrint_PrintXTFloppyType
+	cmp		bl, FLOPPY_TYPE_35_ED
+	ja		SHORT BootMenuPrint_PrintUnknownFloppyType
+	jmp		SHORT BootMenuPrint_PrintKnownFloppyType
+
+;--------------------------------------------------------------------
+; Prints Menuitem information string for two possible XT floppy drives.
+;
+; BootMenuPrint_PrintXTFloppyType
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_PrintXTFloppyType:
+	mov		si, g_szFddSizeOr
+	jmp		SHORT BootMenuPrint_FormatUnknownFloppyType
+
+;--------------------------------------------------------------------
+; Prints Menuitem information string for unknown floppy drive type.
+;
+; BootMenuPrint_PrintUnknownFloppyType
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_PrintUnknownFloppyType:
+	mov		si, g_szFddUnknown
+BootMenuPrint_FormatUnknownFloppyType:
+	ePUSH_T	ax, g_szCapacity
+	mov		dh, 2					; 2 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+;--------------------------------------------------------------------
+; Prints Menuitem information string for known floppy drive type.
+;
+; BootMenuPrint_PrintKnownFloppyType
+;	Parameters:
+;		BX:		Floppy drive type
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_PrintKnownFloppyType:
+	dec		bx						; Cannot be 0 (FLOPPY_TYPE_525_OR_35_DD)
+	shl		bx, 1					; Shift for WORD lookup
+	push	WORD [cs:bx+.rgwCapacity]
+	mov		ax, [cs:bx+.rgwPhysicalSize]
+	push	ax						; '1/4' or '1/2'
+	mov		al, ah
+	push	ax						; '5' or '3'
+	ePUSH_T	ax, g_szCapacity
+	mov		si, g_szFddSize
+	mov		dh, 8					; 8 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+ALIGN WORD_ALIGN
+.rgwCapacity:
+	dw		360
+	dw		1200
+	dw		720
+	dw		1440
+	dw		2880
+	dw		2880
+.rgwPhysicalSize:
+	db		172, '5'	; 1, FLOPPY_TYPE_525_DD
+	db		172, '5'	; 2, FLOPPY_TYPE_525_HD
+	db		171, '3'	; 3, FLOPPY_TYPE_35_DD
+	db		171, '3'	; 4, FLOPPY_TYPE_35_HD
+	db		171, '3'	; 5, 3.5" ED on some BIOSes
+	db		171, '3'	; 6, FLOPPY_TYPE_35_ED
+
+
+;--------------------------------------------------------------------
+; Clears remaining characters from current information line
+; and clears following lines.
+;
+; BootMenuPrint_ClearThreeInfoLines
+; BootMenuPrint_ClearTwoInfoLines
+; BootMenuPrint_ClearOneInfoLine
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AX:		1
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_ClearThreeInfoLines:
+	call	MenuDraw_NewlineStrClrLn
+ALIGN JUMP_ALIGN
+BootMenuPrint_ClearTwoInfoLines:
+	call	MenuDraw_NewlineStrClrLn
+ALIGN JUMP_ALIGN
+BootMenuPrint_ClearOneInfoLine:
+	call	MenuDraw_NewlineStrClrLn
+	mov		ax, 1
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem information strings.
+;
+; BootMenuPrint_HardDiskMenuitemInformation
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if drive number was valid
+;				0 if drive number was invalid
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitemInformation:
+	ePUSH_T	ax, BootMenuPrint_HardDiskPrinted
+	call	FindDPT_ForDriveNumber		; DS:DI to point DPT
+	jnc		SHORT BootMenuPrint_HardDiskMenuitemInfoForForeignDrive
+	call	BootMenuPrint_HardDiskMenuitemInfoSizeForOurDrive
+	jmp		BootMenuPrintCfg_ForOurDrive
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem information strings for drive that
+; is handled by some other BIOS.
+;
+; BootMenuPrint_HardDiskMenuitemInfoForForeignDrive
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitemInfoForForeignDrive:
+	call	DriveXlate_ToOrBack
+	call	HCapacity_GetSectorCountFromForeignAH08h
+	call	HCapacity_ConvertSectorCountToSize
+	ePUSH_T	dx, BootMenuPrint_ClearThreeInfoLines	; Return address
+	push	cx							; Magnitude character
+	push	si							; Tenths
+	push	ax							; Size in magnitude
+	ePUSH_T	ax, g_szCapacity			; "Capacity"
+	mov		si, g_szSizeSingle
+	mov		dh, 8						; 8 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem information size string for drive that
+; is handled by our BIOS.
+;
+; BootMenuPrint_HardDiskMenuitemInfoSizeForOurDrive
+;	Parameters:
+;		DL:		Untranslated Hard Disk number
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_HardDiskMenuitemInfoSizeForOurDrive:
+	ePUSH_T	ax, BootMenuPrint_ClearOneInfoLine	; Return address
+
+	; Get and push total LBA size
+	call	BootInfo_GetTotalSectorCount
+	call	HCapacity_ConvertSectorCountToSize
+	push	cx								; Magnitude character
+	push	si								; Tenths
+	push	ax								; Size in magnitude
+
+	; Get and push L-CHS size
+	mov		dl, [di+DPT.bDrvNum]			; Restore drive number
+	call	HCapacity_GetSectorCountFromOurAH08h
+	call	HCapacity_ConvertSectorCountToSize
+	push	cx								; Magnitude character
+	push	si								; Tenths
+	push	ax								; Size in magnitude
+
+	ePUSH_T	ax, g_szCapacity				; "Capacity"
+	mov		si, g_szSizeDual
+	mov		dh, 14							; 14 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Prints Function Menuitem information strings.
+;
+; BootMenuPrint_HardDiskMenuitemInformation
+;	Parameters:
+;		DX:		Function ID
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		1 if function ID was valid
+;				0 if function ID was valid
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FunctionMenuitemInformation:
+	jmp		SHORT BootMenuPrint_ClearThreeInfoLines
+
+
+;--------------------------------------------------------------------
+; Prints Boot Menu title strings.
+;
+; BootMenuPrint_TitleStrings
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AX:		Was printing successfull
+;	Corrupts registers:
+;		BX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_TitleStrings:
+	mov		si, ROMVARS.szTitle
+	call	PrintString_FromCS
+	call	BootMenuPrint_ClearOneInfoLine
+	mov		si, ROMVARS.szVersion
+	call	PrintString_FromCS
+	call	BootMenuPrint_ClearOneInfoLine
+	mov		si, g_szTitleLn3
+	call	PrintString_FromCS
+	jmp		SHORT BootMenuPrint_ClearOneInfoLine
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrintCfg.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrintCfg.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootMenuPrintCfg.asm	(revision 37)
@@ -0,0 +1,224 @@
+; File name		:	BootMenuPrintCfg.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.3.2010
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for printing drive configuration
+;					information on Boot Menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints Hard Disk configuration for drive handled by our BIOS.
+; Cursor is set to configuration header string position.
+;
+; BootMenuPrintCfg_ForOurDrive
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrintCfg_ForOurDrive:
+	call	BootMenuPrintCfg_HeaderAndChangeLine
+	call	BootMenuPrintCfg_GetPointers
+	call	BootMenuPrintCfg_PushAndFormatCfgString
+	jmp		BootMenuPrint_ClearOneInfoLine
+
+
+;--------------------------------------------------------------------
+; Prints configuration header and changes for printing values.
+;
+; BootMenuPrintCfg_HeaderAndChangeLine
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrintCfg_HeaderAndChangeLine:
+	mov		si, g_szCfgHeader
+	call	PrintString_FromCS
+	jmp		BootMenuPrint_ClearOneInfoLine
+
+
+;--------------------------------------------------------------------
+; Return all necessary pointers to drive information structs.
+;
+; BootMenuPrintCfg_GetPointers
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Corrupts registers:
+;		AX, DL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrintCfg_GetPointers:
+	mov		dl, [di+DPT.bDrvNum]		; Load Drive number to DL
+	call	BootInfo_GetOffsetToBX		; ES:BX now points...
+	LOAD_BDA_SEGMENT_TO	es, ax			; ...to BOOTNFO
+	mov		al, [di+DPT.bIdeOff]
+	xchg	si, ax						; CS:SI now points to IDEVARS
+	ret
+
+
+;--------------------------------------------------------------------
+; Pushes all string formatting parameters and prints
+; formatted configuration string.
+;
+; BootMenuPrintCfg_PushAndFormatCfgString
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrintCfg_PushAndFormatCfgString:
+	; Fall to first push below
+
+;--------------------------------------------------------------------
+; BootMenuPrintCfg_PushResetStatus
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+BootMenuPrintCfg_PushResetStatus:
+	eMOVZX	ax, BYTE [di+DPT.bReset]
+	push	ax
+
+;--------------------------------------------------------------------
+; BootMenuPrintCfg_PushIRQ
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+BootMenuPrintCfg_PushIRQ:
+	mov		dl, ' '						; Load space to DL
+	mov		al, [cs:si+IDEVARS.bIRQ]
+	test	al, al						; Interrupts disabled?
+	jz		SHORT .PushIrqDisabled
+	add		al, '0'						; Digit to ASCII
+	cmp		al, '9'						; Only one digit needed?
+	jbe		SHORT .PushCharacters
+
+	; Two digits needed
+	sub		al, 10						; Limit to single digit ASCII
+	mov		dl, '1'						; Load '1 to DX
+	jmp		SHORT .PushCharacters
+ALIGN JUMP_ALIGN
+.PushIrqDisabled:
+	mov		al, '-'						; Load line to AL
+	xchg	ax, dx						; Space to AL, line to DL
+ALIGN JUMP_ALIGN
+.PushCharacters:
+	push	ax
+	push	dx
+
+;--------------------------------------------------------------------
+; BootMenuPrintCfg_PushBusType
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (jumps to next push below)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+BootMenuPrintCfg_PushBusType:
+	xchg	ax, bx		; Store BX to AX
+	eMOVZX	bx, BYTE [cs:si+IDEVARS.bBusType]
+	mov		bx, [cs:bx+.rgwBusTypeValues]	; Char to BL, Int to BH	
+	eMOVZX	dx, bh
+	push	dx			; Push 8, 16 or 32
+	push	bx			; Push character
+	xchg	bx, ax		; Restore BX
+	jmp		SHORT .NextPush
+ALIGN WORD_ALIGN
+.rgwBusTypeValues:
+	db		'D', 8		; BUS_TYPE_8_DUAL
+	db		' ', 16		; BUS_TYPE_16
+	db		' ', 32		; BUS_TYPE_32
+	db		'S', 8		; BUS_TYPE_8_SINGLE
+ALIGN JUMP_ALIGN
+.NextPush:
+
+;--------------------------------------------------------------------
+; BootMenuPrintCfg_PushBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+BootMenuPrintCfg_PushBlockMode:
+	eMOVZX	ax, BYTE [di+DPT.bSetBlock]
+	push	ax
+
+;--------------------------------------------------------------------
+; BootMenuPrintCfg_PushAddressingMode
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:BX:	Ptr to BOOTNFO
+;		CS:SI:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (jumps to next push below)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+BootMenuPrintCfg_PushAddressingMode:
+	mov		dx, bx				; Backup BX to DX
+	mov		bx, MASK_DPT_ADDR	; Load addressing mode mask
+	and		bl, [di+DPT.bFlags]	; Addressing mode now in BX
+	push	WORD [cs:bx+.rgszAddressingModeString]
+	mov		bx, dx
+	jmp		SHORT .NextPush
+ALIGN WORD_ALIGN
+.rgszAddressingModeString:
+	dw	g_szLCHS
+	dw	g_szPCHS
+	dw	g_szLBA28
+	dw	g_szLBA48
+ALIGN JUMP_ALIGN
+.NextPush:
+
+;--------------------------------------------------------------------
+; Prints formatted configuration string from parameters pushed to stack.
+;
+; BootMenuPrintCfg_ValuesFromStack
+;	Parameters:
+;		Stack:	All formatting parameters
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+BootMenuPrintCfg_ValuesFromStack:
+	mov		si, g_szCfgFormat
+	mov		dh, 14						; 14 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootPrint.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootPrint.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootPrint.asm	(revision 37)
@@ -0,0 +1,110 @@
+; File name		:	BootPrint.asm
+; Project name	:	IDE BIOS
+; Created date	:	19.3.2010
+; Last update	:	1.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for printing boot related strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints trying to boot string.
+;
+; BootPrint_TryToBootFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_TryToBootFromDL:
+	push	dx
+	ePUSH_T	ax, BootPrint_PopDxAndReturn	; Return address
+
+	xor		dh, dh				; Translated drive number to DX
+	push	dx					; Push translated drive number
+	call	DriveXlate_ToOrBack
+	push	dx					; Push untranslated drive number
+
+	mov		ax, g_szFloppyDrv	; Assume "Floppy Drive"
+	test	dl, 80h				; Hard Disk?
+	jz		SHORT .PushHardOrFloppy
+	add		ax, BYTE g_szHardDrv - g_szFloppyDrv
+.PushHardOrFloppy:
+	push	ax
+
+	mov		si, g_szTryToBoot
+	mov		dh, 6				; 6 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+ALIGN JUMP_ALIGN
+BootPrint_PopDxAndReturn:
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints message that valid boot sector has been found.
+;
+; BootPrint_BootSectorLoaded
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_BootSectorLoaded:
+	push	dx
+	ePUSH_T	ax, BootPrint_PopDxAndReturn	; Return address
+
+	ePUSH_T	ax, g_szFound
+	ePUSH_T	ax, g_szBootSector
+	mov		si, g_szSectRead
+	mov		dh, 4							; 4 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Prints message that first sector is not boot sector.
+;
+; BootPrint_FirstSectorNotBootable
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_FirstSectorNotBootable:
+	ePUSH_T	ax, g_szNotFound
+	ePUSH_T	ax, g_szBootSector
+	mov		si, g_szSectRead
+	mov		dh, 4				; 4 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Prints error code for failed first sector read attempt.
+;
+; BootPrint_FailedToLoadFirstSector
+;	Parameters:
+;		AH:		INT 13h error code
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_FailedToLoadFirstSector:
+	eMOVZX	cx, ah				; Error code to CX
+	push	cx					; Push INT 13h error code
+	mov		si, g_szReadError
+	mov		dh, 2				; 2 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootVars.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootVars.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Boot/BootVars.asm	(revision 37)
@@ -0,0 +1,113 @@
+; File name		:	BootVars.asm
+; Project name	:	IDE BIOS
+; Created date	:	1.4.2010
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions to access BOOTVARS struct.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Stores POST stack pointer to BOOTVARS.
+;
+; BootVars_StorePostStackPointer
+;	Parameters:
+;		DS:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootVars_StorePostStackPointer:
+	pop		ax							; Pop return address
+	mov		[BOOTVARS.dwPostStack], sp
+	mov		[BOOTVARS.dwPostStack+2], ss
+	jmp		ax
+
+
+;--------------------------------------------------------------------
+; Initializes stack for boot menu usage.
+; POST stack is not large enough when DPTs are stored to 30:0h.
+;
+; BootVars_SwitchToBootMenuStack
+;	Parameters:
+;		Nothing
+;	Returns:
+;		SS:SP:	Pointer to top of Boot Menu stack
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootVars_SwitchToBootMenuStack:
+	pop		ax							; Pop return address
+	cli									; Disable interrupts
+	LOAD_BDA_SEGMENT_TO	ss, sp
+	mov		sp, BOOTVARS.rgbMnuStack	; Load offset to stack
+	sti									; Enable interrupts
+	jmp		ax
+
+
+;--------------------------------------------------------------------
+; Restores SS and SP to initial boot loader values.
+;
+; BootVars_SwitchBackToPostStack
+;	Parameters:
+;		Nothing
+;	Returns:
+;		SS:SP:	Ptr to POST stack
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootVars_SwitchBackToPostStack:
+	pop		ax							; Pop return address
+	cli									; Disable interrupts
+	LOAD_BDA_SEGMENT_TO	ss, sp
+	eLSS	sp, ss:BOOTVARS.dwPostStack
+	sti									; Enable interrupts
+	jmp		ax
+
+
+;--------------------------------------------------------------------
+; Backups system INT 18h ROM Boot / Boot Failure handler and
+; installs our own for boot menu INT 18h callbacks.
+;
+; BootVars_StoreSystemInt18hAndInstallOurs
+;	Parameters:
+;		DS:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootVars_StoreSystemInt18hAndInstallOurs:
+	mov		bx, INTV_BOOT_FAILURE*4		; Offset to INT 18h vector
+	les		ax, [bx]					; Load system INT 18h
+	mov		[BOOTVARS.dwSys18h], ax
+	mov		[BOOTVARS.dwSys18h+2], es
+	mov		WORD [bx], Int18h_BootError	; Install our INT 18h
+	mov		WORD [bx+2], cs
+	ret
+
+
+;--------------------------------------------------------------------
+; Restores system INT 18h ROM Boot or Boot Error handler.
+;
+; BootVars_RestoreSystemInt18h
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DS, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootVars_RestoreSystemInt18h:
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	les		ax, [BOOTVARS.dwSys18h]
+	mov		[INTV_BOOT_FAILURE*4], ax
+	mov		[INTV_BOOT_FAILURE*4+2], es
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h.asm	(revision 37)
@@ -0,0 +1,293 @@
+; File name		:	Int13h_Jump.asm
+; Project name	:	IDE BIOS
+; Created date	:	21.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h BIOS functions (Floppy and Hard disk).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Macro that prints drive and function number.
+; Used only for debugging.
+;
+; DEBUG_PRINT_DRIVE_AND_FUNCTION
+;	Parameters:
+;		AH:		INT 13h function number
+;		DL:		Drive number
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro DEBUG_PRINT_DRIVE_AND_FUNCTION 0
+	push	dx
+	push	ax
+	mov		al, dl
+	call	Print_IntHexW
+	pop		ax
+	pop		dx
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Int 13h software interrupt handler.
+; Jumps to specific function defined in AH.
+;
+; Int13h_Jump
+;	Parameters:
+;		AH:		Bios function
+;		DL:		Drive number
+;	Returns:
+;		Depends on function
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_DiskFunctions:
+	; Save registers
+	sti									; Enable interrupts
+	push	ds							; Store DS
+	push	di							; Store DI
+
+	;DEBUG_PRINT_DRIVE_AND_FUNCTION
+	call	RamVars_GetSegmentToDS
+	call	DriveXlate_WhenEnteringInt13h
+	call	RamVars_IsFunctionHandledByThisBIOS
+	jnc		SHORT Int13h_DirectCallToAnotherBios
+	;DEBUG_PRINT_DRIVE_AND_FUNCTION
+
+	; Jump to correct BIOS function
+	cmp		ah, 25h						; Valid BIOS function?
+	ja		SHORT Int13h_UnsupportedFunction
+	mov		di, ax
+	eSHR_IM	di, 7						; Shift function to DI...
+	and		di, BYTE 7Eh				; ...and prepare for word lookup
+	jmp		[cs:di+g_rgw13hFuncJump]	; Jump to BIOS function
+
+
+;--------------------------------------------------------------------
+; Directs call to another INT13h function whose pointer is
+; stored to RAMVARS.
+;
+; Int13h_DirectCallToAnotherBios
+;	Parameters:
+;		AH:		Bios function
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;		DI:		Corrupted
+;		Stack from top to down:
+;				Original DI
+;				Original DS
+;	Returns:
+;		Depends on function
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_UnsupportedFunction:
+Int13h_DirectCallToAnotherBios:
+	; Temporarily store original DI and DS from stack to RAMVARS
+	pop		WORD [RAMVARS.wI13hDI]
+	pop		WORD [RAMVARS.wI13hDS]
+
+	; Special return processing required if target function
+	; returns something in DL
+	mov		di, Int13h_ReturnFromAnotherBiosWithValueInDL
+	call	DriveXlate_DoesFunctionReturnSomethingInDL
+	jc		SHORT .PushIretAddress
+	add		di, BYTE Int13h_ReturnFromAnotherBios - Int13h_ReturnFromAnotherBiosWithValueInDL
+.PushIretAddress:
+	pushf								; Push FLAGS to simulate INT
+	push	cs							; Push return segment
+	push	di							; Push return offset
+
+	; "Return" to another INT 13h with original DI and DS
+	push	WORD [RAMVARS.fpOldI13h+2]	; Segment
+	push	WORD [RAMVARS.fpOldI13h]	; Offset
+	lds		di, [RAMVARS.dwI13DIDS]
+	cli									; Disable interrupts as INT would
+	retf
+
+
+;--------------------------------------------------------------------
+; Int13h_CallPreviousInt13hHandler
+;	Parameters:
+;		AH:		Bios function
+;		DS:		RAMVARS segment
+;		Other:	Depends on function to call
+;	Returns:
+;		Depends on function to call
+;	Corrupts registers:
+;		FLAGS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_CallPreviousInt13hHandler:
+	pushf								; Push flags to simulate INT
+	cli									; Disable interrupts since INT does that
+	call	FAR [RAMVARS.fpOldI13h]
+	sti
+	ret
+
+
+;--------------------------------------------------------------------
+; Int13h_ReturnFromAnotherBiosWithValueInDL
+; Int13h_ReturnFromAnotherBios
+;	Parameters:
+;		AH:		Error code
+;		DL:		Drive number (only on Int13h_ReturnFromAnotherBios)
+;		CF:		Error status
+;	Returns:
+;		Depends on function
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_ReturnFromAnotherBiosWithValueInDL:
+	push	ds
+	push	di
+	pushf								; Store return flags
+	call	RamVars_GetSegmentToDS
+	call	DriveXlate_WhenLeavingInt13hWithReturnValueInDL
+	jmp		SHORT Int13h_Leave
+
+ALIGN JUMP_ALIGN
+Int13h_ReturnFromAnotherBios:
+	push	ds
+	push	di
+	pushf								; Store return flags
+	call	RamVars_GetSegmentToDS
+	call	DriveXlate_WhenLeavingInt13h
+	jmp		SHORT Int13h_Leave
+
+
+;--------------------------------------------------------------------
+; Returns from any BIOS function implemented by this BIOS.
+;
+; Int13h_ReturnWithValueInDL
+; Int13h_PopXRegsAndReturn
+; Int13h_PopDiDsAndReturn
+;	Parameters:
+;		DL:		Drive number (not Int13h_ReturnWithoutSwappingDrives)
+;		DS:		RAMVARS segment
+;	Returns:
+;		Depends on function
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_ReturnWithValueInDL:
+	pushf
+	call	DriveXlate_WhenLeavingInt13hWithReturnValueInDL
+	jmp		SHORT Int13h_LeaveAfterStoringErrorCodeToBDA
+
+ALIGN JUMP_ALIGN
+Int13h_PopXRegsAndReturn:
+	pop		bx							; Pop old AX to BX
+	mov		al, bl						; Restore AL
+	pop		bx
+	pop		cx
+	pop		dx
+	; Fall to Int13h_PopDiDsAndReturn
+
+ALIGN JUMP_ALIGN
+Int13h_PopDiDsAndReturn:
+	pushf
+	call	DriveXlate_WhenLeavingInt13h
+	; Fall to Int13h_LeaveAfterStoringErrorCodeToBDA
+
+Int13h_LeaveAfterStoringErrorCodeToBDA:
+	LOAD_BDA_SEGMENT_TO	ds, di
+	mov		[BDA.bHDStatus], ah
+	; Fall to Int13h_Leave
+
+Int13h_Leave:
+	popf
+	pop		di
+	pop		ds
+	retf	2
+
+
+; Jump table for correct BIOS function
+ALIGN WORD_ALIGN
+g_rgw13hFuncJump:
+	dw	AH0h_HandlerForDiskControllerReset				; 00h, Disk Controller Reset (All)
+	dw	AH1h_HandlerForReadDiskStatus					; 01h, Read Disk Status (All)
+	dw	AH2h_HandlerForReadDiskSectors					; 02h, Read Disk Sectors (All)
+	dw	AH3h_HandlerForWriteDiskSectors					; 03h, Write Disk Sectors (All)
+	dw	AH4h_HandlerForVerifyDiskSectors				; 04h, Verify Disk Sectors (All)
+	dw	AH5h_HandlerForFormatDiskTrack					; 05h, Format Disk Track (XT, AT, EISA)
+	dw	Int13h_UnsupportedFunction						; 06h, Format Disk Track with Bad Sectors (XT)
+	dw	Int13h_UnsupportedFunction						; 07h, Format Multiple Cylinders (XT)
+	dw	AH8h_HandlerForReadDiskDriveParameters			; 08h, Read Disk Drive Parameters (All)
+	dw	AH9h_HandlerForInitializeDriveParameters		; 09h, Initialize Drive Parameters (All)
+	dw	Int13h_UnsupportedFunction						; 0Ah, Read Disk Sectors with ECC (XT, AT, EISA)
+	dw	Int13h_UnsupportedFunction						; 0Bh, Write Disk Sectors with ECC (XT, AT, EISA)
+	dw	AHCh_HandlerForSeek								; 0Ch, Seek (All)
+	dw	AHDh_HandlerForResetHardDisk					; 0Dh, Alternate Disk Reset (All)
+	dw	Int13h_UnsupportedFunction						; 0Eh, Read Sector Buffer (XT, PS/1), ESDI Undocumented Diagnostic (PS/2)
+	dw	Int13h_UnsupportedFunction						; 0Fh, Write Sector Buffer (XT, PS/1), ESDI Undocumented Diagnostic (PS/2)
+	dw	AH10h_HandlerForCheckDriveReady					; 10h, Check Drive Ready (All)
+	dw	AH11h_HandlerForRecalibrate						; 11h, Recalibrate (All)
+	dw	Int13h_UnsupportedFunction						; 12h, Controller RAM Diagnostic (XT)
+	dw	Int13h_UnsupportedFunction						; 13h, Drive Diagnostic (XT)
+	dw	AH14h_HandlerForControllerInternalDiagnostic	; 14h, Controller Internal Diagnostic (All)
+	dw	AH15h_HandlerForReadDiskDriveSize				; 15h, Read Disk Drive Size (AT+)
+	dw	Int13h_UnsupportedFunction						; 16h, 
+	dw	Int13h_UnsupportedFunction						; 17h, 
+	dw	Int13h_UnsupportedFunction						; 18h, 
+	dw	Int13h_UnsupportedFunction						; 19h, Park Heads (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Ah, Format ESDI Drive (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Bh, Get ESDI Manufacturing Header (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Ch, ESDI Special Functions (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Dh, 
+	dw	Int13h_UnsupportedFunction						; 1Eh, 
+	dw	Int13h_UnsupportedFunction						; 1Fh, 
+	dw	Int13h_UnsupportedFunction						; 20h, 
+	dw	Int13h_UnsupportedFunction						; 21h, Read Disk Sectors, Multiple Blocks (PS/1)
+	dw	Int13h_UnsupportedFunction						; 22h, Write Disk Sectors, Multiple Blocks (PS/1)
+	dw	AH23h_HandlerForSetControllerFeatures			; 23h, Set Controller Features Register (PS/1)
+	dw	AH24h_HandlerForSetMultipleBlocks				; 24h, Set Multiple Blocks (PS/1)
+	dw	AH25h_HandlerForGetDriveInformation				; 25h, Get Drive Information (PS/1)
+;	dw	Int13h_UnsupportedFunction						; 26h, 
+;	dw	Int13h_UnsupportedFunction						; 27h, 
+;	dw	Int13h_UnsupportedFunction						; 28h, 
+;	dw	Int13h_UnsupportedFunction						; 29h, 
+;	dw	Int13h_UnsupportedFunction						; 2Ah, 
+;	dw	Int13h_UnsupportedFunction						; 2Bh, 
+;	dw	Int13h_UnsupportedFunction						; 2Ch, 
+;	dw	Int13h_UnsupportedFunction						; 2Dh, 
+;	dw	Int13h_UnsupportedFunction						; 2Eh, 
+;	dw	Int13h_UnsupportedFunction						; 2Fh, 
+;	dw	Int13h_UnsupportedFunction						; 30h, 
+;	dw	Int13h_UnsupportedFunction						; 31h, 
+;	dw	Int13h_UnsupportedFunction						; 32h, 
+;	dw	Int13h_UnsupportedFunction						; 33h, 
+;	dw	Int13h_UnsupportedFunction						; 34h, 
+;	dw	Int13h_UnsupportedFunction						; 35h, 
+;	dw	Int13h_UnsupportedFunction						; 36h, 
+;	dw	Int13h_UnsupportedFunction						; 37h, 
+;	dw	Int13h_UnsupportedFunction						; 38h, 
+;	dw	Int13h_UnsupportedFunction						; 39h, 
+;	dw	Int13h_UnsupportedFunction						; 3Ah, 
+;	dw	Int13h_UnsupportedFunction						; 3Bh, 
+;	dw	Int13h_UnsupportedFunction						; 3Ch, 
+;	dw	Int13h_UnsupportedFunction						; 3Dh, 
+;	dw	Int13h_UnsupportedFunction						; 3Eh, 
+;	dw	Int13h_UnsupportedFunction						; 3Fh, 
+;	dw	Int13h_UnsupportedFunction						; 40h, 
+;	dw	Int13h_UnsupportedFunction						; 41h, Check if Extensions Present (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 42h, Extended Read Sectors (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 43h, Extended Write Sectors (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 44h, Extended Verify Sectors (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 45h, Lock and Unlock Drive (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 46h, Eject Media Request (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 47h, Extended Seek (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 48h, Get Extended Drive Parameters (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 49h, Get Extended Disk Change Status (EBIOS)
+;	dw	Int13h_UnsupportedFunction						; 4Ah, Initiate Disk Emulation (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Bh, Terminate Disk Emulation (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Ch, Initiate Disk Emulation and Boot (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Dh, Return Boot Catalog (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Eh, Set Hardware Configuration (EBIOS)
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH0h_HReset.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH0h_HReset.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH0h_HReset.asm	(revision 37)
@@ -0,0 +1,182 @@
+; File name		:	AH0h_HReset.asm
+; Project name	:	IDE BIOS
+; Created date	:	27.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=0h, Disk Controller Reset.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=0h, Disk Controller Reset.
+;
+; AH0h_HandlerForDiskControllerReset
+;	Parameters:
+;		AH:		Bios function 0h
+;		DL:		Drive number (ignored so all drives are reset)
+;				If bit 7 is set all hard disks and floppy disks reset.
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h return status (from drive requested in DL)
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH0h_HandlerForDiskControllerReset:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	eMOVZX	bx, dl						; Copy requested drive to BL, zero BH to assume no errors
+	call	ResetFloppyDrivesWithInt40h
+	test	bl, 80h
+	jz		SHORT .SkipHardDiskReset
+	call	ResetForeignHardDisks
+	call	AH0h_ResetHardDisksHandledByOurBIOS
+ALIGN JUMP_ALIGN
+.SkipHardDiskReset:
+	mov		ah, bh						; Copy error code to AH
+	xor		al, al						; Zero AL...
+	cmp		al, bh						; ...and set CF if error
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; ResetFloppyDrivesWithInt40h
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, DL, DI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+ResetFloppyDrivesWithInt40h:
+	call	GetDriveNumberForForeignBiosesToDL
+	and		dl, 7Fh						; Clear hard disk bit
+	xor		ah, ah						; Disk Controller Reset
+	int		INTV_FLOPPY_FUNC
+	jmp		SHORT BackupErrorCodeFromTheRequestedDriveToBH
+
+
+;--------------------------------------------------------------------
+; ResetForeignHardDisks
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, DL, DI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+ResetForeignHardDisks:
+	call	GetDriveNumberForForeignBiosesToDL
+	xor		ah, ah						; Disk Controller Reset
+	call	Int13h_CallPreviousInt13hHandler
+	jmp		SHORT BackupErrorCodeFromTheRequestedDriveToBH
+
+
+;--------------------------------------------------------------------
+; GetDriveNumberForForeignBiosesToDL
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		BL if foreign drive
+;				80h if our drive
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+GetDriveNumberForForeignBiosesToDL:
+	mov		dl, bl
+	call	RamVars_IsDriveHandledByThisBIOS
+	jc		SHORT .GetFirstDriveForForeignBios
+	ret		; Return what was in BL unmodified
+ALIGN JUMP_ALIGN
+.GetFirstDriveForForeignBios:
+	mov		dl, 80h
+	ret
+
+
+;--------------------------------------------------------------------
+; ResetHardDisksHandledByOurBIOS
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH0h_ResetHardDisksHandledByOurBIOS:
+	mov		dh, [RAMVARS.bDrvCnt]		; Load drive count to DH
+	test	dh, dh
+	jz		SHORT .AllDrivesReset		; Return if no drives
+	mov		dl, [RAMVARS.bFirstDrv]		; Load number of first our drive
+	add		dh, dl						; DH = one past last drive to reset
+ALIGN JUMP_ALIGN
+.DriveResetLoop:
+	call	AHDh_ResetDrive
+	call	.BackupErrorCodeFromMasterOrSlaveToBH
+	inc		dx
+	cmp		dl, dh						; All done?
+	jb		SHORT .DriveResetLoop		;  If not, reset next drive
+.AllDrivesReset:
+	ret
+
+;--------------------------------------------------------------------
+; .BackupErrorCodeFromMasterOrSlaveToBH
+;	Parameters:
+;		AH:		Error code for drive DL reset
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DL:		Drive just resetted
+;		DS:		RAMVARS segment
+;	Returns:
+;		BH:		Backuped error code
+;		DL:		Incremented if next drive is slave drive
+;				(=already resetted)
+;	Corrupts registers:
+;		CX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.BackupErrorCodeFromMasterOrSlaveToBH:
+	call	BackupErrorCodeFromTheRequestedDriveToBH
+	mov		cx, [RAMVARS.wIdeBase]		; Load base port for resetted drive
+
+	inc		dx							; DL to next drive
+	call	FindDPT_ForDriveNumber		; Get DPT to DS:DI, store port to RAMVARS
+	jnc		SHORT .NoMoreDrivesOrNoSlaveDrive
+	cmp		cx, [RAMVARS.wIdeBase]		; Next drive is from same controller?
+	je		SHORT BackupErrorCodeFromTheRequestedDriveToBH
+.NoMoreDrivesOrNoSlaveDrive:
+	dec		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; BackupErrorCodeFromTheRequestedDriveToBH
+;	Parameters:
+;		AH:		Error code from the last resetted drive
+;		DL:		Drive last resetted
+;		BL:		Requested drive (DL when entering AH=00h)
+;	Returns:
+;		BH:		Backuped error code
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BackupErrorCodeFromTheRequestedDriveToBH:
+	cmp		dl, bl				; Requested drive?
+	jne		SHORT .Return
+	mov		bh, ah
+ALIGN JUMP_ALIGN
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH10h_HReady.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH10h_HReady.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH10h_HReady.asm	(revision 37)
@@ -0,0 +1,38 @@
+; File name		:	AH10h_HReady.asm
+; Project name	:	IDE BIOS
+; Created date	:	9.12.2007
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=10h, Check Drive Ready.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=10h, Check Drive Ready.
+;
+; AH10h_HandlerForCheckDriveReady
+;	Parameters:
+;		AH:		Bios function 10h
+;		DL:		Drive number (8xh)
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH10h_HandlerForCheckDriveReady:
+	; Save registers
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	; Wait until drive is ready
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	call	HStatus_WaitRdyDefTime
+	jmp		Int13h_PopXRegsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH11h_HRecal.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH11h_HRecal.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH11h_HRecal.asm	(revision 37)
@@ -0,0 +1,57 @@
+; File name		:	AH11h_HRecal.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.9.2007
+; Last update	:	29.7.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=11h, Recalibrate.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=11h, Recalibrate.
+;
+; AH11h_HandlerForRecalibrate
+;	Parameters:
+;		AH:		Bios function 11h
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH11h_HandlerForRecalibrate:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	call	AH11h_RecalibrateDrive
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Int 13h function AH=11h, Recalibrate.
+;
+; AH11h_HRecalibrate
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		AH:		BIOS Error code
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH11h_RecalibrateDrive:
+	; Recalibrate command is optional, vendor specific and not even
+	; supported on later ATA-standards. Let's do seek instead.
+	mov		cx, 1						; Seek to Cylinder 0, Sector 1
+	xor		dh, dh						; Head 0
+	jmp		AHCh_SeekToCylinder
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH14h_HDiag.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH14h_HDiag.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH14h_HDiag.asm	(revision 37)
@@ -0,0 +1,39 @@
+; File name		:	AH14h_HDiag.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=14h, Controller Internal Diagnostic.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=14h, Controller Internal Diagnostic.
+;
+; AH14h_HandlerForControllerInternalDiagnostic
+;	Parameters:
+;		AH:		Bios function 14h
+;		DL:		Drive number (8xh)
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		BIOS Error code
+;		AL:		0 (custom for this BIOS: .bReset byte from DPT)
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH14h_HandlerForControllerInternalDiagnostic:
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		al, [di+DPT.bReset]			; Load reset byte to AL
+	test	al, al						; Any error?
+	jnz		SHORT .ReturnError
+	xor		ah, ah						; Zero AH and CF since success
+	jmp		Int13h_PopDiDsAndReturn
+.ReturnError:
+	mov		ah, RET_HD_RESETFAIL
+	stc
+	jmp		Int13h_PopDiDsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH15h_HSize.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 37)
@@ -0,0 +1,46 @@
+; File name		:	AH15h_HSize.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=15h, Read Disk Drive Size.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=15h, Read Disk Drive Size.
+;
+; AH15h_HandlerForReadDiskDriveSize
+;	Parameters:
+;		AH:		Bios function 15h
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		If succesfull:
+;			AH:		3 (Hard disk accessible)
+;			CX:DX:	Total number of sectors
+;			CF:		0
+;		If failed:
+;			AH:		0 (Drive not present)
+;			CX:DX:	0
+;			CF:		1
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH15h_HandlerForReadDiskDriveSize:
+	push	bx
+	push	ax
+
+	call	HCapacity_GetSectorCountFromOurAH08h; Sector count to DX:AX
+	mov		cx, dx								; HIWORD to CX
+	xchg	dx, ax								; LOWORD to DX
+
+	pop		ax
+	pop		bx
+	mov		ah, 3								; Type code = Hard disk
+	clc
+	jmp		Int13h_ReturnWithValueInDL
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH1h_HStatus.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH1h_HStatus.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH1h_HStatus.asm	(revision 37)
@@ -0,0 +1,37 @@
+; File name		:	AH1h_HStatus.asm
+; Project name	:	IDE BIOS
+; Created date	:	27.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=1h, Read Disk Status.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=1h, Read Disk Status.
+;
+; AH1h_HandlerForReadDiskStatus
+;	Parameters:
+;		AH:		Bios function 1h
+;		DL:		Drive number (8xh)
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h floppy return status
+;		CF:		0 if AH = RET_HD_SUCCESS, 1 otherwise (error)
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH1h_HandlerForReadDiskStatus:
+	push	ds
+
+	LOAD_BDA_SEGMENT_TO	ds, di
+	xor		ah, ah					; Zero AH
+	cmp		ah, [BDA.bHDLastSt]		; Set CF if error code is non-zero
+	mov		ah, [BDA.bHDLastSt]		; Last error to AH
+
+	pop		ds
+	jmp		Int13h_PopDiDsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH23h_HFeatures.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH23h_HFeatures.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH23h_HFeatures.asm	(revision 37)
@@ -0,0 +1,71 @@
+; File name		:	AH23h_HFeatures.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.12.2009
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=23h,
+;					Set Controller Features Register.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=23h, Set Controller Features Register.
+;
+; AH23h_HandlerForSetControllerFeatures
+;	Parameters:
+;		AH:		Bios function 23h
+;		AL:		Feature Number (parameter to Features Register = subcommand)
+;		DL:		Drive number (8xh)
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Parameter registers are undocumented, specific for this BIOS:
+;		BH:		Parameter to Sector Count Register (subcommand specific)
+;		BL:		Parameter to Sector Number Register (subcommand specific)
+;		CL:		Parameter to Low Cylinder Register (subcommand specific)
+;		CH:		Parameter to High Cylinder Register (subcommand specific)
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH23h_HandlerForSetControllerFeatures:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	push	si
+
+	; Backup AL and BH to SI
+	mov		ah, bh
+	xchg	si, ax
+
+	; Select Master or Slave and wait until ready
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	call	HDrvSel_SelectDriveAndDisableIRQ
+	jc		SHORT .Return				; Return if error
+
+	; Output Feature Number
+	mov		ax, si						; Feature number to AL
+	mov		dx, [RAMVARS.wIdeBase]		; Load base port address
+	inc		dx							; REGW_IDE_FEAT
+	out		dx, al
+
+	; Output parameters to Sector Number Register and Cylinder Registers
+	xor		bh, bh						; Zero head number
+	dec		dx							; Back to base port address
+	call	HCommand_OutputTranslatedLCHSaddress
+
+	; Output parameter to Sector Count Register and command
+	xchg	ax, si						; Sector Count Reg param to AH
+	mov		al, ah						; Sector Count Reg param to AL
+	mov		ah, HCMD_SET_FEAT			; Load Set Features command to AH
+	call	HCommand_OutputSectorCountAndCommand
+
+	call	HStatus_WaitBsyDefTime		; Wait until drive ready
+.Return:
+	pop		si
+	jmp		Int13h_PopXRegsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH24h_HSetBlocks.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH24h_HSetBlocks.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH24h_HSetBlocks.asm	(revision 37)
@@ -0,0 +1,77 @@
+; File name		:	AH24h_HSetBlocks.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.12.2009
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=24h, Set Multiple Blocks.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=24h, Set Multiple Blocks.
+;
+; AH24h_HandlerForSetMultipleBlocks
+;	Parameters:
+;		AH:		Bios function 24h
+;		AL:		Number of Sectors per Block (1, 2, 4, 8, 16, 32, 64 or 128)
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH24h_HandlerForSetMultipleBlocks:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	call	AH24h_SetBlockSize
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Sets block size for block mode transfers.
+;
+; AH24h_SetBlockSize
+;	Parameters:
+;		AL:		Number of Sectors per Block (1, 2, 4, 8, 16, 32, 64 or 128)
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH24h_SetBlockSize:
+	; Select Master or Slave and wait until ready
+	mov		bl, al								; Backup block size
+	call	FindDPT_ForDriveNumber				; DS:DI now points to DPT
+	call	HDrvSel_SelectDriveAndDisableIRQ	; Select drive and wait until ready
+	jc		SHORT .Return						; Return if error
+
+	; Output block size and command
+	mov		al, bl								; Restore block size to AL
+	mov		ah, HCMD_SET_MUL					; Load command to AH
+	mov		dx, [RAMVARS.wIdeBase]				; Load base port address
+	add		dx, BYTE REG_IDE_CNT
+	call	HCommand_OutputSectorCountAndCommand
+	call	HStatus_WaitBsyDefTime				; Wait until drive not busy
+	jc		SHORT .DisableBlockMode
+
+	; Store new block size to DPT and return
+	mov		[di+DPT.bSetBlock], bl				; Store new block size
+	xor		ah, ah								; Zero AH and CF since success
+	ret
+.DisableBlockMode:
+	mov		BYTE [di+DPT.bSetBlock], 1			; Disable block mode
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH25h_HDrvID.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH25h_HDrvID.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH25h_HDrvID.asm	(revision 37)
@@ -0,0 +1,137 @@
+; File name		:	AH25h_HDrvID.asm
+; Project name	:	IDE BIOS
+; Created date	:	24.10.2009
+; Last update	:	14.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=25h, Get Drive Information.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=25h, Get Drive Information.
+;
+; AH25h_HandlerForGetDriveInformation
+;	Parameters:
+;		AH:		Bios function 25h
+;		DL:		Drive number
+;		ES:BX:	Ptr to buffer to receive 512-byte drive information
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		ES:BX:	Ptr to 512-byte buffer to receive drive Information
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH25h_HandlerForGetDriveInformation:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	push	es
+
+	; Wait until previously selected drive is ready
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	call	HDrvSel_SelectDriveAndDisableIRQ
+	jc		SHORT .Return				; Return if error
+
+	; Get drive information
+	call	HPIO_NormalizeDataPointer
+	push	bx
+	mov		dx, [RAMVARS.wIdeBase]		; Load base port address
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]	; Load offset to IDEVARS
+	mov		bl, [cs:bx+IDEVARS.bBusType]; Load bus type to BL
+	mov		bh, [di+DPT.bDrvSel]		; Load drive sel byte to BH
+	pop		di							; Pop buffer offset to DI
+	call	AH25h_GetDriveInfo			; Get drive information
+.Return:
+	pop		es
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Gets drive information using Identify Device command.
+;
+; AH25h_GetDriveInfo
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Select Register
+;		BL:		Bus type
+;		DX:		IDE Controller base port address
+;		DS:		Segment to RAMVARS
+;		ES:DI:	Ptr to buffer to receive 512 byte drive information
+;	Returns:
+;		AH:		Int 13h return status (will be stored to BDA)
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH25h_GetDriveInfo:
+	push	di
+	push	dx
+	push	bx
+
+	; Select Master or Slave drive.
+	; DO NOT WAIT UNTIL CURRENTLY SELECTED IS READY!
+	; It makes slave drive detection impossible if master is not present.
+	mov		[RAMVARS.wIdeBase], dx		; Store IDE Base port to RAMVARS
+	add		dx, BYTE REG_IDE_DRVHD		; DX to Drive and Head Sel Register
+	mov		al, bh						; Drive Select byte to AL
+	out		dx, al						; Select Master or Slave drive
+	sub		dx, BYTE REG_IDE_DRVHD		; Back to IDE Base port
+	call	AH25h_GetDriveDetectionTimeoutValue
+	call	HStatus_WaitRdy				; Wait until ready to accept commands
+	jc		SHORT .Return				; Return if error
+
+	; Output command
+	mov		al, HCMD_ID_DEV				; Load Identify Device command to AL
+	out		dx, al						; Output command
+	call	SoftDelay_BeforePollingStatusRegister
+	call	HStatus_WaitDrqDefTime		; Wait until ready to transfer (no IRQ!)
+	jc		SHORT .Return				; Return if error
+
+	; Transfer data
+	sub		dx, BYTE REGR_IDE_ST		; DX to IDE Data Reg
+	xor		bh, bh						; BX now contains bus type
+	mov		cx, 256						; Transfer 256 words (single sector)
+	cld									; INSW to increment DI
+	call	[cs:bx+g_rgfnPioRead]		; Read ID sector
+	call	HStatus_WaitRdyDefTime		; Wait until drive ready
+
+	; Return
+.Return:
+	pop		bx
+	pop		dx
+	pop		di
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns timeout value for drive detection.
+; Long timeout is required for detecing first drive to make sure it is
+; ready after power-on (ATA specification says up to 31 seconds).
+; Short timeout is used for additional drives to prevent long boot time
+; when drive has failed or it is not present.
+;
+; AH25h_GetDriveDetectionTimeoutValue
+;	Parameters:
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		CL:		Timeout value
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH25h_GetDriveDetectionTimeoutValue:
+	cmp		BYTE [RAMVARS.bDrvCnt], 0	; Detecting first drive?
+	je		SHORT .GetLongDelayForInitialDetection
+	mov		cl, B_TIMEOUT_DRVINFO		; Load short timeout
+	ret
+ALIGN JUMP_ALIGN
+.GetLongDelayForInitialDetection:
+	mov		cl, B_TIMEOUT_RESET			; Load long timeout
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH2h_HRead.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 37)
@@ -0,0 +1,65 @@
+; File name		:	AH2h_HRead.asm
+; Project name	:	IDE BIOS
+; Created date	:	27.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=2h, Read Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=2h, Read Disk Sectors.
+;
+; AH2h_HandlerForReadDiskSectors
+;	Parameters:
+;		AH:		Bios function 2h
+;		AL:		Number of sectors to read (1...255)
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number (8xh)
+;		ES:BX:	Pointer to buffer recieving data
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h/40h floppy return status
+;		AL:		Burst error length if AH=11h, undefined otherwise
+;		CF:		0 if successfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH2h_HandlerForReadDiskSectors:
+	test	al, al						; Invalid sector count?
+	jz		SHORT AH2h_ZeroCntErr		;  If so, return with error
+
+	; Save registers
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	; Select sector or block mode command
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		ah, HCMD_READ_SECT			; Load sector mode command
+	cmp		BYTE [di+DPT.bSetBlock], 1	; Block mode enabled?
+	jbe		SHORT .XferData				;  If not, jump to transfer
+	mov		ah, HCMD_READ_MUL			; Load block mode command
+
+	; Transfer data
+ALIGN JUMP_ALIGN
+.XferData:
+	call	HCommand_OutputCountAndLCHSandCommand
+	jc		SHORT .Return				; Return if error
+	call	HPIO_ReadBlock				; Read data from IDE-controller
+.Return:
+	jmp		Int13h_PopXRegsAndReturn
+
+; Invalid sector count (also for AH=3h and AH=4h)
+AH2h_ZeroCntErr:
+	mov		ah, RET_HD_INVALID			; Invalid value passed
+	stc									; Set CF since error
+	jmp		Int13h_PopDiDsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH3h_HWrite.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 37)
@@ -0,0 +1,58 @@
+; File name		:	AH3h_HWrite.asm
+; Project name	:	IDE BIOS
+; Created date	:	13.10.2007
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=3h, Write Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=3h, Write Disk Sectors.
+;
+; AH3h_HandlerForWriteDiskSectors
+;	Parameters:
+;		AH:		Bios function 3h
+;		AL:		Number of sectors to write
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number (8xh)
+;		ES:BX:	Pointer to source data
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH3h_HandlerForWriteDiskSectors:
+	test	al, al						; Invalid sector count?
+	jz		SHORT AH2h_ZeroCntErr		;  If so, return with error
+
+	; Save registers
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	; Select sector or block mode command
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		ah, HCMD_WRITE_SECT			; Load sector mode command
+	cmp		BYTE [di+DPT.bSetBlock], 1	; Block mode enabled?
+	jbe		SHORT .XferData				;  If not, jump to transfer
+	mov		ah, HCMD_WRITE_MUL			; Load block mode command
+
+	; Transfer data
+ALIGN JUMP_ALIGN
+.XferData:
+	call	HCommand_OutputCountAndLCHSandCommand
+	jc		SHORT .Return				; Return if error
+	call	HPIO_WriteBlock				; Write data to IDE-controller
+.Return:
+	jmp		Int13h_PopXRegsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH4h_HVerify.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 37)
@@ -0,0 +1,73 @@
+; File name		:	AH4h_HVerify.asm
+; Project name	:	IDE BIOS
+; Created date	:	13.10.2007
+; Last update	:	13.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=4h, Verify Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=4h, Verify Disk Sectors.
+;
+; AH4h_HandlerForVerifyDiskSectors
+;	Parameters:
+;		AH:		Bios function 4h
+;		AL:		Number of sectors to verify
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number
+;		ES:BX:	Pointer to source data (not used)
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH4h_HandlerForVerifyDiskSectors:
+	test	al, al						; Invalid sector count?
+	jz		SHORT AH2h_ZeroCntErr		;  If so, return with error
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	call	AH4h_VerifySectors
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Verifies hard disk sectors.
+;
+; AH4h_VerifySectors
+;	Parameters:
+;		AL:		Number of sectors to verify
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH4h_VerifySectors:
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		ah, HCMD_VERIFY_SECT		; Load command to AH
+	call	HCommand_OutputCountAndLCHSandCommand
+	jc		SHORT .Return				; Return if error
+	mov		bx, di						; DS:BX now points to DPT
+	jmp		HStatus_WaitIrqOrRdy		; Wait for IRQ or RDY
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH5h_HFormat.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH5h_HFormat.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH5h_HFormat.asm	(revision 37)
@@ -0,0 +1,44 @@
+; File name		:	AH5h_HFormat.asm
+; Project name	:	IDE BIOS
+; Created date	:	2.11.2007
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=5h, Format Disk Track.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=5h, Format Disk Track.
+;
+; AH5h_HandlerForFormatDiskTrack
+;	Parameters:
+;		AH:		Bios function 5h
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number
+;		ES:BX:	Pointer to address table
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH5h_HandlerForFormatDiskTrack:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	; Format command is vendor specific on IDE drives.
+	; Let's do verify instead.
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		al, [di+DPT.bPSect]			; Load Sectors per Track to AL
+	call	AH4h_VerifySectors
+	jmp		Int13h_PopXRegsAndReturn
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH8h_HParams.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH8h_HParams.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH8h_HParams.asm	(revision 37)
@@ -0,0 +1,127 @@
+; File name		:	AH8h_HParams.asm
+; Project name	:	IDE BIOS
+; Created date	:	27.9.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=8h, Read Disk Drive Parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=8h, Read Disk Drive Parameters.
+;
+; AH8h_HandlerForReadDiskDriveParameters
+;	Parameters:
+;		AH:		Bios function 8h
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...255)
+;		DL:		Number of drives
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH8h_HandlerForReadDiskDriveParameters:
+	call	RamVars_IsDriveHandledByThisBIOS
+	jnc		SHORT .GetDriveParametersForForeignHardDiskInDL
+
+	push	bx
+	call	AH8h_GetDriveParameters
+	pop		bx
+	jmp		Int13h_ReturnWithValueInDL
+
+ALIGN JUMP_ALIGN
+.GetDriveParametersForForeignHardDiskInDL:
+	call	Int13h_CallPreviousInt13hHandler
+	call	RamVars_GetCountOfKnownDrivesToDL
+	jmp		Int13h_ReturnWithValueInDL
+
+
+;--------------------------------------------------------------------
+; Returns L-CHS parameters for drive and total hard disk count.
+;
+; AH8h_GetDriveParameters
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...255)
+;		DL:		Number of drives
+;		DS:DI:	Ptr to DPT
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successfull, 1 if error
+;	Corrupts registers:
+;		AL, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH8h_GetDriveParameters:
+	call	FindDPT_ForDriveNumber
+	call	AccessDPT_GetLCHSfromPCHS	; AX=sectors, BX=cylinders, DX=heads
+	call	AH8h_ReserveCylinders
+	call	AH8h_PackReturnValues
+	xor		ax, ax						; Clear AH and CF
+	ret
+
+
+;--------------------------------------------------------------------
+; Reserves diagnostic cylinder if so configured.
+;
+; AH8h_ReserveCylinders
+;	Parameters:
+;		BX:		Total number of L-CHS cylinders available
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		BX:		Number of L-CHS cylinders available after reserving
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH8h_ReserveCylinders:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_MAXSIZE
+	jnz		SHORT .Return
+	dec		bx							; Reserve diagnostic cylinder
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Packs L-CHS values to INT 13h, AH=08h return values.
+;
+; AH8h_PackReturnValues
+;	Parameters:
+;		AX:		Number of L-CHS sectors per track (1...63)
+;		BX:		Number of L-CHS cylinders available (1...1024)
+;		DX:		Number of L-CHS heads (1...256)
+;		DS:		RAMVARS segment
+;	Returns:
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...255)
+;		DL:		Number of drives
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH8h_PackReturnValues:
+	dec		bx						; Cylinder count to last cylinder
+	dec		dx						; Head count to max head number
+	mov		dh, dl					; Max head number to DH
+	mov		ch, bl					; Cylinder bits 7...0 to CH
+	mov		cl, bh					; Cylinder bits 9...8 to CL
+	eROR_IM	cl, 2					; Cylinder bits 9...8 to CL bits 7...6
+	or		cl, al					; Sectors per track to CL bits 5...0
+	jmp		RamVars_GetCountOfKnownDrivesToDL
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH9h_HInit.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH9h_HInit.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AH9h_HInit.asm	(revision 37)
@@ -0,0 +1,150 @@
+; File name		:	AH9h_HInit.asm
+; Project name	:	IDE BIOS
+; Created date	:	9.12.2007
+; Last update	:	1.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=9h, Initialize Drive Parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=9h, Initialize Drive Parameters.
+;
+; AH9h_HandlerForInitializeDriveParameters
+;	Parameters:
+;		AH:		Bios function 9h
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH9h_HandlerForInitializeDriveParameters:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	call	AH9h_InitializeDriveForUse
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Initialized drive to be ready for use.
+;
+; AH9h_InitializeDriveForUse
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		AL, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH9h_InitializeDriveForUse:
+	push	dx
+	push	cx
+
+	; Try to select drive and wait until ready
+	call	FindDPT_ForDriveNumber
+	or		BYTE [di+DPT.bReset], MASK_RESET_ALL		; Everything uninitialized
+	call	HDrvSel_SelectDriveAndDisableIRQ
+	jc		SHORT .ReturnNotSuccessfull
+	and		BYTE [di+DPT.bReset], ~FLG_RESET_nDRDY		; Clear since success
+
+	; Initialize CHS parameters if LBA is not used
+	call	AH9h_InitializeDeviceParameters
+	jc		SHORT .RecalibrateDrive
+	and		BYTE [di+DPT.bReset], ~FLG_RESET_nINITPRMS
+
+	; Recalibrate drive by seeking to cylinder 0
+ALIGN JUMP_ALIGN
+.RecalibrateDrive:
+	call	AH11h_RecalibrateDrive
+	mov		dl, [di+DPT.bDrvNum]		; Restore DL
+	jc		SHORT .InitializeBlockMode
+	and		BYTE [di+DPT.bReset], ~FLG_RESET_nRECALIBRATE
+
+	; Initialize block mode transfers
+ALIGN JUMP_ALIGN
+.InitializeBlockMode:
+	call	AH9h_InitializeBlockMode
+	;mov		dl, [di+DPT.bDrvNum]		; Restore DL
+	jc		SHORT .ReturnNotSuccessfull
+	and		BYTE [di+DPT.bReset], ~FLG_RESET_nSETBLOCK
+
+.ReturnNotSuccessfull:
+	pop		cx
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Sends Initialize Device Parameters command to IDE Hard Disk.
+; Initialization is used to initialize logical CHS parameters. Drives
+; may not support all CHS values.
+; This command is only supported by drives that supports CHS addressing.
+;
+; AH9h_InitializeDeviceParameters
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Cleared if succesfull
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH9h_InitializeDeviceParameters:
+	; No need to initialize CHS parameters if LBA mode enabled
+	test	BYTE [di+DPT.bDrvSel], FLG_IDE_DRVHD_LBA	; Clears CF
+	jnz		SHORT .Return
+
+	push	dx
+	mov		bh, [di+DPT.bPHeads]
+	dec		bh						; Max head number
+	mov		dx, [RAMVARS.wIdeBase]
+	call	HCommand_OutputTranslatedLCHSaddress
+	mov		ah, HCMD_INIT_DEV
+	mov		al, [di+DPT.bPSect]		; Sectors per track
+	call	HCommand_OutputSectorCountAndCommand
+	call	HStatus_WaitBsyDefTime	; Wait until drive ready (DRDY won't be set!)
+	pop		dx
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Initializes block mode transfers.
+;
+; AH9h_InitializeBlockMode
+;	Parameters:
+;		DL:		Drive number
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Cleared if succesfull
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH9h_InitializeBlockMode:
+	mov		ax, FLG_DRVPARAMS_BLOCKMODE
+	call	AccessDPT_TestIdeVarsFlagsForMasterOrSlaveDrive
+	jz		SHORT .Return				; Block mode disabled (CF cleared)
+	eMOVZX	ax, BYTE [di+DPT.bMaxBlock]	; Load max block size, zero AH
+	test	al, al						; Block mode supported? (clears CF)
+	jz		SHORT .Return				;  If not, return
+	jmp		AH24h_SetBlockSize
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHCh_HSeek.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHCh_HSeek.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHCh_HSeek.asm	(revision 37)
@@ -0,0 +1,68 @@
+; File name		:	AHCh_HSeek.asm
+; Project name	:	IDE BIOS
+; Created date	:	13.12.2007
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=Ch, Seek.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=Ch, Seek.
+;
+; AHCh_HandlerForSeek
+;	Parameters:
+;		AH:		Bios function Ch
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive number
+;	Parameters loaded by Int13h_Jump:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHCh_HandlerForSeek:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+	call	AHCh_SeekToCylinder
+	jmp		Int13h_PopXRegsAndReturn
+
+
+;--------------------------------------------------------------------
+; Seeks to a cylinder.
+;
+; AHCh_SeekToCylinder
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DL:		Drive Number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		AH:		BIOS Error code
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHCh_SeekToCylinder:
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	mov		ax, HCMD_SEEK<<8			; Load cmd to AH, AL=zero sector cnt
+	call	HCommand_OutputCountAndLCHSandCommand
+	jc		SHORT .Return				; Return if error
+	mov		bx, di						; DS:BX now points to DPT
+	jmp		HStatus_WaitIrqOrRdy		; Wait for IRQ or RDY
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHDh_HReset.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHDh_HReset.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/AHDh_HReset.asm	(revision 37)
@@ -0,0 +1,141 @@
+; File name		:	AHDh_HReset.asm
+; Project name	:	IDE BIOS
+; Created date	:	9.12.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 13h function AH=Dh, Reset Hard Disk (Alternate reset).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=Dh, Reset Hard Disk (Alternate reset).
+;
+; AHDh_HandlerForResetHardDisk
+;	Parameters:
+;		AH:		Bios function Dh
+;		DL:		Drive number
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;		IF:		1
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHDh_HandlerForResetHardDisk:
+	call	AHDh_ResetDrive
+	jmp		Int13h_PopDiDsAndReturn
+
+
+;--------------------------------------------------------------------
+; Resets hard disk.
+;
+; AHDh_ResetDrive
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if succesfull, 1 if error
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHDh_ResetDrive:
+	push	dx
+	push	cx
+	push	bx
+	push	ax
+
+	call	FindDPT_ForDriveNumber		; DS:DI now points to DPT
+	call	Interrupts_UnmaskInterruptControllerForDriveInDSDI
+	call	AHDh_ResetMasterAndSlave
+	;jc		SHORT .ReturnError			; CF would be set if slave drive present without master
+										; (error register has special values after reset)
+
+	; Initialize Master and Slave drives
+	mov		dx, [RAMVARS.wIdeBase]		; Load base port address
+	call	AHDh_InitializeMasterAndSlave
+
+	pop		bx							; Pop old AX
+	mov		al, bl						; Restore AL
+	pop		bx
+	pop		cx
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Resets Master and Slave drives at wanted port.
+; Both IDE drives will be reset. It is not possible to reset
+; Master or Slave only.
+;
+; AHDh_ResetMasterAndSlave
+;	Parameters:
+;		DS:DI:	Ptr to DPT for Master or Slave drive
+;	Returns:
+;		CF:		0 if reset succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHDh_ResetMasterAndSlave:
+	; Reset controller
+	; HSR0: Set_SRST
+	mov		al, [di+DPT.bDrvCtrl]		; Load value for ACR
+	or		al, FLG_IDE_CTRL_SRST		; Set Reset bit
+	call	HDrvSel_OutputDeviceControlByte
+	mov		cx, 5						; Delay at least 5us
+	call	SoftDelay_us
+
+	; HSR1: Clear_wait
+	and		al, ~FLG_IDE_CTRL_SRST		; Clear Reset bit
+	out		dx, al						; End Reset
+	mov		cx, 2000					; Delay at least 2ms
+	call	SoftDelay_us
+
+	; HSR2: Check_status
+	mov		cl, B_TIMEOUT_RESET			; Reset timeout delay
+	mov		dx, [RAMVARS.wIdeBase]		; Load base port address
+	jmp		HStatus_WaitBsyBase
+
+
+;--------------------------------------------------------------------
+; Initializes Master and Slave drive.
+;
+; AHDh_InitializeMasterAndSlave
+;	Parameters:
+;		DX:		IDE Base Port address
+;	Returns:
+;		AH:		Error code
+;		CF:		0 if initialization succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHDh_InitializeMasterAndSlave:
+	push	dx							; Store base port address
+	xor		cx, cx						; Assume no errors
+	call	FindDPT_ForIdeMasterAtPort
+	jnc		SHORT .InitializeSlave		; Master drive not present
+	call	AH9h_InitializeDriveForUse
+	mov		cl, ah						; Copy error code to CL
+ALIGN JUMP_ALIGN
+.InitializeSlave:
+	pop		dx							; Restore base port address
+	call	FindDPT_ForIdeSlaveAtPort
+	jnc		SHORT .CombineErrors		; Slave drive not present
+	call	AH9h_InitializeDriveForUse
+	mov		ch, ah						; Copy error code to CH
+ALIGN JUMP_ALIGN
+.CombineErrors:
+	or		cl, ch						; OR error codes, clear CF
+	jnz		SHORT .ReturnError
+	ret
+.ReturnError:
+	mov		ah, RET_HD_RESETFAIL		; Load Reset Failed error code
+	stc
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HAddress.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HAddress.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HAddress.asm	(revision 37)
@@ -0,0 +1,178 @@
+; File name		:	HAddress.asm
+; Project name	:	IDE BIOS
+; Created date	:	11.3.2010
+; Last update	:	4.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for address translations.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Outputs sector count, L-CHS address and command to IDE registers.
+; This function does not wait until command has been completed.
+;
+; HAddress_ConvertParamsFromBiosLCHStoIDE
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		BL:		LBA Low Register / Sector Number Register (LBA 7...0)
+;		CL:		LBA Mid Register / Low Cylinder Register (LBA 15...8)
+;		CH:		LBA High Register / High Cylinder Register (LBA 23...16)
+;		BH:		Drive and Head Register (LBA 27...24)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN WORD_ALIGN
+g_rgfnAddressTranslation:
+	dw		HAddress_DoNotConvertLCHS					; 0, ADDR_DPT_LCHS
+	dw		HAddress_ConvertLCHStoPCHS					; 1, ADDR_DPT_PCHS
+	dw		HAddress_ConvertLCHStoLBARegisterValues		; 2, ADDR_DPT_LBA28
+	dw		HAddress_ConvertLCHStoLBARegisterValues		; 3, ADDR_DPT_LBA48
+
+ALIGN JUMP_ALIGN
+HAddress_ConvertParamsFromBiosLCHStoIDE:
+	mov		bl, [di+DPT.bFlags]
+	and		bx, BYTE MASK_DPT_ADDR						; Addressing mode to BX
+	push	WORD [cs:bx+g_rgfnAddressTranslation]		; Push return address
+	; Fall to HAddress_ExtractLCHSFromBiosParams
+
+;---------------------------------------------------------------------
+; Extracts L-CHS parameters from BIOS function parameters.
+;
+; HAddress_ExtractLCHSFromBiosParams:
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Sector number
+;		DH:		Head number
+;	Returns:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HAddress_ExtractLCHSFromBiosParams:
+	mov		bl, cl				; Copy sector number...
+	and		bl, 3Fh				; ...and limit to 1...63
+	sub		cl, bl				; Remove from cylinder number high
+	eROL_IM	cl, 2				; High bits to beginning
+	mov		bh, dh				; Copy Head number
+	xchg	cl, ch				; Cylinder number now in CX
+	ret
+
+
+;---------------------------------------------------------------------
+; Converts BIOS LCHS parameters to IDE P-CHS parameters.
+; PCylinder	= (LCylinder << n) + (LHead / PHeadCount)
+; PHead		= LHead % PHeadCount
+; PSector	= LSector
+;
+; HAddress_ConvertLCHStoPCHS:
+;	Parameters:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...15)
+;		CX:		Cylinder number (0...16382)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HAddress_ConvertLCHStoPCHS:
+	; LHead / PHeadCount and LHead % PHeadCount
+	eMOVZX	ax, bh					; Copy L-CHS Head number to AX
+	div		BYTE [di+DPT.bPHeads]	; AL = LHead / PHeadCount, AH = LHead % PHeadCount
+	mov		bh, ah					; Copy P-CHS Head number to BH
+	xor		ah, ah					; AX = LHead / PHeadCount
+
+	; (LCylinder << n) + (LHead / PHeadCount)
+	mov		dx, cx					; Copy L-CHS Cylinder number to DX
+	mov		cl, [di+DPT.bShLtoP]	; Load shift count
+	shl		dx, cl					; DX = LCylinder << n
+	add		ax, dx					; AX = P-CHS Cylinder number
+	mov		cx, ax					; Copy P-CHS Cylinder number to CX
+ALIGN JUMP_ALIGN
+HAddress_DoNotConvertLCHS:
+	ret
+
+
+;---------------------------------------------------------------------
+; Converts LCHS parameters to 28-bit LBA address.
+; Returned address is in same registers that
+; HAddress_DoNotConvertLCHS and HAddress_ConvertLCHStoPCHS returns.
+;
+; HAddress_ConvertLCHStoLBARegisterValues:
+;	Parameters:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		BL:		LBA Low Register / Sector Number Register (LBA 7...0)
+;		CL:		LBA Mid Register / Low Cylinder Register (LBA 15...8)
+;		CH:		LBA High Register / High Cylinder Register (LBA 23...16)
+;		BH:		Drive and Head Register (LBA 27...24)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HAddress_ConvertLCHStoLBARegisterValues:
+	call	HAddress_ConvertLCHStoLBA28
+	mov		bl, al					; Sector Number Register (LBA 7...0)
+	mov		cl, ah					; Low Cylinder Register (LBA 15...8)
+	mov		ch, dl					; High Cylinder Register (LBA 23...16)
+	mov		bh, dh					; Drive and Head Register (LBA 27...24)
+	ret
+
+;---------------------------------------------------------------------
+; Converts LCHS parameters to 28-bit LBA address.
+; Only 24-bits are used since LHCS to LBA28 conversion has 8.4GB limit.
+; LBA = ((cylToSeek*headsPerCyl+headToSeek)*sectPerTrack)+sectToSeek-1
+;
+; HAddress_ConvertLCHStoLBA28:
+;	Parameters:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		DX:AX:	28-bit LBA address (DH is always zero)
+;	Corrupts registers:
+;		BX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HAddress_ConvertLCHStoLBA28:
+	; cylToSeek*headsPerCyl (18-bit result)
+	mov		ax, cx					; Copy Cylinder number to AX
+	mul		WORD [di+DPT.wLHeads]	; DX:AX = cylToSeek*headsPerCyl
+
+	; +=headToSeek (18-bit result)
+	add		al, bh					; Add Head number to DX:AX
+	adc		ah, dh					; DH = Zero after previous multiplication
+	adc		dl, dh
+
+	; *=sectPerTrack (18-bit by 6-bit multiplication with 24-bit result)
+	eMOVZX	cx, BYTE [di+DPT.bPSect]; Load Sectors per Track
+	xchg	ax, dx					; Hiword to AX, loword to DX
+	mul		cl						; AX = hiword * Sectors per Track
+	mov		bh, al					; Backup hiword * Sectors per Track
+	xchg	ax, dx					; Loword back to AX
+	mul		cx						; DX:AX = loword * Sectors per Track
+	add		dl, bh					; DX:AX = (cylToSeek*headsPerCyl+headToSeek)*sectPerTrack
+
+	; +=sectToSeek-1 (24-bit result)
+	xor		bh, bh					; Sector number now in BX
+	dec		bx						; sectToSeek-=1
+	add		ax, bx					; Add to loword
+	adc		dl, bh					; Add possible carry to byte2, BH=zero
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCapacity.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCapacity.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCapacity.asm	(revision 37)
@@ -0,0 +1,167 @@
+; File name		:	HCapacity.asm
+; Project name	:	IDE BIOS
+; Created date	:	16.3.2010
+; Last update	:	3.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for hard disk capacity calculations.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Calculates sector count from L-CHS values returned by INT 13h, AH=08h.
+;
+; HCapacity_GetSectorCountFromForeignAH08h:
+; HCapacity_GetSectorCountFromOurAH08h:
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DX:AX:	Total sector count
+;		BX:		Zero
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCapacity_GetSectorCountFromForeignAH08h:
+	mov		ah, 08h			; Get Drive Parameters
+	call	Int13h_CallPreviousInt13hHandler
+	jmp		SHORT HCapacity_ConvertAH08hReturnValuesToSectorCount
+
+ALIGN JUMP_ALIGN
+HCapacity_GetSectorCountFromOurAH08h:
+	push	di
+	call	AH8h_GetDriveParameters
+	pop		di
+	; Fall to HCapacity_ConvertAH08hReturnValuesToSectorCount
+
+ALIGN JUMP_ALIGN
+HCapacity_ConvertAH08hReturnValuesToSectorCount:
+	call	HAddress_ExtractLCHSFromBiosParams
+	xor		ax, ax			; Zero AX
+	inc		cx				; Max cylinder number to cylinder count
+	xchg	al, bh			; AX=Max head number, BX=Sectors per track
+	inc		ax				; AX=Head count
+	mul		bx				; AX=Head count * Sectors per track
+	mul		cx				; DX:AX = Total sector count
+	xor		bx, bx			; Zero BX for 48-bit sector count
+	ret
+
+
+;--------------------------------------------------------------------
+; Converts sector count to hard disk size.
+;
+; HCapacity_ConvertSectorCountToSize:
+;	Parameters:
+;		BX:DX:AX:	Total sector count
+;	Returns:
+;		AX:			Size in magnitude
+;		SI:			Tenths
+;		CX:			Magnitude character:
+;						'k' = *1024   B = kiB
+;						'M' = *1024 kiB = MiB
+;						'G' = *1024 MiB = GiB
+;						'T' = *1024 GiB = TiB
+;						'P' = *1024 TiB = PiB
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCapacity_ConvertSectorCountToSize:
+	call	HCapacity_ConvertSectorCountToKiB
+	mov		cx, 1					; Magnitude is 1 for kiB
+ALIGN JUMP_ALIGN
+.MagnitudeLoop:
+	test	bx, bx					; Bits 32...47 in use?
+	jnz		SHORT .ShiftByMagnitude	;  If so, jump to shift
+	test	dx, dx					; Bits 16...31 in use?
+	jnz		SHORT .ShiftByMagnitude	;  If so, jump to shift
+	cmp		ax, 10000				; 5 digits needed?
+	jb		SHORT .ShiftComplete	;  If less, all done
+ALIGN JUMP_ALIGN
+.ShiftByMagnitude:
+	call	HCapacity_ShiftForNextMagnitude
+	jmp		SHORT .MagnitudeLoop
+ALIGN JUMP_ALIGN
+.ShiftComplete:
+	mov		bx, cx					; Copy shift count to BX
+	mov		cl, [cs:bx+.rgbMagnitudeToChar]
+	jmp		SHORT HCapacity_ConvertSizeRemainderToTenths
+ALIGN WORD_ALIGN
+.rgbMagnitudeToChar:	db	" kMGTP"
+
+;--------------------------------------------------------------------
+; Converts 48-bit sector count to size in kiB.
+;
+; HCapacity_ConvertSectorCountToKiB:
+;	Parameters:
+;		BX:DX:AX:	Total sector count
+;	Returns:
+;		BX:DX:AX:	Total size in kiB
+;		CF:			Remainder from division
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCapacity_ConvertSectorCountToKiB:
+HCapacity_DivideSizeByTwo:
+	shr		bx, 1					; Divide sector count by 2...
+	rcr		dx, 1					; ...to get disk size in...
+	rcr		ax, 1					; ...kiB
+	ret
+
+;--------------------------------------------------------------------
+; Divides size by 1024 and increments magnitude.
+;
+; HCapacity_ShiftForNextMagnitude:
+;	Parameters:
+;		BX:DX:AX:	Size in magnitude
+;		CX:			Magnitude (0=B, 1=kiB, 2=MiB...)
+;	Returns:
+;		BX:DX:AX:	Size in magnitude
+;		SI:			Remainder (0...1023)
+;		CX:			Magnitude (1=kiB, 2=MiB...)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCapacity_ShiftForNextMagnitude:
+	push	cx
+	xor		si, si					; Zero remainder
+	mov		cl, 10					; Divide by 1024
+ALIGN JUMP_ALIGN
+.ShiftLoop:
+	call	HCapacity_DivideSizeByTwo
+	rcr		si, 1					; Update remainder
+	loop	.ShiftLoop
+	eSHR_IM	si, 6					; Remainder to SI beginning
+	pop		cx
+	inc		cx						; Increment shift count
+	ret
+
+;--------------------------------------------------------------------
+; Converts remainder from HCapacity_ShiftForNextMagnitude to tenths.
+;
+; HCapacity_ConvertSizeRemainderToTenths:
+;	Parameters:
+;		BX:DX:AX:	Size in magnitude
+;		SI:			Remainder from last magnitude division (0...1023)
+;	Returns:
+;		BX:DX:AX:	Size in magnitude
+;		SI:			Tenths
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCapacity_ConvertSizeRemainderToTenths:
+	push	dx
+	push	ax
+
+	mov		ax, 10
+	mul		si					; DX:AX = remainder * 10
+	eSHR_IM	ax, 10				; Divide AX by 1024
+	xchg	si, ax				; SI = tenths
+
+	pop		ax
+	pop		dx
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCommand.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCommand.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HCommand.asm	(revision 37)
@@ -0,0 +1,115 @@
+; File name		:	HCommand.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.3.2010
+; Last update	:	16.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for outputting IDE commands and parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Outputs sector count, L-CHS address and command to IDE registers.
+; This function does not wait until command has been completed.
+;
+; HCommand_OutputCountAndLCHSandCommand
+;	Parameters:
+;		AH:		Seek or data transfer command
+;		AL:		Sector count (1...255, 0=256)
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code (if error)
+;		CF:		0 if succesfull
+;				1 if any error
+;	Corrupts registers:
+;		CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCommand_OutputCountAndLCHSandCommand:
+	push	bx
+	push	ax										; Store sector count and command
+	call	HDrvSel_SelectDriveForDataTransfer
+	jc		SHORT .ReturnError
+	call	HIRQ_ClearTaskFlag
+	call	HAddress_ConvertParamsFromBiosLCHStoIDE
+	mov		dx, [RAMVARS.wIdeBase]					; Load IDE Base Port address
+	call	HCommand_OutputTranslatedLCHSaddress	; DX to Sector count register
+	pop		ax										; Restore sector count and command
+	call	HCommand_OutputSectorCountAndCommand
+
+	clc												; Clear CF since success
+	pop		bx
+	ret
+.ReturnError:
+	pop		bx										; Discard pushed AX
+	pop		bx
+	ret
+
+
+;--------------------------------------------------------------------
+; Outputs L-CHS address that has been translated P-CHS or LBA28
+; when necessary.
+;
+; HCommand_OutputTranslatedLCHSaddress
+;	Parameters:
+;		BL:		LBA Low Register / Sector Number Register (LBA 7...0)
+;		CL:		LBA Mid Register / Low Cylinder Register (LBA 15...8)
+;		CH:		LBA High Register / High Cylinder Register (LBA 23...16)
+;		BH:		Drive and Head Register (LBA 27...24)
+;		DX:		IDE Base Port address
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		DX:		IDE Sector Count Register address
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HCommand_OutputTranslatedLCHSaddress:
+	add		dx, BYTE REG_IDE_LBA_LOW
+	mov		al, bl
+	out		dx, al						; Output LBA 7...0
+
+	; Some (VLB) controllers fail to accept WORD write to cylinder
+	; registers so we must output two bytes instead.
+	inc		dx							; REG_IDE_LBA_MID
+	mov		al, cl
+	out		dx, al						; Output LBA 8...15
+
+	inc		dx							; REG_IDE_LBA_HIGH
+	mov		al, ch
+	out		dx, al						; Output LBA 16...23
+
+	inc		dx							; REG_IDE_DRVHD
+	mov		al, [di+DPT.bDrvSel]		; Load other bits for Drive and Head Register
+	or		al, bh
+	out		dx, al						; Output LBA 27...24
+
+	sub		dx, BYTE REG_IDE_DRVHD-REG_IDE_CNT
+	ret
+
+
+;--------------------------------------------------------------------
+; Outputs sector count and seek or data transfer command.
+;
+; HCommand_OutputSectorCountAndCommand
+;	Parameters:
+;		AH:		Seek or data transfer command
+;		AL:		Sector count (1...255, 0=256)
+;		DX:		IDE Sector Count Register address
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AH, DX
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+HCommand_OutputSectorCountAndCommand:
+	out		dx, al						; Output sector count
+	add		dx, BYTE REGW_IDE_CMD-REG_IDE_CNT
+	xchg	al, ah						; AL=Command, AH=Sector count
+	out		dx, al
+	mov		al, ah						; Restore sector count to AL
+	jmp		SoftDelay_BeforePollingStatusRegister
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HDrvSel.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HDrvSel.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HDrvSel.asm	(revision 37)
@@ -0,0 +1,112 @@
+; File name		:	HDrvSel.asm
+; Project name	:	IDE BIOS
+; Created date	:	25.2.2010
+; Last update	:	13.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for selecting Master or Slave drive.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Selects Master or Slave drive for transferring data.
+; This means that interrupts will be enabled if so configured in
+; IDEVARS. This function returns after drive is ready to accept commands.
+;
+; HDrvSel_SelectDriveForDataTransfer
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if drive selected successfully
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HDrvSel_SelectDriveForDataTransfer:
+	mov		al, [di+DPT.bDrvCtrl]			; Load Device Control Byte
+	; Fall to HDrvSel_SelectDriveAndSetControlByte
+
+;--------------------------------------------------------------------
+; Selects Master or Slave drive.
+; Device Control Byte can be used to enable or disable interrupts.
+; This function returns only after drive is ready to accept commands.
+;
+; HDrvSel_SelectDriveAndSetControlByte
+;	Parameters:
+;		AL:		Device Control Byte (to enable/disable interrupts)
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if drive selected successfully
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+HDrvSel_SelectDriveAndSetControlByte:
+	push	dx
+	push	cx
+
+	; Output Device Control Register to enable/disable interrupts
+	call	HDrvSel_OutputDeviceControlByte
+
+	; Select Master or Slave drive
+	mov		dx, [RAMVARS.wIdeBase]
+	add		dx, BYTE REG_IDE_DRVHD
+	mov		al, [di+DPT.bDrvSel]			; Load Master/Slave selection byte
+	out		dx, al							; Select drive
+
+	; Wait until drive is ready to accept commands
+	call	SoftDelay_BeforePollingStatusRegister
+	call	HStatus_WaitRdyDefTime
+	pop		cx
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Outputs Device Control Byte to Device Control Register.
+;
+; HDrvSel_OutputDeviceControlByte
+;	Parameters:
+;		AL:		Device Control Byte
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		DX:		Device Control Register address
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HDrvSel_OutputDeviceControlByte:
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]		; CS:BX now points to IDEVARS
+	mov		dx, [cs:bx+IDEVARS.wPortCtrl]	; Load Control Block base address
+	add		dx, BYTE REGW_IDEC_CTRL			; Add offset to Device Control Register
+	out		dx, al							; Output Device Control byte
+	ret
+
+
+;--------------------------------------------------------------------
+; Selects Master or Slave drive and disables interrupts. Interrupts should
+; be disabled for commands that do not transfer data.
+; This function returns after drive is ready to accept commands.
+;
+; HDrvSel_SelectDriveAndDisableIRQ
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if drive selected successfully
+;				1 if any error
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HDrvSel_SelectDriveAndDisableIRQ:
+	push	bx
+	mov		al, [di+DPT.bDrvCtrl]	; Load Device Control Byte
+	or		al, FLG_IDE_CTRL_nIEN	; Disable interrupts
+	call	HDrvSel_SelectDriveAndSetControlByte
+	pop		bx
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HError.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HError.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HError.asm	(revision 37)
@@ -0,0 +1,131 @@
+; File name		:	HError.asm
+; Project name	:	IDE BIOS
+; Created date	:	30.11.2007
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Error checking functions for BIOS Hard disk functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; HError_ProcessTimeoutAfterPollingBSYandSomeOtherStatusBit
+; HError_ProcessErrorsAfterPollingBSY
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AH:		BIOS error code
+;		CF:		Set if error
+;				Cleared if no error
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HError_ProcessTimeoutAfterPollingBSYandSomeOtherStatusBit:
+	call	HError_GetStatusAndErrorRegistersToAXandStoreThemToBDA
+	call	GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX
+	jc		SHORT .ReturnErrorCodeInAH
+	mov		ah, RET_HD_TIMEOUT			; Force timeout since no actual error...
+	stc									; ...but wanted bit was never set
+.ReturnErrorCodeInAH:
+	ret
+
+
+ALIGN JUMP_ALIGN
+HError_ProcessErrorsAfterPollingBSY:
+	call	HError_GetStatusAndErrorRegistersToAXandStoreThemToBDA
+	jmp		SHORT GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX
+
+
+;--------------------------------------------------------------------
+; HError_GetStatusAndErrorRegistersToAXandStoreThemToBDA
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AL:		IDE Status Register contents
+;		AH:		IDE Error Register contents
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HError_GetStatusAndErrorRegistersToAXandStoreThemToBDA:
+	push	ds
+	push	dx
+
+	mov		dx, [RAMVARS.wIdeBase]		; Load IDE base port address
+	inc		dx							; Increment to Error Register
+	in		al, dx						; Read Error Register...
+	mov		ah, al						; ...and copy it to AH
+	add		dx, BYTE REGR_IDE_ST - REGR_IDE_ERROR
+	in		al, dx						; Read Status Register to AL
+
+	LOAD_BDA_SEGMENT_TO	ds, dx
+	mov		[HDBDA.wHDStAndErr], ax
+
+	pop		dx
+	pop		ds
+	ret
+
+
+;--------------------------------------------------------------------
+; GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX
+;	Parameters:
+;		AL:		IDE Status Register contents
+;		AH:		IDE Error Register contents
+;	Returns:
+;		AH:		BIOS INT 13h error code
+;		CF:		Set if error
+;				Cleared if no error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX:
+	test	al, FLG_IDE_ST_BSY
+	jz		SHORT .CheckErrorBitsFromStatusRegisterInAL
+	mov		ah, RET_HD_TIMEOUT
+	jmp		SHORT .ReturnBiosErrorCodeInAH
+
+ALIGN JUMP_ALIGN
+.CheckErrorBitsFromStatusRegisterInAL:
+	test	al, FLG_IDE_ST_DF | FLG_IDE_ST_CORR | FLG_IDE_ST_ERR
+	jnz		SHORT .ProcessErrorFromStatusRegisterInAL
+	xor		ah, ah					; No errors, zero AH and CF
+	ret
+
+.ProcessErrorFromStatusRegisterInAL:
+	test	al, FLG_IDE_ST_ERR		; Error specified in Error register?
+	jnz		SHORT .ConvertBiosErrorToAHfromErrorRegisterInAH
+	mov		ah, RET_HD_ECC			; Assume ECC corrected error
+	test	al, FLG_IDE_ST_CORR		; ECC corrected error?
+	jnz		SHORT .ReturnBiosErrorCodeInAH
+	mov		ah, RET_HD_CONTROLLER	; Must be Device Fault
+	jmp		SHORT .ReturnBiosErrorCodeInAH
+
+.ConvertBiosErrorToAHfromErrorRegisterInAH:
+	push	bx
+	mov		bx, .rgbRetCodeLookup
+.ErrorBitLoop:
+	rcr		ah, 1					; Set CF if error bit set
+	jc		SHORT .LookupErrorCode
+	inc		bx
+	cmp		bx, .rgbRetCodeLookup + 8
+	jb		SHORT .ErrorBitLoop		; Loop until all bits checked
+.LookupErrorCode:
+	mov		ah, [cs:bx+.rgbRetCodeLookup]
+	pop		bx
+
+.ReturnBiosErrorCodeInAH:
+	stc								; Set CF since error
+	ret
+
+.rgbRetCodeLookup:
+	db	RET_HD_ADDRMARK		; Bit0=AMNF, Address Mark Not Found
+	db	RET_HD_SEEK_FAIL	; Bit1=TK0NF, Track 0 Not Found
+	db	RET_HD_INVALID		; Bit2=ABRT, Aborted Command
+	db	RET_HD_NOTLOCKED	; Bit3=MCR, Media Change Requested
+	db	RET_HD_NOT_FOUND	; Bit4=IDNF, ID Not Found
+	db	RET_HD_LOCKED		; Bit5=MC, Media Changed
+	db	RET_HD_UNCORRECC	; Bit6=UNC, Uncorrectable Data Error
+	db	RET_HD_BADSECTOR	; Bit7=BBK, Bad Block Detected
+	db	RET_HD_STATUSERR	; When Error Register is zero
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HIRQ.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HIRQ.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HIRQ.asm	(revision 37)
@@ -0,0 +1,146 @@
+; File name		:	HIRQ.asm
+; Project name	:	IDE BIOS
+; Created date	:	11.12.2009
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Interrupt handling related functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; HIRQ_WaitForIRQ
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set if wait done by operating system
+;				Cleared if BIOS must perform task flag polling
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HIRQ_WaitForIRQ:
+	test	BYTE [bx+DPT.bDrvCtrl], FLG_IDE_CTRL_nIEN	; Clears CF
+	jz		SHORT .NotifyOperatingSystemAboutWaitingForIRQ
+	ret		; Go to poll status register
+
+;--------------------------------------------------------------------
+; .NotifyOperatingSystemAboutWaitingForIRQ
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:		Set if wait done by operating system
+;				Cleared if BIOS must perform task flag polling
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.NotifyOperatingSystemAboutWaitingForIRQ:
+	push	ds
+
+	LOAD_BDA_SEGMENT_TO	ds, ax			; Zero AX
+	cli									; Disable interrupts
+	cmp		al, [ds:BDA.bHDTaskFlg]		; Task flag already set?
+	jc		SHORT .ReturnFromWaitNotify	;  If so, skip OS notification
+
+	mov		ah, 90h						; Hard disk busy (AX=9000h)
+	int		INTV_SYSTEM_SERVICES		; OS hook, device busy
+	jnc		SHORT .ReturnFromWaitNotify	; CF cleared, BIOS handles waiting
+
+	; Make sure that OS hooks are supported, otherwise the CF means unsupported function
+	test	ah, ah						; OS hook supported? (clears CF)
+	jnz		SHORT .ReturnFromWaitNotify	; AH has error, BIOS must do the wait
+	stc									; Set CF since wait done by OS
+.ReturnFromWaitNotify:
+	pop		ds
+	sti									; Enable interrupts
+	ret
+
+
+;--------------------------------------------------------------------
+; Clears task (interrupt) flag from BIOS Data Area.
+;
+; HIRQ_ClearTaskFlag
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HIRQ_ClearTaskFlag:
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, ax		; Also zero AX
+	mov		[BDA.bHDTaskFlg], al
+	pop		ds
+	ret
+
+
+;--------------------------------------------------------------------
+; IDE Interrupt Service Routines.
+;
+; HIRQ_InterruptServiceRoutineForIrqs2to7
+; HIRQ_InterruptServiceRoutineForIrqs8to15
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HIRQ_InterruptServiceRoutineForIrqs2to7:
+	push	ax
+	call	AcknowledgeIdeInterruptAndStoreStatusAndErrorRegistersToBDA
+
+	mov		al, CMD_END_OF_INTERRUPT
+	jmp		SHORT AcknowledgeMasterInterruptController
+
+
+ALIGN JUMP_ALIGN
+HIRQ_InterruptServiceRoutineForIrqs8to15:
+	push	ax
+	call	AcknowledgeIdeInterruptAndStoreStatusAndErrorRegistersToBDA
+
+	mov		al, CMD_END_OF_INTERRUPT	; Load EOI command to AL
+	out		WPORT_8259SL_COMMAND, al	; Acknowledge Slave 8259
+AcknowledgeMasterInterruptController:
+	out		WPORT_8259MA_COMMAND, al	; Acknowledge Master 8259
+
+	; Issue Int 15h, function AX=9100h (Interrupt ready)
+	mov		ax, 9100h					; Interrupt ready, device 0 (HD)
+	int		INTV_SYSTEM_SERVICES
+
+	pop		ax							; Restore AX
+	iret
+
+;--------------------------------------------------------------------
+; Acknowledges IDE interrupt by reading status register and
+; stores Status and Error Registers to BDA. Task flag in BDA will
+; also be set.
+;
+; AcknowledgeIdeInterruptAndStoreStatusAndErrorRegistersToBDA
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AcknowledgeIdeInterruptAndStoreStatusAndErrorRegistersToBDA:
+	push	ds
+	push	di
+
+	; Reading Status Register acknowledges IDE interrupt
+	call	RamVars_GetSegmentToDS
+	call	HError_GetStatusAndErrorRegistersToAXandStoreThemToBDA
+
+	; Set Task Flag
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	mov		BYTE [BDA.bHDTaskFlg], 0FFh		; Set task flag
+
+	pop		di
+	pop		ds
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HPIO.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HPIO.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HPIO.asm	(revision 37)
@@ -0,0 +1,324 @@
+; File name		:	HPIO.asm
+; Project name	:	IDE BIOS
+; Created date	:	14.12.2007
+; Last update	:	1.8.2010
+; Author		:	Tomi Tilli
+; Description	:	PIO transfer functions.
+
+; Structure containing variables for PIO transfer functions
+struc PIOVARS
+	.fnXfer			resb	2	; Offset to transfer function
+	.wBlockSize		resb	2	; Block size in WORDs
+	.wWordsLeft		resb	2	; Number of WORDs left to transfer
+								; (full sectors, can be partial block)
+endstruc
+
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Normalizes far pointer to that offset overflows won't happen
+; when transferring data using PIO.
+;
+; HPIO_NORMALIZE_PTR
+;	Parameters:
+;		%1:%2:		Far pointer to normalize
+;		%3:			Scratch register
+;		%4:			Scratch register
+;	Returns:
+;		%1:%2:		Normalized far pointer
+;	Corrupts registers:
+;		%3, %4
+;--------------------------------------------------------------------
+%macro HPIO_NORMALIZE_PTR 4
+	mov		%4, %2				; Copy offset to scratch reg
+	and		%2, BYTE 0Fh		; Clear offset bits 15...4
+	eSHR_IM	%4, 4				; Divide offset by 16
+	mov		%3, %1				; Copy segment to scratch reg
+	add		%3, %4				; Add shifted offset to segment
+	mov		%1, %3				; Set normalized segment
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Reads sectors from hard disk using PIO transfer mode.
+;
+; HPIO_ReadBlock
+;	Parameters:
+;		AL:		Number of sectors to read (1...255)
+;		ES:BX:	Pointer to buffer to recieve data
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if transfer succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_ReadBlock:
+	push	es
+
+	; Create PIOVARS to stack
+	eENTER	PIOVARS_size, 0
+	sub		bp, BYTE PIOVARS_size			; SS:BP now points to PIOVARS
+	push	si
+	mov		si, g_rgfnPioRead				; Offset to read function lookup
+	call	HPIO_InitializePIOVARS			; Store word count and block size
+	pop		si
+
+	; Start to read data
+	xchg	bx, di							; DS:BX points DPT, ES:DI points buffer
+	mov		dx, [RAMVARS.wIdeBase]			; Load IDE Base Port address
+	call	HPIO_ReadFromDrive
+
+	; Destroy stack frame
+	rcl		al, 1							; CF to AL bit 0
+	add		bp, BYTE PIOVARS_size
+	eLEAVE
+	rcr		al, 1							; Restore CF
+	mov		di, bx							; Restore DI
+	pop		es
+	ret
+
+
+;--------------------------------------------------------------------
+; Initializes PIOVARS members.
+;
+; HPIO_InitializePIOVARS
+;	Parameters:
+;		AL:		Number of sectors to transfer (1...255)
+;		SI:		Offset to transfer function lookup table
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:BX:	Ptr to source or destination data buffer
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		ES:BX:	Normalized pointer to data buffer
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_InitializePIOVARS:
+	; Store number of WORDs to transfer
+	mov		ah, al								; Number of WORDs to transfer...
+	xor		al, al								; ...to AX
+	mov		[bp+PIOVARS.wWordsLeft], ax			; Store WORD count
+
+	; Store block size in WORDs
+	mov		ah, [di+DPT.bSetBlock]				; AX = block size in WORDs
+	mov		[bp+PIOVARS.wBlockSize], ax			; Store block size
+
+	; Get transfer function based on bus type
+	xchg	ax, bx								; Backup BX
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]			; CS:BX now points to IDEVARS
+	mov		bl, BYTE [cs:bx+IDEVARS.bBusType]	; Load bus type to BX
+	mov		bx, [cs:bx+si]						; Load offset to transfer function
+	mov		[bp+PIOVARS.fnXfer], bx				; Store offset to transfer function
+	xchg	bx, ax
+	; Fall to HPIO_NormalizePtr
+
+;--------------------------------------------------------------------
+; Initializes PIOVARS members.
+;
+; HPIO_InitializePIOVARS
+;	Parameters:
+;		ES:BX:	Ptr to source or destination data buffer
+;	Returns:
+;		ES:BX:	Normalized pointer to data buffer
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+HPIO_NormalizeDataPointer:
+	HPIO_NORMALIZE_PTR	es, bx, ax, cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Reads blocks using PIO transfers.
+;
+; HPIO_ReadFromDrive
+;	Parameters:
+;		DX:		IDE Data port address
+;		DS:BX:	Ptr to DPT (in RAMVARS segment)
+;		ES:DI:	Normalized ptr to buffer to recieve data
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if transfer succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_ReadFromDrive:
+	cld									; INS to increment DI
+ALIGN JUMP_ALIGN
+.BlockLoop:
+	call	HStatus_WaitIrqOrDrq		; Wait until ready to transfer
+	jc		SHORT .RetError				; Return if error (code in AH)
+	mov		cx, [bp+PIOVARS.wBlockSize]	; Load block size
+	sub		[bp+PIOVARS.wWordsLeft], cx	; Transferring last (possibly partial) block?
+	jbe		SHORT .XferLastBlock		;  If so, jump to transfer
+	call	[bp+PIOVARS.fnXfer]			; Transfer full block
+	jmp		SHORT .BlockLoop			; Loop while blocks left
+ALIGN JUMP_ALIGN
+.XferLastBlock:
+	add		cx, [bp+PIOVARS.wWordsLeft]	; CX to partial block size
+	call	[bp+PIOVARS.fnXfer]			; Transfer possibly partial block
+	jmp		HStatus_WaitBsyDefTime		; Check for errors
+.RetError:
+	ret
+
+
+;--------------------------------------------------------------------
+; Writes sectors to hard disk using PIO transfer mode.
+;
+; HPIO_WriteBlock
+;	Parameters:
+;		AL:		Number of sectors to write (1...255)
+;		ES:BX:	Pointer to buffer containing data
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if transfer successfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_WriteBlock:
+	push	es
+	push	si
+
+	; Create PIOVARS to stack
+	eENTER	PIOVARS_size, 0
+	sub		bp, BYTE PIOVARS_size			; SS:BP now points to PIOVARS
+	mov		si, g_rgfnPioWrite				; Offset to write function lookup
+	call	HPIO_InitializePIOVARS			; Store word count and block size
+
+	; Prepare pointers and start transfer
+	mov		si, bx							; ES:SI now points source buffer
+	mov		bx, di							; DS:BX now points DPT
+	call	HPIO_WriteToDrive
+
+	; Destroy stack frame
+	rcl		al, 1							; CF to AL bit 0
+	add		bp, BYTE PIOVARS_size
+	eLEAVE
+	rcr		al, 1							; Restore CF
+	pop		si
+	pop		es
+	ret
+
+;--------------------------------------------------------------------
+; Writes blocks using PIO transfers.
+;
+; HPIO_WriteToDrive
+;	Parameters:
+;		DS:BX:	Ptr to DPT (in RAMVARS segment)
+;		ES:SI:	Normalized ptr to buffer containing data
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if transfer succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_WriteToDrive:
+	cld										; OUTS to increment SI
+	call	HStatus_WaitDrqDefTime			; Always poll DRQ for first block, get status reg to DX
+	jc		SHORT .RetError					; Return if error (code in AH)
+	sub		dx, BYTE REGR_IDE_ST			; DX to Data Port address
+ALIGN JUMP_ALIGN
+.BlockLoop:
+	mov		cx, [bp+PIOVARS.wBlockSize]		; Load block size
+	sub		[bp+PIOVARS.wWordsLeft], cx		; Transferring last (possibly partial) block?
+	jbe		SHORT .XferLastBlock			;  If so, jump to transfer
+	call	[bp+PIOVARS.fnXfer]				; Transfer full block
+	call	HStatus_WaitIrqOrDrq			; Wait until ready to transfer
+	jnc		SHORT .BlockLoop				; If no error, loop while blocks left
+.RetError:
+	ret
+ALIGN JUMP_ALIGN
+.XferLastBlock:
+	add		cx, [bp+PIOVARS.wWordsLeft]		; CX to partial block size
+	call	[bp+PIOVARS.fnXfer]				; Transfer possibly partial block
+	jmp		HStatus_WaitIrqOrRdy			; Check for errors
+
+
+;--------------------------------------------------------------------
+; Bus specific transfer functions and lookup table.
+;
+; HPIO_DualByteRead		Dual port 8-bit XTIDE PIO read transfer
+; HPIO_WordRead			Normal 16-bit IDE PIO read transfer
+; HPIO_DualByteWrite	Dual port 8-bit XTIDE PIO write transfer
+; HPIO_WordWrite		Normal 16-bit IDE PIO write transfer
+;	Parameters:
+;		CX:		Block size in WORDs
+;		DX:		IDE Data port address
+;		ES:DI:	Normalized ptr to buffer to recieve data (read only)
+;		ES:SI:	Normalized ptr to buffer containing data (write only)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HPIO_DualByteRead:
+	eREP_DUAL_BYTE_PORT_INSW
+	ret
+ALIGN JUMP_ALIGN
+HPIO_WordRead:
+	rep
+	db		6Dh			; INSW
+	ret
+ALIGN JUMP_ALIGN
+HPIO_DWordRead:
+	shr		cx, 1		; WORD count to DWORD count
+	rep
+	db		66h			; Override operand size to 32-bit
+	db		6Dh			; INSW/INSD
+	ret
+ALIGN JUMP_ALIGN
+HPIO_SingleByteRead:
+	eREP_SINGLE_BYTE_PORT_INSW
+	ret
+
+ALIGN JUMP_ALIGN
+HPIO_DualByteWrite:
+	eREP_DUAL_BYTE_PORT_OUTSW
+	ret
+ALIGN JUMP_ALIGN
+HPIO_WordWrite:
+	eSEG	es			; Source is ES segment
+	rep
+	db		6Fh			; OUTSW
+	ret
+ALIGN JUMP_ALIGN
+HPIO_DWordWrite:
+	shr		cx, 1		; WORD count to DWORD count
+	eSEG	es			; Source is ES segment
+	rep
+	db		66h			; Override operand size to 32-bit
+	db		6Fh			; OUTSW/OUTSD
+	ret
+ALIGN JUMP_ALIGN
+HPIO_SingleByteWrite:
+	eREP_SINGLE_BYTE_PORT_OUTSW
+	ret
+
+ALIGN WORD_ALIGN
+g_rgfnPioRead:
+	dw		HPIO_DualByteRead		; 8-bit dual port reads
+	dw		HPIO_WordRead			; 16-bit reads
+	dw		HPIO_DWordRead			; 32-bit reads
+	dw		HPIO_SingleByteRead		; 8-bit single port reads
+g_rgfnPioWrite:
+	dw		HPIO_DualByteWrite		; 8-bit dual port writes
+	dw		HPIO_WordWrite			; 16-bit writes
+	dw		HPIO_DWordWrite			; 32-bit writes
+	dw		HPIO_SingleByteWrite	; 8-bit single port writes
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HStatus.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HStatus.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int13h/Common/HStatus.asm	(revision 37)
@@ -0,0 +1,224 @@
+; File name		:	HStatus.asm
+; Project name	:	IDE BIOS
+; Created date	:	15.12.2009
+; Last update	:	23.8.2010
+; Author		:	Tomi Tilli
+; Description	:	IDE Status Register polling functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Waits Hard Disk IRQ when not transferring data.
+; If interrupts are disabled, RDY flag is polled.
+;
+; HStatus_WaitIrqOrRdy
+;	Parameters:
+;		DS:BX:	Ptr to DPT
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if wait succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_WaitIrqOrRdy:
+	call	HIRQ_WaitForIRQ
+	jnc		SHORT .PollRdySinceNoWaitingOnOsHook
+	jmp		HError_ProcessErrorsAfterPollingBSY
+
+ALIGN JUMP_ALIGN
+.PollRdySinceNoWaitingOnOsHook:
+	mov		cl, B_TIMEOUT_DRQ				; Load DRQ (not RDY) timeout
+	jmp		SHORT HStatus_WaitRdy			; Jump to poll RDY
+
+
+;--------------------------------------------------------------------
+; Waits until Hard Disk is ready to transfer data.
+;
+; HStatus_WaitIrqOrDrq
+;	Parameters:
+;		DS:BX:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if wait succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_WaitIrqOrDrq:
+	call	HIRQ_WaitForIRQ
+	jnc		SHORT .PollDrqSinceNoWaitingOnOsHook
+	jmp		HError_ProcessErrorsAfterPollingBSY
+
+ALIGN JUMP_ALIGN
+.PollDrqSinceNoWaitingOnOsHook:
+	push	dx
+	push	cx
+	call	HStatus_WaitDrqDefTime
+	pop		cx
+	pop		dx
+	ret
+
+
+;--------------------------------------------------------------------
+; Waits until busy flag is cleared from selected Hard Disk drive.
+;
+; HStatus_WaitBsyDefTime	Uses default timeout
+; HStatus_WaitBsy			Uses user defined timeout
+; HStatus_WaitBsyBase		Uses user base port address and timeout
+;	Parameters:
+;		CL:		Timeout value in system timer ticks (not HStatus_WaitBsyDefTime)
+;		DX:		IDE Base port address (HUtil_WaitBsyBase only)
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		DX:		IDE Status Register Address
+;		CF:		0 if wait succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_WaitBsyDefTime:
+	mov		cl, B_TIMEOUT_BSY			; Load timeout value
+ALIGN JUMP_ALIGN
+HStatus_WaitBsy:
+	mov		dx, [RAMVARS.wIdeBase]		; Load offset to base port
+ALIGN JUMP_ALIGN
+HStatus_WaitBsyBase:
+	add		dx, BYTE REGR_IDE_ST		; Add offset to status reg
+	jmp		SHORT HStatus_PollBsy		; Wait until not busy
+
+
+;--------------------------------------------------------------------
+; Waits until Hard Disk is ready to accept commands.
+;
+; HStatus_WaitRdyDefTime	Uses default timeout
+; HStatus_WaitRdy			Uses user defined timeout
+; HStatus_WaitRdyBase		Uses user base port address and timeout
+;	Parameters:
+;		CL:		Timeout value in system timer ticks (not HStatus_WaitRdyDefTime)
+;		DX:		IDE Base port address (HStatus_WaitRdyBase only)
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		DX:		IDE Status Register Address
+;		CF:		0 if wait succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_WaitRdyDefTime:
+	mov		cl, B_TIMEOUT_RDY			; Load timeout value
+ALIGN JUMP_ALIGN
+HStatus_WaitRdy:
+	mov		dx, [RAMVARS.wIdeBase]		; Load offset to base port
+ALIGN JUMP_ALIGN
+HStatus_WaitRdyBase:
+	add		dx, BYTE REGR_IDE_ST		; Add offset to status reg
+	mov		ah, FLG_IDE_ST_DRDY			; Flag to poll
+	jmp		SHORT HStatus_PollBsyAndFlg	; Wait until flag set
+
+
+;--------------------------------------------------------------------
+; Waits until Hard Disk is ready to transfer data.
+; Note! This function polls DRQ even if interrupts are enabled!
+;
+; HStatus_WaitDrqDefTime	Uses default timeout
+; HStatus_WaitDrq			Uses user defined timeout
+; HStatus_WaitDrqBase		Uses user base port address and timeout
+;	Parameters:
+;		CL:		Timeout value in system timer ticks (not HStatus_WaitDrqDefTime)
+;		DX:		IDE Base port address (HStatus_WaitDrqBase only)
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		DX:		IDE Status Register Address
+;		CF:		0 if wait succesfull
+;				1 if any error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_WaitDrqDefTime:
+	mov		cl, B_TIMEOUT_DRQ			; Load timeout value
+ALIGN JUMP_ALIGN
+HStatus_WaitDrq:
+	mov		dx, [RAMVARS.wIdeBase]		; Load offset to base port
+ALIGN JUMP_ALIGN
+HStatus_WaitDrqBase:
+	add		dx, BYTE REGR_IDE_ST		; Add offset to status reg
+	mov		ah, FLG_IDE_ST_DRQ			; Flag to poll
+	; Fall to HStatus_PollBsyAndFlg
+
+;--------------------------------------------------------------------
+; IDE Status register polling.
+; This function first waits until controller is not busy.
+; When not busy, IDE Status Register is polled until wanted flag is set.
+;
+; HStatus_PollBusyAndFlg
+;	Parameters:
+;		AH:		Status Register Flag to poll (until set) when not busy
+;		CL:		Timeout value in system timer ticks
+;		DX:		IDE Status Register Address
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Clear if wait completed successfully (no errors)
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_PollBsyAndFlg:
+	call	SoftDelay_InitTimeout				; Initialize timeout counter
+	in		al, dx								; Discard contents for first read
+												; (should read Alternate Status Register)
+ALIGN JUMP_ALIGN
+.PollLoop:
+	in		al, dx								; Load IDE Status Register
+	test	al, FLG_IDE_ST_BSY					; Controller busy?
+	jnz		SHORT .UpdateTimeout				;  If so, jump to timeout update
+	test	al, ah								; Test secondary flag
+	jnz		SHORT GetErrorCodeFromPollingToAH	; If set, break loop
+ALIGN JUMP_ALIGN
+.UpdateTimeout:
+	call	SoftDelay_UpdTimeout				; Update timeout counter
+	jnc		SHORT .PollLoop						; Loop if time left (sets CF on timeout)
+	jmp		HError_ProcessTimeoutAfterPollingBSYandSomeOtherStatusBit
+
+;--------------------------------------------------------------------
+; IDE Status register polling.
+; This function waits until controller is not busy.
+;
+; HStatus_PollBsy
+;	Parameters:
+;		CL:		Timeout value in system timer ticks
+;		DX:		IDE Status Register Address
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Clear if wait completed successfully (no errors)
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HStatus_PollBsy:
+	call	SoftDelay_InitTimeout				; Initialize timeout counter
+	in		al, dx								; Discard contents for first read
+												; (should read Alternate Status Register)
+ALIGN JUMP_ALIGN
+.PollLoop:
+	in		al, dx								; Load IDE Status Reg
+	test	al, FLG_IDE_ST_BSY					; Controller busy?
+	jz		SHORT GetErrorCodeFromPollingToAH	;  If not, jump to check errors
+	call	SoftDelay_UpdTimeout				; Update timeout counter
+	jnc		SHORT .PollLoop						; Loop if time left (sets CF on timeout)
+ALIGN JUMP_ALIGN
+GetErrorCodeFromPollingToAH:
+	jmp		HError_ProcessErrorsAfterPollingBSY
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int18h.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int18h.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int18h.asm	(revision 37)
@@ -0,0 +1,27 @@
+; File name		:	Int18h.asm
+; Project name	:	IDE BIOS
+; Created date	:	6.1.2010
+; Last update	:	25.3.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 18h BIOS functions (ROM boot and Boot error).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 18h software interrupt handler.
+; Enters boot menu again after displaying callback message.
+;
+; Int18h_BootError
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing (jumps to Int19hMenu_Display)
+;	Corrupts registers:
+;		Doesn't matter
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int18h_BootError:
+	mov		si, g_sz18hCallback
+	call	PrintString_FromCS		; No need to clean stack
+	jmp		Int19hMenu_Display		; Return to boot menu
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19h.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19h.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19h.asm	(revision 37)
@@ -0,0 +1,217 @@
+; File name		:	Int19h.asm
+; Project name	:	IDE BIOS
+; Created date	:	3.8.2007
+; Last update	:	1.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 19h BIOS functions (Boot Strap Loader).
+
+; Section containing code
+SECTION .text
+
+B_READ_RETRY_TIMES	EQU	3	; Number of times to retry
+
+
+;--------------------------------------------------------------------
+; Int 19h software interrupt handler for late initialization.
+; Calls actual Int 19h after initialization is complete.
+;
+; Int19h_LateInitialization
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_LateInitialization:
+	call	Initialize_ShouldSkip			; Skip initialization?
+	jc		SHORT .SkipInitialization
+	call	Initialize_AndDetectDrives
+	int		INTV_BOOTSTRAP					; Call actual boot loader
+.SkipInitialization:
+	call	RamVars_Initialize				; RAMVARS must be initialized even for simple boot loader
+	; Fall to Int19h_SimpleBootLoader
+
+;--------------------------------------------------------------------
+; Simple boot loader.
+; Boot sequence is fixed to 00h, 80h and INT 18h.
+;
+; Int19h_SimpleBootLoader
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_SimpleBootLoader:
+	sti										; Enable interrupts
+	call	RamVars_GetSegmentToDS
+	xor		dx, dx
+	call	Int19h_TryToLoadBootSectorFromDL
+	jc		SHORT Int19h_JumpToBootSector
+	mov		dl, 80h
+	call	Int19h_TryToLoadBootSectorFromDL
+	jc		SHORT Int19h_JumpToBootSector
+	call	Int19h_BootFailure				; Should never return		
+	jmp		SHORT Int19h_SimpleBootLoader
+
+;--------------------------------------------------------------------
+; Boots if boot sector is successfully read from the drive.
+;
+; Int19h_TryToLoadBootSectorFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		ES:BX:	Ptr to boot sector (if successfull)
+;		CF:		Set if boot sector loaded succesfully
+;				Cleared if failed to load boot sector
+;	Corrupts registers:
+;		AX, CX, DH, DI, (DL if failed to read boot sector)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_TryToLoadBootSectorFromDL:
+	call	BootPrint_TryToBootFromDL
+	call	Int19h_LoadFirstSectorFromDL
+	jc		SHORT .FailedToLoadFirstSector
+	cmp		WORD [es:bx+510], 0AA55h		; Valid boot sector?
+	jne		SHORT .FirstSectorNotBootable
+	call	BootPrint_BootSectorLoaded
+	stc
+	ret
+.FailedToLoadFirstSector:
+	call	BootPrint_FailedToLoadFirstSector
+	clc
+	ret
+.FirstSectorNotBootable:
+	call	BootPrint_FirstSectorNotBootable
+	clc
+	ret
+
+;--------------------------------------------------------------------
+; Reads first sector (boot sector) from drive DL.
+;
+; Int19h_LoadFirstSectorFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;	Returns:
+;		AH:		INT 13h error code
+;		ES:BX:	Ptr to boot sector (if successfull)
+;		CF:		Cleared if read successfull
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX, DH, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_LoadFirstSectorFromDL:
+	LOAD_BDA_SEGMENT_TO	es, bx				; ES:BX now points to...
+	mov		bx, BOOTVARS.rgbBootSect		; ...boot sector location
+	mov		di, B_READ_RETRY_TIMES			; Retry counter
+ALIGN JUMP_ALIGN
+.ReadRetryLoop:
+	call	.ResetBootDriveFromDL
+	call	.LoadFirstSectorFromDLtoESBX
+	jnc		SHORT .Return
+	dec		di								; Decrement retry counter
+	jnz		SHORT .ReadRetryLoop			; Loop while retries left
+	stc
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+;--------------------------------------------------------------------
+; .ResetBootDriveFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;	Returns:
+;		AH:		INT 13h error code
+;		CF:		Cleared if read successfull
+;				Set if any error
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.ResetBootDriveFromDL:
+	xor		ax, ax							; AH=0h, Disk Controller Reset
+	test	dl, 80h							; Floppy drive?
+	jz		SHORT .ResetDriveFromDL			;  If so, jump to reset
+	mov		ah, 0Dh							; AH=Dh, Reset Hard Disk (Alternate reset)
+.ResetDriveFromDL:
+	int		INTV_DISK_FUNC
+	ret
+
+;--------------------------------------------------------------------
+; Reads first sector (boot sector) from drive DL to ES:BX.
+;
+; .LoadFirstSectorFromDLtoESBX
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		ES:BX:	Destination buffer for boot sector
+;	Returns:
+;		AH:		INT 13h error code
+;		ES:BX:	Ptr to boot sector
+;		CF:		Cleared if read successfull
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX, DH
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.LoadFirstSectorFromDLtoESBX:
+	mov		ax, 0201h						; Read 1 sector
+	mov		cx, 1							; Cylinder 0, Sector 1
+	xor		dh, dh							; Head 0
+	int		INTV_DISK_FUNC
+	ret
+
+
+;--------------------------------------------------------------------
+; Jumps to boot sector pointed by ES:BX.
+;
+; Int19h_JumpToBootSector
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		ES:BX:	Ptr to boot sector
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_JumpToBootSector:
+	push	es								; Push boot sector segment
+	push	bx								; Push boot sector offset
+	call	Int19h_ClearSegmentsForBoot
+	xor		dh, dh							; Device supported by INT 13h
+	retf
+
+;--------------------------------------------------------------------
+; Clears DS and ES registers to zero.
+;
+; Int19h_ClearSegmentsForBoot
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS=ES:	Zero
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_ClearSegmentsForBoot:
+	xor		ax, ax
+	mov		ds, ax
+	mov		es, ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Calls INT 18h (ROM Basic or Boot Failure). Called after booting from
+; floppy drive or hard disk fails.
+;
+; Int19h_BootFailure
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Should never return (but might)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_BootFailure:
+	call	Int19h_ClearSegmentsForBoot
+	int		INTV_BOOT_FAILURE
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19hMenu.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19hMenu.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Handlers/Int19hMenu.asm	(revision 37)
@@ -0,0 +1,116 @@
+; File name		:	Int19hMenu.asm
+; Project name	:	IDE BIOS
+; Created date	:	25.3.2010
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Int 19h BIOS functions for Boot Menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Initial Boot Menu Loader.
+; Prepares BOOTVARS for displaying Boot Menu and accepting
+; callbacks from INT 18h and 19h.
+;
+; Int19hMenu_BootLoader
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Jumps to Int19hMenu_Display, then never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_BootLoader:
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	call	BootVars_StorePostStackPointer
+	call	BootVars_StoreSystemInt18hAndInstallOurs
+
+	; Install new INT 19h handler now that BOOTVARS has been initialized
+	mov		WORD [INTV_BOOTSTRAP*4], Int19hMenu_Display
+	mov		WORD [INTV_BOOTSTRAP*4+2], cs
+	; Fall to Int19hMenu_Display
+
+;--------------------------------------------------------------------
+; Displays Boot Menu so user can select drive to boot from.
+;
+; Int19hMenu_Display
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_Display:
+	sti									; Enable interrupts
+	call	BootVars_SwitchToBootMenuStack
+	call	RamVars_GetSegmentToDS
+	; Fall to Int19hMenu_ProcessMenuSelectionsUntilBootable
+
+;--------------------------------------------------------------------
+; Processes user menu selections until bootable drive is selected.
+;
+; Int19hMenu_ProcessMenuSelectionsUntilBootable
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_ProcessMenuSelectionsUntilBootable:
+	call	Int19hMenu_GetDriveOrFunctionFromBootMenu
+	jc		SHORT Int19hMenu_ExecuteSelectedFunction
+	call	Int19h_TryToLoadBootSectorFromDL
+	jnc		SHORT Int19hMenu_ProcessMenuSelectionsUntilBootable	; Boot failure
+	call	BootVars_SwitchBackToPostStack
+	jmp		SHORT Int19h_JumpToBootSector
+
+
+;--------------------------------------------------------------------
+; Selects Floppy or Hard Disk Drive to boot from or some function.
+;
+; Int19hMenu_GetDriveOrFunctionFromBootMenu
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DX:		Drive number (translated, 00h or 80h) or
+;				Function ID
+;		CF:		Cleared if drive selected
+;				Set if function selected
+;	Corrupts registers:
+;		All non segment regs
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_GetDriveOrFunctionFromBootMenu:
+	call	BootMenu_DisplayAndReturnSelection
+	jc		SHORT .ReturnFunction
+	call	DriveXlate_ToOrBack			; Translate drive number
+	clc
+ALIGN JUMP_ALIGN
+.ReturnFunction:
+	ret
+
+
+;--------------------------------------------------------------------
+; Executes any function (non-drive) selected from Boot Menu.
+;
+; Int19hMenu_ExecuteSelectedFunction
+;	Parameters:
+;		DX:		Function ID (selected from Boot Menu)
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All non segment regs
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_ExecuteSelectedFunction:
+	ePUSH_T	ax, Int19hMenu_ProcessMenuSelectionsUntilBootable
+	test	dx, dx						; 0, IDF_BOOTMNU_ROM
+	jz		SHORT .Int18hRomBoot
+	ret
+ALIGN JUMP_ALIGN
+.Int18hRomBoot:
+	call	BootVars_RestoreSystemInt18h
+	call	BootVars_SwitchBackToPostStack
+	call	Int19h_BootFailure			; Should never return
+	jmp		SHORT Int19hMenu_BootLoader	; Status unknown so reinitialize boot loader
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/AtaID.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/AtaID.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/AtaID.asm	(revision 37)
@@ -0,0 +1,93 @@
+; File name		:	AtaID.asm
+; Project name	:	IDE BIOS
+; Created date	:	6.4.2010
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for accessing ATA information read with
+;					IDENTIFY DEVICE command.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Returns P-CHS values from ATA information.
+;
+; AtaID_GetPCHS
+;	Parameters:
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		AX:		Number of user specified P-CHS cylinders
+;		BL:		Number of user specified P-CHS sectors per track
+;		BH:		Number of user specified P-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AtaID_GetPCHS:
+	mov		ax, [es:si+ATA1.wCylCnt]	; Cylinders (1...16383)
+	mov		bh, [es:si+ATA1.wHeadCnt]	; Heads (1...16)
+	mov		bl, [es:si+ATA1.wSPT]		; Sectors per Track (1...63)
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns total number of available sectors from ATA information.
+;
+; AtaID_GetTotalSectorCount
+;	Parameters:
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AtaID_GetTotalSectorCount:
+	xor		bx, bx
+	test	WORD [es:si+ATA1.wCaps], A1_wCaps_LBA
+	jz		SHORT AtaID_GetChsSectorCount
+	; Fall to AtaID_GetLbaSectorCount
+
+;--------------------------------------------------------------------
+; Returns total number of available sectors for LBA addressing.
+;
+; AtaID_GetLbaSectorCount
+;	Parameters:
+;		BX:		Zero
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+AtaID_GetLbaSectorCount:
+	test	WORD [es:si+ATA6.wSetSup83], A6_wSetSup83_LBA48
+	jz		SHORT .GetLba28SectorCount
+	mov		ax, [es:si+ATA6.qwLBACnt]
+	mov		dx, [es:si+ATA6.qwLBACnt+2]
+	mov		bx, [es:si+ATA6.qwLBACnt+4]
+	ret
+ALIGN JUMP_ALIGN
+.GetLba28SectorCount:
+	mov		ax, [es:si+ATA1.dwLBACnt]
+	mov		dx, [es:si+ATA1.dwLBACnt+2]
+	ret
+
+;--------------------------------------------------------------------
+; Returns total number of available sectors for P-CHS addressing.
+;
+; AtaID_GetChsSectorCount
+;	Parameters:
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		DX:AX:	24-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AtaID_GetChsSectorCount:
+	mov		al, [es:si+ATA1.wSPT]		; AL=Sectors per track
+	mul		BYTE [es:si+ATA1.wHeadCnt]	; AX=Sectors per track * number of heads
+	mul		WORD [es:si+ATA1.wCylCnt]	; DX:AX=Sectors per track * number of heads * number of cylinders
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectDrives.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectDrives.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectDrives.asm	(revision 37)
@@ -0,0 +1,208 @@
+; File name		:	DetectDrives.asm
+; Project name	:	IDE BIOS
+; Created date	:	17.3.2010
+; Last update	:	23.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for detecting drive for the BIOS.
+
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Detects all IDE hard disks to be controlled by this BIOS.
+;
+; DetectDrives_FromAllIDEControllers
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All (not segments)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_FromAllIDEControllers:
+	call	RamVars_GetIdeControllerCountToCX
+	mov		bp, ROMVARS.ideVars0			; CS:BP now points to first IDEVARS
+ALIGN JUMP_ALIGN
+.DriveDetectLoop:
+	call	DetectDrives_WithIDEVARS		; Detect Master and Slave
+	add		bp, BYTE IDEVARS_size			; Point to next IDEVARS
+	loop	.DriveDetectLoop
+	ret
+
+
+;--------------------------------------------------------------------
+; Detects IDE hard disks by using information from IDEVARS.
+;
+; DetectDrives_WithIDEVARS
+;	Parameters:
+;		CS:BP:		Ptr to IDEVARS
+;		DS:			RAMVARS segment
+;		ES:			Zero (BDA segment)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_WithIDEVARS:
+	push	cx
+	call	DetectPrint_StartingMasterDetect	; Print detection string
+	call	DetectDrives_DetectMasterDrive		; Detect and create DPT + BOOTNFO
+	call	DetectPrint_DriveNameOrNotFound		; Print found or not found string
+
+	call	DetectPrint_StartingSlaveDetect
+	call	DetectDrives_DetectSlaveDrive
+	call	DetectPrint_DriveNameOrNotFound
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Detects IDE Master or Slave drive.
+;
+; DetectDrives_DetectMasterDrive
+; DetectDrives_DetectSlaveDrive
+;	Parameters:
+;		CS:BP:	Ptr to IDEVARS
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;		ES:BX:	Ptr to BOOTNFO (if successful)
+;		CF:		Cleared if drive detected successfully
+;				Set if any drive not found or other error
+;	Corrupts registers:
+;		AX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_DetectMasterDrive:
+	mov		bh, MASK_IDE_DRVHD_SET		; Select Master drive
+	jmp		SHORT DetectDrives_StartDetection
+ALIGN JUMP_ALIGN
+DetectDrives_DetectSlaveDrive:
+	mov		bh, MASK_IDE_DRVHD_SET | FLG_IDE_DRVHD_DRV
+	; Fall to DetectDrives_StartDetection
+
+;--------------------------------------------------------------------
+; Detects IDE Master or Slave drive.
+;
+; DetectDrives_StartDetection
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;		ES:BX:	Ptr to BOOTNFO (if successful)
+;		CF:		Cleared if drive detected successfully
+;				Set if any drive not found or other error
+;	Corrupts registers:
+;		AX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_StartDetection:
+	call	DetectDrives_ReadAtaInfoFromDrive	; Assume hard disk
+	jnc		SHORT DetectDrives_CreateBiosTablesForHardDisk
+	call	DetectDrives_ReadAtapiInfoFromDrive	; Assume CD-ROM
+	jnc		SHORT DetectDrives_CreateBiosTablesForCDROM
+	ret
+
+
+;--------------------------------------------------------------------
+; Reads ATA information from the drive (for hard disks).
+;
+; DetectDrives_ReadAtaInfoFromDrive
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;		ES:SI	Ptr to ATA information (read with IDENTIFY DEVICE command)
+;		CF:		Cleared if ATA-information read successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BL, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_ReadAtaInfoFromDrive:
+	mov		bl, [cs:bp+IDEVARS.bBusType]; Load BUS type
+	mov		dx, [cs:bp+IDEVARS.wPort]	; Load IDE Base Port address
+	mov		di, BOOTVARS.rgbAtaInfo		; ES:DI now points to ATA info location
+	call	AH25h_GetDriveInfo
+	mov		si, di						; ES:SI now points to ATA information
+	ret
+
+
+;--------------------------------------------------------------------
+; Reads ATAPI information from the drive (for CD/DVD-ROMs).
+;
+; DetectDrives_ReadAtapiInfoFromDrive
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;		ES:SI	Ptr to ATAPI information (read with IDENTIFY PACKET DEVICE command)
+;		CF:		Cleared if ATAPI-information read successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BL, CX, DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_ReadAtapiInfoFromDrive:
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; Creates all BIOS tables for detected hard disk.
+;
+; DetectDrives_CreateBiosTablesForHardDisk
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		ES:SI	Ptr to ATA information for the drive
+;		DS:		RAMVARS segment
+;	Returns:
+;		ES:BX:	Ptr to BOOTNFO (if successful)
+;		CF:		Cleared if BIOS tables created succesfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_CreateBiosTablesForHardDisk:
+	call	CreateDPT_FromAtaInformation
+	jc		SHORT .InvalidAtaInfo
+	call	BootInfo_CreateForHardDisk
+	;jc		SHORT .InvalidAtaInfo
+	; Call to search for BIOS partitions goes here
+	;clc
+.InvalidAtaInfo:
+	ret
+
+
+;--------------------------------------------------------------------
+; Creates all BIOS tables for detected CD/DVD-ROM.
+;
+; DetectDrives_CreateBiosTablesForCDROM
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		ES:SI	Ptr to ATAPI information for the drive
+;		DS:		RAMVARS segment
+;	Returns:
+;		ES:BX:	Ptr to BOOTNFO (if successful)
+;		CF:		Cleared if BIOS tables created succesfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectDrives_CreateBiosTablesForCDROM:
+	stc
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectPrint.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectPrint.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DetectPrint.asm	(revision 37)
@@ -0,0 +1,96 @@
+; File name		:	DetectPrint.asm
+; Project name	:	IDE BIOS
+; Created date	:	28.3.2010
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for printing drive detection strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints BIOS name and segment address where it is found.
+;
+; DetectPrint_RomFoundAtSegment
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectPrint_RomFoundAtSegment:
+	push	cs
+	ePUSH_T	ax, ROMVARS.szTitle
+	mov		si, g_szRomAt
+	mov		dh, 4						; 4 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Displays IDE drive detection string for specific device.
+;
+; DetectPrint_StartingMasterDetect
+; DetectPrint_StartingSlaveDetect
+;	Parameters:
+;		CS:BP:	Ptr to IDEVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectPrint_StartingMasterDetect:
+	mov		ax, g_szMaster
+	jmp		SHORT DetectPrint_StartingDriveDetect
+ALIGN JUMP_ALIGN
+DetectPrint_StartingSlaveDetect:
+	mov		ax, g_szSlave
+	; Fall to DetectPrint_StartingDriveDetect
+
+;--------------------------------------------------------------------
+; Displays IDE drive detection string.
+;
+; DetectPrint_StartingDriveDetect
+;	Parameters:
+;		AX:		Offset to "Master" or "Slave" string
+;		CS:BP:	Ptr to IDEVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectPrint_StartingDriveDetect:
+	push	WORD [cs:bp+IDEVARS.wPort]
+	push	ax
+	mov		si, g_szDetect
+	mov		dh, 4						; 4 bytes pushed to stack
+	jmp		PrintString_JumpToFormat
+
+
+;--------------------------------------------------------------------
+; Displays Detected Drive Name from BOOTVARS or
+; drive not found string if no drive was found.
+;
+; DetectPrint_DriveNameOrNotFound
+;	Parameters:
+;		ES:BX:	Ptr to BOOTNFO (if drive found)
+;		CF:		Cleared if drive found
+;				Set it drive not found
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DetectPrint_DriveNameOrNotFound:
+	jc		SHORT .PrintDriveNotFound
+	lea		si, [bx+BOOTNFO.szDrvName]
+	call	PrintString_FromES
+	jmp		Print_Newline
+ALIGN JUMP_ALIGN
+.PrintDriveNotFound:
+	mov		si, g_szNotFound
+	jmp		PrintString_FromCS
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DriveXlate.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DriveXlate.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/DriveXlate.asm	(revision 37)
@@ -0,0 +1,290 @@
+; File name		:	DriveXlate.asm
+; Project name	:	IDE BIOS
+; Created date	:	15.3.2010
+; Last update	:	24.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for swapping drive letters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Translates drive number when entering INT 13h.
+;
+; DriveXlate_WhenEnteringInt13h
+;	Parameters:
+;		DL:		Drive number to be possibly translated
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_WhenEnteringInt13h:
+	inc		BYTE [RAMVARS.xlateVars+XLATEVARS.bRecurCnt]
+	cmp		BYTE [RAMVARS.xlateVars+XLATEVARS.bRecurCnt], 1
+	je		SHORT DriveXlate_ToOrBack
+	ret
+
+
+;--------------------------------------------------------------------
+; DriveXlate_WhenLeavingInt13hWithReturnValueInDL
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_WhenLeavingInt13hWithReturnValueInDL:
+	dec		BYTE [RAMVARS.xlateVars+XLATEVARS.bRecurCnt]
+	ret
+
+;--------------------------------------------------------------------
+; Translates drive number when leaving INT 13h.
+;
+; DriveXlate_WhenLeavingInt13h
+;	Parameters:
+;		DL:		Drive number to be possibly translated
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_WhenLeavingInt13h:
+	dec		BYTE [RAMVARS.xlateVars+XLATEVARS.bRecurCnt]
+	jz		SHORT DriveXlate_ToOrBack
+	ret
+
+
+;--------------------------------------------------------------------
+; Translates drive number to or back.
+;
+; DriveXlate_ToOrBack
+;	Parameters:
+;		DL:		Drive number to be possibly translated
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_ToOrBack:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_DRVXLAT
+	jz		SHORT .Return			; Return if translation disabled
+	xchg	di, ax					; Backup AX
+	call	DriveXlate_SwapFloppyDriveOrHardDisk
+	xchg	ax, di
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Swaps Floppy Drive or Hard Disk number.
+;
+; DriveXlate_SwapFloppyDriveOrHardDisk
+;	Parameters:
+;		DL:		Drive number to be possibly swapped
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_SwapFloppyDriveOrHardDisk:
+	test	dl, 80h							; Hard disk?
+	jnz		SHORT DriveXlate_SwapHardDisk	; If so, jump to swap
+	; Fall to DriveXlate_SwapFloppyDrive
+
+;--------------------------------------------------------------------
+; Swaps Floppy Drive number.
+;
+; DriveXlate_SwapFloppyDrive
+;	Parameters:
+;		DL:		Drive number to be possibly swapped
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+DriveXlate_SwapFloppyDrive:
+	eMOVZX	ax, BYTE [RAMVARS.xlateVars+XLATEVARS.bFDSwap]
+	jmp		SHORT DriveXlate_SwapDrive
+
+;--------------------------------------------------------------------
+; Swaps Hard Disk number.
+;
+; DriveXlate_SwapHardDisk
+;	Parameters:
+;		DL:		Drive number to be possibly swapped
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_SwapHardDisk:
+	mov		ah, 80h
+	mov		al, BYTE [RAMVARS.xlateVars+XLATEVARS.bHDSwap]
+	; Fall to DriveXlate_SwapDrive
+
+;--------------------------------------------------------------------
+; Swaps Hard Disk or Floppy Drive number.
+;
+; DriveXlate_SwapDrive
+;	Parameters:
+;		AL:		Drive number to swap to 00h/80h
+;		AH:		00h/80h to be swapped to stored drive number
+;		DL:		Drive number to be possibly swapped
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+DriveXlate_SwapDrive:
+	cmp		ah, dl				; Swap DL from 00h/80h to xxh?
+	je		SHORT .SwapToXXhInAL
+	cmp		al, dl				; Swap DL from xxh to 00h/80h?
+	je		SHORT .SwapTo00hOr80hInAH
+	ret
+ALIGN JUMP_ALIGN
+.SwapTo00hOr80hInAH:
+	mov		dl, ah
+	ret
+ALIGN JUMP_ALIGN
+.SwapToXXhInAL:
+	mov		dl, al
+	ret
+
+
+;--------------------------------------------------------------------
+; Resets drive swapping variables to defaults (no swapping).
+;
+; DriveXlate_Reset
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+DriveXlate_Reset:
+	mov		WORD [RAMVARS.xlateVars], 8000h	; .bFDSwap and .bHDSwap
+	mov		BYTE [RAMVARS.xlateVars+XLATEVARS.bRecurCnt], 0
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores drive to be swapped.
+;
+; DriveXlate_SetDriveToSwap
+;	Parameters:
+;		DL:		Drive to swap to 00h or 80h
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+DriveXlate_SetDriveToSwap:
+	test	dl, 80h				; Floppy drive?
+	jnz		SHORT DriveXlate_SetHardDiskToSwap
+	; Fall to DriveXlate_SetFloppyDriveToSwap
+
+;--------------------------------------------------------------------
+; Stores floppy drive to be swapped.
+;
+; DriveXlate_SetFloppyDriveToSwap
+;	Parameters:
+;		DL:		Drive to swap to 00h
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+DriveXlate_SetFloppyDriveToSwap:
+	mov		[RAMVARS.xlateVars+XLATEVARS.bFDSwap], dl
+	ret
+
+;--------------------------------------------------------------------
+; Stores hard disk to be swapped.
+;
+; DriveXlate_SetHardDiskToSwap
+;	Parameters:
+;		DL:		Drive to swap to 80h
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+DriveXlate_SetHardDiskToSwap:
+	mov		[RAMVARS.xlateVars+XLATEVARS.bHDSwap], dl
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks if INT 13h function returns some value in DL
+; (other than the drive number that was also parameter).
+;
+; DriveXlate_DoesFunctionReturnSomethingInDL
+;	Parameters:
+;		AH:		INT 13h BIOS Function
+;		DL:		Drive number
+;	Returns:
+;		CF:		Set if something is returned in DL
+;				Cleared if only drive number parameter is returned in DL
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+DriveXlate_DoesFunctionReturnSomethingInDL:
+	cmp		ah, 08h			; AH=08h, Read Disk Drive Parameters?
+	je		SHORT DriveXlate_FunctionReturnsSomethingInDL
+	test	dl, 80h
+	jz		SHORT DriveXlate_DoesFloppyFunctionReturnSomethingInDL
+	; Fall to DriveXlate_DoesHardDiskFunctionReturnSomethingInDL
+
+;--------------------------------------------------------------------
+; Checks if INT 13h hard disk or floppy drive function returns some
+; value in DL other than the drive number that was also parameter).
+; Some functions return different values for hard disks and floppy drives.
+;
+; DriveXlate_DoesHardDiskFunctionReturnSomethingInDL
+; DriveXlate_DoesFloppyFunctionReturnSomethingInDL
+;	Parameters:
+;		AH:		INT 13h BIOS Function
+;		DL:		Hard Disk number
+;	Returns:
+;		CF:		Set if something is returned in DL
+;				Cleared if only drive number parameter is returned in DL
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+; ALIGN JUMP_ALIGN
+DriveXlate_DoesHardDiskFunctionReturnSomethingInDL:
+	cmp		ah, 15h			; AH=15h, Read Disk Drive Size?
+	je		SHORT DriveXlate_FunctionReturnsSomethingInDL
+DriveXlate_DoesFloppyFunctionReturnSomethingInDL:
+	clc
+	ret
+
+ALIGN JUMP_ALIGN
+DriveXlate_FunctionReturnsSomethingInDL:
+	stc
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/FloppyDrive.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/FloppyDrive.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/FloppyDrive.asm	(revision 37)
@@ -0,0 +1,139 @@
+; File name		:	FloppyDrive.asm
+; Project name	:	IDE BIOS
+; Created date	:	25.3.2010
+; Last update	:	28.7.2010
+; Author		:	Tomi Tilli
+; Description	:	Various floppy drive related functions that
+;					Boot Menu uses.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Checks is floppy drive handler installed to interrupt vector 40h.
+;
+; FloppyDrive_IsInt40hInstalled
+;	Parameters:
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		CF:		Set if INT 40h is installed
+;				Cleared if INT 40h is not installed
+;	Corrupts registers:
+;		BX, CX, DI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+FloppyDrive_IsInt40hInstalled:
+	cmp		WORD [es:INTV_FLOPPY_FUNC*4+2], 0C000h	; Any ROM segment?
+	cmc
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns floppy drive type.
+; PC/XT system do not support AH=08h but FLOPPY_TYPE_525_OR_35_DD
+; is still returned for them.
+;
+; FloppyDrive_GetType
+;	Parameters:
+;		DL:		Floppy Drive number
+;	Returns:
+;		BX:		Floppy Drive Type:
+;					FLOPPY_TYPE_525_OR_35_DD
+;					FLOPPY_TYPE_525_DD
+;					FLOPPY_TYPE_525_HD
+;					FLOPPY_TYPE_35_DD
+;					FLOPPY_TYPE_35_HD
+;					FLOPPY_TYPE_35_ED
+;		CF:		Set if AH=08h not supported (XT systems) or error
+;				Cleared if type read correctly (AT systems)
+;	Corrupts registers:
+;		AX, CX, DX, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetType:
+	mov		ah, 08h			; Get Drive Parameters
+	xor		bx, bx			; FLOPPY_TYPE_525_OR_35_DD when function not supported
+	int		INTV_FLOPPY_FUNC
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns number of Floppy Drives in system.
+;
+; FloppyDrive_GetCount
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Number of Floppy Drives
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetCount:
+	push	es
+	call	FloppyDrive_GetCountFromBIOS
+	jnc		SHORT .CompareToUserMinimum
+	call	FloppyDrive_GetCountFromBDA
+ALIGN JUMP_ALIGN
+.CompareToUserMinimum:
+	MAX_U	cl, [cs:ROMVARS.bMinFddCnt]
+	xor		ch, ch
+	pop		es
+	ret
+
+
+;--------------------------------------------------------------------
+; Reads Floppy Drive Count from BIOS.
+; Does not work on most XT systems. Call FloppyDrive_GetCountFromBDA
+; if this function fails.
+;
+; FloppyDrive_GetCountFromBIOS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CL:		Number of Floppy Drives
+;		CF:		Cleared if successfull
+;				Set if BIOS function not supported
+;	Corrupts registers:
+;		CH, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetCountFromBIOS:
+	push	di
+	push	dx
+	push	bx
+	push	ax
+
+	mov		ah, 08h					; Get Drive Parameters
+	xor		dx, dx					; Floppy Drive 00h
+	int		INTV_FLOPPY_FUNC
+	mov		cl, dl					; Number of Floppy Drives to CL
+
+	pop		ax
+	pop		bx
+	pop		dx
+	pop		di
+	ret
+
+
+;--------------------------------------------------------------------
+; Reads Floppy Drive Count (0...4) from BIOS Data Area.
+; This function should be used only if FloppyDrive_GetCountFromBIOS fails.
+;
+; FloppyDrive_GetCountFromBDA
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CL:		Number of Floppy Drives
+;	Corrupts registers:
+;		CH, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetCountFromBDA:
+	LOAD_BDA_SEGMENT_TO	es, cx
+	mov		cl, [es:BDA.wEquipment]			; Load Equipment WORD low byte
+	mov		ch, cl							; Copy it to CH
+	and		cx, 0C001h						; Leave bits 15..14 and 0
+	eROL_IM	ch, 2							; EW low byte bits 7..6 to 1..0
+	add		cl, ch							; CL = Floppy Drive count
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Initialize.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Initialize.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Initialize.asm	(revision 37)
@@ -0,0 +1,122 @@
+; File name		:	Initialize.asm
+; Project name	:	IDE BIOS
+; Created date	:	23.3.2010
+; Last update	:	23.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for initializing the BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Initializes the BIOS.
+; This function is called from main BIOS ROM search routine.
+;
+; Initialize_FromMainBiosRomSearch
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Initialize_FromMainBiosRomSearch:
+	pushf
+	push	es
+	push	ds
+	ePUSHA
+
+	call	Initialize_ShouldSkip
+	jc		SHORT .ReturnFromRomInit
+
+	ePUSH_T	ax, .ReturnFromRomInit		; Push return address
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_LATE
+	jnz		SHORT Initialize_PrepareLateInitialization
+	jmp		SHORT Initialize_AndDetectDrives
+
+ALIGN JUMP_ALIGN
+.ReturnFromRomInit:
+	ePOPA
+	pop		ds
+	pop		es
+	popf
+	retf
+
+
+;--------------------------------------------------------------------
+; Checks if user wants to skip ROM initialization.
+;
+; Initialize_ShouldSkip
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:		Set if ROM initialization is to be skipped
+;				Cleared to continue ROM initialization
+;	Corrupts registers:
+;		AX, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Initialize_ShouldSkip:
+	sti							; Enable interrupts
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	mov		al, [BDA.bKBFlgs1]	; Load shift flags
+	eSHR_IM	al, 3				; Set CF if CTRL is held down
+	ret
+
+
+;--------------------------------------------------------------------
+; Installs INT 19h boot loader handler for late initialization.
+;
+; Initialize_PrepareLateInitialization
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Initialize_PrepareLateInitialization:
+	LOAD_BDA_SEGMENT_TO	es, bx
+	mov		bl, INTV_BOOTSTRAP
+	mov		si, Int19h_LateInitialization
+	jmp		Interrupts_InstallHandlerToVectorInBXFromCSSI
+
+
+;--------------------------------------------------------------------
+; Initializes the BIOS variables and detects IDE drives.
+;
+; Initialize_AndDetectDrives
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All, including segments
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Initialize_AndDetectDrives:
+	call	DetectPrint_RomFoundAtSegment
+	call	RamVars_Initialize
+	call	RamVars_GetSegmentToDS
+	LOAD_BDA_SEGMENT_TO	es, ax
+	call	Interrupts_InitializeInterruptVectors
+	call	DetectDrives_FromAllIDEControllers
+	call	CompatibleDPT_CreateForDrives80hAnd81h
+	; Fall to .ResetDetectedDrives
+
+;--------------------------------------------------------------------
+; Resets all hard disks.
+;
+; Initialize_ResetDetectedDrives
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, DI
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+.ResetDetectedDrives:
+	jmp		AH0h_ResetHardDisksHandledByOurBIOS
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Interrupts.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Interrupts.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/Interrupts.asm	(revision 37)
@@ -0,0 +1,272 @@
+; File name		:	Interrupts.asm
+; Project name	:	IDE BIOS
+; Created date	:	23.8.2010
+; Last update	:	23.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for initializing the BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Interrupts_InitializeInterruptVectors
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All except segments
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+Interrupts_InitializeInterruptVectors:
+	call	Interrupts_InitializeInt13hAnd40h
+	call	Interrupts_InitializeInt19h
+	jmp		SHORT Interrupts_InitializeHardwareIrqHandlers
+
+
+;--------------------------------------------------------------------
+; Interrupts_Int13hAnd40h
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+Interrupts_InitializeInt13hAnd40h:
+	mov		ax, [es:INTV_DISK_FUNC*4]			; Load old INT 13h offset
+	mov		dx, [es:INTV_DISK_FUNC*4+2]			; Load old INT 13h segment
+	mov		[RAMVARS.fpOldI13h], ax				; Store old INT 13h offset
+	mov		[RAMVARS.fpOldI13h+2], dx			; Store old INT 13h segment
+	mov		bx, INTV_DISK_FUNC					; INT 13h interrupt vector offset
+	mov		si, Int13h_DiskFunctions			; Interrupt handler offset
+	call	Interrupts_InstallHandlerToVectorInBXFromCSSI
+
+	; Only store INT 13h handler to 40h if 40h is not already installed.
+	; At least AMI BIOS for 286 stores 40h handler by itself and calls
+	; 40h from 13h. That system locks to infinite loop if we copy 13h to 40h.
+	call	FloppyDrive_IsInt40hInstalled
+	jnc		SHORT .InitializeInt40h
+	ret
+
+;--------------------------------------------------------------------
+; .InitializeInt40h
+;	Parameters:
+;		DX:AX:	Ptr to old INT 13h handler
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+.InitializeInt40h:
+	mov		[es:INTV_FLOPPY_FUNC*4], ax		; Store offset
+	mov		[es:INTV_FLOPPY_FUNC*4+2], dx	; Store segment
+	ret
+
+
+;--------------------------------------------------------------------
+; Interrupts_InitializeInt19h
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+Interrupts_InitializeInt19h:
+	eMOVZX	bx, [cs:ROMVARS.bBootLdrType]	; Load boot loader type
+	mov		si, INTV_BOOTSTRAP				; 19h
+	xchg	bx, si							; SI=Loader type, BX=19h
+	jmp		[cs:si+.rgwSetupBootLoader]		; Jump to install selected loader
+ALIGN WORD_ALIGN
+.rgwSetupBootLoader:
+	dw		.SetupBootMenuLoader		; BOOTLOADER_TYPE_MENU
+	dw		.SetupSimpleLoader			; BOOTLOADER_TYPE_SIMPLE
+	dw		.SetupBootMenuLoader		; reserved
+	dw		.NoBootLoader				; BOOTLOADER_TYPE_NONE
+
+ALIGN JUMP_ALIGN
+.NoBootLoader:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_LATE
+	jnz		SHORT .SetupSimpleLoader	; Boot loader required for late initialization
+	ret
+ALIGN JUMP_ALIGN
+.SetupSimpleLoader:
+	mov		si, Int19h_SimpleBootLoader
+	jmp		Interrupts_InstallHandlerToVectorInBXFromCSSI
+ALIGN JUMP_ALIGN
+.SetupBootMenuLoader:
+	mov		si, Int19hMenu_BootLoader
+	jmp		Interrupts_InstallHandlerToVectorInBXFromCSSI
+
+
+;--------------------------------------------------------------------
+; Interrupts_InitializeHardwareIrqHandlers
+;	Parameters:
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI
+;--------------------------------------------------------------------		
+ALIGN JUMP_ALIGN
+Interrupts_InitializeHardwareIrqHandlers:
+	call	RamVars_GetIdeControllerCountToCX
+	mov		di, ROMVARS.ideVars0			; CS:SI points to first IDEVARS
+ALIGN JUMP_ALIGN
+.IdeControllerLoop:
+	eMOVZX	bx, BYTE [cs:di+IDEVARS.bIRQ]
+	add		di, BYTE IDEVARS_size			; Increment to next controller
+	call	.InstallLowOrHighIrqHandler
+	loop	.IdeControllerLoop
+	ret
+
+;--------------------------------------------------------------------
+; .InstallLowOrHighIrqHandler
+;	Parameters:
+;		BX:		IRQ number, 0 if IRQ disabled
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI
+;--------------------------------------------------------------------		
+ALIGN JUMP_ALIGN
+.InstallLowOrHighIrqHandler:
+	cmp		bl, 8
+	jae		SHORT .InstallHighIrqHandler
+	test	bl, bl
+	jnz		SHORT .InstallLowIrqHandler
+	ret		; IRQ not used
+
+;--------------------------------------------------------------------
+; .InstallHighIrqHandler
+;	Parameters:
+;		BX:		IRQ number (8...15)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI
+;--------------------------------------------------------------------		
+ALIGN JUMP_ALIGN
+.InstallHighIrqHandler:
+	add		bx, BYTE INTV_IRQ8 - 8			; Interrupt vector number
+	mov		si, HIRQ_InterruptServiceRoutineForIrqs8to15
+	jmp		SHORT Interrupts_InstallHandlerToVectorInBXFromCSSI
+
+;--------------------------------------------------------------------
+; .InstallLowIrqHandler
+;	Parameters:
+;		BX:		IRQ number (0...7)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI
+;--------------------------------------------------------------------		
+ALIGN JUMP_ALIGN
+.InstallLowIrqHandler:
+	add		bx, BYTE INTV_IRQ0				; Interrupt vector number
+	mov		si, HIRQ_InterruptServiceRoutineForIrqs2to7
+	; Fall to Interrupts_InstallHandlerToVectorInBXFromCSSI
+
+
+;--------------------------------------------------------------------
+; Interrupts_InstallHandlerToVectorInBXFromCSSI
+;	Parameters:
+;		BX:		Interrupt vector number (for example 13h)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;		CS:SI:	Ptr to interrupt handler
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+Interrupts_InstallHandlerToVectorInBXFromCSSI:
+	eSHL_IM	bx, 2					; Shift for DWORD offset
+	mov		[es:bx], si				; Store offset
+	mov		[es:bx+2], cs			; Store segment
+	ret
+
+
+;--------------------------------------------------------------------
+; Interrupts_UnmaskInterruptControllerForDriveInDSDI
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Interrupts_UnmaskInterruptControllerForDriveInDSDI:
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]
+	mov		al, [cs:bx+IDEVARS.bIRQ]
+	cmp		al, 8
+	jae		SHORT .UnmaskHighIrqController
+	test	al, al
+	jnz		SHORT .UnmaskLowIrqController
+	ret		; Interrupts disabled
+
+;--------------------------------------------------------------------
+; .UnmaskHighIrqController
+;	Parameters:
+;		AL:		IRQ number (8...15)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.UnmaskHighIrqController:
+	sub		al, 8				; Slave interrupt number
+	mov		dx, PORT_8259SL_IMR	; Load Slave Mask Register address
+	call	.ClearBitFrom8259MaskRegister
+	mov		al, 2				; Master IRQ 2 to allow slave IRQs
+	; Fall to .UnmaskLowIrqController
+
+;--------------------------------------------------------------------
+; .UnmaskLowIrqController
+;	Parameters:
+;		AL:		IRQ number (0...7)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.UnmaskLowIrqController:
+	mov		dx, PORT_8259MA_IMR	; Load Mask Register address
+	; Fall to .ClearBitFrom8259MaskRegister
+
+;--------------------------------------------------------------------
+; .ClearBitFrom8259MaskRegister
+;	Parameters:
+;		AL:		8259 interrupt index (0...7)
+;		DX:		Port address to Interrupt Mask Register
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+.ClearBitFrom8259MaskRegister:
+	push	cx
+	xchg	ax, cx				; IRQ index to CL
+	mov		ch, 1				; Load 1 to be shifted
+	shl		ch, cl				; Shift bit to correct position
+	not		ch					; Invert to create bit mask for clearing
+	in		al, dx				; Read Interrupt Mask Register
+	and		al, ch				; Clear wanted bit
+	out		dx, al				; Write modified Interrupt Mask Register
+	pop		cx
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/PrintString.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/PrintString.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Initialization/PrintString.asm	(revision 37)
@@ -0,0 +1,77 @@
+; File name		:	PrintString.asm
+; Project name	:	IDE BIOS
+; Created date	:	19.3.2010
+; Last update	:	31.3.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for printing strings used in this IDE BIOS.
+
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints string with formatting parameters.
+; Do not call PrintString_JumpToFormat!!! Jump there only!
+; 
+; PrintString_JumpToFormat
+;	Parameters:
+;		DH:		Number of bytes pushed to stack
+;		CS:SI:	Ptr to string to format
+;		Stack:	Parameters for formatting placeholders.
+;				Parameter for first placeholder must be pushed last
+;				(to top of stack).
+;				High word must be pushed first for 32-bit parameters.
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+PrintString_JumpToFormat:
+	mov		cx, ds				; Backup DS
+	push	cs					; Push string segment...
+	pop		ds					; ...and pop it to DS
+	mov		dl, ' '				; Min length character
+	call	Print_Format
+	mov		ds, cx				; Restore DS
+	eMOVZX	ax, dh				; Bytes in stack
+	add		sp, ax				; Clean stack
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints STOP terminated string from wanted segment.
+; 
+; PrintString_FromCS
+; PrintString_FromES
+; PrintString_FromDS
+;	Parameters:
+;		SI:		Offset to string to print
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+PrintString_FromCS:
+	push	ds
+	push	cs					; Push string segment...
+	pop		ds					; ...and pop it to DS
+	call	PrintString_FromDS
+	pop		ds
+	ret
+
+ALIGN JUMP_ALIGN
+PrintString_FromES:
+	push	ds
+	push	es					; Push string segment...
+	pop		ds					; ...and pop it to DS
+	call	PrintString_FromDS
+	pop		ds
+	ret
+
+ALIGN JUMP_ALIGN
+PrintString_FromDS:
+	mov		dx, si				; DS:DX now points to string
+	PRINT_STR_LEN
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/keys.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/keys.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/keys.asm	(revision 37)
@@ -0,0 +1,328 @@
+; File name		:	keys.asm
+; Project name	:	Keyboard library
+; Created date	:	17.11.2009
+; Last update	:	31.12.2009
+; Author		:	Tomi Tilli
+; Description	:	ASM library to for keyboard related functions.		
+
+;--------------- Equates -----------------------------
+
+; String library function to include
+%define USE_KEYS_STROKE			; Keys_GetStroke, Keys_IsStroke and Keys_WaitStroke
+;%define USE_KEYS_PRNTGETUINT	; Keys_PrintGetUint
+;%define USE_KEYS_PRNTGETYN		; Keys_PrintGetYN
+%define USE_KEYS_CLRBUFFER		; Keys_ClrBuffer
+
+; Some BIOS Scan Codes
+KEY_BSC_F1		EQU		3Bh
+KEY_BSC_F2		EQU		3Ch
+KEY_BSC_F3		EQU		3Dh
+KEY_BSC_F4		EQU		3Eh
+KEY_BSC_F5		EQU		3Fh
+KEY_BSC_F6		EQU		40h
+KEY_BSC_F7		EQU		41h
+KEY_BSC_F8		EQU		42h
+KEY_BSC_F9		EQU		43h
+KEY_BSC_F10		EQU		44h
+KEY_BSC_F11		EQU		57h
+KEY_BSC_F12		EQU		58h
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+
+;--------------------------------------------------------------------
+; Checks is keystroke available in keyboard buffer.
+; 
+; Keys_GetStroke	Removes key from buffer if keystroke available
+; Keys_IsStroke		Does not remove key from buffer
+; Keys_WaitStroke	Waits until keystroke is available and removes it from buffer
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		ASCII character (if keystroke available)
+;		AH:		BIOS scan code (if keystroke available)
+;		ZF:		Set if no keystroke available
+;				Cleared if keystroke available
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_STROKE
+ALIGN JUMP_ALIGN
+Keys_GetStroke:
+	call	Keys_IsStroke
+	jnz		Keys_WaitStroke
+	ret
+ALIGN JUMP_ALIGN
+Keys_IsStroke:
+	mov		ah, 01h				; Check for Keystroke
+	int		16h
+	ret
+ALIGN JUMP_ALIGN
+Keys_WaitStroke:
+	xor		ah, ah				; Get Keystroke
+	int		16h
+	test	ax, ax				; Clear ZF
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Reads keystokes, prints them and converts them to unsigned WORD
+; after user has pressed ENTER. Returned value is always valid unless
+; user has cancelled by pressing ESC.
+; 
+; Keys_PrintGetUint
+;	Parameters:
+;		CX:		Base (10=dec, 16=hex etc.)
+;		DX:		Max number of characters wanted
+;	Returns:
+;		DX:AX:	Unsigned DWORD that the user has entered
+;		CF:		Set if unsigned DWORD read successfully
+;				Cleared is user has cancelled
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_PRNTGETUINT
+ALIGN JUMP_ALIGN
+Keys_PrintGetUint:
+	push	es
+	push	di
+	push	si
+
+	; Reserve stack for buffer
+	inc		dx					; Increment for STOP char
+	push	ss					; Copy SS...
+	pop		es					; ...to ES
+	mov		si, sp				; Backup SP
+	sub		sp, dx				; Reserve buffer from stack
+	mov		di, sp				; ES:DI now points to buffer
+
+	; Get user inputted string
+	mov		bx, String_IsBaseChar
+	call	Keys_GetStrToBuffer
+	jnc		.Return				; Return if user cancellation
+
+	; Convert string to DWORD
+	call	String_StrToUInt	; Get DWORD to DX:AX
+	
+	; Return
+ALIGN JUMP_ALIGN
+.Return:
+	mov		sp, si				; Destroy stack buffer
+	pop		si
+	pop		di
+	pop		es
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Reads keystokes until Y or N is pressed.
+; CF will be set to match selection.
+; 
+; Keys_PrintGetYN
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AX:		'Y' if Y pressed
+;				'N' if N pressed
+;				Zero if ESC pressed
+;		CF:		Set if Y pressed
+;				Cleared if N or ESC pressed
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_PRNTGETYN
+ALIGN JUMP_ALIGN
+Keys_PrintGetYN:
+	call	Keys_WaitStroke		; Wait until keystroke
+	call	String_ToLower		; Char in AL to lower case
+	cmp		al, 'y'				; Y pressed?
+	je		.RetY				;  If so, return
+	cmp		al, 'n'				; N pressed?
+	je		.RetN				;  If so, return
+	cmp		al, ESC				; ESC pressed?
+	je		.RetEsc				;  If so, return N
+	call	Keys_Bell			; Play error sound
+	jmp		Keys_PrintGetYN		; Loop until right key pressed
+ALIGN JUMP_ALIGN
+.RetY:
+	mov		ax, 'Y'
+	stc
+	ret
+ALIGN JUMP_ALIGN
+.RetN:
+	mov		ax, 'N'
+	ret
+ALIGN JUMP_ALIGN
+.RetEsc:
+	xor		ax, ax
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Clears BIOS keystroke buffer.
+; 
+; Keys_ClrBuffer
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_CLRBUFFER
+ALIGN JUMP_ALIGN
+Keys_ClrBuffer:
+	call	Keys_GetStroke		; Get keystroke
+	jnz		Keys_ClrBuffer		; Loop if keystroke found in buffer
+	ret
+%endif
+
+
+;-------------- Private functions ---------------------
+
+;--------------------------------------------------------------------
+; Reads user inputted string to buffer. Character verification is
+; supported to ignore unwanted characters.
+; Function returns when ENTER or ESC will be pressed.
+; 
+; Keys_GetStrToBuffer
+;	Parameters:
+;		DX:		Buffer length in characters with STOP included
+;		ES:DI:	Ptr to buffer
+;		CS:BX:	Ptr to char verification function:
+;					Parameters:
+;						AL:		Character to verify
+;						CX:		Anything passed to Keys_GetStrToBuffer
+;					Returns:
+;						CF:		Set if character is wanted type
+;								Cleared if character is not wanted
+;					Corrupts registers:
+;						Nothing
+;	Returns:
+;		AX:		String length in characters without STOP
+;		CF:		Set if string has been read successfully
+;				Cleared if user cancellation
+;	Corrupts registers:
+;		DX
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_PRNTGETUINT
+ALIGN JUMP_ALIGN
+Keys_GetStrToBuffer:
+	push	di
+	push	si
+	dec		dx					; Decrement for STOP char
+	xor		si, si				; Zero char counter
+	cld							; STOSB to increment DI
+ALIGN JUMP_ALIGN
+.CharLoop:
+	call	Keys_WaitStroke		; Wait for keystroke
+	cmp		al, CR				; Enter pressed?
+	je		.End				;  If so, return (CF cleared)
+	cmp		al, ESC				; Esc pressed?
+	je		.Cancel				;  If so, jump to cancel
+	cmp		al, BS				; Backspace pressed?
+	je		.Backspace			;  If so, jump to process it
+	call	bx					; Is wanted character?
+	jnc		.Bell				;  If not, play error sound and wait next key
+
+	; Limit char count
+	cmp		si, dx				; Max number of chars entered?
+	jae		.CharLoop			;  If so, wait for ENTER or BACKSPACE
+
+	; Write base character in AL
+	stosb						; Store char from AL to [ES:DI]
+	inc		si					; Increment char count
+	push	dx
+	mov		dl, al				; Copy char to DL
+	PRINT_CHAR					; Print character
+	pop		dx
+	jmp		.CharLoop			; Jump to wait next char
+ALIGN JUMP_ALIGN
+.Bell:
+	call	Keys_Bell
+	jmp		.CharLoop			; Jump to wait next char
+ALIGN JUMP_ALIGN
+.Backspace:
+	call	Keys_Backspace
+	jmp		.CharLoop			; Jump to wait next char
+ALIGN JUMP_ALIGN
+.Cancel:
+	xor		si, si				; Zero string length (clear CF)
+	jmp		.Return
+ALIGN JUMP_ALIGN
+.End:
+	stc							; Set CF since success
+.Return:
+	mov		al, STOP			; End string
+	stosb
+	mov		ax, si				; String length
+	pop		si
+	pop		di
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Plays bell sound for invalid key presses.
+; 
+; Keys_Bell
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_PRNTGETUINT or USE_KEYS_PRNTGETYN
+ALIGN JUMP_ALIGN
+Keys_Bell:
+	push	dx
+	mov		dl, BELL
+	PRINT_CHAR
+	pop		dx
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Handles backspace key by removing last written character.
+; 
+; Keys_Backspace
+;	Parameters:
+;		SI:		Character counter
+;		ES:DI:	Ptr to buffer
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_KEYS_PRNTGETUINT
+ALIGN JUMP_ALIGN
+Keys_Backspace:
+	push	dx
+	test	si, si				; At the beginning?
+	jz		.Return				;  If so, return
+	dec		si					; Decrement char counter
+	dec		di					; Decrement offset to buffer
+	mov		dl, BS				; Write backspace
+	PRINT_CHAR
+	mov		dl, ' '				; Write space
+	PRINT_CHAR
+	mov		dl, BS				; Back again
+	PRINT_CHAR
+ALIGN JUMP_ALIGN
+.Return:
+	pop		dx
+	ret
+%endif
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/math.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/math.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/math.asm	(revision 37)
@@ -0,0 +1,184 @@
+; File name		:	math.asm
+; Project name	:	Math library
+; Created date	:	7.10.2009
+; Last update	:	1.1.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to for math related functions.		
+
+;--------------- Equates -----------------------------
+
+; String library function to include
+;%define USE_MATH_MULDWBYW		; Math_MulDWbyW
+%define USE_MATH_DIVDWBYW		; Math_DivDWbyW
+%define USE_MATH_REMTOTENTHS	; Math_RemToTenths
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+
+;--------------------------------------------------------------------
+; Macro to select lesser of two unsigned operands.
+; 
+; MIN_U
+;	Parameters:
+;		%1:		Operand 1
+;		%2:		Operand 2
+;	Returns:
+;		%1:		Lesser unsigned operand
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro MIN_U 2
+	cmp		%1, %2				; Is %1 smaller?
+	jb		%%Return			;  If so, return
+	mov		%1, %2				; Copy %2 to %1
+ALIGN JUMP_ALIGN
+%%Return:
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Macro to select greater of two unsigned operands.
+; 
+; MAX_U
+;	Parameters:
+;		%1:		Operand 1
+;		%2:		Operand 2
+;	Returns:
+;		%1:		Greater unsigned operand
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro MAX_U 2
+	cmp		%1, %2				; Is %1 greater?
+	ja		%%Return			;  If so, return
+	mov		%1, %2				; Copy %2 to %1
+ALIGN JUMP_ALIGN
+%%Return:
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Macro to select lesser and greater of two unsigned operands.
+; 
+; MINMAX_U
+;	Parameters:
+;		%1:		Operand 1
+;		%2:		Operand 2
+;	Returns:
+;		%1:		Lesser unsigned operand
+;		%2:		Greater unsigned operand
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro MINMAX_U 2
+	cmp		%1, %2				; Is %1 smaller?
+	jbe		%%Return			;  If so, return
+	xchg	%1, %2				; Exchange operands
+ALIGN JUMP_ALIGN
+%%Return:
+%endmacro
+
+
+;--------------------------------------------------------------------
+; DWORD * WORD multiplication.
+; Multiplies unsigned 32-bit integer by unsigned 16-bit integer.
+; Result is unsigned 32-bit integer, so overflow is possible.
+; 
+; Math_MulDWbyW
+;	Parameters:
+;		DX:AX:	32-bit unsigned integer to multiply
+;		CX:		16-bit unsigned multiplier
+;	Returns:
+;		DX:AX:	32-bit unsigned integer
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_MATH_MULDWBYW
+ALIGN JUMP_ALIGN
+Math_MulDWbyW:
+	jcxz	.RetZero			; If CX=0, return 0
+	push	bx
+	mov		bx, dx				; Copy hiword to BX
+	xor		dx, dx				; Zero DX for multiplication
+	mul		cx					; DX:AX = AX (loword) * CX (multiplier)
+	push	dx					; Push possible overflow
+	xchg	ax, bx				; => AX=old hiword, BX=new loword
+	xor		dx, dx				; Zero DX for division
+	mul		cx					; DX:AX = AX (hiword) * CX (multiplier)
+	pop		dx					; Pop possible overflow from first mul
+	add		dx, ax				; Add new hiword to overflow from first mul
+	mov		ax, bx				; Copy new loword to AX
+	pop		bx
+	ret
+ALIGN JUMP_ALIGN
+.RetZero:						; Return 0 in DX:AX
+	xor		ax, ax
+	xor		dx, dx
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Divide a 32-bit unsigned integer so that quotient can be 32-bit.
+; 
+; Math_DivDWbyW
+;	Parameters:
+;		DX:AX:	32-bit unsigned divident
+;		CX:		16-bit unsigned divisor
+;	Returns:
+;		DX:AX:	32-bit unsigned quotient
+;		BX:		16-bit unsigned remainder
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_MATH_DIVDWBYW
+ALIGN JUMP_ALIGN
+Math_DivDWbyW:
+	mov		bx, ax
+	mov		ax, dx
+	xor		dx, dx
+	div		cx
+	xchg	ax, bx
+	div		cx
+	xchg	dx, bx
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Converts remainder to tenths.
+; 
+; Math_RemToTenths
+;	Parameters:
+;		BX:		16-bit unsigned remainder
+;		CX:		16-bit unsigned divisor used when calculated the remainder (max 2559)
+;	Returns:
+;		BX:		Remainder converted to tenths
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_MATH_REMTOTENTHS
+ALIGN JUMP_ALIGN
+Math_RemToTenths:
+	push	cx
+	push	ax
+	mov		ax, cx				; Copy divisor to AX
+	mov		cl, 10				; Load 10 to CL
+	div		cl					; AL = Divisor divided by 10
+	inc		ax					; Increment to compensate new remainder
+	xchg	ax, bx				; AX = 16-bit remainder to convert
+								; BL = Original divisor divided by 10
+	div		bl					; AX = Original remainder converted to tenths
+	eMOVZX	bx, al				; Copy return value to BX
+	pop		ax
+	pop		cx
+	ret
+%endif
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menu.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menu.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menu.asm	(revision 37)
@@ -0,0 +1,720 @@
+; File name		:	menu.asm
+; Project name	:	Menu library
+; Created date	:	9.11.2009
+; Last update	:	21.1.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to menu system.
+;
+;					Menu.asm contains function to be called from
+;					user code. Functions in other menu source files
+;					are only to be called by menu library itself!
+
+; Optional features.
+;%define USE_MENU_DIALOGS		; All dialogs
+;%define USE_MENU_SETSEL		; Menu_SetSel
+;%define USE_MENU_TOGGLEINFO	; Menu_ToggleInfo
+%define USE_MENU_INVITEMCNT		; Menu_InvItemCnt
+
+; Include other menu source files.
+%include "menudraw.asm"
+%include "menucrsr.asm"
+%include "menuloop.asm"
+%ifdef USE_MENU_DIALOGS
+	%include "menumsg.asm"
+	%include "menudlg.asm"
+	%include "menuprog.asm"
+	%include "menufile.asm"
+%endif
+
+;--------------- Equates -----------------------------
+
+; Menu Initialization Variables.
+; Menu must always be initialized to stack.
+struc MENUVARS
+	; Menu size set by user
+	.wSize:
+	.bWidth		resb	1	; Menu full width in chars (borders included)
+	.bHeight	resb	1	; Menu full height in chars (borders included)
+	.wTopDwnH:
+	.bTitleH	resb	1	; Title height in chars (borders not included, 0=disabled)
+	.bInfoH		resb	1	; Info height in chars (borders not included, 0=disabled)
+	
+	; Menu callback system set by user
+	.fnEvent	resb	2	; Offset to event callback function
+	
+	; Menu library internal variables.
+	; Do not modify from outside menu library!
+	.wTimeInit	resb	2	; System time ticks for autoselect (0=disabled)
+	.wTimeout	resb	2	; System time ticks left for autoselect
+	.wTimeLast	resb	2	; System time ticks when last read
+	.wInitCrsr:				; Initial cursor coordinates
+	.bInitX		resb	1
+	.bInitY		resb	1
+
+	; Item related variables
+	.wItemCnt	resb	2	; Total number of items in menu
+	.wItemSel	resb	2	; Index of currently selected (pointed) menuitem
+	.wItemTop	resb	2	; Index of first visible menuitem
+	.bVisCnt	resb	1	; Maximum number of visible menuitems
+	.bFlags		resb	1	; Menu flags
+
+	; User specific variables start here.
+	; 4-byte user pointer is stored here if menu created with Menu_Enter.
+	; Data is user specific if menu was created directly with Menu_Init.
+	.user		resb	0
+endstruc
+
+; Screen row count (can be used to limit max menu height)
+CNT_SCRN_ROW	EQU		25	; Number of rows on screen
+
+; Menu flags
+FLG_MNU_EXIT	EQU	(1<<0)	; Set when menu operation is to be stopped
+FLG_MNU_NOARRW	EQU	(1<<1)	; Do not draw item selection arrow
+FLG_MNU_HIDENFO	EQU	(1<<2)	; Hide menu information
+
+; Menu update and invalidate flags
+MFL_UPD_TITLE	EQU	(1<<0)	; Update title string(s)
+MFL_UPD_NFO		EQU	(1<<1)	; Update info string(s)
+MFL_UPD_ITEM	EQU	(1<<2)	; Update item string(s)
+MFL_UPD_NOCLEAR	EQU	(1<<4)	; Do not clear old chars (prevents flickering)
+
+
+;--------------------------------------------------------------------
+; Event callback function prototype.
+;
+; MENUVARS.fnEvent
+;	Parameters:
+;		BX:			Callback event
+;		CX:			Menuitem index (usually index of selected Menuitem)
+;		DX:			Event parameter (event specific)
+;		SS:BP:		Ptr to MENUVARS
+;		Other regs:	Undefined
+;	Returns:
+;		AH:			Event specific or unused. Set to 0 if unused.
+;		AL:			1=Event processed
+;					0=Event not processed (default action if any)
+;		Other regs:	Event specific or unused.
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+EVNT_MNU_EXIT		EQU	0		; Menu will quit
+								;	Ret AH:	1 to cancel exit
+								;			0 to allow menu exit
+EVNT_MMU_SELCHG		EQU	1		; Menuitem selection changed (with arrows)
+EVNT_MNU_SELSET		EQU	2		; Menuitem selected (with Enter)
+EVNT_MNU_KEY		EQU	3		; Keyboard key pressed
+								;	DH: BIOS Scan Code
+								;	DL: ASCII Char (if any)
+EVNT_MNU_UPD		EQU	4		; Menu needs to be updated (use currect cursor position)
+								;	DL:	MFL_UPD_TITLE set to update title string
+								;		MFL_UPD_NFO set to update info string
+								;		MFL_UPD_ITEM Set to update menuitem string
+								;			CX: Index of Menuitem to update
+EVNT_MNU_GETDEF		EQU	5		; Request menuitem to be selected by default
+								;	Ret CX:	Index of menuitem to select
+EVNT_MNU_INITDONE	EQU	6		; Menu has been initialized (created) but not yet drawn
+
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+
+;--------------------------------------------------------------------
+; Enters menu or submenu. Menu_Init does not have to be called
+; if this function is used to enter menu or submenu.
+; Menu_Init need to be called only when creating stack frame manually.
+; Manual creation allows custom menu position and user defined variables.
+;
+; Menu_Enter
+;	Parameters:
+;		AL:		Menu width with borders included
+;		AH:		Menu height with borders included
+;		BL:		Title line count (0=disable title)
+;		BH:		Info line count (0=disable info)
+;		CL:		Number of menuitems in top menu
+;		CH:		Menu flags
+;		DX:		Selection timeout in milliseconds (0=timeout disabled)
+;		DS:SI:	User specific far pointer (will be stored to MENUVARS.user)
+;		CS:DI:	Pointer to menu event handler function
+;	Returns:
+;		CX:		Index of last pointed Menuitem (not necessary selected with ENTER)
+;				FFFFh if cancelled with ESC
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_Enter:
+	; Create stack frame
+	eENTER	MENUVARS_size+4, 0
+	sub		bp, MENUVARS_size+4	; Point to MENUVARS
+
+	; Initialize menu variables
+	mov		[bp+MENUVARS.wSize], ax
+	mov		[bp+MENUVARS.wTopDwnH], bx
+	mov		[bp+MENUVARS.fnEvent], di
+	mov		[bp+MENUVARS.user], si
+	mov		[bp+MENUVARS.user+2], ds
+
+	; Prepare to call Menu_Init
+	push	dx					; Store timeout
+	call	MenuCrsr_GetCenter	; Get centered coordinates to DX
+	pop		ax					; Restore timeout to AX
+	xor		bx, bx				; Zero BX
+	xchg	bl, ch				; Menu flags to BL, Item count to CX
+	call	Menu_Init
+
+	; Destroy stack frame
+	add		bp, MENUVARS_size+4	; Point to old BP
+	eLEAVE						; Destroy stack frame
+	ret
+
+
+;--------------------------------------------------------------------
+; Initialize Menu.
+; This function returns only after Menu_Exit has been called from
+; event callback function (MENUVARS.fnEvent).
+; Caller must clean MENUVARS from stack once this function returns!
+;
+; Multiple menus can be created to implement submenus.
+;
+; Menu_Init
+;	Parameters:
+;		AX:		Selection timeout (ms, 0=timeout disabled)
+;		BL:		Menu flags
+;		CX:		Number of menuitems in top menu
+;		DX:		Top left coordinate for menu
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		CX:		Index of last pointed Menuitem (not necessary selected with ENTER)
+;				FFFFh if cancelled with ESC
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_Init:
+	; Initialize internal variables
+	call	Menu_StartTimeout
+	xor		ax, ax						; Zero AX
+	mov		[bp+MENUVARS.wInitCrsr], dx
+	mov		[bp+MENUVARS.wItemCnt], cx
+	mov		[bp+MENUVARS.wItemSel], ax
+	mov		[bp+MENUVARS.wItemTop], ax
+	mov		[bp+MENUVARS.bFlags], bl
+
+	; Calculate number of visible menuitems
+	eMOVZX	ax, [bp+MENUVARS.bHeight]	; Load menu total height
+	times 2 dec	ax						; Decrement top and borders
+	or		ah, [bp+MENUVARS.bTitleH]	; Load title height
+	jz		.CheckInfo					;  If no title, check if info
+	sub		al, ah						; Subtract title lines
+	dec		ax							; Decrement item border
+ALIGN JUMP_ALIGN
+.CheckInfo:
+	xor		ah, ah						; Zero AH
+	or		ah, [bp+MENUVARS.bInfoH]	; Load info height
+	jz		.StoreVisible				;  If no info, jump to store
+	sub		al, ah						; Subtract info lines
+	dec		ax							; Decrement item border
+ALIGN JUMP_ALIGN
+.StoreVisible:
+	mov		[bp+MENUVARS.bVisCnt], al	; Store max visible menuitems
+
+	; Get default menuitem
+	mov		bx, EVNT_MNU_GETDEF
+	call	MenuLoop_SendEvent
+	test	al, al						; Default menuitem returned?
+	jz		.InitDone					;  If not, continue
+	mov		[bp+MENUVARS.wItemSel], cx	; Store default
+	eMOVZX	ax, [bp+MENUVARS.bVisCnt]	; Load one past last to be displayed
+	cmp		cx, ax						; Visible selection?
+	jb		.InitDone					;  If so, continue
+	mov		[bp+MENUVARS.wItemTop], cx	; Set selected to topmost
+
+	; Send EVNT_MNU_INITDONE event
+ALIGN JUMP_ALIGN
+.InitDone:
+	mov		bx, EVNT_MNU_INITDONE
+	call	MenuLoop_SendEvent
+
+	; Draw menu
+	call	MenuCrsr_Hide				; Hide cursor
+	mov		cx, -1						; Invalidate all menuitems
+	mov		dl, MFL_UPD_TITLE | MFL_UPD_ITEM | MFL_UPD_NFO
+	call	Menu_Invalidate
+
+	; Enter menu loop until Menu_Exit is called
+	call	MenuLoop_Enter
+	call	MenuCrsr_Show				; Show cursor again
+	mov		cx, [bp+MENUVARS.wItemSel]	; Load return value
+	ret
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Below functions are called only from event callback function ;
+; (MENUVARS.fnEvent)                                           ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;--------------------------------------------------------------------
+; Sets wanted menuitem selected and draws changes.
+;
+; Menu_SetSel
+;	Parameters:
+;		CX:		Index of menuitem to set selected
+;		SS:BP:	Ptr to MENUVARS for menu to refresh
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef USE_MENU_SETSEL
+ALIGN JUMP_ALIGN
+Menu_SetSel:
+	cmp		cx, [bp+MENUVARS.wItemCnt]	; Valid menuitem index?
+	jae		.Return						;  If not, return
+	mov		[bp+MENUVARS.wItemSel], cx	; Store new selected index
+
+	; Scroll if necessary
+	mov		ax, [bp+MENUVARS.wItemTop]	; Load index of topmost visible
+	MIN_U	ax, cx						; AX = new topmost visible
+	mov		[bp+MENUVARS.wItemTop], ax	; Store new topmost
+	add		al, [bp+MENUVARS.bVisCnt]	; AX to one past...
+	adc		ah, 0						; ...last visible
+	cmp		cx, ax						; After last visible?
+	jb		.SendSelChg					;  If not, continue
+	mov		[bp+MENUVARS.wItemTop], cx	; New selection to topmost
+
+	; Send EVNT_MMU_SELCHG message
+ALIGN JUMP_ALIGN
+.SendSelChg:
+	mov		bx, EVNT_MMU_SELCHG
+	call	MenuLoop_SendEvent
+
+	; Redraw changes
+	mov		cx, -1						; Invalidate all menuitems
+	mov		dl, MFL_UPD_ITEM
+	call	Menu_Invalidate
+.Return:
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Shows or hides menu information at the bottom of menu.
+;
+; Menu_ShowInfo		Enables menu information
+; Menu_HideInfo		Disables menu information
+; Menu_ToggleInfo	Enables or disables menu information
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS for menu
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+%ifdef USE_MENU_TOGGLEINFO
+ALIGN JUMP_ALIGN
+Menu_ShowInfo:
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_HIDENFO
+	jnz		Menu_ToggleInfo
+	ret
+ALIGN JUMP_ALIGN
+Menu_HideInfo:
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_HIDENFO
+	jz		Menu_ToggleInfo
+	ret
+ALIGN JUMP_ALIGN
+Menu_ToggleInfo:
+	xor		BYTE [bp+MENUVARS.bFlags], FLG_MNU_HIDENFO
+	; Fall to Menu_RefreshMenu
+%endif
+
+
+;--------------------------------------------------------------------
+; Refreshes menu. This function must be called when
+; call to submenu Menu_Enter (or Menu_Init) returns.
+;
+; Menu_RefreshMenu
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS for menu to refresh
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_RefreshMenu:
+	push	cx
+	call	MenuCrsr_Hide				; Hide cursor
+	call	Menu_RestartTimeout			; Restart selection timeout
+	call	Menu_GetTime				; Get system time ticks to CX:DX
+	mov		[bp+MENUVARS.wTimeLast], dx	; Store last time updated
+	call	Keys_ClrBuffer				; Clear keyboard buffer
+	call	MenuDraw_ClrScr				; Clear screen
+	mov		cx, -1						; Invalidate all menuitems
+	mov		dl, MFL_UPD_TITLE | MFL_UPD_NFO | MFL_UPD_ITEM
+	call	Menu_Invalidate				; Redraw everything
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Destroy menu by causing Menu_Init to return.
+;
+; Menu_Exit
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		CF:		Set if user cancelled exit
+;				Cleared if user allowed exit
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_Exit:
+	mov		bx, EVNT_MNU_EXIT
+	call	MenuLoop_SendEvent
+	rcr		ah, 1					; AH bit 0 to CF
+	jc		.Return					; Do not exit if AH non-zero
+	or		BYTE [bp+MENUVARS.bFlags], FLG_MNU_EXIT	; (Clear CF)
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Invalidate any menu string.
+; Menu then sends EVNT_MNU_UPD events when necessary.
+;
+; Menu_InvItemCnt	Changes total item count and invalidates
+;	Parameters: (in addition to Menu_Invalidate)
+;		CX:		New Total item count
+; Menu_Invalidate
+;	Parameters:
+;		DL:		Invalidate flags (any combination is valid):
+;					MFL_UPD_NOCLEAR	Set to prevent clearing old chars
+;					MFL_UPD_TITLE	Invalidate menu title string
+;					MFL_UPD_NFO		Invalidate menu info string
+;					MFL_UPD_ITEM	Invalidate menuitem strings
+;						CX: Index of Menuitem to update
+;							-1 to update all menuitems
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef USE_MENU_INVITEMCNT
+ALIGN JUMP_ALIGN
+Menu_InvItemCnt:
+	xor		ax, ax
+	mov		[bp+MENUVARS.wItemCnt], cx
+	mov		[bp+MENUVARS.wItemSel], ax
+	mov		[bp+MENUVARS.wItemTop], ax
+	mov		cx, -1					; Invalidate all items
+	or		dl, MFL_UPD_ITEM
+%endif
+ALIGN JUMP_ALIGN
+Menu_Invalidate:
+	push	di
+	mov		di, dx
+	test	di, MFL_UPD_ITEM		; Invalidate Menuitems?
+	jz		.InvTitle				;  If not, jump to invalidate Title
+	cmp		cx, -1					; Redraw all menuitems?
+	je		.InvAllItems			;  If so, jump to draw
+	call	MenuCrsr_PointNthItem	; Set cursor position
+	call	MenuDraw_Item			; Draw single menuitem
+	jmp		.InvTitle				; Jump to invalidate Title
+ALIGN JUMP_ALIGN
+.InvAllItems:
+	test	di, MFL_UPD_NOCLEAR		; Keep background?
+	jnz		.DrawAllItems			;  If not, jump to draw
+	call	MenuDraw_ItemBorders	; Draw item borders
+ALIGN JUMP_ALIGN
+.DrawAllItems:
+	call	MenuDraw_AllItemsNoBord	; Draw items without borders
+
+ALIGN JUMP_ALIGN
+.InvTitle:
+	test	di, MFL_UPD_TITLE		; Invalidate Title?
+	jz		.InvInfo				;  If not, jump to invalidate Info
+	test	di, MFL_UPD_NOCLEAR		; Keep background?
+	jnz		.DrawTitle				;  If not, jump to draw
+	call	MenuDraw_TitleBorders	; Draw borders
+ALIGN JUMP_ALIGN
+.DrawTitle:
+	call	MenuDraw_TitleNoBord	; Draw title without borders
+
+ALIGN JUMP_ALIGN
+.InvInfo:
+	test	di, MFL_UPD_NFO			; Invalidate Info?
+	jz		.Return					;  If not, return
+	test	di, MFL_UPD_NOCLEAR		; Keep background?
+	jnz		.DrawInfo				;  If not, jump to draw
+	call	MenuDraw_InfoBorders	; Draw borders
+ALIGN JUMP_ALIGN
+.DrawInfo:
+	call	MenuDraw_InfoNoBord		; Draw info without borders
+ALIGN JUMP_ALIGN
+.Return:
+	pop		di
+	ret
+
+
+;--------------------------------------------------------------------
+; Starts or stops menu selection timeout.
+;
+; Menu_StopTimeout		; Stops timeout
+; Menu_StartTimeout		; Starts timeout with new value
+; Menu_RestartTimeout	; Restarts timeout with previous value
+;	Parameters:
+;		AX:		New timeout value in ms (for Menu_StartTimeout only)
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_StopTimeout:
+	xor		ax, ax
+ALIGN JUMP_ALIGN
+Menu_StartTimeout:
+	push	dx
+	push	bx
+	xor		dx, dx
+	mov		bx, 55						; 1 timer tick = 54.945ms
+	div		bx							; DX:AX / 55
+	mov		[bp+MENUVARS.wTimeInit], ax	; Store timer tick count
+	mov		[bp+MENUVARS.wTimeout], ax
+	pop		bx
+	pop		dx
+	ret
+ALIGN JUMP_ALIGN
+Menu_RestartTimeout:
+	mov		ax, [bp+MENUVARS.wTimeInit]
+	mov		[bp+MENUVARS.wTimeout], ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns system time in clock ticks. One tick is 54.95ms.
+;
+; Menu_GetTime
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		Midnight flag, set if midnight passed since last read
+;		CX:DX:	Number of clock ticks since midnight
+;	Corrupts registers:
+;		AH
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_GetTime:
+	xor		ah, ah				; Get System Time
+	int		1Ah
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks if Menuitem is currently visible.
+;
+; Menu_IsItemVisible
+;	Parameters:
+;		AX:		Menuitem index
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		CF:		Set if Menuitem is visible
+;				Cleared if Menuitem is not visible
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_IsItemVisible:
+	push	dx
+	mov		dx, [bp+MENUVARS.wItemTop]		; Load index of first visible
+	cmp		ax, dx							; First visible menuitem?
+	jb		.RetFalse						;  If below, return false
+	add		dl, [bp+MENUVARS.bVisCnt]		; Inc to one past...
+	adc		dh, 0							; ...last visible menuitem
+	cmp		ax, dx							; Over last visible?
+	jae		.RetFalse						;  If so, return false
+	pop		dx
+	ret										; Return with CF set
+ALIGN JUMP_ALIGN
+.RetFalse:
+	pop		dx
+	clc
+	ret
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Optional Dialog functions start here ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifdef USE_MENU_DIALOGS
+
+;--------------------------------------------------------------------
+; Shows message dialog to display string.
+; String can be multiple lines but line feeds will be determined
+; by menu system.
+;
+; Menu_ShowMsgDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Ptr to STOP terminated string to display
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowMsgDlg:
+	call	MenuMsg_ShowMessage
+	jmp		Menu_RefreshMenu
+
+
+;--------------------------------------------------------------------
+; Shows dialog that asks unsigned DWORD from user.
+;
+; Menu_ShowDWDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		CX:		Numeric base (10=dec, 16=hex...)
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Ptr to STOP terminated string to display
+;	Returns:
+;		DX:AX:	User inputted data
+;		CF:		Set if user data inputted successfully
+;				Cleared is input cancelled
+;	Corrupts registers:
+;		BX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowDWDlg:
+	mov		dx, MenuDlg_DWEvent	; Offset to event handler
+	call	MenuDlg_Show
+	push	ax
+	push	dx
+	pushf
+	call	Menu_RefreshMenu
+	popf
+	pop		dx
+	pop		ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Shows dialog that asks Y/N input from user.
+;
+; Menu_ShowYNDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Ptr to STOP terminated string to display
+;	Returns:
+;		AX:		'Y' if Y pressed
+;				'N' if N pressed
+;				Zero if ESC pressed
+;		CF:		Set if Y pressed
+;				Cleared if N or ESC pressed
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowYNDlg:
+	mov		dx, MenuDlg_YNEvent	; Offset to event handler
+	call	MenuDlg_Show
+	push	ax
+	pushf
+	call	Menu_RefreshMenu
+	popf
+	pop		ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Shows dialog that asks any string from user.
+;
+; Menu_ShowStrDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		CX:		Buffer length with STOP included
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Ptr to STOP terminated string to display
+;		DS:SI:	Prt to buffer to receive string
+;	Returns:
+;		AX:		String length in characters without STOP
+;		CF:		Set if string inputted successfully
+;				Cleared if user cancellation
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowStrDlg:
+	mov		dx, MenuDlg_StrEvent	; Offset to event handler
+	call	MenuDlg_Show
+	push	ax
+	pushf
+	call	Menu_RefreshMenu
+	popf
+	pop		ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Shows progress bar dialog.
+;
+; Menu_ShowProgDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		BH:		Dialog height with borders included
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Far ptr to user specified task function
+;		DS:SI:	User specified far pointer
+;	Returns:
+;		AX:		User specified return code
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowProgDlg:
+	call	MenuProg_Show
+	push	ax
+	call	Menu_RefreshMenu
+	pop		ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Shows dialog that user can use to select file.
+;
+; Menu_ShowFileDlg
+;	Parameters:
+;		BL:		Dialog width with borders included
+;		SS:BP:	Ptr to MENUVARS
+;		ES:DI:	Ptr to STOP terminated info string
+;		DS:SI:	Ptr to file search string (* and ? wildcards supported)
+;	Returns:
+;		DS:SI:	Ptr to DTA for selected file
+;		CF:		Set if file selected successfully
+;				Cleared if user cancellation
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Menu_ShowFileDlg:
+	call	MenuFile_ShowDlg
+	pushf
+	call	Menu_RefreshMenu
+	popf
+	ret
+
+
+%endif ; USE_MENU_DIALOGS
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menucrsr.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menucrsr.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menucrsr.asm	(revision 37)
@@ -0,0 +1,252 @@
+; File name		:	menucrsr.asm
+; Project name	:	Menu library
+; Created date	:	10.11.2009
+; Last update	:	17.1.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to menu system.
+;					Contains menu cursor functions.
+
+;--------------- Equates -----------------------------
+
+W_OFF_CRSR_STR	EQU		0102h	; User string cursor offset
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Returns X and Y coordinates for menu top left corner.
+; This function is used for calculating initial coordinates when
+; initializing menu for first time.
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		DL:		X coordinate for centered menu
+;		DH:		Y coordinate for centered menu
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_GetCenter:
+	mov		ah, 0Fh						; Get Current Video Mode
+	int		10h
+	mov		dl, ah						; Copy column count to DL
+	sub		dl, [bp+MENUVARS.bWidth]	; Subtract menu width from columns
+	shr		dl, 1						; Divide by 2 for start X
+	mov		dh, CNT_SCRN_ROW			; Load row count
+	sub		dh, [bp+MENUVARS.bHeight]	; Subtract menu height from rows
+	shr		dh, 1						; Divide by 2 for start y
+	ret
+
+
+;--------------------------------------------------------------------
+; Sets cursor to start of menu string.
+; MenuCrsr_Point1stItem		Sets cursor to first menuitem string
+; MenuCrsr_PointInfo		Sets cursor to info string
+; MenuCrsr_PointTitle		Sets cursor to title string
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_Point1stItem:
+	xor		dx, dx						; Zero DX
+	call	MenuCrsr_PointItemBrdr		; Point to item border (left)
+	mov		cx, W_OFF_CRSR_STR & 0FFh	; Offset to user string (move X only)
+	jmp		MenuCrsr_Move				; Move cursor
+ALIGN JUMP_ALIGN
+MenuCrsr_PointInfo:
+	xor		dx, dx						; Zero DX
+	call	MenuCrsr_PointNfoBrdr		; Point to Info border (top left)
+	mov		cx, W_OFF_CRSR_STR			; Movement from border to user str
+	jmp		MenuCrsr_Move				; Move cursor
+ALIGN JUMP_ALIGN
+MenuCrsr_PointTitle:
+	xor		dx, dx						; Zero DX
+	call	MenuCrsr_PointTitleBrdr		; Point to Title border (top left)
+	mov		cx, W_OFF_CRSR_STR			; Movement from border to user str
+	jmp		MenuCrsr_Move				; Move cursor
+
+
+;--------------------------------------------------------------------
+; Sets cursor to start of wanted menuitem string.
+;
+; MenuCrsr_PointNthItem
+;	Parameters:
+;		CX:		Menuitem index where to set cursor
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_PointNthItem:
+	push	cx
+	push	cx
+	call	MenuCrsr_Point1stItem		; Point to topmost menuitem
+	pop		cx
+	sub		cx, [bp+MENUVARS.wItemTop]	; Number of newlines needed
+	jcxz	.Return
+ALIGN JUMP_ALIGN
+.NewLineLoop:
+	call	MenuDraw_NewlineStr
+	loop	.NewLineLoop
+ALIGN JUMP_ALIGN
+.Return:
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Sets cursor to start of menu border.
+; MenuCrsr_PointBelowBrdr	Sets cursor to below menu bottom border
+; MenuCrsr_PointNfoBrdr		Sets cursor to top left corner of info borders
+; MenuCrsr_PointItemBrdr	Sets cursor to first menuitem left border
+; MenuCrsr_PointTitleBrdr	Sets cursor to top left corner of title borders
+;	Parameters:
+;		DX:		0
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_PointBelowBrdr:
+	mov		dh, [bp+MENUVARS.bInfoH]	; Load info height without borders
+	test	dh, dh						; Info displayed?
+	jz		.BottomOnly					; If not, continue
+	inc		dh							; Increment Y for top border
+ALIGN JUMP_ALIGN
+.BottomOnly:
+	inc		dh							; Increment Y for bottom border
+ALIGN JUMP_ALIGN
+MenuCrsr_PointNfoBrdr:
+	add		dh, [bp+MENUVARS.bVisCnt]	; Load max number of visible menuitems
+ALIGN JUMP_ALIGN
+MenuCrsr_PointItemBrdr:
+	inc		dh							; Add title top border
+	mov		al, [bp+MENUVARS.bTitleH]	; Load title height
+	add		dh, al						; Add title height to DH
+	test	al, al						; Title visible?
+	jz		MenuCrsr_PointTitleBrdr		;  If not, jump to set cursor
+	inc		dh							; Title bottom border
+ALIGN JUMP_ALIGN
+MenuCrsr_PointTitleBrdr:
+	add		dx, [bp+MENUVARS.wInitCrsr]	; Add initial cursor position
+	; Fall to MenuCrsr_SetCursor
+
+
+;--------------------------------------------------------------------
+; Sets cursor position in DX.
+;	Parameters:
+;		DL:		Cursor X coordinate
+;		DH:		Cursor Y coordinate
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_SetCursor:
+	xor		bx, bx						; Zero page
+	mov		ah, 02h						; Set Cursor Position and Size
+	int		10h
+	ret
+
+
+;--------------------------------------------------------------------
+; Return cursor position in DX.
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CL:		Cursor start scan line
+;		CH:		Cursor end scan line
+;		DL:		Cursor X coordinate
+;		DH:		Cursor Y coordinate
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_GetCursor:
+	xor		bx, bx						; Zero page
+	mov		ah, 03h						; Get Cursor Position and Size
+	int		10h
+	ret
+
+
+;--------------------------------------------------------------------
+; Moves cursor from current location.
+;	Parameters:
+;		CL:		Cursor X coordinate movement (can be negative)
+;		CH:		Cursor Y coordinate movement (can be negative)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_Move:
+	push	cx
+	call	MenuCrsr_GetCursor			; Get cursor position to DX
+	pop		cx
+	add		dl, cl						; Move X
+	add		dh, ch						; Move Y
+	jmp		MenuCrsr_SetCursor
+
+
+;--------------------------------------------------------------------
+; Shows cursor that has been hidden.
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_Show:
+	mov		cx, 0607h		; Two line cursor near or at the bottom of cell
+	jmp		MenuCrsr_SetShape
+
+
+;--------------------------------------------------------------------
+; Hides cursor.
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_Hide:
+	mov		cx, 2000h
+	; Fall to MenuCrsr_SetShape
+
+;--------------------------------------------------------------------
+; Sets cursor shape.
+;	Parameters:
+;		CL:		Cursor start scan line
+;		CH:		Cursor end scan line
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuCrsr_SetShape:
+	mov		ax, 0103h		; Set Text-Mode Cursor Shape
+							; AL=assumed video mode to prevent lock ups on some BIOSes
+	int		10h
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menudraw.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menudraw.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menudraw.asm	(revision 37)
@@ -0,0 +1,470 @@
+; File name		:	menudraw.asm
+; Project name	:	Menu library
+; Created date	:	9.11.2009
+; Last update	:	25.5.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to menu system.
+;					Contains menu drawing functions.
+
+;--------------- Equates -----------------------------
+
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+g_strTimeout:	db	B_LL,BHL_TVR,"Selection Timeout %us",TVL_BHR,STOP
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+
+;--------------------------------------------------------------------
+; Clears screen.
+;
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_ClrScr:
+	xor		dx, dx						; Cursor to (0,0)
+	call	MenuCrsr_SetCursor
+	mov		ah, 0Fh						; Get Current Video Mode
+	int		10h
+	mov		al, CNT_SCRN_ROW			; Load row count
+	mul		ah							; AX=Column count * row count
+	mov		cx, ax						; Copy char count to CX
+	mov		bx, ATTR_MDA_NORMAL			; Page zero, normal attribute
+	mov		ax, 0920h					; Write Char and attr, space char
+	int		10h
+	ret
+
+
+;--------------------------------------------------------------------
+; Changes line. When printing menu strings, this function must be
+; called instead of normal Print_Newline.
+;
+; MenuDraw_NewlineStrClrLn	Clear current line from cursor pos before newline
+; MenuDraw_NewlineStr
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_NewlineStrClrLn:
+	push	cx
+	call	MenuCrsr_GetCursor				; Get current cursor to DX
+	eMOVZX	cx, BYTE [bp+MENUVARS.bWidth]	; Load menu width
+	add		cl, [bp+MENUVARS.bInitX]		; Add menu start X coord
+	sub		cl, W_OFF_CRSR_STR & 0FFh		; Subtract right borders
+	sub		cl, dl							; Subtract current X coord
+	mov		dl, ' '							; Clear with space
+	call	Print_Repeat					; Clear line to the end
+	pop		cx
+ALIGN JUMP_ALIGN
+MenuDraw_NewlineStr:
+	push	cx
+	call	MenuCrsr_GetCursor				; Get current cursor to DX
+	mov		dl, [bp+MENUVARS.bInitX]		; Load X offset to border
+	add		dx, W_OFF_CRSR_STR				; Inc X and Y
+	call	MenuCrsr_SetCursor				; Set new cursor
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; Draws multiline Title or Info string.
+;
+; MenuDraw_MultilineStr
+;	Parameters:
+;		CX:		Max Title or Info line count (menu initialization params)
+;		ES:DI:	Ptr to STOP terminated string to display
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef USE_MENU_DIALOGS
+ALIGN JUMP_ALIGN
+MenuDraw_MultilineStr:
+	push	si
+	xor		si, si
+ALIGN JUMP_ALIGN
+.LineLoop:
+	xchg	cx, si							; Idx to CX, count to SI
+	push	cx
+	call	MenuMsg_WriteLine				; Write line
+	pop		cx
+	jc		.Return							;  Return if last token written
+	call	MenuDraw_NewlineStr				; Cursor to next line
+	inc		cx								; Increment line index
+	xchg	cx, si							; Count to CX, idx to SI
+	loop	.LineLoop						; Loop while lines left
+ALIGN JUMP_ALIGN
+.Return:
+	pop		si
+	ret
+%endif ; USE_MENU_DIALOGS
+
+
+;--------------------------------------------------------------------
+; Draws menu component.
+;
+; MenuDraw_Title			Draws Title borders and user string
+; MenuDraw_Info				Draws Info borders and user string
+; MenuDraw_AllItems			Draws Item borders and all user menuitems
+; MenuDraw_TitleNoBord		MenuDraw_Title without clearing old chars
+; MenuDraw_InfoNoBord		MenuDraw_Info without clearing old chars
+; MenuDraw_AllItemsNoBord	MenuDraw_AllItems without clearing old chars
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+;MenuDraw_Title:
+;	call	MenuDraw_TitleBorders			; Draw borders to clear old strings
+ALIGN JUMP_ALIGN
+MenuDraw_TitleNoBord:
+	cmp		BYTE [bp+MENUVARS.bTitleH], 0	; Any title strings?
+	jz		MenuDraw_NothingToDraw			;  If not, return
+	call	MenuCrsr_PointTitle				; Set cursor position
+	mov		dl, MFL_UPD_TITLE				; Update title string
+	jmp		MenuDraw_SendEvent
+
+;ALIGN JUMP_ALIGN
+;MenuDraw_Info:
+;	call	MenuDraw_InfoBorders			; Draw borders to clear old strings
+ALIGN JUMP_ALIGN
+MenuDraw_InfoNoBord:
+	cmp		BYTE [bp+MENUVARS.bInfoH], 0	; Any info strings?
+	jz		MenuDraw_NothingToDraw			;  If not, return
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_HIDENFO
+	jnz		MenuDraw_NothingToDraw			; Return if info is hidden
+	call	MenuCrsr_PointInfo				; Set cursor position
+	mov		dl, MFL_UPD_NFO					; Update title string
+	jmp		MenuDraw_SendEvent
+
+;ALIGN JUMP_ALIGN
+;MenuDraw_AllItems:
+;	call	MenuDraw_ItemBorders			; Draw borders to clear old strings
+ALIGN JUMP_ALIGN
+MenuDraw_AllItemsNoBord:	
+	cmp		WORD [bp+MENUVARS.wItemCnt], 0	; Any items to draw?
+	jz		MenuDraw_NothingToDraw			;  If not, return
+	call	MenuCrsr_Point1stItem			; Set cursor position
+	mov		cx, [bp+MENUVARS.wItemTop]		; Load idx of first menuitem to draw
+	eMOVZX	dx, BYTE [bp+MENUVARS.bVisCnt]	; Load number of visible menuitems
+	MIN_U	dx, [bp+MENUVARS.wItemCnt]		; Limit to item count
+	add		dx, cx							; One past last menuitem to draw
+ALIGN JUMP_ALIGN
+.DrawLoop:
+	push	dx
+	call	MenuDraw_Item					; Draw menuitem
+	pop		dx
+	inc		cx								; Increment menuitem index
+	cmp		cx, dx							; More items left?
+	jb		.DrawLoop						;  If so, loop
+	jmp		MenuDraw_NothingToDraw
+
+ALIGN JUMP_ALIGN
+MenuDraw_SendEvent:
+	mov		bx, EVNT_MNU_UPD				; Update string
+	call	MenuLoop_SendEvent
+ALIGN JUMP_ALIGN
+MenuDraw_NothingToDraw:
+	call	MenuCrsr_PointBelowBrdr			; Cursor to safe location
+	ret
+
+
+;--------------------------------------------------------------------
+; Draws Menuitem without borders.
+; This function does not set initial cursor position but does
+; change line for next menuitem!
+;
+; MenuDraw_Item
+;	Parameters:
+;		CX:		Index of menuitem to draw
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AL:		1=Menuitem drawed by user event handler
+;				0=Menuitem not drawed by user event handler
+;	Corrupts registers:
+;		AH, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_Item:
+	push	cx
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_NOARRW
+	jnz		.DrawString					; Don't draw arrow unless wanted
+	mov		dl, RARROW					; Prepare to draw selection arrow
+	cmp		cx, [bp+MENUVARS.wItemSel]	; Drawing selected item?
+	je		.DrawArrow					;  If so, jump to draw arrow
+	mov		dl, ' '						; Load space instead of arrow
+ALIGN JUMP_ALIGN
+.DrawArrow:
+	PRINT_CHAR
+	mov		dl, ' '						; Draw space before user str
+	PRINT_CHAR
+ALIGN JUMP_ALIGN
+.DrawString:
+	mov		dl, MFL_UPD_ITEM			; Draw item string
+	mov		bx, EVNT_MNU_UPD			; Update string
+	call	[bp+MENUVARS.fnEvent]		; Send event
+	call	MenuDraw_NewlineStr			; Move cursor to next menuitem
+	pop		cx
+	ret
+
+
+;-------------- Private functions --------------------
+
+;--------------------------------------------------------------------
+; Changes line. When printing menu borders, this function must be
+; called instead of normal Print_Newline.
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_NewlineBrdr:
+	call	MenuCrsr_GetCursor			; Get current cursor to DX
+	mov		dl, [bp+MENUVARS.bInitX]	; Load X offset to border
+	inc		dh							; Increment Y coordinate
+	jmp		MenuCrsr_SetCursor			; Set new cursor
+
+
+;--------------------------------------------------------------------
+; Draws menu borders. User strings will be cleared.
+;
+; MenuDraw_TitleBorders		Draws Title borders
+; MenuDraw_InfoBorders		Draws Info borders
+; MenuDraw_ItemBorders		Draws Item borders
+; MenuDraw_Timeout			Draw timeout border (not whole InfoBorders)
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_TitleBorders:
+	xor		dx, dx							; Zero DX
+	call	MenuCrsr_PointTitleBrdr			; Set cursor
+	call	MenuDraw_TopBorder				; Draw top border
+	call	MenuDraw_NewlineBrdr			; Change line
+	eMOVZX	cx, BYTE [bp+MENUVARS.bTitleH]	; Load number of title strings
+	jcxz	.Return							; Return if no title strings
+ALIGN JUMP_ALIGN
+.LineLoop:
+	push	cx
+	call	MenuDraw_StringBorder
+	call	MenuDraw_NewlineBrdr
+	pop		cx
+	loop	.LineLoop
+	jmp		MenuDraw_MiddleBorder			; Thin border before menuitems
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+ALIGN JUMP_ALIGN
+MenuDraw_InfoBorders:
+	xor		dx, dx							; Zero DX
+	call	MenuCrsr_PointNfoBrdr			; Set cursor
+	eMOVZX	cx, BYTE [bp+MENUVARS.bInfoH]	; Load number of info strings
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_HIDENFO	; Information hidden?
+	jnz		SHORT .JumpToBottomBorder
+	test	cx, cx							; Any info strings?
+	jz		SHORT MenuDraw_BottomBorder
+	push	cx
+	call	MenuDraw_MiddleBorder			; Draw middle border
+	call	MenuDraw_NewlineBrdr			; Change line
+	pop		cx
+ALIGN JUMP_ALIGN
+.LineLoop:
+	push	cx
+	call	MenuDraw_StringBorder
+	call	MenuDraw_NewlineBrdr
+	pop		cx
+	loop	.LineLoop
+ALIGN JUMP_ALIGN
+.JumpToBottomBorder:
+	jmp		SHORT MenuDraw_BottomBorder
+
+ALIGN JUMP_ALIGN
+MenuDraw_Timeout:
+	xor		dx, dx							; Zero DX
+	call	MenuCrsr_PointNfoBrdr			; Set cursor
+	mov		ch, [bp+MENUVARS.bInfoH]		; Load info str count to CH
+	and		cx, 0FF00h						; Any info strings? (clears CL)
+	jz		SHORT MenuDraw_BottomBorder		;  If not, draw bottom border
+	inc		ch								; Increment for info top border
+	call	MenuCrsr_Move					; Move cursor
+	jmp		SHORT MenuDraw_BottomBorder
+
+ALIGN JUMP_ALIGN
+MenuDraw_ItemBorders:
+	cmp		WORD [bp+MENUVARS.wItemCnt], BYTE 0	; Any items?
+	jz		SHORT .Return					;  If not, return
+	xor		dx, dx							; Zero DX
+	call	MenuCrsr_PointItemBrdr			; Set cursor
+	eMOVZX	cx, BYTE [bp+MENUVARS.bVisCnt]	; Load max number of item strings
+ALIGN JUMP_ALIGN
+.LineLoop:
+	push	cx
+	call	MenuDraw_ScrollBorder
+	call	MenuDraw_NewlineBrdr
+	pop		cx
+	loop	.LineLoop
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Draw horizontal border line to current cursor location.
+; MenuDraw_TopBorder	Draw thick top menu border
+; MenuDraw_StringBorder	Draw thick user string border
+; MenuDraw_ScrollBorder	Draw scrolling border for menuitems
+; MenuDraw_MiddleBorder	Draw thin middle menu border
+; MenuDraw_BottomBorder	Draw thick bottom menu border with timeout if set
+;	Parameters:
+;		CX:		Loop counter (Items left, MenuDraw_ScrollBorder only)
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_TopBorder:
+	mov		bh, B_TL
+	mov		bl, B_H
+	mov		dh, B_TR
+	jmp		SHORT MenuDraw_BorderChars
+	
+ALIGN JUMP_ALIGN
+MenuDraw_StringBorder:
+	mov		bh, B_V
+	mov		bl, ' '
+	mov		dh, B_V
+	jmp		SHORT MenuDraw_BorderChars
+
+ALIGN JUMP_ALIGN
+MenuDraw_ScrollBorder:
+	call	MenuDraw_GetScrollChar			; Load scroll char to DH
+	mov		bh, B_V
+	mov		bl, ' '
+	jmp		SHORT MenuDraw_BorderChars
+
+ALIGN JUMP_ALIGN
+MenuDraw_MiddleBorder:
+	mov		bh, BVL_THR
+	mov		bl, T_H
+	mov		dh, THL_BVR
+
+ALIGN JUMP_ALIGN
+MenuDraw_BorderChars:
+	mov		dl, bh							; Leftmost
+	PRINT_CHAR
+	eMOVZX	cx, BYTE [bp+MENUVARS.bWidth]
+	times 2 dec cx							; Subtract borders
+	mov		dl, bl							; Middle
+	call	Print_Repeat
+	mov		dl, dh							; Rightmost
+	PRINT_CHAR
+	ret
+
+ALIGN JUMP_ALIGN
+MenuDraw_BottomBorder:
+	mov		bh, B_LL
+	mov		bl, B_H
+	mov		dh, B_LR
+	cmp		WORD [bp+MENUVARS.wTimeInit], 0	; Timeout enabled?
+	jz		MenuDraw_BorderChars			;  If not, draw normal
+
+	; Print timeout value
+	push	ds
+	push	si
+	push	cs
+	pop		ds								; Copy CS to DS
+	mov		si, g_strTimeout				; Load ptr to timeout str (DS:SI)
+	mov		ax, 55							; 1 timer tick = 54.945ms
+	mul		WORD [bp+MENUVARS.wTimeout]		; DX:AX = millisecs
+	eSHR_IM	ax, 10							; ms to s (close enough to 1000)
+	push	ax								; Push seconds
+	call	Print_Format					; Print timeout
+	add		sp, 2							; Clean stack
+	pop		si
+	pop		ds
+
+	; Print remaining border chars
+	call	MenuCrsr_GetCursor				; Get cursor location to DX
+	sub		dl, [bp+MENUVARS.bInitX]		; Compensate for start X...
+	inc		dx								; ...and lower right corner
+	mov		dh, [bp+MENUVARS.bWidth]		; Load menu width to DH
+	sub		dh, dl							; Subtract current X coordinate
+	eMOVZX	cx, dh							; Number of border chars needed
+	mov		dl, B_H
+	call	Print_Repeat
+	mov		dl, B_LR
+	PRINT_CHAR
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns character for scroll bars if needed.
+; If scroll bars are not needed, normal border character will be returned.
+;
+; Note! Current implementation doesn't always return thumb character
+;		if there are a lot of pages. Checking last char only is not enough.
+;
+; MenuDraw_GetScrollChar
+;	Parameters:
+;		CX:		Loop counter (Items left, MenuDraw_ScrollBorder only)
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		DH:		Scroll bar character
+;	Corrupts registers:
+;		AX, BX, CX, DL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuDraw_GetScrollChar:
+	mov		dh, B_V						; Assume no scroll bars needed
+	mov		ax, [bp+MENUVARS.wItemCnt]	; Load menuitem count to AX
+	eMOVZX	bx, BYTE [bp+MENUVARS.bVisCnt]	; Load visible menuitems to BX
+	cmp		ax, bx						; Need scroll bars?
+	jbe		.Return						;  If not, return
+	
+	; Calculate last menuitem index for thumb char on this line
+	push	bx							; Store number of visible menuitems
+	sub		bx, cx						; Calculate Line index
+	inc		bx							; Increment for next line index
+	mul		bx							; DX:AX=Total item count * Next line idx
+	pop		bx							; Pop number of visible menuitems
+	div		bx							; AX=First Menuitem for next string line
+	dec		ax							; AX=Last Menuitem for this string line
+
+	; Draw thumb or track
+	mov		dh, FULL_BLCK				; Assume thumb line
+	call	Menu_IsItemVisible			; Is thumb menuitem visible?
+	jc		.Return						;  If so, draw thumb
+	mov		dh, T_V						; Load track character
+ALIGN JUMP_ALIGN
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menuloop.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menuloop.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/menu/menuloop.asm	(revision 37)
@@ -0,0 +1,335 @@
+; File name		:	menuloop.asm
+; Project name	:	Menu library
+; Created date	:	11.11.2009
+; Last update	:	25.5.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to menu system.
+;					Contains event dispatching loop.
+
+;--------------- Equates -----------------------------
+
+; BIOS scan codes
+KEY_ENTER		EQU		1Ch
+KEY_ESC			EQU		01h
+KEY_UP			EQU		48h
+KEY_DOWN		EQU		50h
+KEY_PGUP		EQU		49h
+KEY_PGDN		EQU		51h
+KEY_HOME		EQU		47h
+KEY_END			EQU		4Fh
+CNT_MENU_KEYS	EQU		8		; Number of menukeys
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+
+;--------------------------------------------------------------------
+; Waits keyboard input, updates timeout and dispatch event for
+; user handler.
+;	Parameters:
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuLoop_Enter:
+	; Get current time for timeout
+	call	Menu_GetTime					; Get system time ticks to CX:DX
+	mov		[bp+MENUVARS.wTimeLast], dx		; Store last read time
+
+	; Check if menu operation should be continued
+ALIGN JUMP_ALIGN
+.CheckExit:
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_EXIT
+	jnz		.Return							; Return if exit flag set
+
+	; Check if keystroke available
+	call	Keys_GetStroke					; Get keystroke to AX
+	jz		.CheckTimeout					; If no keystroke, jump to check timeout
+	call	MenuLoop_ProcessKey				; Convert keystroke to events
+
+	; Check if timeout needs updating
+ALIGN JUMP_ALIGN
+.CheckTimeout:
+	cmp		WORD [bp+MENUVARS.wTimeInit], 0	; Timeout enabled?
+	jz		.CheckExit						;  If not, loop
+	call	Menu_GetTime					; Get system time ticks to CX:DX
+	mov		cx, dx							; Copy time loword to CX
+	sub		dx, [bp+MENUVARS.wTimeLast]		; Has time changed?
+	je		.CheckExit						;  If not, loop
+
+	; Update timeout
+	mov		[bp+MENUVARS.wTimeLast], cx		; Store last update time
+	sub		[bp+MENUVARS.wTimeout], dx		; Update timeout
+	ja		.PrintTimeout					;  If time left, just print new value
+	call	MenuLoop_SendSelEvent			; Send selection event
+
+	; Print timeout value
+ALIGN JUMP_ALIGN
+.PrintTimeout:
+	call	MenuDraw_Timeout
+	xor		dx, dx
+	call	MenuCrsr_PointBelowBrdr
+	jmp		.CheckExit
+
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Sends Menu event to user handler (MENUVARS.fnEvent).
+; MenuLoop_SendSelEvent		Sends Menuitem Selected event to user event handler
+; MenuLoop_SendEvent		Sends any event to user event handler
+;	Parameters:
+;		BX:		Event code (MenuLoop_SendEvent only)
+;		DX:		Event parameter (event specific)
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		AH:		Event specific or unused
+;		AL:		1=Event processed
+;				0=Event not processed (default action if any)
+;	Corrupts registers:
+;		BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuLoop_SendSelEvent:
+	mov		bx, EVNT_MNU_SELSET
+ALIGN JUMP_ALIGN
+MenuLoop_SendEvent:
+	mov		cx, [bp+MENUVARS.wItemSel]
+	call	[bp+MENUVARS.fnEvent]
+	ret
+
+
+;-------------- Private functions ---------------------
+
+
+;--------------------------------------------------------------------
+; Processed menu key input.
+; Menu keys will be handled and other keys dispatched as key events.
+;	Parameters:
+;		AH:		BIOS Scan Code for key
+;		AL:		ASCII character
+;		SS:BP:	Ptr to MENUVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MenuLoop_ProcessKey:
+	push	es
+	push	di
+
+	; Check if wanted key
+	push	cs
+	pop		es					; Copy CS to ES
+	mov		cx, CNT_MENU_KEYS	; Load number of menu keys
+	mov		di, .rgbKeyToIdx	; Load offset to translation table
+	xchg	al, ah				; Scan code to AL
+	cld							; SCASB to increment DI
+	repne scasb					; Compare [ES:DI] to AL until match
+	jne		.Dispatch			; If not menukey, jump to dispatch
+
+	; Jump to process menu key
+	mov		di, CNT_MENU_KEYS-1	; Convert CX...	
+	sub		di, cx				; ...to lookup index
+	shl		di, 1				; Prepare for word lookup
+	jmp		[cs:di+.rgwMenuKeyJmp]
+
+	; Dispatch key event
+ALIGN JUMP_ALIGN
+.Dispatch:
+	xchg	al, ah				; Restore AX
+	mov		bx, EVNT_MNU_KEY
+	mov		dx, ax				; Copy keys to DX
+	call	MenuLoop_SendEvent
+ALIGN JUMP_ALIGN
+.Return:
+	pop		di
+	pop		es
+	ret
+
+	;;;;;;;;;;;;;;;;;;;;;
+	; Menu key handlers ;
+	;;;;;;;;;;;;;;;;;;;;;
+
+	; ENTER pressed
+ALIGN JUMP_ALIGN
+.KeyEnter:
+	call	MenuLoop_SendSelEvent			; Send selection event
+	jmp		.Return
+
+	; ESC pressed
+ALIGN JUMP_ALIGN
+.KeyEsc:
+	call	Menu_Exit
+	jc		.Return							; User cancelled exit
+	mov		WORD [bp+MENUVARS.wItemSel], -1
+	jmp		.Return
+
+	; UP pressed
+ALIGN JUMP_ALIGN
+.KeyUp:
+%ifdef USE_MENU_DIALOGS
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_NOARRW	; Message dialog mode?
+	jnz		.TextScrollUp					;  If so, go to text scrolling
+%endif
+	mov		ax, [bp+MENUVARS.wItemSel]		; Load selected index 
+	test	ax, ax							; Already at top?
+	jz		.KeyEnd							;  If so, go to end
+	mov		dx, ax							; Copy selected index to DX
+	dec		ax								; Decrement menuitem index
+	mov		[bp+MENUVARS.wItemSel], ax		; Store new index
+	cmp		ax, [bp+MENUVARS.wItemTop]		; Need to scroll?
+	jb		SHORT .ScrollUp
+	jmp		.DrawSelection					;  If not, go to draw selection
+ALIGN JUMP_ALIGN
+.ScrollUp:
+	dec		WORD [bp+MENUVARS.wItemTop]		; Scroll
+	jmp		.ScrollMenu
+
+%ifdef USE_MENU_DIALOGS
+ALIGN JUMP_ALIGN
+.TextScrollUp:
+	cmp		WORD [bp+MENUVARS.wItemTop], 0	; Already at the top?
+	jz		.Return							;  If so, return
+	dec		WORD [bp+MENUVARS.wItemTop]
+	jmp		.ScrollMenu
+%endif
+
+	; DOWN pressed
+ALIGN JUMP_ALIGN
+.KeyDown:
+%ifdef USE_MENU_DIALOGS
+	test	BYTE [bp+MENUVARS.bFlags], FLG_MNU_NOARRW	; Message dialog mode?
+	jnz		.TextScrollDown					;  If so, go to text scrolling
+%endif
+	mov		ax, [bp+MENUVARS.wItemSel]		; Load selected index
+	mov		dx, ax							; Copy selected index to DX
+	inc		ax								; Increment menuitem index
+	cmp		ax, [bp+MENUVARS.wItemCnt]		; Already at bottom?
+	je		.KeyHome						;  If so, go to beginning
+	mov		[bp+MENUVARS.wItemSel], ax		; Store new menuitem index
+	eMOVZX	bx, BYTE [bp+MENUVARS.bVisCnt]	; Load number of visible items
+	add		bx, [bp+MENUVARS.wItemTop]		; BX to one past last visible index
+	cmp		ax, bx							; Need to scroll?
+	jae		.ScrollDown
+	jmp		.DrawSelection
+ALIGN JUMP_ALIGN
+.ScrollDown:
+	inc		WORD [bp+MENUVARS.wItemTop]		; Scroll
+	jmp		.ScrollMenu
+
+%ifdef USE_MENU_DIALOGS
+ALIGN JUMP_ALIGN
+.TextScrollDown:
+	eMOVZX	ax, BYTE [bp+MENUVARS.bVisCnt]	; Load visible items
+	add		ax, [bp+MENUVARS.wItemTop]		; Add topmost menuitem index
+	cmp		ax, [bp+MENUVARS.wItemCnt]		; Already at the bottom?
+	jae		.Return							;  If so, return
+	inc		WORD [bp+MENUVARS.wItemTop]
+	jmp		.ScrollMenu
+%endif
+
+	; HOME pressed
+ALIGN JUMP_ALIGN
+.KeyHome:
+	xor		ax, ax
+	mov		[bp+MENUVARS.wItemSel], ax
+	mov		[bp+MENUVARS.wItemTop], ax
+	jmp		.ScrollMenu
+
+	; END pressed
+ALIGN JUMP_ALIGN
+.KeyEnd:
+	mov		ax, [bp+MENUVARS.wItemCnt]		; Load number if menuitems
+	mov		bx, ax							; Copy menuitem count to BX
+	dec		ax								; Decrement for last index
+	mov		[bp+MENUVARS.wItemSel], ax		; Store new selection
+	sub		bl, [bp+MENUVARS.bVisCnt]		; BX to first menuitem to draw
+	sbb		bh, 0
+	mov		[bp+MENUVARS.wItemTop], bx		; Store first menuitem to draw
+	jnc		.ScrollMenu	
+	mov		WORD [bp+MENUVARS.wItemTop], 0	; Overflow, start with 0
+	jmp		.ScrollMenu
+
+	; PGUP pressed
+ALIGN JUMP_ALIGN
+.KeyPgUp:
+	mov		ax, [bp+MENUVARS.wItemSel]		; Load selected index
+	div		BYTE [bp+MENUVARS.bVisCnt]		; AL=Current page index
+	sub		al, 1							; Decrement page
+	jc		.KeyHome						; Select first item if overflow
+	mul		BYTE [bp+MENUVARS.bVisCnt]		; AX=Fist menuitem on page
+	mov		[bp+MENUVARS.wItemSel], ax
+	mov		[bp+MENUVARS.wItemTop], ax
+	jmp		.ScrollMenu
+
+	; PGDN pressed
+ALIGN JUMP_ALIGN
+.KeyPgDn:
+	mov		ax, [bp+MENUVARS.wItemSel]		; Load selected index
+	div		BYTE [bp+MENUVARS.bVisCnt]		; AL=Current page index
+	inc		ax								; Increment page
+	mul		BYTE [bp+MENUVARS.bVisCnt]		; AX=First menuitem on page
+	eMOVZX	bx, BYTE [bp+MENUVARS.bVisCnt]	; Load number of visible items
+	add		bx, ax							; BX now one past last visible
+	cmp		bx, [bp+MENUVARS.wItemCnt]		; Went over last?
+	jae		.KeyEnd							;  If so, select last menuitem
+	mov		[bp+MENUVARS.wItemSel], ax
+	mov		[bp+MENUVARS.wItemTop], ax
+	; Fall to .ScrollMenu
+
+	; Menuitem selection changed, redraw all items
+ALIGN JUMP_ALIGN
+.ScrollMenu:
+	mov		bx, EVNT_MMU_SELCHG
+	call	MenuLoop_SendEvent
+	call	Menu_RestartTimeout
+	xor		cx, cx							; Invalidate...
+	dec		cx								; ...all menuitems
+	mov		dl, MFL_UPD_ITEM
+	call	Menu_Invalidate
+	jmp		.Return
+
+; Menuitem selection changed, only two items needs to be redrawn
+ALIGN JUMP_ALIGN
+.DrawSelection:
+	MINMAX_U ax, dx							; First menuitem to AX, next to DX
+	push	dx								; Store second to draw
+	push	ax								; Store first to draw
+	mov		bx, EVNT_MMU_SELCHG
+	call	MenuLoop_SendEvent
+	call	Menu_RestartTimeout
+	pop		cx								; First to draw to CX
+	call	MenuCrsr_PointNthItem			; Set cursor position
+	call	MenuDraw_Item					; Draw first menuitem
+	pop		cx								; Second to draw to CX
+	call	MenuDraw_Item					; Draw second menuitem
+	jmp		.Return
+
+ALIGN WORD_ALIGN
+.rgwMenuKeyJmp:
+	dw		.KeyEnter	; KEY_ENTER
+	dw		.KeyEsc		; KEY_ESC
+	dw		.KeyUp		; KEY_UP
+	dw		.KeyDown	; KEY_DOWN
+	dw		.KeyPgUp	; KEY_PGUP
+	dw		.KeyPgDn	; KEY_PGDN
+	dw		.KeyHome	; KEY_HOME
+	dw		.KeyEnd		; KEY_END
+; Scan code to jump index translation table
+.rgbKeyToIdx:	
+	db	KEY_ENTER,	KEY_ESC,	KEY_UP,		KEY_DOWN,
+	db	KEY_PGUP,	KEY_PGDN,	KEY_HOME,	KEY_END
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/print.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/print.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/print.asm	(revision 37)
@@ -0,0 +1,709 @@
+; File name		:	print.asm
+; Project name	:	Print library
+; Created date	:	6.10.2009
+; Last update	:	31.12.2009
+; Author		:	Tomi Tilli
+; Description	:	ASM library to for character and string
+;					printing related functions.
+
+;--------------- Equates -----------------------------
+
+; String library function to include
+%define USE_PRINT_FORMAT			; Print_Format
+%define USE_PRINT_NEWLINE			; Print_Newline
+;%define USE_PRINT_CHARBUFFER		; Print_CharBuffer
+%define USE_PRINT_REPEAT			; Print_Repeat
+;%define USE_PRINT_BOOL				; Print_Bool
+;%define USE_PRINT_INTSW			; Print_IntSW
+%define USE_PRINT_INTUW				; Print_IntUW
+;%define USE_PRINT_INTUDW			; Print_IntUDW
+%define USE_PRINT_INTHEXB			; Print_IntHexB
+%define USE_PRINT_INTHEXW			; Print_IntHexW
+;%define USE_PRINT_INTHEXDW			; Print_IntHexDW
+
+
+; Text mode character attribute byte bits for CGA+
+FLG_CGA_FG_B		EQU		(1<<0)
+FLG_CGA_FG_G		EQU		(1<<1)
+FLG_CGA_FG_R		EQU		(1<<2)
+FLG_CGA_FG_I		EQU		(1<<3)
+FLG_CGA_BG_B		EQU		(1<<4)
+FLG_CGA_BG_G		EQU		(1<<5)
+FLG_CGA_BG_R		EQU		(1<<6)
+FLG_CGA_BG_I		EQU		(1<<7)
+FLG_CGA_BG_BLNK		EQU		(1<<7)	; Blinking is default
+
+; Text mode character attribute bytes for MDA/Hercules (mono)
+; *Not displayed on some monitors
+ATTR_MDA_HIDDEN		EQU		00h	; Not displayed
+ATTR_MDA_ULINE		EQU		01h	; Underlined
+ATTR_MDA_NORMAL		EQU		07h	; Normal (white on black)
+ATTR_MDA_INT_U		EQU		09h	; High intensity, underlined
+ATTR_MDA_INT		EQU		0Fh	; High intensity
+ATTR_MDA_REVERSE	EQU		70h	; Reverse video (black on white)
+ATTR_MDA_BLNK		EQU		87h	; Blinking white on black*
+ATTR_MDA_BLNK_INT	EQU		8Fh	; Blinking high intensity*
+ATTR_MDA_BLNK_REV	EQU		0F0h; Blinking reverse video
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+g_rgbHex:		db	"0123456789ABCDEF"	; Hexadecimal printing
+g_rgbFormat:	; Placeholders for Print_Format
+%ifdef USE_PRINT_INTSW
+				db	'd'	; Prints signed 16-bit integer (WORD)
+%endif
+%ifdef USE_PRINT_INTUW
+				db	'u'	; Prints unsigned 16-bit integer (WORD)
+%endif
+%ifdef USE_PRINT_INTUDW
+				db	'U'	; Prints unsigned 32-bit integer (DWORD)
+%endif
+%ifdef USE_PRINT_INTHEXW
+				db	'x'	; Prints 8- or 16-bit hexadecimal (BYTE, WORD)
+%endif
+%ifdef USE_PRINT_INTHEXDW
+				db	'X'	; Prints 32-bit hexadecimal (DWORD)
+%endif
+				db	's'	; Prints string (DS segment)
+				db	'S'	; Prints string (far pointer)
+%ifdef USE_PRINT_BOOL
+				db	'b'	; Prints boolean value 0 or 1
+%endif
+				db	'c'	; Prints character
+				db	'C'	; Prints character number of times
+_g_rgbFormatEnd:
+
+; Number of different placeholders for Print_Format
+CNT_PLCEHLDRS		EQU		(_g_rgbFormatEnd-g_rgbFormat)
+
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+; Include one file to use DOS, BIOS or VRAM macros and functions
+;%include "prntdos.asm"			; Include to use DOS printing functions
+%include "prntbios.asm"			; Include to use BIOS printing functions
+;%include "prntvram.asm"			; Include to access VRAM directly
+
+
+;--------------------------------------------------------------------
+; Debugging macro that prints wanted character and newline.
+; 
+; PRINT_DBG_CH
+;	Parameters:
+;		%1:		Character to print
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro PRINT_DBG_CH 1
+	pushf
+	push	dx
+	push	ax
+	mov		dl, %1
+	PRINT_CHAR
+	;mov		dl, CR
+	;PRINT_CHAR
+	;mov		dl, LF
+	;PRINT_CHAR
+	pop		ax
+	pop		dx
+	popf
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Simplified printf-style string formatting function.
+; Strings must end to STOP character.
+; Supports following formatting types:
+;	%d		Prints signed 16-bit integer (WORD)
+;	%u		Prints unsigned 16-bit integer (WORD)
+;	%U		Prints unsigned 32-bit integer (DWORD)
+;	%x		Prints 8- or 16-bit hexadecimal (BYTE, WORD)
+;	%X		Prints 32-bit hexadecimal (DWORD)
+;	%s		Prints string (DS segment)
+;	%S		Prints string (far pointer)
+;	%b		Prints boolean value 0 or 1
+;	%c		Prints character
+;	%[num]C	Prints character number of times (up to 256, 0=256)
+;	%%		Prints '%' character (no parameter pushed)
+;
+;	Any placeholder can be set to minimum length by specifying
+;	minimum number of characters. For example %8d would append spaces
+;	after integer so that at least 8 characters would be printed.
+;
+;	NOTE! Caller must clean the stack variables!
+; 
+; Print_Format
+;	Parameters:
+;		DL:			Min length character (usually space)
+;		DS:SI:		Pointer to string to format
+;		Stack:		Parameters for formatting placeholders.
+;					Parameter for first placeholder must be pushed last
+;					(to top of stack).
+;					High word must be pushed first for 32-bit parameters.
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_FORMAT
+ALIGN JUMP_ALIGN
+Print_Format:
+	push	es
+	push	bp
+	push	di
+	push	cx
+	push	dx					; Push min length character
+	push	cs					; Copy CS...
+	pop		es					; ...to ES
+	mov		bp, sp				; Copy SP to BP
+	add		bp, 2*6				; Set BP to point first stack parameter
+	cld							; Set LODSB to increment SI
+ALIGN JUMP_ALIGN
+.PrintLoop:			; Load characters from string
+	lodsb						; Load char from DS:SI to AL, increment SI
+	xor		cx, cx				; Zero minimum length
+	cmp		al, STOP			; End of string?
+	je		.Return				;  If so, return
+	cmp		al, '%'				; Format placeholder?
+	je		.Format				;  If so, jump to format
+ALIGN JUMP_ALIGN
+.PrintChar:			; Prints single character from AL
+	mov		dl, al				; Copy character to DL
+	PRINT_CHAR					; Print character
+	mov		dx, 1				; One char printed
+ALIGN JUMP_ALIGN
+.PrintXtraSoMin:	; Checks how many spaces to append
+	sub		cx, dx				; Number of spaces needed
+	jle		.PrintLoop			; Read next character if no spaces needed
+	pop		dx					; Pop min length character to DL
+ALIGN JUMP_ALIGN
+.PrintSpaceLoop:	; Loop to print the required spaces
+	PRINT_CHAR
+	loop	.PrintSpaceLoop
+	push	dx					; Store min length character
+	jmp		.PrintLoop			; Jump to read next character
+ALIGN JUMP_ALIGN
+.Return:			; The only return point for this function
+	pop		dx
+	pop		cx
+	pop		di
+	pop		bp
+	pop		es
+	ret
+ALIGN JUMP_ALIGN
+.UpdateMinLen:		; Updates placeholder minimum length
+	mov		al, ah				; Copy digit to AL
+	mov		ah, cl				; Copy previous length to AH
+	aad							; AL=10*AH+AL, AH=0
+	mov		cx, ax				; Copy new length to CX
+ALIGN JUMP_ALIGN
+.Format:
+	lodsb						; Load char from DS:SI to AL, increment SI
+	cmp		al, STOP
+	je		.Return				; Invalid string
+	mov		ah, al				; Copy char to AH
+	sub		ah, '0'				; Possible digit char to digit
+	cmp		ah, 9				; Was valid digit?
+	jbe		.UpdateMinLen		;  If so, jump to update minimum length
+	push	cx					; Store number of spaces needed
+	mov		cx, CNT_PLCEHLDRS	; Load number of placeholders to CX
+	mov		di, g_rgbFormat		; Load offset to format placeholder table
+	repne scasb					; Compare AL to [ES:DI] until match
+	pop		cx					; Restore spaces needed
+	jne		.PrintChar			; If no match, jump to print character
+	sub		di, g_rgbFormat+1	; To placeholder index
+	shl		di, 1				; Shift for word lookup
+	jmp		[cs:di+.g_rgwFormJump]	; Jump to format
+
+%ifdef USE_PRINT_INTSW
+ALIGN JUMP_ALIGN
+.Print_d:	; Print signed 16-bit integer
+	mov		ax, [bp]			; Load word to print
+	times 2 inc	bp
+	call	Print_IntSW
+	jmp		.PrintXtraSoMin
+%endif
+%ifdef USE_PRINT_INTUW
+ALIGN JUMP_ALIGN
+.Print_u:	; Print unsigned 16-bit integer
+	mov		ax, [bp]			; Load word to print
+	times 2 inc	bp
+	call	Print_IntUW
+	jmp		.PrintXtraSoMin
+%endif
+%ifdef USE_PRINT_INTUDW
+ALIGN JUMP_ALIGN
+.Print_U:	; Print unsigned 32-bit integer
+	mov		ax, [bp]			; Load loword
+	mov		dx, [bp+2]			; Load hiword
+	add		bp, 4
+	call	Print_IntUDW
+	jmp		.PrintXtraSoMin
+%endif
+%ifdef USE_PRINT_INTHEXW
+ALIGN JUMP_ALIGN
+.Print_x:	; Prints 8- or 16-bit hexadecimal
+	mov		ax, [bp]			; Load word to print
+	times 2 inc	bp
+%ifdef USE_PRINT_INTHEXB
+	test	ah, ah				; 16-bit hexadecimal?
+	jnz		.Print_x16			;  If so, jump to print it
+	call	Print_IntHexB
+	jmp		.PrintXtraSoMin
+.Print_x16:
+%endif
+	call	Print_IntHexW
+	jmp		.PrintXtraSoMin
+%endif
+%ifdef USE_PRINT_INTHEXDW
+ALIGN JUMP_ALIGN
+.Print_X:	; Prints 32-bit hexadecimal
+	mov		ax, [bp]			; Load loword
+	mov		dx, [bp+2]			; Load hiword
+	add		bp, 4
+	call	Print_IntHexDW
+	jmp		.PrintXtraSoMin
+%endif
+ALIGN JUMP_ALIGN
+.Print_s:	; Prints string from DS segment
+	mov		dx, [bp]			; Load offset to string
+	times 2 inc	bp
+	PRINT_STR_LEN				; Print string
+	jmp		.PrintXtraSoMin
+ALIGN JUMP_ALIGN
+.Print_S:	; Prints string using far pointer
+	push	ds					; Store DS
+	mov		dx, [bp]			; Load offset to string
+	mov		ds, [bp+2]			; Load segment to string
+	add		bp, 4
+	PRINT_STR_LEN				; Print string
+	pop		ds					; Restore DS
+	jmp		.PrintXtraSoMin
+%ifdef USE_PRINT_BOOL
+ALIGN JUMP_ALIGN
+.Print_b:	; Prints boolean value
+	mov		ax, [bp]			; Load boolean value to print
+	times 2 inc	bp
+	call	Print_Bool
+	jmp		.PrintXtraSoMin
+%endif
+ALIGN JUMP_ALIGN
+.Print_c:	; Prints character
+	mov		ax, [bp]			; Load character to print
+	times 2 inc	bp
+	jmp		.PrintChar			; Jump to print character
+ALIGN JUMP_ALIGN
+.Print_C:
+	mov		dx, [bp]			; Load character to print
+	times 2 inc	bp
+ALIGN JUMP_ALIGN
+.CharLoop:
+	PRINT_CHAR
+	loop	.CharLoop
+	jmp		.PrintLoop
+
+ALIGN JUMP_ALIGN
+.g_rgwFormJump:					; Jump table for Print_Format
+%ifdef USE_PRINT_INTSW
+	dw		.Print_d
+%endif
+%ifdef USE_PRINT_INTUW
+	dw		.Print_u
+%endif
+%ifdef USE_PRINT_INTUDW
+	dw		.Print_U
+%endif
+%ifdef USE_PRINT_INTHEXW
+	dw		.Print_x
+%endif
+%ifdef USE_PRINT_INTHEXDW
+	dw		.Print_X
+%endif
+	dw		.Print_s
+	dw		.Print_S
+%ifdef USE_PRINT_BOOL
+	dw		.Print_b
+%endif
+	dw		.Print_c
+	dw		.Print_C
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints newline character to change line.
+; 
+; Print_Newline
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_NEWLINE
+ALIGN JUMP_ALIGN
+Print_Newline:
+	push	ax
+	push	dx
+	mov		dl, LF
+	PRINT_CHAR
+	mov		dl, CR
+	PRINT_CHAR
+	pop		dx
+	pop		ax
+	ret
+%endif
+	
+
+;--------------------------------------------------------------------
+; Prints wanted number of characters.
+; 
+; Print_CharBuffer
+;	Parameters:
+;		CX:		Number of characters to print
+;		ES:DI:	Ptr to character buffer
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_CHARBUFFER
+ALIGN JUMP_ALIGN
+Print_CharBuffer:
+	jcxz	.Return
+	push	ds
+	push	si
+	push	dx
+	push	es
+	pop		ds
+	mov		si, di
+	cld							; LODSB to increment SI
+ALIGN JUMP_ALIGN
+.Rep:
+	lodsb						; Load from [DS:SI] to AL
+	mov		dl, al				; Copy to DL for printing
+	PRINT_CHAR
+	loop	.Rep
+	pop		dx
+	pop		si
+	pop		ds
+.Return:
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Repeats wanted character.
+; 
+; Print_Repeat
+;	Parameters:
+;		CX:		Number of times to repeat character
+;		DL:		Character to repeat
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_REPEAT
+ALIGN JUMP_ALIGN
+Print_Repeat:
+	jcxz	.Return
+ALIGN JUMP_ALIGN
+.Rep:
+	PRINT_CHAR
+	loop	.Rep
+.Return:
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints boolean value.
+; 
+; Print_Bool
+;	Parameters:
+;		AX:		Boolean value (0=FALSE, non-zero=TRUE)
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_BOOL
+ALIGN JUMP_ALIGN
+Print_Bool:
+	mov		dl, '0'				; Assume FALSE
+	test	ax, ax				; Is FALSE?
+	jz		.Print				;  If so, jump to print
+	inc		dx					; Increment to '1'
+ALIGN JUMP_ALIGN
+.Print:
+	PRINT_CHAR
+	mov		dx, 1				; One character printed
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints signed or unsigned 16-bit integer.
+; 
+; Print_IntSW	Prints signed 16-bit word
+; Print_IntUW	Prints unsigned 16-bit word
+;	Parameters:
+;		AX:		Word to print
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTSW
+ALIGN JUMP_ALIGN
+Print_IntSW:
+	push	di					; Store DI
+	cmp		ax, 0				; Positive integer?
+	jge		Print_IntUW			;  If so, jump to print it
+	push	ax					; Store word
+	mov		dl, '-'				; Print '-'
+	PRINT_CHAR
+	mov		di, 1				; One character printed
+	pop		ax					; Restore word
+	neg		ax					; Negative to positive
+	jmp		Print_ContinueFromIntSW
+%endif
+
+%ifdef USE_PRINT_INTUW or USE_PRINT_INTSW
+ALIGN JUMP_ALIGN
+Print_IntUW:
+	push	di					; Store DI
+	xor		di, di				; Zero character counter
+Print_ContinueFromIntSW:
+	push	bx					; Store BX
+	push	cx					; Store CX
+	mov		bx, 10				; Load divisor to BX
+	mov		cx, 5				; Load number of divisions to CX
+ALIGN JUMP_ALIGN
+.DivLoop:
+	xor		dx, dx				; Zero DX for division
+	div		bx					; DX:AX / 10 => AX=quot, DX=rem
+	push	dx					; Push digit
+	loop	.DivLoop			; Loop to separate all characters
+	xor		bx, bx				; First char printed flag
+	mov		cl, 5				; Load number of characters to CL
+ALIGN JUMP_ALIGN
+.PrintLoop:
+	pop		dx					; Pop character to DX
+	or		bx, dx				; Still skipping zeroes?
+	loopz	.PrintLoop			;  If so, loop
+	add		dx, '0'				; Digit to character
+	PRINT_CHAR					; Print character
+	inc		di					; Increment chars printed
+	test	cx, cx				; Characters left
+	jnz		.PrintLoop			;  If so, loop
+	mov		dx, di				; Copy chars printed to DX
+	pop		cx
+	pop		bx
+	pop		di
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints unsigned 32-bit integer.
+; 
+; Print_IntUDW
+;	Parameters:
+;		DX:AX:	32-bit unsigned integer to print
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTUDW
+ALIGN JUMP_ALIGN
+Print_IntUDW:
+	push	di					; Store DI
+	push	si					; Store SI
+	push	bx					; Store BX
+	push	cx					; Store CX
+	mov		cx, 10				; Load divider to CX
+	mov		si, cx				; Load number of divisions (10) to SI
+	xor		di, di				; Zero DI (char counter)
+ALIGN JUMP_ALIGN
+.DivLoop:
+	call	Math_DivDWbyW		; DX:AX / 10 => DX:AX=quot, BX=rem
+	push	bx					; Push digit
+	dec		si					; Decrement number of divisions
+	jnz		.DivLoop			;  Loop while divisions left
+	xor		bx, bx				; First char printed flag
+ALIGN JUMP_ALIGN
+.PrintLoop:
+	pop		dx					; Pop character to DX
+	or		bx, dx				; Still skipping zeroes?
+	loopz	.PrintLoop			;  If so, loop
+	add		dx, '0'				; Digit to character
+	PRINT_CHAR					; Print character
+	inc		di					; Increment chars printed
+	test	cx, cx				; Characters left
+	jnz		.PrintLoop			;  If so, loop
+	mov		dx, di				; Copy characters printed to DX
+	pop		cx
+	pop		bx
+	pop		si
+	pop		di
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints 8-bit byte as hexadecimal string.
+; 
+; Print_IntHexB
+;	Parameters:
+;		AL:		8-bit BYTE to print
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTHEXB
+ALIGN JUMP_ALIGN
+Print_IntHexB:
+	push	bx
+	xor		ah, ah				; Zero AH, AX=word to print
+	mov		bx, 0FFh			; Set to print two digits
+	call	Print_HexString		; Print hex string
+	push	dx					; Store number of chars printed
+	mov		dl, 'h'				; Print 'h' at the end
+	PRINT_CHAR
+	pop		dx					; Restore number of chars printed
+	inc		dx					; Increment for 'h'
+	pop		bx
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints 16-bit word as hexadecimal string.
+; 
+; Print_IntHexW
+;	Parameters:
+;		AX:		16-bit WORD to print
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTHEXW
+ALIGN JUMP_ALIGN
+Print_IntHexW:
+	push	bx
+	xor		bx, bx				; Set to print all zeroes...
+	dec		bx					; ...BX = FFFFh
+	call	Print_HexString		; Print hex string
+	push	dx					; Store number of chars printed
+	mov		dl, 'h'				; Print 'h' at the end
+	PRINT_CHAR
+	pop		dx					; Restore number of chars printed
+	inc		dx					; Increment for 'h'
+	pop		bx
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prints 32-bit dword as hexadecimal string.
+; 
+; Print_IntHexDW
+;	Parameters:
+;		DX:AX:	32-bit DWORD to print
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTHEXDW
+ALIGN JUMP_ALIGN
+Print_IntHexDW:
+	push	cx
+	push	bx
+	push	ax					; Store loword
+	mov		ax, dx				; Copy hiword to AX
+	xor		bx, bx				; Set to print all zeroes...
+	dec		bx					; ...BX = FFFFh
+	call	Print_HexString		; Print hex string
+	mov		cx, dx				; Copy number of chars printed
+	pop		ax					; Pop loword
+	call	Print_HexString		; Print hex string
+	add		cx, dx				; Add number of chars printed
+	mov		dl, 'h'				; Print 'h' at the end
+	PRINT_CHAR
+	inc		cx					; Increment number of chars printed
+	mov		dx, cx				; Copy number of chars printed to DX
+	pop		bx
+	pop		cx
+	ret
+%endif
+
+
+;-------------- Private functions --------------------
+
+;--------------------------------------------------------------------
+; Prints hexadecimal character for every nybble for WORD.
+; 
+; Print_HexString
+;	Parameters:
+;		AX:		16-bit WORD to print
+;		BX:		Mask for zero nybbles to print:
+;				FFFFh	= prints all digits
+;				0FFFh	= does not print digit 3 if it is zero
+;				00FFh	= does not print digits 3 and 2 if both are zeroes
+;				000Fh	= prints only digit 0 if other are zeroes
+;				0000h	= prints nothing if value is zero
+;	Returns:
+;		DX:		Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%ifdef USE_PRINT_INTHEXB or USE_PRINT_INTHEXW or USE_PRINT_INTHEXDW
+ALIGN JUMP_ALIGN
+Print_HexString:
+	push	bp
+	push	di
+	push	si
+	push	cx
+
+	mov		di, ax				; Backup WORD to DI
+	mov		cl, 12				; Prepare to shift nybbles
+	xor		dx, dx				; Zero DX
+ALIGN JUMP_ALIGN
+.NybbleLoop:
+	mov		bp, bx				; Copy mask to BP
+	mov		si, di				; Copy WORD to SI
+	shr		bp, cl				; Shift wanted mask nybble to BP
+	shr		si, cl				; Shift wanted nybble to SI
+	and		bp, 0Fh				; Clear unwanted mask bits
+	and		si, 0Fh				; Clear unwanted bits
+	or		bp, si				; Skip zeroes in front?
+	jz		.SkipPrint			;  If so, skip printing
+	mov		dl, [cs:si+g_rgbHex]; Load char to DL
+	PRINT_CHAR					; Print character
+	inc		dh					; Increment characters printed
+.SkipPrint:
+	sub		cl, 4				; Prepare to shift next nybble
+	jnc		.NybbleLoop			; Loop while nybbles left
+	mov		dl, dh				; Copy chars printed to DL
+	xor		dh, dh				; Zero DH
+
+	pop		cx
+	pop		si
+	pop		di
+	pop		bp
+	ret
+%endif
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/prntbios.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/prntbios.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/prntbios.asm	(revision 37)
@@ -0,0 +1,109 @@
+; File name		:	prntbios.asm
+; Project name	:	Print library
+; Created date	:	7.12.2009
+; Last update	:	17.1.2010
+; Author		:	Tomi Tilli
+; Description	:	ASM library to for character and string
+;					printing using BIOS.
+
+;--------------- Equates -----------------------------
+
+; Int 10h (BIOS) functions
+FN_BIOS_WR_CHAR_TEL		EQU	0Eh	; Teletype Output
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints character. All character printing functions must
+; use this macro to print characters (so printing implementation
+; can be easily modified when needed).
+; 
+; PRINT_CHAR
+;	Parameters:
+;		DL:		Character to print
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%macro PRINT_CHAR 0
+	call	Print_BiosTeleChar
+%endmacro
+
+ALIGN JUMP_ALIGN
+Print_BiosTeleChar:
+	push	bp					; Save because of buggy BIOSes
+	push	bx
+	mov		ah, FN_BIOS_WR_CHAR_TEL
+	mov		al, dl				; Copy char to write
+	xor		bx, bx				; Page 0
+	int		10h
+	pop		bx
+	pop		bp
+	ret
+
+
+;--------------------------------------------------------------------
+; Prints string. All string printing functions must
+; use this macro to print strings (so printing implementation
+; can be easily modified when needed).
+; 
+; PRINT_STR
+;	Parameters:
+;		DS:DX:		Ptr to STOP terminated string
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%macro PRINT_STR 0
+	push	dx
+	call	Print_BiosTeleStr
+	pop		dx
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Prints string and returns number of characters printed.
+; All string printing functions must use this macro to print strings
+; (so printing implementation can be easily modified when needed).
+; 
+; PRINT_STR_LEN
+;	Parameters:
+;		DS:DX:		Ptr to STOP terminated string
+;	Returns:
+;		DX:			Number of characters printed
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+%macro PRINT_STR_LEN 0
+	call	Print_BiosTeleStr
+%endmacro
+
+ALIGN JUMP_ALIGN
+Print_BiosTeleStr:
+	push	bp						; Save because of buggy BIOSes
+	push	si
+	push	bx
+	mov		si, dx					; Copy offset to string
+	xor		dx, dx					; Zero char counter
+	xor		bx, bx					; Page 0
+	cld								; LODSB to increment SI
+ALIGN JUMP_ALIGN
+.CharLoop:
+	lodsb							; Load char from [DS:SI] to AL
+	cmp		al, STOP				; End of string?
+	je		.Return					;  If so, return
+	mov		ah, FN_BIOS_WR_CHAR_TEL	; Some BIOSes corrupts AX when returning
+	int		10h
+	inc		dx						; Increment chars printed
+	jmp		.CharLoop				; Loop while chars left
+ALIGN JUMP_ALIGN
+.Return:
+	pop		bx
+	pop		si
+	pop		bp
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/string.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/string.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Libraries/string.asm	(revision 37)
@@ -0,0 +1,643 @@
+; File name		:	string.asm
+; Project name	:	String library
+; Created date	:	7.10.2009
+; Last update	:	26.11.2009
+; Author		:	Tomi Tilli
+; Description	:	ASM library to work as Standard C String and Character.
+
+;--------------- Equates -----------------------------
+
+; String library function to include
+;%define USE_STR_ISCHAR
+;%define USE_STR_ISBASECHAR
+;%define USE_STR_BUFFHASCHAR
+;%define USE_STR_BUFFCMP
+;%define USE_STR_TOUINT
+;%define USE_STR_LEN
+;%define USE_STR_TOKEN
+;%define USE_STR_WITHIN
+;%define USE_STR_TOLOWER
+;%define USE_STR_TOUPPER
+
+; Special characters for strings
+STOP				EQU		0	; String ending character
+BELL				EQU		7	; Bell
+BS					EQU		8	; Backspace
+TAB					EQU		9	; Horizontal tab
+LF					EQU		10	; Line feed       \ Combine to...
+CR					EQU		13	; Carriage return / ...get a newline
+ESC					EQU		27	; ESC
+
+; Misc characters
+UARROW				EQU		24	; Up arrow
+DARROW				EQU		25	; Down arrow
+RARROW				EQU		26	; Right arrow
+LARROW				EQU		27	; Left arrow
+
+; Characters for printing boxes
+B_V					EQU		186	; Bold vertical border (Y-axis)
+B_H					EQU		205	; Bold horizontal border (X-axis)
+B_TL				EQU		201	; Bold top left border
+B_TR				EQU		187	; Bold top right border
+B_LR				EQU		188	; Bold lower right border
+B_LL				EQU		200	; Bold lower left border
+
+T_V					EQU		179	; Thin vertical border (Y-axis)
+T_H					EQU		196	; Thin horizontal border (X-axis)
+T_TL				EQU		218	; Thin top left border
+T_TR				EQU		191	; Thin top right border
+T_LR				EQU		217	; Thin lower right border
+T_LL				EQU		192	; Thin lower left border
+
+BVL_THR				EQU		199	; Bold vert on left, Thin horiz on right (||-)
+THL_BVR				EQU		182	; Thin horiz on left, Bold vert on right (-||)
+TVL_BHR				EQU		198	; Thin vert on left, Bold horiz on right (|=)
+BHL_TVR				EQU		181	; Bold horiz on left, Thin vert on right (=|)
+
+; Blocks
+MIN_BLCK			EQU		176	; Few character pixels set
+FULL_BLCK			EQU		219	; All character pixels set
+
+
+;-------------- Private global variables -------------
+; Section containing initialized data
+;SECTION .data
+
+
+;-------------- Public functions ---------------------
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Checks if character is some type of character.
+; 
+; String_IsAlphaNum (checks if alphanumeric letter, isalnum on C)
+; String_IsAlpha (checks if alphabetic letter, isalpha on C)
+; String_IsDigit (checks if decimal digit, isdigit on C)
+; String_IsLower (checks if lowercase letter, islower on C)
+; String_IsSpace (checks if any space character, isspace on C)
+; String_IsUpper (checks if uppercase letter, isupper on C)
+; String_IsHexDigit (checks if hexadecimal digit, isxdigit on C)
+;	Parameters:
+;		AL:		Character to check
+;	Returns:
+;		CF:		Set if character is the type to check
+;				Cleared if character is not the type to check
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_ISCHAR
+ALIGN JUMP_ALIGN
+String_IsAlphaNum:
+	call	String_IsAlpha		; Is alphabetic letter?
+	jnc		.CheckDigit			;  If not, jump to check if digit
+	ret
+.CheckDigit:
+	call	String_IsDigit		; Is dec digit?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsAlpha:
+	call	String_IsLower		; Is lower case letter?
+	jnc		.CheckUpper			;  If not, jump to check if upper
+	ret
+.CheckUpper:
+	call	String_IsUpper		; Is upper case letter?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsDigit:
+	cmp		al, '0'				; At least first dec digit?
+	jb		_String_IsRetFalse	;  If not, return FALSE
+	cmp		al, '9'+1			; At most last dec digit?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsLower:
+	cmp		al, 'a'				; At least first lower case letter?
+	jb		_String_IsRetFalse	;  If not, return FALSE
+	cmp		al, 'z'+1			; At most last lower case letter?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsSpace:
+	cmp		al, ' '+1			; Space or non-visible character?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsUpper:
+	cmp		al, 'A'				; At least first upper case letter?
+	jb		_String_IsRetFalse	;  If not, return FALSE
+	cmp		al, 'Z'+1			; At most last upper case letter?
+	ret
+
+ALIGN JUMP_ALIGN
+String_IsHexDigit:
+	call	String_IsAlphaNum	; Is alphabetic letter or digit?
+	jc		.CheckHex			;  If so, jump to check A...F
+	ret
+.CheckHex:
+	push	ax					; Store character
+	call	String_ToLower		; Convert to lower case letter
+	cmp		al, 'f'+1			; Last valid hex alphanumeric?
+	pop		ax					; Restore character
+	ret
+
+ALIGN JUMP_ALIGN
+_String_IsRetFalse:
+	clc							; Clear CF since false
+	ret
+%endif ; USE_STR_ISCHAR
+
+
+;--------------------------------------------------------------------
+; Checks if character belongs to specified numeric base.
+; 
+; String_IsBaseChar
+;	Parameters:
+;		AL:		Character to check
+;		CL:		Numeric base (10=dec, 16=hex etc.)
+;	Returns:
+;		AH:		Integer value for character
+;		CF:		Set if character belongs to base
+;				Set if character does not belong to base
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_ISBASECHAR
+ALIGN JUMP_ALIGN
+String_IsBaseChar:
+	mov		ah, al				; Copy char to AH
+	call	String_IsDigit		; Is '0'...'9'?
+	jc		.ConvertDigit		;  If so, jump to convert
+	call	String_IsAlpha		; Is alphabetic letter?
+	jnc		.RetFalse			;  If not, return FALSE
+	call	String_ToLower		; Convert to lower case
+	xchg	al, ah				; Converted char to AH
+	sub		ah, 'a'-10			; From char to integer: a=10, b=11...
+	cmp		ah, cl				; Belongs to base?
+	jae		.RetFalse			; If not, return FALSE
+	stc							; Set CF since belongs to base
+	ret
+ALIGN JUMP_ALIGN
+.ConvertDigit:
+	sub		ah, '0'				; Convert char to integer
+	cmp		ah, cl				; Belongs to base?
+	jae		.RetFalse			; If not, return FALSE
+	stc							; Set CF since belongs to base
+	ret
+ALIGN JUMP_ALIGN
+.RetFalse:
+	clc							; Clear CF since char doesn't belong to b
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Finds first occurrence of character from buffer (memchr on C).
+; 
+; String_BuffHasChar
+;	Parameters:
+;		AL:		Character to check
+;		CX:		Buffer length in bytes (1...65535, 0 clears CF)
+;		ES:DI:	Pointer to buffer
+;	Returns:
+;		AX:		Index of character in buffer (if char found)
+;		ES:BX:	Pointer to character location (if char found)
+;		CF:		Set if character found
+;				Cleared if character not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_BUFFHASCHAR
+ALIGN JUMP_ALIGN
+String_BuffHasChar:
+	jcxz	.Return				; Check length so no need to initialise ZF
+	push	di					; Store offset to buffer
+times 2 push	cx				; Store CX			
+	cld							; Set SCASB to increment DI
+	repne scasb					; Compare bytes to AL until found or CX=0
+	jne		.CharNotFound		; Character not found, return FALSE
+
+	; Character found
+	pop		ax					; Pop buffer length
+	sub		ax, cx				; Subtract number of chars left
+	dec		ax					; Number of chars scanned to found index
+	lea		bx, [di-1]			; Load character offset to BX
+	pop		cx					; Restore CX
+	pop		di					; Restore DI
+	stc							; Set CF since char found
+	ret
+.CharNotFound:
+times 2 pop	cx					; Restore CX
+	pop		di					; Restore DI
+.Return:
+	clc							; Clear CF since char not found
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Compares two buffers (memcmp on C).
+; 
+; String_BuffCmp
+;	Parameters:
+;		CX:		Buffer length in bytes (1...65535, 0 clears ZF)
+;		DS:SI:	Pointer to buffer 1
+;		ES:DI:	Pointer to buffer 2
+;	Returns:
+;		AX:		Index of unequal character (if buffers are not equal)
+;		ZF:		Set if buffers are equal
+;				Cleared if buffers are not equal
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_BUFFCMP
+ALIGN JUMP_ALIGN
+String_BuffCmp:
+	jcxz	.ReturnUnequal		; Check length so no need to initialise ZF
+	push	di					; Store offset to buffer 2
+	push	si					; Store offset to buffer 1
+times 2 push	cx				; Store CX			
+	cld							; Set CMPSB to increment SI and DI
+	repe cmpsb					; Compare bytes until not equal or CX=0
+	jne		.BuffersUnequal		; Unequal byte found, return FALSE
+	times 2 pop	cx				; Restore CX
+	pop		si					; Restore SI
+	pop		di					; Restore DI
+	ret
+.BuffersUnequal:
+	pop		ax					; Pop buffer length
+	sub		ax, cx				; Subtrack number of chars left
+	dec		ax					; Number of chars compared to unequal idx
+	xor		cx, cx				; Zero CX
+	dec		cx					; ZF=0
+	pop		cx					; Restore CX
+	pop		si					; Restore SI
+	pop		di					; Restore DI
+	ret
+.ReturnUnequal:
+	xor		ax, ax				; Zero AX
+	dec		ax					; AX = FFFFh, ZF=0
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Converts a string buffer to unsigned 32-bit integer.
+; 
+; String_BuffToUInt
+;	Parameters:
+;		ES:DI:	Pointer to string buffer to convert
+;		CX:		Base (10=dec, 16=hex etc.)
+;		SI:		Buffer length in characters
+;	Returns:
+;		DX:AX:	32-bit unsigned integer
+;		CF:		Set if converted successfully
+;				Cleared if error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOUINT
+ALIGN JUMP_ALIGN
+String_BuffToUInt:
+	; Copy ES:DI to DS:SI
+	push	ds					; Store DS
+	push	si					; Store SI
+	push	di					; Store DI
+	push	bx					; Store BX
+	xchg	si, di				; Offset to SI, lenght to DI
+	push	es
+	pop		ds
+
+	; Prepare to read chars
+	xor		dx, dx				; Zero DX (HIWORD)
+	xor		bx, bx				; Zero BX (LOWORD)
+ALIGN JUMP_ALIGN
+.CharLoop:
+	lodsb						; Load char to AL
+	call	String_IsBaseChar	; Is valid character? (AH=digit)
+	jnc		.RetFalse			;  If not, return FALSE
+	xchg	ax, bx				; AX=LOWORD, BX=digit and char
+	call	Math_MulDWbyW		; DX:AX *= CX
+	xchg	ax, bx				; AX=digit and char, BX=LOWORD
+	mov		al, ah				; Copy digit to AL
+	xor		ah, ah				; Zero AH, AX=digit
+	add		bx, ax				; Add digit to LOWORD
+	adc		dx, 0				; Add carry to HIWORD
+	dec		di					; Decrement characters left
+	jnz		.CharLoop			; Loop while characters left
+
+	mov		ax, bx				; Copy loword to AX
+	pop		bx					; Restore BX
+	pop		di					; Restore DI
+	pop		si					; Restore SI
+	pop		ds					; Restore DS
+	stc							; Set CF since success
+	ret
+ALIGN JUMP_ALIGN
+.RetFalse:
+	mov		ax, bx				; Copy (likely incomplete) loword to AX
+	pop		bx					; Restore BX
+	pop		di					; Restore DI
+	pop		si					; Restore SI
+	pop		ds					; Restore DS
+	clc							; Clear CF since error
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Returns string lenght. Strings must end to STOP character (strlen on C).
+; 
+; String_StrLen
+;	Parameters:
+;		ES:DI:	Pointer to string
+;	Returns:
+;		AX:		String length in characters excluding STOP char
+;		CF:		Set if STOP character was found
+;				Cleared if STOP character was not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_LEN
+ALIGN JUMP_ALIGN
+String_StrLen:
+	push	cx					; Store CX
+	mov		al, STOP			; Load string end char to AL
+	mov		cx, -1				; Scan for maximum string length
+	call	String_BuffHasChar	; Find offset for string ending char
+	pop		cx					; Restore CX
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Returns length for token string. Token strings ends to any whitespace
+; character or to STOP.
+; 
+; String_TokenLen
+;	Parameters:
+;		ES:DI:	Pointer to token string
+;	Returns:
+;		AX:		Token length in characters
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOKEN
+ALIGN JUMP_ALIGN
+String_TokenLen:
+	push	bx					; Store BX
+	xor		bx, bx				; Zero BX for token length
+ALIGN JUMP_ALIGN
+.CharLoop:
+	mov		al, [es:di+bx]		; Load character to AL
+	cmp		al, STOP			; End of token?
+	je		.Return				;  If so, return
+	call	String_IsSpace		; End of token?
+	jc		.Return				;  If so, return
+	inc		bx					; Increment token length
+	jmp		.CharLoop			; Loop while characters left
+ALIGN JUMP_ALIGN
+.Return:
+	mov		ax, bx				; Copy string length to AX
+	pop		bx					; Restore BX
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Returns index and ptr to first occurrence of
+; string 2 in string 1 (strstr on C).
+; Strings must be STOP terminated strings.
+; 
+; String_StrWithin
+;	Parameters:
+;		DS:SI:	Pointer to string 1
+;		ES:DI:	Pointer to string 2
+;	Returns:
+;		AX:		Index to first occurrence of string 2 in string 1
+;		DS:BX:	Pointer to first occurrence of string 2 in string 1
+;		CF:		Set if string 2 was found in string 1
+;				Cleared if string 2 was not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_WITHIN
+ALIGN JUMP_ALIGN
+String_StrWithin:
+	push	cx					; Store CX
+	push	si					; Store SI
+	call	String_StrLen		; Load str2 length to AX
+	mov		cx, ax				; Copy str2 length to CX
+
+ALIGN JUMP_ALIGN
+.Str1CharLoop:
+	cmp		BYTE [si], STOP		; End of string?
+	je		.Str2NotFound		;  If so, return FALSE
+	call	String_BuffCmp		; str2 found in str1?
+	je		.Str2Found			;  If so, break loop
+	add		si, ax				; Add index to first unmatching char
+	inc		si					; Increment str1 ptr
+	jmp		.Str1CharLoop		; Loop while characters left
+
+ALIGN JUMP_ALIGN
+.Str2Found:
+	mov		bx, si				; Copy ptr to BX
+	mov		ax, si				; Copy ptr to AX
+	pop		si					; Restore SI
+	pop		cx					; Restore CX
+	sub		ax, si				; Calculate index to str2 in str1
+	stc							; Set CF since str2 found
+	ret
+ALIGN JUMP_ALIGN
+.Str2NotFound:
+	xor		bx, bx				; Zero BX
+	pop		si					; Restore SI
+	pop		cx					; Restore CX
+	clc							; Clear CF since str2 was not found
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Returns pointer to wanted token inside STOP terminated string.
+; Tokens are separated by any white space characters.
+; 
+; String_StrToken
+;	Parameters:
+;		CX:		Index of token to return
+;		ES:DI:	Pointer to string
+;	Returns:
+;		AX:		Token string length (if token found)
+;		ES:DI:	Pointer to token (if token found)
+;		CF:		Set if token found
+;				Cleared if token not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOKEN
+ALIGN JUMP_ALIGN
+String_StrToken:
+	push	cx					; Store CX
+	push	si					; Store SI
+	push	ds					; Store DS
+	push	es					; Copy ES:DI to DS:SI
+	pop		ds
+	mov		si, di
+	inc		cx					; Increment to number of tokens to search
+	cld							; LODSB to increment SI
+ALIGN JUMP_ALIGN
+.ConsumeWhite:
+	lodsb						; Load char to AL from [DS:SI]
+	cmp		al, STOP			; End of string?
+	je		.NotFound			;  If so, token was not found
+	call	String_IsSpace		; Any whitespace character?
+	jc		.ConsumeWhite		;  If so, skip it
+	dec		si					; Decrement SI to point first non-space
+	mov		di, si				; Copy offset to token to DI
+ALIGN JUMP_ALIGN
+.TokenLoop:
+	lodsb						; Load char to AL
+	cmp		al, STOP			; End of string?
+	je		.EndOfString		;  If so, end token
+	call	String_IsSpace		; Any whitespace character?
+	jnc		.TokenLoop			;  If not, loop
+	loop	.ConsumeWhite		; Loop until wanted token found
+.RetToken:
+	pop		ds					; Restore DS
+	pop		si					; Restore SI
+	pop		cx					; Restore CX
+	call	String_TokenLen		; Get token length to AX
+	stc							; Set CF since token found
+	ret
+ALIGN JUMP_ALIGN
+.EndOfString:
+	dec		si					; Offset to STOP
+	cmp		di, si				; STOP only char in token?
+	je		.NotFound			;  If so, then it is not valid token
+	loop	.NotFound			; If last token was not wanted
+	jmp		.RetToken
+ALIGN JUMP_ALIGN
+.NotFound:
+	pop		ds					; Restore DS
+	pop		si					; Restore SI
+	pop		cx					; Restore CX
+	clc							; Clear CF since token not found
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Converts a STOP terminated string to unsigned 32-bit integer.
+; 
+; String_StrToUInt
+;	Parameters:
+;		ES:DI:	Pointer to string to convert
+;		CX:		Base (10=dec, 16=hex etc.)
+;	Returns:
+;		DX:AX:	32-bit unsigned integer
+;		CF:		Set if converted successfully
+;				Cleared if error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOUINT
+ALIGN JUMP_ALIGN
+String_StrToUInt:
+	push	si
+	call	String_StrLen		; Get string length to AX
+	mov		si, ax				; Copy length to SI
+	call	String_BuffToUInt	; Convert to integer in DX:AX
+	pop		si
+	ret
+%endif
+%if 0
+String_StrToUInt:		; Faster but we want to minimize size
+	; Copy ES:DI to DS:SI
+	push	ds					; Store DS
+	push	si					; Store SI
+	push	bx					; Store BX
+	mov		si, di				; Copy ES:DI to DS:SI
+	push	es
+	pop		ds
+
+	; Prepare to read chars
+	xor		dx, dx				; Zero DX (HIWORD)
+	xor		bx, bx				; Zero BX (LOWORD)
+ALIGN JUMP_ALIGN
+.CharLoop:
+	lodsb						; Load char to AL
+	cmp		al, STOP			; End of string?
+	je		.ConvComplete		;  If so, break loop
+	call	String_IsBaseChar	; Is valid character? (AH=digit)
+	jnc		.RetFalse			;  If not, return FALSE
+	xchg	ax, bx				; AX=LOWORD, BX=digit and char
+	call	Math_MulDWbyW		; DX:AX *= CX
+	xchg	ax, bx				; AX=digit and char, BX=LOWORD
+	mov		al, ah				; Copy digit to AL
+	xor		ah, ah				; Zero AH, AX=digit
+	add		bx, ax				; Add digit to LOWORD
+	adc		dx, 0				; Add carry to HIWORD
+	jmp		.CharLoop			; Loop while valid characters
+ALIGN JUMP_ALIGN
+.ConvComplete:
+	mov		ax, bx				; Copy loword to AX
+	pop		bx					; Restore BX
+	pop		si					; Restore SI
+	pop		ds					; Restore DS
+	stc							; Set CF since success
+	ret
+ALIGN JUMP_ALIGN
+.RetFalse:
+	mov		ax, bx				; Copy (likely incomplete) loword to AX
+	pop		bx					; Restore BX
+	pop		si					; Restore SI
+	pop		ds					; Restore DS
+	clc							; Clear CF since error
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Converts upper case character to lower case character.
+; 
+; String_ToLower
+;	Parameters:
+;		AL:		Character to convert
+;	Returns:
+;		AL:		Character with possible conversion
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOLOWER
+ALIGN JUMP_ALIGN
+String_ToLower:
+	call	String_IsUpper		; Is upper case character?
+	jnc		.Return				;  If not, return
+	add		al, 'a'-'A'			; Convert to lower case
+.Return:
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Converts lower case character to upper case character.
+; 
+; String_ToUpper
+;	Parameters:
+;		AL:		Character to convert
+;	Returns:
+;		AL:		Character with possible conversion
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%ifdef USE_STR_TOUPPER
+ALIGN JUMP_ALIGN
+String_ToUpper:
+	call	String_IsLower		; Is lower case character?
+	jnc		.Return				;  If not, return
+	sub		al, 'a'-'A'			; Convert to upper case
+.Return:
+	ret
+%endif
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Main.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Main.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Main.asm	(revision 37)
@@ -0,0 +1,180 @@
+; File name		:	Main.asm
+; Project name	:	XTIDE Universal BIOS
+; Created date	:	28.7.2007
+; Last update	:	26.7.2010
+; Author		:	Tomi Tilli
+; Description	:	Main file for BIOS. This is the only file that needs
+;					to be compiled since other files are included to this
+;					file (so no linker needed, Nasm does it all).
+;
+;					Tomi Tilli
+;					aitotat@gmail.com
+
+ORG 000h						; Code start offset 0000h
+
+; Included .inc files
+%include "emulate.inc"			; Must be included first!
+%include "BiosData.inc"			; For BIOS Data area equates
+%include "Interrupts.inc"		; For interrupt equates
+%include "ATA_ID.inc"			; For ATA Drive Information structs
+%include "IdeRegisters.inc"		; For ATA Registers, flags and commands
+%include "Int13h.inc"			; Equates for INT 13h functions
+%include "CustomDPT.inc"		; For Disk Parameter Table
+%include "CompatibleDPT.inc"	; For standard Disk Parameter Tables
+%include "RomVars.inc"			; For ROMVARS and IDEVARS structs
+%include "RamVars.inc"			; For RAMVARS struct
+%include "BootVars.inc"			; For BOOTVARS and BOOTNFO structs
+%include "BootMenu.inc"			; For Boot Menu
+%include "IDE_8bit.inc"			; For IDE 8-bit data port macros
+
+
+; Section containing code
+SECTION .text
+
+; ROM variables (must start at offset 0)
+CNT_ROM_BLOCKS		EQU		16	; 16 * 512B = 8kB BIOS
+istruc ROMVARS
+	at	ROMVARS.wRomSign,	dw	0AA55h			; PC ROM signature
+	at	ROMVARS.bRomSize,	db	CNT_ROM_BLOCKS	; ROM size in 512B blocks
+	at	ROMVARS.rgbJump, 	jmp	Initialize_FromMainBiosRomSearch
+	at	ROMVARS.rgbDate,	db	"08/24/10"		; Build data (mm/dd/yy)
+	at	ROMVARS.rgbSign,	db	"XTIDE110"		; Signature for flash program
+	at	ROMVARS.szTitle
+		db	"-=XTIDE Universal BIOS"
+%ifdef USE_AT
+		db	" (AT)=-",STOP
+%elifdef USE_186
+		db	" (XT+)=-",STOP
+%else
+		db	" (XT)=-",STOP
+%endif
+	at	ROMVARS.szVersion,	db	"v1.1.4 (08/24/10)",STOP
+
+;---------------------------;
+; AT Build default settings ;
+;---------------------------;
+%ifdef USE_AT
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | FLG_ROMVARS_DRVXLAT | FLG_ROMVARS_DRVNFO | FLG_ROMVARS_MAXSIZE
+	at	ROMVARS.bIdeCnt,		db	3						; Number of supported controllers
+	at	ROMVARS.bBootDrv,		db	80h						; Boot Menu default drive
+	at	ROMVARS.bBootMnuH,		db	20						; Boot Menu maximum height
+	at	ROMVARS.bBootDelay,		db	30						; Boot Menu selection delay (secs)
+	at	ROMVARS.bBootLdrType,	db	BOOTLOADER_TYPE_MENU	; Boot loader type
+	at	ROMVARS.bMinFddCnt, 	db	0						; Do not force minimum number of floppy drives
+	at	ROMVARS.bStealSize,		db	1						; Steal 1kB from base memory
+
+	at	ROMVARS.ideVars0+IDEVARS.wPort,			dw	1F0h			; Controller Command Block base port
+	at	ROMVARS.ideVars0+IDEVARS.wPortCtrl,		dw	3F0h			; Controller Control Block base port
+	at	ROMVARS.ideVars0+IDEVARS.bBusType,		db	BUS_TYPE_16		; Bus type
+	at	ROMVARS.ideVars0+IDEVARS.bIRQ,			db	14				; IRQ
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars1+IDEVARS.wPort,			dw	170h			; Controller Command Block base port
+	at	ROMVARS.ideVars1+IDEVARS.wPortCtrl,		dw	370h			; Controller Control Block base port
+	at	ROMVARS.ideVars1+IDEVARS.bBusType,		db	BUS_TYPE_16		; Bus type
+	at	ROMVARS.ideVars1+IDEVARS.bIRQ,			db	15				; IRQ
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars2+IDEVARS.wPort,			dw	300h			; Controller Command Block base port
+	at	ROMVARS.ideVars2+IDEVARS.wPortCtrl,		dw	308h			; Controller Control Block base port
+	at	ROMVARS.ideVars2+IDEVARS.bBusType,		db	BUS_TYPE_8_DUAL	; Bus type
+	at	ROMVARS.ideVars2+IDEVARS.bIRQ,			db	0				; IRQ
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+%else
+;-----------------------------------;
+; XT and XT+ Build default settings ;
+;-----------------------------------;
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_LATE | FLG_ROMVARS_DRVXLAT | FLG_ROMVARS_ROMBOOT | FLG_ROMVARS_DRVNFO | FLG_ROMVARS_MAXSIZE
+	at	ROMVARS.bIdeCnt,		db	1						; Number of supported controllers
+	at	ROMVARS.bBootDrv,		db	80h						; Boot Menu default drive
+	at	ROMVARS.bBootMnuH,		db	20						; Boot Menu maximum height
+	at	ROMVARS.bBootDelay,		db	30						; Boot Menu selection delay (secs)
+	at	ROMVARS.bBootLdrType,	db	BOOTLOADER_TYPE_MENU	; Boot loader type
+	at	ROMVARS.bMinFddCnt, 	db	1						; Assume at least 1 floppy drive present if autodetect fails
+	at	ROMVARS.bStealSize,		db	1						; Steal 1kB from base memory in full mode
+
+	at	ROMVARS.ideVars0+IDEVARS.wPort,			dw	300h			; Controller Command Block base port
+	at	ROMVARS.ideVars0+IDEVARS.wPortCtrl,		dw	308h			; Controller Control Block base port
+	at	ROMVARS.ideVars0+IDEVARS.bBusType,		db	BUS_TYPE_8_DUAL	; Bus type
+	at	ROMVARS.ideVars0+IDEVARS.bIRQ,			db	0				; IRQ
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	FLG_DRVPARAMS_BLOCKMODE
+%endif
+iend
+
+
+; Include .asm files (static data and libraries)
+%include "Strings.asm"			; For BIOS message strings
+%include "math.asm"				; For Math library
+%include "string.asm"			; For String library
+%include "print.asm"			; For Print library
+%include "keys.asm"				; For keyboard library (required by menu library)
+%include "menu.asm"				; For menu library
+%include "PrintString.asm"		; Customized printing for this BIOS
+%include "SoftDelay.asm"		; For software delay loops
+
+; Include .asm files (Initialization and drive detection)
+%include "Initialize.asm"		; For BIOS initialization
+%include "Interrupts.asm"		; For Interrupt initialization
+%include "RamVars.asm"			; For RAMVARS initialization and access
+%include "CreateDPT.asm"		; For creating DPTs
+%include "FindDPT.asm"			; For finding DPTs
+%include "AccessDPT.asm"		; For accessing DPTs
+%include "CompatibleDPT.asm"	; For creating compatible DPTs
+%include "BootInfo.asm"			; For creating BOOTNFO structs
+%include "AtaID.asm"			; For ATA Identify Device information
+%include "DetectDrives.asm"		; For detecting IDE drives
+%include "DetectPrint.asm"		; For printing drive detection strings
+
+; Include .asm files (boot menu)
+%include "BootVars.asm"			; For accessing BOOTVARS struct
+%include "BootMenu.asm"			; For Boot Menu operations
+%include "BootMenuEvent.asm"	; For menu library event handling
+%include "FloppyDrive.asm"		; Floppy Drive related functions
+%include "BootMenuPrint.asm"	; For printing Boot Menu strings
+%include "BootMenuPrintCfg.asm"	; For printing hard disk configuration
+
+; Include .asm files (general drive accessing)
+%include "DriveXlate.asm"		; For swapping drive numbers
+%include "HAddress.asm"			; For sector address translations
+%include "HCapacity.asm"		; For calculating drive capacity
+%include "HError.asm"			; For error checking
+%include "HPIO.asm"				; For PIO transfers
+%include "HIRQ.asm"				; For IRQ handling
+%include "HStatus.asm"			; For reading hard disk status
+%include "HDrvSel.asm"			; For selecting drive to access
+%include "HCommand.asm"			; For outputting command and parameters
+
+; Include .asm files (Interrupt handlers)
+%include "Int13h.asm"			; For Int 13h, Disk functions
+%include "Int18h.asm"			; For Int 18h, ROM Boot and Boot error
+%include "Int19h.asm"			; For Int 19h, Boot Loader
+%include "Int19hMenu.asm"		; For Int 19h, Boot Loader for Boot Menu
+%include "BootPrint.asm"		; For printing boot information
+
+; Include .asm files (Hard Disk BIOS functions)
+%include "AH0h_HReset.asm"		; Required by Int13h_Jump.asm
+%include "AH1h_HStatus.asm"		; Required by Int13h_Jump.asm
+%include "AH2h_HRead.asm"		; Required by Int13h_Jump.asm
+%include "AH3h_HWrite.asm"		; Required by Int13h_Jump.asm
+%include "AH4h_HVerify.asm"		; Required by Int13h_Jump.asm
+%include "AH5h_HFormat.asm"		; Required by Int13h_Jump.asm
+%include "AH8h_HParams.asm"		; Required by Int13h_Jump.asm
+%include "AH9h_HInit.asm"		; Required by Int13h_Jump.asm
+%include "AHCh_HSeek.asm"		; Required by Int13h_Jump.asm
+%include "AHDh_HReset.asm"		; Required by Int13h_Jump.asm
+%include "AH10h_HReady.asm"		; Required by Int13h_Jump.asm
+%include "AH11h_HRecal.asm"		; Required by Int13h_Jump.asm
+%include "AH14h_HDiag.asm"		; Required by Int13h_Jump.asm
+%include "AH15h_HSize.asm"		; Required by Int13h_Jump.asm
+%include "AH23h_HFeatures.asm"	; Required by Int13h_Jump.asm
+%include "AH24h_HSetBlocks.asm"	; Required by Int13h_Jump.asm
+%include "AH25h_HDrvID.asm"		; Required by Int13h_Jump.asm
+
+
+
+; Fill with zeroes until size is what we want
+times (CNT_ROM_BLOCKS*512)-($-$$) db 0
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/SoftDelay.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/SoftDelay.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/SoftDelay.asm	(revision 37)
@@ -0,0 +1,148 @@
+; File name		:	SoftDelay.asm
+; Project name	:	IDE BIOS
+; Created date	:	22.9.2007
+; Last update	:	13.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Software delay loops for I/O timeout and other loops.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; There should be at least 400ns delay between outputting
+; IDE command / drive selection and reading IDE Status Register.
+;
+; SoftDelay_BeforePollingStatusRegister
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN						; Cycles required
+SoftDelay_BeforePollingStatusRegister:	; 8088 | 286 | 386 | 486
+	push	cx							;   15 |   3 |   2 |   1
+	mov		cx, 2						;    4 |   2 |   2 |   1
+.DelayLoop:
+	loop	.DelayLoop					;      |  10 |  12 |   6
+	pop		cx							;    8 |   5 |   4 |   4
+	ret									;   20 |  11m|  10m|   5
+
+
+;--------------------------------------------------------------------
+; Initializes timeout counter. Timeouts are implemented using system
+; timer ticks. First tick might take 0...54.9ms and remaining ticks
+; will occur at 54.9ms intervals. Use delay of two (or more) ticks to
+; ensure at least 54.9ms wait.
+;
+; SoftDelay_InitTimeout
+;	Parameters:
+;		CL:		Number of system timer ticks before timeout
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SoftDelay_InitTimeout:
+	mov		[RAMVARS.bEndTime], cl		; Store timeout ticks
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, cx
+	mov		cl, [BDA.dwTimerTicks]		; Load current time lowest byte
+	pop		ds
+	add		[RAMVARS.bEndTime], cl		; Timeout to end time
+	sti									; Enable interrupts
+	ret
+
+
+;--------------------------------------------------------------------
+; Updates timeout counter. Timeout counter can be
+; initialized with SoftDelay_InitTimeout.
+;
+; SoftDelay_UpdTimeout
+;	Parameters:
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		CF:		Set if timeout
+;				Cleared if time left
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SoftDelay_UpdTimeout:
+	push	ax
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	mov		al, [BDA.dwTimerTicks]		; Load current time lowest byte
+	pop		ds
+
+	cmp		al, [RAMVARS.bEndTime]		; End time reached?
+	pop		ax
+	je		SHORT .ReturnTimeout
+	clc
+	ret
+.ReturnTimeout:
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; Microsecond delay.
+; Current implementation uses BIOS event wait services that are not
+; available on XT systems. Calling overhead should be enough so it does
+; not matter for IDE waits. On AT+ the delay will be at least 1ms since
+; RTC resolution is 977 microsecs.
+;
+; SoftDelay_us
+;	Parameters:
+;		CX:		Number of microsecs to wait
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SoftDelay_us:
+	push	dx
+	push	ax
+
+	xor		dx, dx						; Zero DX
+	xchg	cx, dx						; Microsecs now in CX:DX
+	mov		ah, 86h						; Event Wait
+	int		INTV_SYSTEM_SERVICES
+
+	pop		ax
+	pop		dx
+	mov		cx, 2						; Prepare to wait 2 timer ticks
+	jc		SHORT SoftDelay_TimerTicks	; Unsupported or busy
+	ret
+
+
+;--------------------------------------------------------------------
+; Timer tick delay.
+; One tick is about 54.9ms but first tick may occur anytime between
+; 0...54.9ms!
+;
+; SoftDelay_TimerTicks
+;	Parameters:
+;		CX:		Number of timer ticks to wait
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SoftDelay_TimerTicks:
+	push	ds
+	push	ax
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	add		cx, [BDA.dwTimerTicks]		; CX to end time
+	sti									; Enable interrupts
+.DelayLoop:
+	cmp		cx, [BDA.dwTimerTicks]		; Wait complete?
+	jne		SHORT .DelayLoop			;  If not, loop
+	pop		ax
+	pop		ds
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/Strings.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/Strings.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/Strings.asm	(revision 37)
@@ -0,0 +1,53 @@
+; File name		:	Strings.asm
+; Project name	:	IDE BIOS
+; Created date	:	4.12.2007
+; Last update	:	9.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Strings and equates for BIOS messages.
+
+; Section containing code
+SECTION .text
+
+; POST drive detection strings
+g_szRomAt:		db	"%s @ %x",CR,LF,STOP
+g_szMaster:		db	"Master",STOP
+g_szSlave:		db	"Slave ",STOP
+g_szDetect:		db	"IDE %s at %x: ",STOP			; IDE Master at 1F0h:
+g_szNotFound:	db	"not found",CR,LF,STOP
+
+; Boot loader strings
+g_szFloppyDrv:	db	"Floppy Drive",STOP
+g_szHardDrv:	db	" Hard Drive ",STOP
+g_szTryToBoot:	db	"Booting from %s %x",175,"%x ... ",STOP
+g_szBootSector:	db	"Boot Sector",STOP
+g_szFound:		db	"found",STOP
+g_szSectRead:	db	"%s %s!",CR,LF,STOP
+g_szReadError:	db	"Error %x!",CR,LF,STOP
+g_sz18hCallback:db	"Boot menu callback via INT 18h",STOP
+
+; Boot menu bottom of screen strings
+g_szFDD:		db	"FDD",STOP
+g_szHDD:		db	"HDD",STOP
+g_szBottomScrn:	db	"%c to %c boots from %s with %s mappings",CR,LF,STOP
+
+; Boot Menu title strings
+g_szTitleLn3:	db	"Copyright 2009-2010 by Tomi Tilli",STOP
+
+; Boot Menu menuitem strings
+g_szFDLetter:	db	"%s %c",STOP
+g_szforeignHD:	db	"Foreign Hard Disk",STOP
+g_szRomBoot:	db	"ROM Boot",STOP
+
+; Boot Menu information strings
+g_szCapacity:	db	"Capacity : ",STOP
+g_szSizeSingle:	db	"%s%u.%u %ciB",STOP
+g_szSizeDual:	db	"%s%u.%u %ciB / %u.%u %ciB",STOP
+g_szCfgHeader:	db	"Addr.", T_V, "Block", T_V, "Bus",   T_V, "IRQ",   T_V, "Reset", STOP
+g_szCfgFormat:	db	"%s"   , T_V, "%5u",   T_V, "%c%2u", T_V, " %c%c", T_V, "%5x",   STOP
+g_szLCHS:		db	"L-CHS",STOP
+g_szPCHS:		db	"P-CHS",STOP
+g_szLBA28:		db	"LBA28",STOP
+g_szLBA48:		db	"LBA48",STOP
+g_szFddUnknown:	db	"%sUnknown",STOP
+g_szFddSizeOr:	db	"%s5",172,22h," or 3",171,22h," DD",STOP
+g_szFddSize:	db	"%s%c%c",22h,", %u kiB",STOP	; 3½", 1440 kiB
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/AccessDPT.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/AccessDPT.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/AccessDPT.asm	(revision 37)
@@ -0,0 +1,77 @@
+; File name		:	AccessDPT.asm
+; Project name	:	IDE BIOS
+; Created date	:	16.3.2010
+; Last update	:	26.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for accessing DPT data.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Returns L-CHS values from DPT.
+;
+; AccessDPT_GetLCHSfromPCHS
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AX:		Number of L-CHS sectors per track
+;		BX:		Number of L-CHS cylinders
+;		DX:		Number of L-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_GetLCHSfromPCHS:
+	xchg	ax, cx
+	mov		cl, [di+DPT.bShLtoP]		; Load shift count
+	mov		bx, [di+DPT.wPCyls]			; Load P-CHS cylinders
+	shr		bx, cl						; Shift to L-CHS cylinders
+	xchg	cx, ax
+	mov		dx, [di+DPT.wLHeads]		; Load L-CHS heads
+	eMOVZX	ax, BYTE [di+DPT.bPSect]	; Load Sectors per track
+	ret
+
+
+;--------------------------------------------------------------------
+; Tests IDEVARS flags for master or slave drive.
+;
+; AccessDPT_TestIdeVarsFlagsForMasterOrSlaveDrive
+;	Parameters:
+;		AX:		Bitmask to test DRVPARAMS.wFlags
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		ZF:		Set if tested bit was zero
+;				Cleared if tested bit was non-zero
+;		CF:		0
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_TestIdeVarsFlagsForMasterOrSlaveDrive:
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	test	[cs:bx+DRVPARAMS.wFlags], ax
+	ret
+
+;--------------------------------------------------------------------
+; Returns pointer to DRVPARAMS for master or slave drive.
+;
+; AccessDPT_GetPointerToDRVPARAMStoCSBX
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		CS:BX:	Ptr to DRVPARAMS
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_GetPointerToDRVPARAMStoCSBX:
+	eMOVZX	bx, [di+DPT.bIdeOff]		; CS:BX points to IDEVARS
+	test	BYTE [di+DPT.bDrvSel], FLG_IDE_DRVHD_DRV
+	jnz		SHORT .ReturnPointerToSlaveDRVPARAMS
+	add		bx, BYTE IDEVARS.drvParamsMaster
+	ret
+ALIGN JUMP_ALIGN
+.ReturnPointerToSlaveDRVPARAMS:
+	add		bx, BYTE IDEVARS.drvParamsSlave
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CompatibleDPT.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CompatibleDPT.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CompatibleDPT.asm	(revision 37)
@@ -0,0 +1,213 @@
+; File name		:	CompatibleDPT.asm
+; Project name	:	IDE BIOS
+; Created date	:	6.4.2010
+; Last update	:	6.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for creating Disk Parameter Tables for
+;					software compatibility only. These DPTs are not used
+;					by our BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Creates compatible for drives 80h and 81h. There will be stored
+; to interrupt vectors 41h and 46h.
+;
+; CompatibleDPT_CreateForDrives80hAnd81h
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All except DS and ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CompatibleDPT_CreateForDrives80hAnd81h:
+	; Only create compatible DPTs in full mode
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jz		SHORT CompatibleDPT_StoreCustomDPTs
+
+	mov		dl, 80h
+	call	FindDPT_ForDriveNumber	; DPT to DS:DI
+	jnc		SHORT .CreateForDrive81h
+	call	CompatibleDPT_CreateForDrive80h
+ALIGN JUMP_ALIGN
+.CreateForDrive81h:
+	mov		dl, 81h
+	call	FindDPT_ForDriveNumber
+	jnc		SHORT .Return
+	call	CompatibleDPT_CreateForDrive81h
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores pointers to our custom DPTs for drives 80h and 81h.
+;
+; CompatibleDPT_StoreCustomDPTs
+;	Parameters:
+;		ES:		BDA and interrupt vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		DX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CompatibleDPT_StoreCustomDPTs:
+	mov		dl, 80h
+	call	FindDPT_ForDriveNumber	; DPT to DS:DI
+	jnc		SHORT .FindForDrive81h
+	mov		[es:INTV_HD0DPT*4], di
+	mov		[es:INTV_HD0DPT*4+2], ds
+ALIGN JUMP_ALIGN
+.FindForDrive81h:
+	inc		dx
+	call	FindDPT_ForDriveNumber
+	jnc		SHORT .Return
+	mov		[es:INTV_HD1DPT*4], di
+	mov		[es:INTV_HD1DPT*4+2], ds
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Copies parameters from our custom DPT struct to a
+; standard COMPATIBLE_FDPT or COMPATIBLE_EDPT struct.
+;
+; CompatibleDPT_CreateForDrive80h
+; CompatibleDPT_CreateForDrive81h
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		ES:		BDA and interrupt vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CompatibleDPT_CreateForDrive80h:
+	mov		si, FULLRAMVARS.drv80hCompDPT	; DS:SI now points compatible DPT
+	call	CompatibleDPT_CopyFromCustom
+	mov		[es:INTV_HD0DPT*4], si
+	mov		[es:INTV_HD0DPT*4+2], ds
+	ret
+ALIGN JUMP_ALIGN
+CompatibleDPT_CreateForDrive81h:
+	mov		si, FULLRAMVARS.drv81hCompDPT	; DS:SI now points compatible DPT
+	call	CompatibleDPT_CopyFromCustom
+	mov		[es:INTV_HD1DPT*4], si
+	mov		[es:INTV_HD1DPT*4+2], ds
+	ret
+
+
+;--------------------------------------------------------------------
+; Copies parameters from our custom DPT struct to a
+; standard COMPATIBLE_FDPT or COMPATIBLE_EDPT struct.
+;
+; CompatibleDPT_CopyFromCustom
+;	Parameters:
+;		DS:SI:	Ptr to COMPATIBLE_FDPT or COMPATIBLE_EDPT
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CompatibleDPT_CopyFromCustom:
+	call	AccessDPT_GetLCHSfromPCHS			; AX=Lsects, BX=Lcyls, DX=Lheads
+	test	BYTE [di+DPT.bFlags], FLG_DPT_EBIOS	; Drive larger than 504 MiB?
+	jnz		SHORT CompatibleDPT_CopyFromCustomToEDPT
+	; Fall to CompatibleDPT_CopyFromCustomToFDPT
+
+;--------------------------------------------------------------------
+; Copies parameters from our custom DPT struct to a
+; standard COMPATIBLE_FDPT struct for drives up to 504 MiB.
+;
+; CompatibleDPT_CopyFromCustomToFDPT
+;	Parameters:
+;		AX:		L-CHS sectors per track
+;		BX:		L-CHS cylinders
+;		DX:		L-CHS heads
+;		DS:SI:	Ptr to COMPATIBLE_FDPT
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+CompatibleDPT_CopyFromCustomToFDPT:
+	mov		[si+COMPATIBLE_FDPT.wCyls], bx
+	mov		[si+COMPATIBLE_FDPT.bHeads], dl
+	mov		[si+COMPATIBLE_FDPT.bSectPerTrack], al
+	mov		WORD [si+COMPATIBLE_FDPT.wWrPreCmpCyl], -1
+	mov		al, [di+DPT.bDrvCtrl]
+	mov		[si+COMPATIBLE_FDPT.bDrvCtrl], al
+	mov		BYTE [si+COMPATIBLE_FDPT.bNormTimeout], B_TIMEOUT_BSY
+	mov		BYTE [si+COMPATIBLE_FDPT.bFormatTimeout], B_TIMEOUT_DRQ
+	mov		BYTE [si+COMPATIBLE_FDPT.bCheckTimeout], B_TIMEOUT_DRQ
+	dec		bx
+	mov		[si+COMPATIBLE_FDPT.wLZoneCyl], bx
+	ret
+
+
+;--------------------------------------------------------------------
+; Copies parameters from our custom DPT struct to a
+; standard COMPATIBLE_EDPT struct.
+;
+; CompatibleDPT_CopyFromCustomToEDPT
+;	Parameters:
+;		AX:		L-CHS sectors per track
+;		BX:		L-CHS cylinders
+;		DX:		L-CHS heads
+;		DS:SI:	Ptr to COMPATIBLE_EDPT
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CompatibleDPT_CopyFromCustomToEDPT:
+	mov		[si+COMPATIBLE_EDPT.wLCyls], bx
+	mov		[si+COMPATIBLE_EDPT.bLHeads], dl
+	mov		BYTE [si+COMPATIBLE_EDPT.bSignature], COMPATIBLE_EDPT_SIGNATURE
+	mov		[si+COMPATIBLE_EDPT.bPSect], al
+	mov		[si+COMPATIBLE_EDPT.bLSect], al
+	mov		al, [di+DPT.bDrvCtrl]
+	mov		[si+COMPATIBLE_EDPT.bDrvCtrl], al
+	mov		ax, [di+DPT.wPCyls]
+	mov		[si+COMPATIBLE_EDPT.wPCyls], ax
+	mov		al, [di+DPT.bPHeads]
+	mov		[si+COMPATIBLE_EDPT.bPHeads], al
+	; Fall to CompatibleDPT_StoreChecksum
+
+;--------------------------------------------------------------------
+; Stores checksum byte to the end of COMPATIBLE_EDPT struct.
+;
+; CompatibleDPT_StoreChecksum
+;	Parameters:
+;		DS:SI:	Ptr to COMPATIBLE_EDPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+CompatibleDPT_StoreChecksum:
+	xor		ax, ax
+	xor		bx, bx
+	mov		cx, COMPATIBLE_EDPT_size-1
+ALIGN JUMP_ALIGN
+.SumLoop:
+	add		al, [bx+si]
+	inc		bx
+	loop	.SumLoop
+	neg		al
+	mov		[si+COMPATIBLE_EDPT.bChecksum], al
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CreateDPT.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CreateDPT.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/CreateDPT.asm	(revision 37)
@@ -0,0 +1,384 @@
+; File name		:	CreateDPT.asm
+; Project name	:	IDE BIOS
+; Created date	:	12.3.2010
+; Last update	:	26.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for creating Disk Parameter Table.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Creates new Disk Parameter Table for detected hard disk.
+; Drive is then fully accessible using any BIOS function.
+;
+; CreateDPT_FromAtaInformation
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;		DS:		RAMVARS segment
+;		ES:		BDA Segment
+;	Returns:
+;		DL:		Drive number for new drive
+;		DS:DI:	Ptr to Disk Parameter Table (if succesfull)
+;		CF:		Cleared if DPT created successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX, BX, DH
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_FromAtaInformation:
+	call	FindDPT_ForNewDrive		; Get new DPT to DS:DI
+	call	CreateDPT_Initialize
+	call	CreateDPT_StoreDriveControlByte
+	call	CreateDPT_StorePCHS
+	call	CreateDPT_StoreLCHS
+	call	CreateDPT_StoreAddressing
+	call	CreateDPT_StoreBlockMode
+	call	CreateDPT_StoreEBIOSSupport
+	jmp		CreateDPT_StoreDriveNumberAndUpdateDriveCount
+
+
+;--------------------------------------------------------------------
+; Initializes empty DPT by storing initial values that are not
+; read from ATA information.
+;
+; CreateDPT_Initialize
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_Initialize:
+	xor		ax, ax						; Clear AX and CF
+	mov		BYTE [di+DPT.bSize], DPT_size
+	mov		BYTE [di+DPT.bDrvNum], al
+	mov		BYTE [di+DPT.bFlags], al
+	mov		BYTE [di+DPT.bReset], MASK_RESET_ALL
+	mov		WORD [di+DPT.bIdeOff], bp
+	mov		BYTE [di+DPT.bDrvSel], bh
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores Drive Control Byte for Device Control Register.
+;
+; CreateDPT_StoreDriveControlByte
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreDriveControlByte:
+	xor		ax, ax							; Zero AX
+	cmp		BYTE [cs:bp+IDEVARS.bIRQ], 0	; Interrupts enabled?
+	jne		SHORT .CheckHeadCount
+	or		al, FLG_IDE_CTRL_nIEN			; Disable interrupts
+ALIGN JUMP_ALIGN
+.CheckHeadCount:
+	cmp		BYTE [es:si+ATA1.wHeadCnt], 8	; 1...8 heads?
+	jbe		SHORT .StoreDriveControlByte
+	or		al, FLG_IDE_CTRL_O8H			; Over 8 heads (pre-ATA)
+ALIGN JUMP_ALIGN
+.StoreDriveControlByte:
+	mov		[di+DPT.bDrvCtrl], al
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores P-CHS values from ATA information or user specified values to DPT.
+;
+; CreateDPT_StorePCHS
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StorePCHS:
+	call	CreateDPT_GetUserOrAtaPCHS
+	mov		[di+DPT.wPCyls], ax
+	mov		[di+DPT.bPHeads], bh
+	mov		[di+DPT.bPSect], bl
+	clc
+	ret
+
+;--------------------------------------------------------------------
+; Returns user specified P-CHS or values read from ATA information.
+;
+; CreateDPT_GetUserOrAtaPCHS
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		AX:		Number of P-CHS cylinders
+;		BL:		Number of P-CHS sectors per track
+;		BH:		Number of P-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_GetUserOrAtaPCHS:
+	mov		ax, FLG_DRVPARAMS_USERCHS	; User specified CHS?
+	call	AccessDPT_TestIdeVarsFlagsForMasterOrSlaveDrive
+	jnz		SHORT CreateDPT_GetUserSpecifiedPCHS
+	jmp		AtaID_GetPCHS
+
+;--------------------------------------------------------------------
+; Returns user specified P-CHS values from ROMVARS.
+;
+; CreateDPT_GetUserSpecifiedPCHS
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		AX:		Number of user specified P-CHS cylinders
+;		BL:		Number of user specified P-CHS sectors per track
+;		BH:		Number of user specified P-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_GetUserSpecifiedPCHS:
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	mov		ax, [cs:bx+DRVPARAMS.wCylinders]
+	mov		bx, [cs:bx+DRVPARAMS.wSectAndHeads]
+	or		BYTE [di+DPT.bFlags], FLG_DPT_USERCHS
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores L-CHS values by converting from P-CHS values if necessary.
+;
+; CreateDPT_StoreLCHS
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreLCHS:
+	mov		cx, [di+DPT.wPCyls]			; P-CHS Cylinders (1...16383)
+	eMOVZX	dx, BYTE [di+DPT.bPHeads]	; P-CHS Heads (1...16)
+	call	CreateDPT_ShiftPCHtoLCH
+	test	dh, dh						; 256 heads?
+	jz		SHORT .StoreToDPT			;  If less, no correction needed
+	dec		dx							; Limit to 255 heads since DOS does not support 256 heads
+ALIGN JUMP_ALIGN
+.StoreToDPT:
+	mov		[di+DPT.bShLtoP], al
+	mov		[di+DPT.wLHeads], dx
+	clc
+	ret
+
+;--------------------------------------------------------------------
+; Returns L-CHS values from P-CHS values.
+; Sectors per track is always the same for both addressing modes.
+;
+; CreateDPT_ShiftPCHtoLCH:
+;	Parameters:
+;		CX:		Number of P-CHS cylinders (1...16383)
+;		DX:		Number of P-CHS heads (1...16)
+;	Returns:
+;		AL:		Number of bits shifted
+;		CX:		Number of L-CHS cylinders (1...1024)
+;		DX:		Number of L-CHS heads (1...256)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_ShiftPCHtoLCH:
+	xor		al, al				; Zero AL
+ALIGN JUMP_ALIGN
+.ShiftLoop:
+	cmp		cx, 1024			; Need to shift?
+	jbe		SHORT .Return		;  If not, return
+	inc		ax					; Increment shift count
+	shr		cx, 1				; Halve cylinders
+	shl		dx, 1				; Double heads
+	jmp		SHORT .ShiftLoop
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores addressing information (L-CHS, P-CHS, LBA28 or LBA48).
+;
+; CreateDPT_StoreAddressing
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreAddressing:
+	cmp		WORD [di+DPT.wPCyls], 1024		; L-CHS possible? (no translation needed)
+	jbe		SHORT .Return					;  If so, nothing needs to be changed
+	test	BYTE [di+DPT.bFlags], FLG_DPT_USERCHS
+	jnz		SHORT .StorePCHS				; Use user defined P-CHS
+	test	WORD [es:si+ATA1.wCaps], A2_wCaps_LBA
+	jz		SHORT .StorePCHS				; Use P-CHS since LBA not supported
+	test	WORD [es:si+ATA6.wSetSup83], A6_wSetSup83_LBA48
+	jz		SHORT .StoreLBA28				; Use LBA-28 since LBA-48 not supported
+	or		BYTE [di+DPT.bFlags], ADDR_DPT_LBA48<<1
+ALIGN JUMP_ALIGN
+.StoreLBA28:
+	or		BYTE [di+DPT.bFlags], ADDR_DPT_LBA28<<1
+	or		BYTE [di+DPT.bDrvSel], FLG_IDE_DRVHD_LBA
+	ret
+ALIGN JUMP_ALIGN
+.StorePCHS:
+	or		BYTE [di+DPT.bFlags], ADDR_DPT_PCHS<<1
+ALIGN JUMP_ALIGN
+.Return:
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores Block Mode information.
+;
+; CreateDPT_StoreBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreBlockMode:
+	mov		al, 1						; Minimum block size is 1 sector
+	mov		ah, [es:si+ATA1.bBlckSize]	; Load max block size in sectors
+	mov		[di+DPT.wSetAndMaxBlock], ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores variables required by EBIOS functions.
+;
+; CreateDPT_StoreEBIOSSupport
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreEBIOSSupport:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE	; (clears CF)
+	jz		SHORT .DoNotSupportEBIOS	; No EBIOS support since small DPTs needed
+	mov		bl, [di+DPT.bFlags]
+	and		bx, BYTE MASK_DPT_ADDR		; Addressing mode (clears CF)
+	jmp		[cs:bx+.rgwAddrJmp]			; Jump to handle addressing mode
+ALIGN WORD_ALIGN
+.rgwAddrJmp:
+	dw		.DoNotSupportEBIOS			; ADDR_DPT_LCHS
+	dw		.DoNotSupportEBIOS			; ADDR_DPT_PCHS
+	dw		.SupportForLBA28			; ADDR_DPT_LBA28
+	dw		.SupportForLBA48			; ADDR_DPT_LBA48
+ALIGN JUMP_ALIGN
+.DoNotSupportEBIOS:
+	ret
+ALIGN JUMP_ALIGN
+.SupportForLBA28:
+	sub		BYTE [di+DPT.bSize], 2		; Only 4 bytes for sector count
+ALIGN JUMP_ALIGN
+.SupportForLBA48:
+	add		BYTE [di+DPT.bSize], EBDPT_size - DPT_size
+	or		BYTE [di+DPT.bFlags], FLG_DPT_EBIOS
+	; Fall to CreateDPT_StoreEbiosSectorCount
+
+;--------------------------------------------------------------------
+; Stores EBIOS total sector count for LBA addressing.
+;
+; CreateDPT_StoreEbiosSectorCount
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+CreateDPT_StoreEbiosSectorCount:
+	call	AtaID_GetTotalSectorCount
+	mov		[di+EBDPT.twCapacity], ax
+	mov		[di+EBDPT.twCapacity+2], dx
+	mov		[di+EBDPT.twCapacity+4], bx
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores number for drive and updates drive count.
+;
+; CreateDPT_StoreDriveNumberAndUpdateDriveCount
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		ES:		BDA Segment
+;	Returns:
+;		DL:		Drive number for new drive
+;		CF:		Cleared if DPT parameters stored successfully
+;				Set if any error
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+CreateDPT_StoreDriveNumberAndUpdateDriveCount:
+	; Make sure that more drives can be accepted
+	mov		dl, [es:BDA.bHDCount]	; Load number of hard disks
+	test	dl, 80h					; Hard disks at maximum?
+	stc								; Assume error
+	jnz		SHORT .TooManyDrives	;  If so, return
+
+	; Store drive number to DPT
+	or		dl, 80h					; Set bit 7 since hard disk
+	mov		[di+DPT.bDrvNum], dl	; Store drive number
+
+	; Update BDA and RAMVARS
+	inc		BYTE [es:BDA.bHDCount]	; Increment drive count to BDA
+	call	RamVars_IncrementHardDiskCount
+	clc
+.TooManyDrives:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/FindDPT.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/FindDPT.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/FindDPT.asm	(revision 37)
@@ -0,0 +1,216 @@
+; File name		:	FindDPT.asm
+; Project name	:	IDE BIOS
+; Created date	:	14.3.2010
+; Last update	:	12.4.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for finding Disk Parameter Table.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Finds pointer to first unused Disk Parameter Table.
+;
+; FindDPT_ForNewDrive
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to first unused DPT
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ForNewDrive:
+	push	si
+	mov		si, FindDPT_ReturnWrongDPT
+	jmp		SHORT FindDPT_StartIterationAndReturnAfterDone
+
+
+;--------------------------------------------------------------------
+; Finds Disk Parameter Table for
+; Master or Slave drive at wanted port.
+;
+; FindDPT_ForIdeSlaveAtPort
+; FindDPT_ForIdeMasterAtPort
+;	Parameters:
+;		DX:		IDE Base Port address
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Drive number (if DPT found)
+;		DS:DI:	Ptr to DPT
+;		CF:		Set if wanted DPT found
+;				Cleared if DPT not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ForIdeSlaveAtPort:
+	push	si
+	mov		si, FindDPT_IterateToSlaveAtPortCallback
+	jmp		SHORT FindDPT_StartIterationAndReturnAfterDone
+
+ALIGN JUMP_ALIGN
+FindDPT_ForIdeMasterAtPort:
+	push	si
+	mov		si, FindDPT_IterateToMasterAtPortCallback
+	jmp		SHORT FindDPT_StartIterationAndReturnAfterDone
+
+;--------------------------------------------------------------------
+; Iteration callback for finding DPT using
+; IDE base port for Master or Slave drive.
+;
+; FindDPT_IterateToSlaveAtPortCallback
+; FindDPT_IterateToMasterAtPortCallback
+;	Parameters:
+;		DX:		IDE Base Port address
+;		DS:DI:	Ptr to DPT to examine
+;	Returns:
+;		DL:		Drive number if correct DPT
+;		CF:		Set if wanted DPT found
+;				Cleared if wrong DPT
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_IterateToSlaveAtPortCallback:
+	test	BYTE [di+DPT.bDrvSel], FLG_IDE_DRVHD_DRV
+	jnz		SHORT FindDPT_IterateToMasterOrSlaveAtPortCallback
+	jmp		SHORT FindDPT_ReturnWrongDPT	; Return if master drive
+
+ALIGN JUMP_ALIGN
+FindDPT_IterateToMasterAtPortCallback:
+	test	BYTE [di+DPT.bDrvSel], FLG_IDE_DRVHD_DRV
+	jnz		SHORT FindDPT_ReturnWrongDPT	; Return if slave drive
+
+	; If BIOS partitioned, ignore all but first partition
+ALIGN JUMP_ALIGN
+FindDPT_IterateToMasterOrSlaveAtPortCallback:
+	test	BYTE [di+DPT.bFlags], FLG_DPT_PARTITION
+	jz		SHORT .CompareBasePortAddress
+	test	BYTE [di+DPT.bFlags], FLG_DPT_FIRSTPART
+	jz		SHORT FindDPT_ReturnWrongDPT
+ALIGN JUMP_ALIGN
+.CompareBasePortAddress:
+	push	bx
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]		; CS:BX now points to IDEVARS
+	cmp		dx, [cs:bx+IDEVARS.wPort]		; Wanted port?
+	pop		bx
+	jne		SHORT FindDPT_ReturnWrongDPT
+	mov		dl, [di+DPT.bDrvNum]			; Load drive number
+	stc										; Set CF since wanted DPT
+	ret
+
+
+;--------------------------------------------------------------------
+; Finds Disk Parameter Table for drive number.
+; IDE Base Port address will be stored to RAMVARS if correct DPT is found.
+;
+; FindDPT_ForDriveNumber
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		CF:		Set if wanted DPT found
+;				Cleared if DPT not found
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ForDriveNumber:
+	push	si
+	mov		si, FindDPT_IterateToDriveNumberCallback
+FindDPT_StartIterationAndReturnAfterDone:
+	call	FindDPT_IterateAllDPTs
+	pop		si
+	ret
+
+;--------------------------------------------------------------------
+; Iteration callback for finding DPT for drive number.
+;
+; FindDPT_IterateToDriveNumberCallback
+;	Parameters:
+;		DL:		Drive number to search for
+;		DS:DI:	Ptr to DPT to examine
+;	Returns:
+;		CF:		Set if wanted DPT found
+;				Cleared if wrong DPT
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_IterateToDriveNumberCallback:
+	cmp		dl, [di+DPT.bDrvNum]			; Wanted DPT found?
+	je		SHORT FindDPT_RightDriveNumber	;  If so, return
+FindDPT_ReturnWrongDPT:
+	clc										; Clear CF since wrong DPT
+	ret
+ALIGN JUMP_ALIGN
+FindDPT_RightDriveNumber:
+	push	bx
+	eMOVZX	bx, BYTE [di+DPT.bIdeOff]		; CS:BX now points to IDEVARS
+	mov		bx, [cs:bx+IDEVARS.wPort]		; Load IDE Base Port address...
+	mov		[RAMVARS.wIdeBase], bx			; ...and store it to RAMVARS
+	pop		bx
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; Iterates all Disk Parameter Tables.
+;
+; FindDPT_IterateAllDPTs
+;	Parameters:
+;		BX,DX:	Parameters to callback function
+;		CS:SI:	Ptr to callback function
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to wanted DPT (if found)
+;		CF:		Set if wanted DPT found
+;				Cleared if DPT not found
+;	Corrupts registers:
+;		Nothing, unless corrupted by callback function
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_IterateAllDPTs:
+	push	ax
+	push	cx
+	call	FindDPT_PointToFirstDPT		; Point DS:DI to first DPT
+	eMOVZX	cx, BYTE [RAMVARS.bDrvCnt]	; Load number of drives
+	xor		ax, ax						; Zero AX for DPT size and clear CF
+	jcxz	.Return						; Return if no drives
+ALIGN JUMP_ALIGN
+.LoopWhileDPTsLeft:
+	call	si							; Is wanted DPT?
+	jc		SHORT .Return				;  If so, return
+	mov		al, [di+DPT.bSize]			; Load DPT size to AX
+	add		di, ax						; Point to next DPT
+	loop	.LoopWhileDPTsLeft			; Check next DPT
+	clc									; Clear CF since DPT not found
+ALIGN JUMP_ALIGN
+.Return:
+	pop		cx
+	pop		ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Sets DI to point to first Disk Parameter Table.
+;
+; FindDPT_PointToFirstDPT
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DI:		Offset to first DPT (even if unused)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_PointToFirstDPT:
+	mov		di, RAMVARS_size
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jz		SHORT .Return							; RAMVARS used (top of interrupt vectors)
+	add		di, BYTE FULLRAMVARS_size-RAMVARS_size	; FULLRAMVARS used (top of base memory)
+ALIGN JUMP_ALIGN
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/RamVars.asm
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/RamVars.asm	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/Src/VariablesAndDPTs/RamVars.asm	(revision 37)
@@ -0,0 +1,248 @@
+; File name		:	RamVars.asm
+; Project name	:	IDE BIOS
+; Created date	:	14.3.2010
+; Last update	:	23.8.2010
+; Author		:	Tomi Tilli
+; Description	:	Functions for accessings RAMVARS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Initializes RAMVARS.
+; Drive detection can be started after this function returns.
+;
+; RamVars_Initialize
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DI, DS, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_Initialize:
+	call	.StealMemoryForRAMVARS	; Get RAMVARS segment to DS even if no stealing
+	call	.ClearRamvarsFromDS
+	jmp		DriveXlate_Reset
+
+;--------------------------------------------------------------------
+; .StealMemoryForRAMVARS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.StealMemoryForRAMVARS:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jz		SHORT RamVars_GetSegmentToDS
+
+	LOAD_BDA_SEGMENT_TO	ds, ax		; Zero AX
+	mov		al, [cs:ROMVARS.bStealSize]
+	sub		[BDA.wBaseMem], ax
+	mov		ax, [BDA.wBaseMem]
+	eSHL_IM	ax, 6					; Segment to first stolen kB (*=40h)
+	mov		ds, ax
+	ret
+
+;--------------------------------------------------------------------
+; .ClearRamvarsFromDS
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.ClearRamvarsFromDS:
+	call	FindDPT_PointToFirstDPT	; Get RAMVARS/FULLRAMVARS size to DI
+	mov		cx, di					; Copy byte count to CX
+	push	ds
+	pop		es
+	xor		di, di					; ES:DI now points to RAMVARS/FULLRAMVARS
+	xor		ax, ax					; Store zeroes
+	rep stosb
+	mov		WORD [FULLRAMVARS.wSign], W_SIGN_FULLRAMVARS
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns segment to RAMVARS.
+; RAMVARS might be located at the top of interrupt vectors (0030:0000h)
+; or at the top of system base RAM.
+;
+; RamVars_GetSegmentToDS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_GetSegmentToDS:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jnz		SHORT .GetStolenSegmentToDS
+	mov		di, SEGMENT_RAMVARS_TOP_OF_INTERRUPT_VECTORS
+	mov		ds, di
+	ret
+
+ALIGN JUMP_ALIGN
+.GetStolenSegmentToDS:
+	LOAD_BDA_SEGMENT_TO	ds, di
+	mov		di, [BDA.wBaseMem]		; Load available base memory size in kB
+	eSHL_IM	di, 6					; Segment to first stolen kB (*=40h)
+ALIGN JUMP_ALIGN
+.LoopStolenKBs:
+	mov		ds, di					; EBDA segment to DS
+	add		di, BYTE 64				; DI to next stolen kB
+	cmp		WORD [FULLRAMVARS.wSign], W_SIGN_FULLRAMVARS
+	jne		SHORT .LoopStolenKBs	; Loop until sign found (always found eventually)
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks if INT 13h function is handled by this BIOS.
+;
+; RamVars_IsFunctionHandledByThisBIOS
+;	Parameters:
+;		AH:		INT 13h function number
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set if function is handled by this BIOS
+;				Cleared if function belongs to some other BIOS
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_IsFunctionHandledByThisBIOS:
+	test	ah, ah			; Reset for all floppy and hard disk drives?
+	jz		SHORT .FunctionIsHandledByOurBIOS
+	cmp		ah, 08h			; Read Disk Drive Parameters?
+	jne		SHORT RamVars_IsDriveHandledByThisBIOS
+	test	dl, 80h			; We dot not handle floppy drives
+	jz		SHORT .FunctionIsNotHandledByOurBIOS
+ALIGN JUMP_ALIGN
+.FunctionIsHandledByOurBIOS:
+	stc
+.FunctionIsNotHandledByOurBIOS:
+	ret
+
+;--------------------------------------------------------------------
+; Checks if drive is handled by this BIOS.
+;
+; RamVars_IsDriveHandledByThisBIOS
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set if drive is handled by this BIOS
+;				Cleared if drive belongs to some other BIOS
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_IsDriveHandledByThisBIOS:
+	xchg	di, ax								; Backup AX
+	mov		ax, [RAMVARS.wDrvCntAndFirst]		; Drive count to AL, First number to AH
+	add		al, ah								; One past last drive to AL
+	cmp		dl, al								; Above last supported?
+	jae		SHORT .DriveNotHandledByThisBIOS
+	cmp		dl, ah								; Below first supported?
+	jb		SHORT .DriveNotHandledByThisBIOS
+	xchg	ax, di
+	stc
+	ret
+ALIGN JUMP_ALIGN
+.DriveNotHandledByThisBIOS:
+	xchg	ax, di
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; Increments hard disk count to RAMVARS.
+;
+; RamVars_IncrementHardDiskCount
+;	Parameters:
+;		DL:		Drive number for new drive
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_IncrementHardDiskCount:
+	inc		BYTE [RAMVARS.bDrvCnt]		; Increment drive count to RAMVARS
+	cmp		BYTE [RAMVARS.bFirstDrv], 0	; First drive set?
+	ja		SHORT .Return				;  If so, return
+	mov		[RAMVARS.bFirstDrv], dl		; Store first drive number
+ALIGN JUMP_ALIGN
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; RamVars_GetHardDiskCountFromBDAtoCX
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		CX:		Total hard disk count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+RamVars_GetHardDiskCountFromBDAtoCX:
+	push	es
+	push	dx
+
+	LOAD_BDA_SEGMENT_TO	es, cx			; Zero CX
+	call	RamVars_GetCountOfKnownDrivesToDL
+	MAX_U	dl, [es:BDA.bHDCount]
+	mov		cl, dl
+
+	pop		dx
+	pop		es
+	ret
+
+;--------------------------------------------------------------------
+; RamVars_GetCountOfKnownDrivesToDL
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Total hard disk count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+RamVars_GetCountOfKnownDrivesToDL:
+	mov		dl, [RAMVARS.bFirstDrv]		; Number for our first drive
+	add		dl, [RAMVARS.bDrvCnt]		; Our drives
+	and		dl, 7Fh						; Clear HD bit for drive count
+	ret
+
+
+;--------------------------------------------------------------------
+; RamVars_GetIdeControllerCountToCX
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Number of IDE controllers to handle
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------	
+ALIGN JUMP_ALIGN
+RamVars_GetIdeControllerCountToCX:
+	mov		cx, 1					; Assume lite mode (one controller)
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jz		SHORT .Return
+	mov		cl, [cs:ROMVARS.bIdeCnt]
+ALIGN JUMP_ALIGN, ret
+.Return:
+	ret
Index: tags/XTIDE_Universal_BIOS_v1.1.4/gpl-2.0.txt
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/gpl-2.0.txt	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/gpl-2.0.txt	(revision 37)
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: tags/XTIDE_Universal_BIOS_v1.1.4/makefile
===================================================================
--- tags/XTIDE_Universal_BIOS_v1.1.4/makefile	(revision 37)
+++ tags/XTIDE_Universal_BIOS_v1.1.4/makefile	(revision 37)
@@ -0,0 +1,124 @@
+###############################################################################
+# Generic makefile for building BIOS binary file.                             #
+# v. 1.0.0 (28.7.2007 ... 28.7.2007)                                          #
+# (C) Tomi Tilli                                                              #
+# aitotat@gmail.com                                                           #
+#                                                                             #
+# Valid makefile targets are:                                                 #
+# all		Removes existing files and builds binary file in \Build           #
+# build		Builds binary file in \Build                                      #
+# clean		Removes all files from \Build                                     #
+#                                                                             #
+# Build directory must be created manually if it does not exist.              #
+#                                                                             #
+###############################################################################
+
+###########################################
+# Source files and destination executable #
+###########################################
+
+# Assembly source code file (*.asm):
+SRC_ASM = Src/Main.asm
+
+# Program executable file name without extension:
+PROG = ide
+
+
+#######################################
+# Destination and include directories #
+#######################################
+
+# Directory where binary file will be compiled to
+BUILD_DIR = Build
+
+# Subdirectories where included files are:
+HEADERS = Inc/
+HEADERS += Src/
+HEADERS += Src/Boot/
+HEADERS += Src/Handlers/
+HEADERS += Src/Handlers/Int13h/
+HEADERS += Src/Handlers/Int13h/Common/
+HEADERS += Src/Initialization/
+HEADERS += Src/Libraries/
+HEADERS += Src/Libraries/menu/
+HEADERS += Src/VariablesAndDPTs/
+
+
+#################################################################
+# Assembler preprocessor defines.                               #
+#################################################################
+DEFINES =
+DEFINES_XT = 
+DEFINES_XTPLUS = USE_186
+DEFINES_AT = USE_186 USE_286 USE_AT
+
+
+###################
+# Other variables #
+###################
+
+# Add -D in front of every preprocessor define declaration
+DEFS = $(DEFINES:%=-D%)
+DEFS_XT = $(DEFINES_XT:%=-D%)
+DEFS_XTPLUS = $(DEFINES_XTPLUS:%=-D%)
+DEFS_AT = $(DEFINES_AT:%=-D%)
+
+# Add -I in front of all header directories
+IHEADERS = $(HEADERS:%=-I%)
+
+# Path + target file to be build
+TARGET = $(BUILD_DIR)/$(PROG)
+
+
+#########################
+# Compilers and linkers #
+#########################
+
+# Make
+MAKE = mingw32-make.exe
+
+# Assembler
+AS = yasm.exe
+#AS = nasm.exe
+
+# use this command to erase files.
+RM = -del /Q
+
+
+#############################
+# Compiler and linker flags #
+#############################
+
+# Assembly compiler flags
+ASFLAGS = -f bin				# Produce binary object files
+ASFLAGS += $(DEFS)				# Preprocessor defines
+ASFLAGS += $(IHEADERS)			# Set header file directory paths
+ASFLAGS += -Worphan-labels		# Warn about labels without colon
+ASFLAGS += -O9					# Optimize operands to their shortest forms
+
+
+############################################
+# Build process. Actual work is done here. #
+############################################
+
+.PHONY: all at xtplus xt clean
+
+# Make clean debug and release versions
+all: clean at xtplus xt
+	@echo All build!
+
+at:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_AT) -o"$(TARGET)_at.bin"
+	@echo AT version "$(TARGET)_at.bin" build.
+
+xtplus:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XTPLUS) -o"$(TARGET)_xtp.bin"
+	@echo XT plus version "$(TARGET)_xtp.bin" build.
+
+xt:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XT) -o"$(TARGET)_xt.bin"
+	@echo XT version "$(TARGET)_xt.bin" build.
+
+clean:
+	@$(RM) $(BUILD_DIR)\*.*
+	@echo Deleted "(*.*)" from "$(BUILD_DIR)/"
