Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/Bootmenu_SerialDetect.txt
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/Bootmenu_SerialDetect.txt	(revision 199)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/Bootmenu_SerialDetect.txt	(revision 199)
@@ -0,0 +1,1 @@
+Set to true, at the end of normal drive detection, COM ports 1-7 (in reverse order) will be scanned for a connection to a serial drive server. This option provides flexibility with the COM port and baud rate to be used, it need not be configured ahead of time, but at the expense of a slower boot process. Even when set to false, this functionality can still be invoked by holding down the ALT key at the end of normal drive detection.
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialBaud.txt
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialBaud.txt	(revision 199)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialBaud.txt	(revision 199)
@@ -0,0 +1,3 @@
+Supported baud rates are 2400, 9600, 38.4K, and 115.2K. The server must also be set to this same speed. Older UARTs may only support 2400 and 9600 baud, but sometimes can be pushed to 38.4K. 115.2K will likely only be possible with a newer UART that inclues a FIFO. Some high speed serial ports include UART clock multipliers, allowing for speeds at 230.4K (2x multiplier) and 460.8K (4x multiplier). These high speeds are supported by these BIOS, even on original 4.77MHz 8088 systems. Note that UART clock multipliers are not detectable by the software and 115.2K will still be used during configuration for high speeds; but if a multiplier is used, the actual speed (including the multiplier) will need to be used on the server.
+
+
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialCOM.txt
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialCOM.txt	(revision 199)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialCOM.txt	(revision 199)
@@ -0,0 +1,1 @@
+Select a serial port by COM port number. COM1 through COM4 have well established I/O port assignments, COM5 and onward are less well established. "COMA" represents COM10, "COMB" represents COM11, and "COMC" represents COM12. Selecting COMx enables the manual selection of an I/O port address.
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialPort.txt
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialPort.txt	(revision 199)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/Help/IDE_SerialPort.txt	(revision 199)
@@ -0,0 +1,1 @@
+Select a serial port by I/O address. Supported values are between 240h and 438h, and must be on an 8-byte boundary. If the entered value corresponds to one fo the established COM port numbers, then the selection of serial port will use COM numbers instead.
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc	(revision 187)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc	(revision 199)
@@ -50,4 +50,6 @@
 	.wMaxValue:
 	.wValueBitmask			resb	2	; Bitmask for item value flag
+	.fnValueReader			resb	2	; Called just after ROMVARS is read, providing a hook for further action
+	.fnValueWriter			resb	2	; Called just before ROMVARS is written, providing a hook for further action
 endstruc
 
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menuitem.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menuitem.asm	(revision 187)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menuitem.asm	(revision 199)
@@ -190,7 +190,13 @@
 ALIGN JUMP_ALIGN
 .TranslateChoiceToValueUsingLookupTable:
+;
+; if the lookup pointer is NULL, no translation is needed
+; 
+	mov		bx, [si+MENUITEM.itemValue+ITEM_VALUE.rgwChoiceToValueLookup]
+	test	bx, bx
+	jz		.StoreByteOrWordValueFromAXtoESDIwithItemInDSSI
+		
 	shl		ax, 1			; Shift for WORD lookup
-	add		ax, [si+MENUITEM.itemValue+ITEM_VALUE.rgwChoiceToValueLookup]
-	xchg	bx, ax
+	add		bx, ax
 	mov		ax, [bx]		; Lookup complete
 	; Fall to .StoreByteOrWordValueFromAXtoESDIwithItemInDSSI
@@ -210,7 +216,16 @@
 ALIGN JUMP_ALIGN
 .StoreByteOrWordValueFromAXtoESDIwithItemInDSSI:
+	push	bx
+	mov		bx,[si+MENUITEM.itemValue+ITEM_VALUE.fnValueWriter]
+	test	bx,bx
+	jz		SHORT .NoWriter	
+
+	call	bx		
+
+.NoWriter:
+	pop		bx
 	test	BYTE [si+MENUITEM.bFlags], FLG_MENUITEM_BYTEVALUE
 	jnz		SHORT .StoreByteFromAL
-
+		
 	mov		[es:di+1], ah
 ALIGN JUMP_ALIGN
@@ -269,7 +284,17 @@
 	push	es
 	push	di
+	push	bx
 	call	GetConfigurationBufferToESDIforMenuitemInDSSI
 	add		di, [si+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset]
 	mov		ax, [es:di]
+
+	mov		bx, [si+MENUITEM.itemValue+ITEM_VALUE.fnValueReader]
+	test	bx,bx
+	jz		SHORT .NoReader
+
+	call	bx
+
+.NoReader:		
+	pop		bx
 	pop		di
 	pop		es
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/BootMenuSettingsMenu.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/BootMenuSettingsMenu.asm	(revision 187)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/BootMenuSettingsMenu.asm	(revision 199)
@@ -10,5 +10,5 @@
 	at	MENUPAGE.fnEnter,			dw	BootMenuSettingsMenu_EnterMenuOrModifyItemVisibility
 	at	MENUPAGE.fnBack,			dw	ConfigurationMenu_EnterMenuOrModifyItemVisibility
-	at	MENUPAGE.wMenuitems,		dw	6
+	at	MENUPAGE.wMenuitems,		dw	7
 iend
 
@@ -66,5 +66,5 @@
 	at	MENUITEM.itemValue + ITEM_VALUE.szDialogTitle,				dw	g_szDlgBootFloppyDrvs
 	at	MENUITEM.itemValue + ITEM_VALUE.szMultichoice,				dw	g_szMultichoiceBootFloppyDrvs
-	at	MENUITEM.itemValue + ITEM_VALUE.rgwChoiceToValueLookup,		dw	g_rgwChoiceToValueLookupForFloppyDrives
+	at	MENUITEM.itemValue + ITEM_VALUE.rgwChoiceToValueLookup,		dw	NULL
 	at	MENUITEM.itemValue + ITEM_VALUE.rgszValueToStringLookup,	dw	g_rgszValueToStringLookupForFloppyDrives
 iend
@@ -101,4 +101,20 @@
 iend
 
+g_MenuitemBootMenuSerialScanDetect:		
+istruc MENUITEM
+	at	MENUITEM.fnActivate,		dw	Menuitem_ActivateMultichoiceSelectionForMenuitemInDSSI
+	at	MENUITEM.fnFormatValue,		dw	MenuitemPrint_WriteLookupValueStringToBufferInESDIfromShiftedItemInDSSI
+	at	MENUITEM.szName,			dw	g_szItemSerialDetect
+	at	MENUITEM.szQuickInfo,		dw	g_szNfoSerialDetect
+	at	MENUITEM.szHelp,			dw	g_szHelpSerialDetect
+	at	MENUITEM.bFlags,			db	FLG_MENUITEM_VISIBLE | FLG_MENUITEM_FLAGVALUE
+	at	MENUITEM.bType,				db	TYPE_MENUITEM_MULTICHOICE
+	at	MENUITEM.itemValue + ITEM_VALUE.wRomvarsValueOffset,		dw	ROMVARS.wFlags
+	at	MENUITEM.itemValue + ITEM_VALUE.szDialogTitle,				dw	g_szDlgSerialDetect
+	at	MENUITEM.itemValue + ITEM_VALUE.szMultichoice,				dw	g_szMultichoiceBooleanFlag
+	at	MENUITEM.itemValue + ITEM_VALUE.rgszValueToStringLookup,	dw	g_rgszValueToStringLookupForFlagBooleans
+	at	MENUITEM.itemValue + ITEM_VALUE.wValueBitmask,				dw	FLG_ROMVARS_SERIAL_SCANDETECT
+iend		
+
 g_rgwChoiceToValueLookupForDisplayModes:
 	dw	DEFAULT_TEXT_MODE
@@ -118,10 +134,4 @@
 	dw	g_szValueBootDispModeMono
 
-g_rgwChoiceToValueLookupForFloppyDrives:	; (No translation)
-	dw	0
-	dw	1
-	dw	2
-	dw	3
-	dw	4
 g_rgszValueToStringLookupForFloppyDrives:
 	dw	g_szValueBootFloppyDrvsAuto
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/IdeControllerMenu.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/IdeControllerMenu.asm	(revision 187)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/IdeControllerMenu.asm	(revision 199)
@@ -10,5 +10,5 @@
 	at	MENUPAGE.fnEnter,			dw	IdeControllerMenu_EnterMenuOrModifyItemVisibility
 	at	MENUPAGE.fnBack,			dw	ConfigurationMenu_EnterMenuOrModifyItemVisibility
-	at	MENUPAGE.wMenuitems,		dw	8
+	at	MENUPAGE.wMenuitems,		dw	11
 iend
 
@@ -50,5 +50,5 @@
 	at	MENUITEM.szQuickInfo,		dw	g_szNfoIdeDevice
 	at	MENUITEM.szHelp,			dw	g_szNfoIdeDevice
-	at	MENUITEM.bFlags,			db	FLG_MENUITEM_VISIBLE | FLG_MENUITEM_BYTEVALUE
+	at	MENUITEM.bFlags,			db	FLG_MENUITEM_VISIBLE | FLG_MENUITEM_BYTEVALUE | FLG_MENUITEM_MODIFY_MENU
 	at	MENUITEM.bType,				db	TYPE_MENUITEM_MULTICHOICE
 	at	MENUITEM.itemValue + ITEM_VALUE.wRomvarsValueOffset,		dw	NULL
@@ -57,4 +57,5 @@
 	at	MENUITEM.itemValue + ITEM_VALUE.rgwChoiceToValueLookup,		dw	g_rgwChoiceToValueLookupForDevice
 	at	MENUITEM.itemValue + ITEM_VALUE.rgszValueToStringLookup,	dw	g_rgszValueToStringLookupForDevice
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueWriter,				dw	IdeControllerMenu_WriteDevice
 iend
 
@@ -89,4 +90,56 @@
 iend
 
+g_MenuitemIdeControllerSerialCOM:
+istruc MENUITEM
+	at	MENUITEM.fnActivate,		dw	Menuitem_ActivateMultichoiceSelectionForMenuitemInDSSI
+	at	MENUITEM.fnFormatValue,		dw	MenuitemPrint_WriteLookupValueStringToBufferInESDIfromUnshiftedItemInDSSI
+	at	MENUITEM.szName,			dw	g_szItemSerialCOM
+	at	MENUITEM.szQuickInfo,		dw	g_szNfoIdeSerialCOM
+	at	MENUITEM.szHelp,			dw	g_szHelpIdeSerialCOM
+	at	MENUITEM.bFlags,			db	FLG_MENUITEM_MODIFY_MENU
+	at	MENUITEM.bType,				db	TYPE_MENUITEM_MULTICHOICE 
+	at	MENUITEM.itemValue + ITEM_VALUE.wRomvarsValueOffset,		dw	NULL
+	at	MENUITEM.itemValue + ITEM_VALUE.szDialogTitle,				dw	g_szDlgDevice
+	at	MENUITEM.itemValue + ITEM_VALUE.szMultichoice,				dw	g_szSerialCOMChoice
+	at	MENUITEM.itemValue + ITEM_VALUE.rgwChoiceToValueLookup,		dw	NULL
+	at	MENUITEM.itemValue + ITEM_VALUE.rgszValueToStringLookup,	dw	g_rgszValueToStringLookupForCOM
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueReader,				dw	IdeControllerMenu_SerialReadCOM  
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueWriter,				dw	IdeControllerMenu_SerialWriteCOM
+iend
+
+g_MenuitemIdeControllerSerialPort:
+istruc MENUITEM
+	at	MENUITEM.fnActivate,		dw	Menuitem_ActivateHexInputForMenuitemInDSSI
+	at	MENUITEM.fnFormatValue,		dw	MenuitemPrint_WriteHexValueStringToBufferInESDIfromItemInDSSI
+	at	MENUITEM.szName,			dw	g_szItemSerialPort
+	at	MENUITEM.szQuickInfo,		dw	g_szNfoIdeSerialPort
+	at	MENUITEM.szHelp,			dw	g_szHelpIdeSerialPort
+	at	MENUITEM.bFlags,			db	FLG_MENUITEM_MODIFY_MENU		
+	at	MENUITEM.bType,				db	TYPE_MENUITEM_HEX
+	at	MENUITEM.itemValue + ITEM_VALUE.wRomvarsValueOffset,		dw	NULL
+	at	MENUITEM.itemValue + ITEM_VALUE.szDialogTitle,				dw	g_szDlgIdeCmdPort
+	at	MENUITEM.itemValue + ITEM_VALUE.wMinValue,					dw	240h
+	at	MENUITEM.itemValue + ITEM_VALUE.wMaxValue,					dw	438h
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueReader,				dw	IdeControllerMenu_SerialReadPort
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueWriter,				dw	IdeControllerMenu_SerialWritePort
+iend		
+
+g_MenuitemIdeControllerSerialBaud:		
+istruc MENUITEM
+	at	MENUITEM.fnActivate,		dw	Menuitem_ActivateMultichoiceSelectionForMenuitemInDSSI
+	at	MENUITEM.fnFormatValue,		dw	MenuitemPrint_WriteLookupValueStringToBufferInESDIfromUnshiftedItemInDSSI
+	at	MENUITEM.szName,			dw	g_szItemSerialBaud
+	at	MENUITEM.szQuickInfo,		dw	g_szNfoIdeSerialBaud
+	at	MENUITEM.szHelp,			dw	g_szHelpIdeSerialBaud
+	at	MENUITEM.bType,				db	TYPE_MENUITEM_MULTICHOICE
+	at	MENUITEM.itemValue + ITEM_VALUE.wRomvarsValueOffset,		dw	NULL
+	at	MENUITEM.itemValue + ITEM_VALUE.szDialogTitle,				dw	g_szDlgDevice
+	at	MENUITEM.itemValue + ITEM_VALUE.szMultichoice,				dw	g_szSerialBaudChoice
+	at	MENUITEM.itemValue + ITEM_VALUE.rgwChoiceToValueLookup,		dw	NULL
+	at	MENUITEM.itemValue + ITEM_VALUE.rgszValueToStringLookup,	dw	g_rgszValueToStringLookupForBaud
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueReader,				dw	IdeControllerMenu_SerialReadBaud
+	at	MENUITEM.itemValue + ITEM_VALUE.fnValueWriter,				dw	IdeControllerMenu_SerialWriteBaud
+iend
+		
 g_MenuitemIdeControllerEnableInterrupt:
 istruc MENUITEM
@@ -135,4 +188,30 @@
 	dw	g_szValueCfgDeviceSerial
 
+g_rgszValueToStringLookupForCOM:		
+	dw	g_szValueCfgCOM1
+	dw	g_szValueCfgCOM2
+	dw	g_szValueCfgCOM3
+	dw	g_szValueCfgCOM4
+	dw	g_szValueCfgCOM5
+	dw	g_szValueCfgCOM6
+	dw	g_szValueCfgCOM7
+	dw	g_szValueCfgCOM8
+	dw	g_szValueCfgCOM9
+	dw	g_szValueCfgCOMA
+	dw	g_szValueCfgCOMB
+	dw	g_szValueCfgCOMC
+	dw	g_szValueCfgCOMx
+
+g_rgszValueToStringLookupForBaud:
+	dw	g_szValueCfgBaud2400
+	dw	g_szValueCfgBaud9600
+	dw	g_szValueCfgBaud38_4
+	dw	g_szValueCfgBaud115_2
+
+g_wPrintBaud:
+	dw	DEVICE_SERIAL_PRINTBAUD_2400
+	dw	DEVICE_SERIAL_PRINTBAUD_9600
+	dw	DEVICE_SERIAL_PRINTBAUD_38_4
+	dw	DEVICE_SERIAL_PRINTBAUD_115_2
 
 ; Section containing code
@@ -161,5 +240,9 @@
 	lea		ax, [bx+IDEVARS.wPort]
 	mov		[cs:g_MenuitemIdeControllerCommandBlockAddress+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
-
+	mov		[cs:g_MenuitemIdeControllerSerialPort+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
+	mov		[cs:g_MenuitemIdeControllerSerialCOM+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax		
+	mov		[cs:g_MenuitemIdeControllerSerialBaud+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
+				;; baud also modifies the next two bytes (print chars in wPortCtrl), but it never reads them
+		
 	lea		ax, [bx+IDEVARS.wPortCtrl]
 	mov		[cs:g_MenuitemIdeControllerControlBlockAddress+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
@@ -168,4 +251,5 @@
 	mov		[cs:g_MenuitemIdeControllerEnableInterrupt+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
 	mov		[cs:g_MenuitemIdeControllerIdeIRQ+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset], ax
+
 	ret
 
@@ -185,4 +269,5 @@
 	pop		ds
 	call	.EnableOrDisableIRQ
+	call	.EnableOrDisableSerial
 	mov		si, g_MenupageForIdeControllerMenu
 	jmp		Menupage_ChangeToNewMenupageInDSSI
@@ -226,5 +311,54 @@
 	ret
 
-
+.EnableOrDisableSerial:
+	mov		bx, g_MenuitemIdeControllerCommandBlockAddress
+	call	.DisableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerControlBlockAddress
+	call	.DisableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerEnableInterrupt
+	call	.DisableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerSerialBaud
+	call	.DisableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerSerialCOM
+	call	.DisableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerSerialPort
+	call	.DisableMenuitemFromCSBX
+				
+	mov		bx, [cs:g_MenuitemIdeControllerDevice+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset]		
+	call	Buffers_GetRomvarsValueToAXfromOffsetInBX
+	cmp		al,DEVICE_SERIAL_PORT
+	jnz		.DisableAllSerial
+
+	mov		bx, g_MenuitemIdeControllerSerialCOM
+	call	.EnableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerSerialBaud
+	call	.EnableMenuitemFromCSBX
+
+	mov		bx, [cs:g_MenuitemIdeControllerSerialCOM+MENUITEM.itemValue+ITEM_VALUE.wRomvarsValueOffset]			
+	call	Buffers_GetRomvarsValueToAXfromOffsetInBX
+	mov		bx, g_MenuitemIdeControllerSerialPort
+	cmp		al,'x'
+	jz		.EnableMenuitemFromCSBX
+	jmp		.DisableMenuitemFromCSBX
+
+.DisableAllSerial:
+
+	mov		bx, g_MenuitemIdeControllerCommandBlockAddress
+	call	.EnableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerControlBlockAddress
+	call	.EnableMenuitemFromCSBX
+
+	mov		bx, g_MenuitemIdeControllerEnableInterrupt
+	call	.EnableMenuitemFromCSBX				
+
+	ret
+		
 ;--------------------------------------------------------------------
 ; MENUITEM activation functions (.fnActivate)
@@ -250,2 +384,243 @@
 	call	MasterSlaveMenu_InitializeToDrvparamsOffsetInBX
 	jmp		MasterSlaveMenu_EnterMenuOrModifyItemVisibility
+
+PackedCOMPortAddresses:				; COM1 - COMC (or COM12)
+	db      (DEVICE_SERIAL_COM1 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COM2 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COM3 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COM4 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1   
+	db		(DEVICE_SERIAL_COM5 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COM6 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COM7 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1   
+	db		(DEVICE_SERIAL_COM8 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1   
+	db		(DEVICE_SERIAL_COM9 - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COMA - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1   
+	db		(DEVICE_SERIAL_COMB - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1
+	db		(DEVICE_SERIAL_COMC - DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT) >> 1  
+	db		0						; null terminated
+
+;------------------------------------------------------------------------------------------
+;
+; Reader/Writer Routines
+;
+; For serial drives, we pack the port number and baud rate into a single byte, and thus
+; we need to take care to properly read/write just the bits we need.  In addition, since
+; we use the Port/PortCtrl bytes in a special way for serial drives, we need to properly
+; default the values stored in both these words  when switching in and out of the Serial 
+; device choice.
+;
+; Writers:
+;	Parameters:
+;       AX:     Value that the MENUITEM system was interacting with
+;		ES:DI:  ROMVARS location where the value is to be stored
+;	    DS:SI:  MENUITEM pointer
+;	Returns:
+;		AX:		Value to actually write to ROMVARS
+;	Corrupts registers:
+;		AX
+;
+; Readers:
+;	Parameters:
+;       AX:     Value read from the ROMVARS location
+;		ES:DI:  ROMVARS location where the value was just read from
+;	    DS:SI:  MENUITEM pointer
+;	Returns:
+;		AX:		Value that the MENUITEM system will interact with and display
+;	Corrupts registers:
+;		AX
+;
+
+;
+; No change to Device byte, but use this opportunity to change defaults stored in wPort and wPortCtrl if we are
+; changing in/out of a Serial device (since we use these bytes in radically different ways).  Also clear the
+; interrupt informtion is we are moving into Serial (since the serial device does not use interrupts).
+;
+ALIGN JUMP_ALIGN
+IdeControllerMenu_WriteDevice:
+		push	ax
+		push	bx
+		push	di
+
+		mov		bl,[es:di]							; what is the current Device?
+		
+		add		di,IDEVARS.wPort - IDEVARS.bDevice	; Get ready to set the Port addresses
+		
+		cmp		al,DEVICE_SERIAL_PORT
+		jz		.changingToSerial
+
+		cmp		bl,DEVICE_SERIAL_PORT
+		jnz		.done								; if we weren't Serial before, nothing to do
+
+.changingFromSerial:
+		cmp		al,DEVICE_16BIT_ATA
+		jl		.xtide
+
+		mov		ax,DEVICE_ATA_DEFAULT_PORT			; Defaults for 16-bit and better ATA devices
+		mov		bx,DEVICE_ATA_DEFAULT_PORTCTRL
+		jmp		.writeNonSerial
+
+.xtide:	
+		mov		ax,DEVICE_XTIDE_DEFAULT_PORT		; Defaults for 8-bit XTIDE devices
+		mov		bx,DEVICE_XTIDE_DEFAULT_PORTCTRL		
+
+.writeNonSerial:		
+		mov		[es:di],ax							; Store defaults in IDEVARS.wPort and IDEVARS.wPortCtrl
+		mov		[es:di+2],bx
+
+		jmp		.done
+
+.changingToSerial:		
+		cmp		bl,DEVICE_SERIAL_PORT
+		jz		.done								; if we were already serial, nothing to do
+
+		mov		ax,DEVICE_SERIAL_DEFAULT_COM
+		call	IdeControllerMenu_SerialWriteCOM
+		mov		[es:di],ax
+		
+		mov		ax,DEVICE_SERIAL_DEFAULT_BAUD
+		call	IdeControllerMenu_SerialWriteBaud
+		mov		[es:di],ax
+				
+		add		di,IDEVARS.bIRQ - IDEVARS.wPort		; clear out the interrupt information, we don't use interrupts
+		mov		al,0
+		mov		[es:di],al
+
+.done:	
+		pop		di
+		pop		bx
+		pop		ax
+
+		ret
+
+;
+; "COMn" ASCII characer -> Numeric COM number
+;
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialReadCOM:
+		xor		ah,ah								; clear out packedportbaud value
+
+		cmp		al,'x'								; base this on the ASCII character used to print
+		jz		.custom
+
+		cmp		al,'A'
+		jae		.over10
+
+		sub		al, '0'+1							; convert ASCII value '0'-'9' to numeric
+		ret
+
+.over10:
+		sub		al, 'A'-10+1						; convert ASCII value 'A'-'C' to numeric
+		ret
+
+.custom:
+		mov		al, 12								; convert ASCII value 'x' (for custom) to numeric
+		ret
+
+;
+; Numeric COM number -> Packed port address, and update ASCII character for printing "COMn"
+;				
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialWriteCOM:
+		push	bx
+
+		cmp		al,12								; custom?
+		jge		.custom
+
+		mov		bx,ax								; lookup packed port address based on COM address
+		mov		ah,[cs:bx+PackedCOMPortAddresses]
+
+		cmp		al,9								; COMA or higher, but not custom
+		jge		.atorabove10
+
+		add		al, '0'+1							; convert numeric to ASCII '1' to '9'
+		jmp		IdeControllerMenu_SerialWriteCOM_PackAndRet
+
+.custom:
+		mov		al,'x'								; ASCII value 'x' for custom
+		mov		ah,0								; 240h is default custom value
+		jmp		IdeControllerMenu_SerialWriteCOM_PackAndRet
+
+.atorabove10:
+		add		al, 'A'-10+1						; convert numeric to ASCII 'A' to 'C'
+
+IdeControllerMenu_SerialWriteCOM_PackAndRet:
+		mov		bl,[es:di+1]						; read baud rate bits
+		and		bl,DEVICE_SERIAL_PACKEDPORTANDBAUD_BAUDMASK  	
+		or		ah,bl
+
+		pop		bx
+		ret		
+
+;
+; Packed Baud -> Numeric Baud
+;				
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialReadBaud:
+		xchg	al,ah
+		and		ax,DEVICE_SERIAL_PACKEDPORTANDBAUD_BAUDMASK			; also clears high order byte
+		ret
+
+;
+; Numeric Baud -> Packed Baud, also update ASCII printing characters for baud rate
+;				
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialWriteBaud:
+		and		ax,DEVICE_SERIAL_PACKEDPORTANDBAUD_BAUDBITS 		; ensure we only have the bits we want
+		
+		push	bx
+
+		mov		bx,ax												; lookup printing word for wPortCtrl
+		shl		bx,1
+		mov		bx,[cs:bx+g_wPrintBaud]
+		mov		[es:di+2],bx
+
+		xchg	al,ah												; or in port bits
+		mov		bx,[es:di]
+		and		bh,DEVICE_SERIAL_PACKEDPORTANDBAUD_PORTMASK 
+		or		ax,bx
+
+		pop		bx
+		ret
+
+;
+; Packed Port -> Numeric Port
+;				
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialReadPort:		
+		mov		al,ah
+		and		ax,DEVICE_SERIAL_PACKEDPORTANDBAUD_PORTMASK    		; note that this clears AH
+		shl		ax,1
+		add		ax,DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT
+		ret
+
+;
+; Numeric Port -> Packed Port, convert from Custom to a defined COM port if we match one
+;
+ALIGN JUMP_ALIGN
+IdeControllerMenu_SerialWritePort:		
+		push	bx
+
+		sub		ax,DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT		; convert from numeric to packed port number
+		shr		ax,1
+		and		al,DEVICE_SERIAL_PACKEDPORTANDBAUD_PORTMASK
+
+		mov		bx,PackedCOMPortAddresses							; loop, looking for port address in known COM address list
+.next:	
+		mov		ah,[cs:bx]
+		inc		bx
+		test	ah,ah
+		jz		.notfound
+		cmp		al,ah
+		jnz		.next
+
+		sub		bx,PackedCOMPortAddresses + 1						; FOUND!, +1 since we already incremented
+		mov		ax,bx
+		pop		bx
+		jmp		IdeControllerMenu_SerialWriteCOM					; if found, use that logic to get ASCII character
+
+.notfound:
+		xchg	ah,al												
+		mov		al,'x'
+		jmp		IdeControllerMenu_SerialWriteCOM_PackAndRet
+
+
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Strings.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Strings.asm	(revision 187)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Strings.asm	(revision 199)
@@ -67,4 +67,5 @@
 g_szDlgFileFilter:		db	"*.*",NULL
 
+
 g_szNfoMainExitToDOS:	db	"Quits XTIDE Universal BIOS Configurator.",NULL
 g_szNfoMainLoadFile:	db	"Load BIOS file to be configured or flashed.",NULL
@@ -111,4 +112,10 @@
 g_szItemIdeEnIRQ:		db	"Enable interrupt",NULL
 g_szItemIdeIRQ:			db	"IRQ",NULL
+g_szItemSerialCOM:		db	"COM Port",NULL
+g_szItemSerialBaud:		db	"Baud Rate",NULL
+g_szItemSerialPort:		db	"COM Port I/O address",NULL
+
+g_szItemIdeSerialComPort:		db		"COM port",NULL
+g_szItemIdeSerialBaudRate:		db		"Baud rate",NULL
 
 g_szDlgDevice:			db	"Select controller type.",NULL
@@ -117,5 +124,5 @@
 g_szDlgIdeEnIRQ:		db	"Enable interrupt?",NULL
 g_szDlgIdeIRQ:			db	"Enter IRQ channel (2...7 for 8-bit controllers, 2...15 for any other controller).",NULL
-
+		
 g_szNfoIdeBackToCfgMenu:db	"Back to XTIDE Universal BIOS Configuration Menu.",NULL
 g_szNfoIdeMaster:		db	"Settings for Master Drive.",NULL
@@ -123,7 +130,10 @@
 g_szNfoIdeDevice:		db	"Select controller device type.",NULL
 g_szNfoIdeCmdPort:		db	"IDE Controller Command Block (base port) address.",NULL
-g_szNfoIdeCtrlPort:		db	"IDE Controller Control Block address. Usually Cmd Block + 200h.",NULL
+g_szNfoIdeCtrlPort:		db	"IDE Controller Control Block address. Usually Cmd Block + 8 for XTIDE, and Cmd Block + 200h for ATA.",NULL
 g_szNfoIdeEnIRQ:		db	"Interrupt or polling mode.",NULL
 g_szNfoIdeIRQ:			db	"IRQ channel to use.",NULL
+g_szNfoIdeSerialCOM:	db	"Select a COM port by number.",NULL
+g_szNfoIdeSerialBaud:	db	"Select the COM port's Baud Rate. The server must match this speed. Note UART clock multipliers may impact the actual speed.",NULL
+g_szNfoIdeSerialPort:	db	"Select a COM port by custom I/O port address. Address must be in the range 240h and 438h and be on an 8-byte boundary.", NULL
 
 g_szHelpIdeCmdPort:		incbin	"IDE_CommandPort.txt"
@@ -135,4 +145,10 @@
 g_szHelpIdeIRQ:			incbin	"IDE_IRQ.txt"
 						db	NULL
+g_szHelpIdeSerialCOM:	incbin  "IDE_SerialCOM.txt"
+						db	NULL
+g_szHelpIdeSerialPort:	incbin  "IDE_SerialPort.txt"
+						db  NULL
+g_szHelpIdeSerialBaud:	incbin  "IDE_SerialBaud.txt"
+						db  NULL
 
 g_szMultichoiceCfgDevice:
@@ -144,4 +160,44 @@
 						db	"Serial port virtual device",NULL
 
+g_szSerialCOMChoice:
+						db  "COM1 - Port 3f8h",LF
+						db	"COM2 - Port 2f8h",LF
+						db  "COM3 - Port 3e8h",LF
+						db  "COM4 - Port 2e8h",LF
+						db  "COM5 - Port 2f0h",LF
+						db  "COM6 - Port 3e0h",LF
+						db	"COM7 - Port 2e0h",LF
+						db	"COM8 - Port 260h",LF
+						db	"COM9 - Port 368h",LF
+						db	"COMA - Port 268h",LF
+						db	"COMB - Port 360h",LF
+						db	"COMC - Port 270h",LF
+						db  "COMx - Custom Port",NULL
+
+g_szValueCfgCOM1:		db		"COM1",NULL
+g_szValueCfgCOM2:		db		"COM2",NULL
+g_szValueCfgCOM3:		db		"COM3",NULL
+g_szValueCfgCOM4:		db		"COM4",NULL
+g_szValueCfgCOM5:		db		"COM5",NULL
+g_szValueCfgCOM6:		db		"COM6",NULL
+g_szValueCfgCOM7:		db		"COM7",NULL
+g_szValueCfgCOM8:		db		"COM8",NULL
+g_szValueCfgCOM9:		db		"COM9",NULL
+g_szValueCfgCOMA:		db		"COMA",NULL
+g_szValueCfgCOMB:		db		"COMB",NULL
+g_szValueCfgCOMC:		db		"COMC",NULL
+g_szValueCfgCOMx:		db		"Custom",NULL
+		
+g_szSerialBaudChoice:
+						db  "2400 baud",LF
+						db	"9600 baud",LF
+						db	"38.4K baud",LF
+						db  "115.2K baud",NULL
+
+g_szValueCfgBaud2400:	db		"2400",NULL
+g_szValueCfgBaud9600:	db		"9600",NULL
+g_szValueCfgBaud38_4:	db		"38.4K",NULL
+g_szValueCfgBaud115_2:	db		"115.2K",NULL
+		
 g_szValueCfgDeviceDual8b:	db	"XTIDE",NULL
 g_szValueCfgDeviceMod:		db	"Chuck(G)",NULL
@@ -149,5 +205,5 @@
 g_szValueCfgDevice16b:		db	"16-bit",NULL
 g_szValueCfgDevice32b:		db	"32-bit",NULL
-g_szValueCfgDeviceSerial:	db	"serial",NULL
+g_szValueCfgDeviceSerial:	db	"Serial",NULL
 
 
@@ -184,4 +240,5 @@
 g_szItemBootFloppyDrvs:	db	"Number of Floppy Drives",NULL
 g_szItemBootSwap:		db	"Swap boot drive numbers",NULL
+g_szItemSerialDetect:	db	"Scan for Serial Drives",NULL
 
 g_szDlgBootTimeout:		db	"Enter Boot Menu selection timeout in BIOS timer ticks (1...1092, 0 disables timeout).",NULL
@@ -190,5 +247,6 @@
 g_szDlgBootFloppyDrvs:	db	"Select number of Floppy Drives to display on boot menu.",NULL
 g_szDlgBootSwap:		db	"Enable drive number translation?",NULL
-
+g_szDlgSerialDetect:	db	"Scan for serial drives?",NULL
+		
 g_szNfoBootTimeout:		db	"Menu item selection timeout in BIOS timer ticks.",NULL
 g_szNfoBootDrive:		db	"Default drive on boot menu.",NULL
@@ -196,4 +254,5 @@
 g_szNfoBootFloppyDrvs:	db	"Number of Floppy Drives to display on boot menu.",NULL
 g_szNfoBootSwap:		db	"Drive Number Translation (swap first drive with selected).",NULL
+g_szNfoSerialDetect:	db	"Will scan COM ports for a serial drive. Can also be invoked by holding down ALT at the end of standard drive detection.",NULL
 
 g_szHelpBootTimeout:	incbin	"Bootmenu_Timeout.txt"
@@ -205,4 +264,6 @@
 g_szHelpBootSwap:		incbin	"Bootmenu_SwapDrives.txt"
 						db	NULL
+g_szHelpSerialDetect:	incbin  "Bootmenu_SerialDetect.txt"
+						db  NULL
 
 g_szMultichoiceBootDispMode:
