Index: /tags/v2.0.0_beta_2/Serial_Server/gpl-2.0.txt
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/gpl-2.0.txt	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/gpl-2.0.txt	(revision 464)
@@ -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/v2.0.0_beta_2/Serial_Server/library/Checksum.cpp
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/Checksum.cpp	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/Checksum.cpp	(revision 464)
@@ -0,0 +1,372 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        checksum.cpp - Checksum function and test routines
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+//
+// This file implements Fletcher's Checksum.  The serial code uses this checksum, as it is very quick 
+// to calculate in assembly and offers reasonable error detection.
+// For more information, see http://en.wikipedia.org/wiki/Fletcher%27s_checksum.
+//
+// Since it is faster in 8088 assembly code to deal with 16-bit quantities than 8-bit quantities, 
+// Fletcher's Checksum has been modified to calculate the 32-bit checksum, and then "fold" the result into a
+// 16-bit quantity.  Fletcher's 32-bit Checksum consists of two parts: concatenated 16-bit accumulators.  
+// To "fold" to 16-bits, The upper and lower 8-bits of each of these accumulators is XOR'd independently, and then 
+// the two results concatenated together, resulting in 16-bits.  Although simpler, an early attempt to XOR the
+// 16-bit accumulators results in poorer error detection behavior.  Folding as described here results in error
+// detection on par with Fletcher's 16-bit Checksum.
+//
+// With #define CHECKSUM_TEST, this file becomes a self-contained command line program that runs
+// some statistical tests comparing various checksum algorithms with random 512-byte sectors and various 
+// levels of errors introduced.
+//
+
+#include "library.h"
+
+unsigned short checksum( unsigned short *wbuff, int wlen )
+{
+	unsigned long a = 0xffff;
+	unsigned long b = 0xffff;
+	int t;
+
+	for( t = 0; t < wlen; t++ )
+	{
+		a += wbuff[t];
+		b += a;
+	}
+
+	a = (a & 0xffff) + (a >> 16);
+	b = (b & 0xffff) + (b >> 16);
+	a = (a & 0xffff) + (a >> 16);
+	b = (b & 0xffff) + (b >> 16);
+
+// Although tempting to use, for its simplicity and size/speed in assembly, the following folding 
+// algorithm results in many undetected single bit errors and therefore should not be used.
+//	return( (unsigned short) (a ^ b) );
+
+	return( (unsigned short) (((a & 0xff) << 8) ^ (a & 0xff00)) + (((b & 0xff00) >> 8) ^ (b & 0xff)) );
+}
+
+#ifdef CHECKSUM_TEST
+
+//====================================================================================================
+// 
+// Test Code
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.h>
+
+#define BUCKETS 65536
+#define BITTEST 16
+
+unsigned char bit[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+class algorithm 
+{
+public:
+	virtual unsigned short checksum( unsigned char *data, int len ) = 0;
+	char *title;
+	unsigned long *found;
+	unsigned long zero;
+	unsigned long total;
+	unsigned long empty;
+	unsigned long min;
+	unsigned long max;
+	double stdev;
+	unsigned long bittest[ BITTEST ];
+	unsigned long missed[ BITTEST ];
+	algorithm *next;
+	algorithm( algorithm *last, char *new_title );
+};
+
+algorithm::algorithm( algorithm *last, char *new_title )
+{
+	zero = total = empty = min = max = 0;
+	stdev = 0.0;
+	for( int t = 0; t < BITTEST; t++ )
+	{
+		bittest[t] = missed[t] = 0;
+	}
+	title = new_title;
+	next = last;
+}
+
+//----------------------------------------------------------------------------------------------------
+// 
+// Standard CRC-16
+//
+// http://sanity-free.org/134/standard_crc_16_in_csharp.html
+//
+
+static unsigned short crc16_table[256];
+
+class crc16_algorithm : public algorithm
+{
+public:
+	crc16_algorithm( algorithm *last ) : algorithm( last, (char *) "crc-16" )
+	{
+		unsigned short value;
+		unsigned short temp;
+		unsigned short i;
+		unsigned short j;
+
+		for(i = 0; i < 256; ++i) 
+		{
+			value = 0;
+			temp = i;
+			for(j = 0; j < 8; ++j) {
+				if(((value ^ temp) & 0x0001) != 0) {
+					value = (unsigned short)((value >> 1) ^ this->crc16_polynomial);
+				}else {
+					value >>= 1;
+				}
+				temp >>= 1;
+			}
+			crc16_table[i] = value;
+		}
+	}
+
+	unsigned short checksum( unsigned char *data, int len );  
+
+private:
+	static const unsigned short crc16_polynomial = 0xA001;
+};
+
+unsigned short crc16_algorithm::checksum( unsigned char *data, int len )
+{
+	unsigned short crc = 0;
+	int i;
+
+	for(i = 0; i < len; ++i) 
+	{
+		unsigned char index = (unsigned char)(crc ^ data[i]);
+		crc = (unsigned short)((crc >> 8) ^ crc16_table[index]);
+	}
+
+	return( crc );
+}
+
+//----------------------------------------------------------------------------------------------------
+// 
+// Basic checksum (just add up the bytes)
+//
+
+class basic_algorithm : public algorithm
+{
+public:
+	unsigned short checksum( unsigned char *data, int len );  
+	basic_algorithm( algorithm *last ) : algorithm( last, (char *) "basic" ) { };
+};
+
+unsigned short basic_algorithm::checksum( unsigned char *bbuff, int blen )
+{
+	unsigned short sum = 0;
+	int i;
+	for( i = 0; i < blen; i++ )
+	{
+		sum += bbuff[ i ];
+	}
+	return( sum );
+}
+
+class fletcher16_algorithm : public algorithm
+{
+public:
+	unsigned short checksum( unsigned char *data, int len );  
+	fletcher16_algorithm( algorithm *last ) : algorithm( last, (char *) "f-16" ) { }
+};
+
+unsigned short fletcher16_algorithm::checksum( unsigned char* data, int count )
+{
+	unsigned short sum1 = 0;
+	unsigned short sum2 = 0;
+	int index;
+
+	for( index = 0; index < count; ++index )
+	{
+		sum1 = (sum1 + data[index]) % 255;
+		sum2 = (sum2 + sum1) % 255;
+	}
+
+	return (sum2 << 8) | sum1;
+}
+
+//----------------------------------------------------------------------------------------------------
+// 
+// Folded Fletcher's Checksum (what we use in the serial code, from the top of this file)
+//
+
+class folded_fletcher32_algorithm : public algorithm
+{
+public:
+	unsigned short checksum( unsigned char *data, int len );  
+	folded_fletcher32_algorithm( algorithm *last ) : algorithm( last, (char *) "fold-f-32" ) { }
+};
+
+unsigned short folded_fletcher32_algorithm::checksum( unsigned char* data, int count )
+{
+	return( ::checksum( (unsigned short *) data, count/2 ) );
+}
+
+//----------------------------------------------------------------------------------------------------
+// 
+// Test Driver and Support routines
+//
+
+void randomize_buff( unsigned char *bbuff, int blen )
+{
+	int i;
+	for( i = 0; i < blen; i++ )
+		bbuff[i] = rand() % 255;
+}
+
+#define BBUFF_LENGTH 512
+
+unsigned char bbuff[ BBUFF_LENGTH ];
+
+int main( int argc, char *argv[] )
+{
+	algorithm *a, *algorithms;
+
+	unsigned short c;
+
+	double p;
+	double average;
+
+	unsigned long iterations;
+
+	time_t now;
+
+	algorithms = new folded_fletcher32_algorithm( NULL );
+	algorithms = new fletcher16_algorithm( algorithms );
+	algorithms = new crc16_algorithm( algorithms );
+	algorithms = new basic_algorithm( algorithms );
+
+	time( &now );
+	srand((unsigned int)now);
+
+	if( argc != 2 )
+	{
+		fprintf( stderr, "usage: checksum number_of_iterations\n" );
+		exit( 1 );
+	}
+	else
+		iterations = atol( argv[1] );
+
+#define PRINTROW( E, F, G ) { printf( E ); for( a = algorithms; a; a = a->next ) printf( F, G ); printf( "\n" ); }
+
+	printf( "\nnumber of iterations: %d\n\n", iterations );
+	PRINTROW( "       ", "%10s  ", a->title );
+	PRINTROW( "=======", "============", NULL );
+
+	for( a = algorithms; a; a = a->next )
+	{
+		a->found = (unsigned long *) calloc( BUCKETS, sizeof(long) );
+		
+		a->zero = (unsigned long) a->checksum( bbuff, BBUFF_LENGTH );
+
+		a->min = iterations+1;
+	}
+	
+	printf( "\n" );
+	PRINTROW( "zero   ", "%10d  ", a->zero );
+
+	for( int t = 0; t < iterations; t++ )
+	{
+		randomize_buff( bbuff, BBUFF_LENGTH );
+
+		for( a = algorithms; a; a = a->next )
+			a->found[ a->checksum( bbuff, BBUFF_LENGTH ) ]++;
+	}
+
+	average = iterations / 65536.0;
+
+	for( int t = 0; t < 65536; t++ )
+	{
+		for( a = algorithms; a; a = a->next )
+		{
+			a->total += a->found[ t ];
+			if( !a->found[ t ] )
+				a->empty++;
+			if( a->found[ t ] > a->max )
+				a->max = a->found[ t ];
+			if( a->found[ t ] < a->min )
+				a->min = a->found[ t ];
+			p = a->found[ t ] - average;
+			a->stdev += p*p;
+		}
+	}
+
+	p = 1.0 / (65536.0-1.0);
+	for( a = algorithms; a; a = a->next )
+	{
+		a->stdev = sqrt( p * a->stdev );
+		if( a->total != iterations )
+			fprintf( stderr, "Bad %s\n", a->title );
+	}
+
+	printf( "\nchecksum distribution test:\n" );
+	PRINTROW( "empty  ", "%10d  ", a->empty );
+	PRINTROW( "min    ", "%10d  ", a->min );
+	PRINTROW( "max    ", "%10d  ", a->max );
+	PRINTROW( "stdev  ", "%10.4lf  ", a->stdev );
+
+	for( int t = 0; t < iterations; t++ )
+	{
+		randomize_buff( bbuff, BBUFF_LENGTH );
+
+		for( int b = 0; b < BITTEST; b++ )
+		{
+			for( a = algorithms; a; a = a->next )
+			{
+			  a->bittest[ b ] = (a->checksum)( bbuff, BBUFF_LENGTH );
+			}
+
+			bbuff[ rand() % 512 ] ^= bit[ rand() % 8 ];
+			
+			if( b > 0 )
+			{
+				for( a = algorithms; a; a = a->next )
+				{
+					if( a->bittest[ 0 ] == a->bittest[ b ] )
+						a->missed[ b ]++;
+				}
+			}
+		}
+	}  
+
+	printf( "\nbit change test:\n" );
+	for( int t = 1; t < BITTEST; t++ )
+	{
+		printf( "%2d        ", t );
+		for( a = algorithms; a; a = a->next )
+			printf( "%7d     ", a->missed[ t ] );
+		printf( "\n" );
+	}
+}
+
+#endif
+
+
+
+
Index: /tags/v2.0.0_beta_2/Serial_Server/library/File.h
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/File.h	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/File.h	(revision 464)
@@ -0,0 +1,117 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        file.h - File access via standard "stdio.h" routines
+//
+// Routines for accessing the file system using generic routines, which
+// should work on all systems.  The issue with using these is that 
+// ftell() and fseek() are limited to 2 GB files (signed 32-bit quantities)
+// and there is no standard for 64-bit quantities.  So, look for a 
+// OS specific version of this file in the distribution, such as 
+// win32/win32file.h which may be in use instead.
+// 
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include <stdio.h>
+
+class FileAccess
+{
+public:
+	int Create( char *p_name )
+	{
+		fp = fopen( p_name, "r" );
+
+		if( fp )
+		{
+			log( 0, "'%s' file already exists", p_name );
+			fclose( fp );
+			return( 0 );
+		}
+		
+		if( !(fp = fopen( p_name, "w" )) )
+			log( -1, "Could not create file '%s'", p_name );
+
+		name = p_name;
+		
+		return( 1 );
+	}
+
+	void Open( char *p_name )
+	{
+		fp = fopen( p_name, "r+" );
+		if( !fp )
+			log( -1, "Could not Open '%s'", p_name );
+		name = p_name;
+	}
+
+	void Close()
+	{
+		if( fp )
+			fclose( fp );
+		fp = NULL;
+	}
+
+	unsigned long SizeSectors(void)
+	{
+		long filesize;
+
+		fseek( fp, 0, SEEK_END );
+		filesize = ftell( fp );
+
+		if( filesize == 0 || filesize == -1L )
+			log( -1, "Could not get file size for '%s', file possibly larger than 2 GB", name );
+
+		if( filesize & 0x1ff )
+			log( -1, "'%s' not made up of 512 byte sectors", name );
+
+		return( filesize >> 9 );     // 512 bytes per sector
+	}
+
+	void SeekSectors( unsigned long lba )
+	{
+		if( fseek( fp, lba * 512, SEEK_SET ) )
+			log( -1, "'%s', Failed to seek to lba=%lu", name, lba );
+	}
+
+	void Read( void *buff, unsigned long len )
+	{
+		if( fread( buff, 1, 512, fp ) != 512 )
+			log( -1, "'%s', Failed to read sector", name );
+	}
+
+	void Write( void *buff, unsigned long len )
+	{
+		if( fwrite( buff, 1, 512, fp ) != 512 )
+			log( -1, "'%s', Failed to write sector", name );
+	}
+
+	FileAccess()
+	{
+		fp = NULL;
+		name = NULL;
+	}
+
+	const static unsigned long MaxSectors = 4194303;  // limited by signed 32-bit file sizes 
+#define USAGE_MAXSECTORS "2048 MB (signed 32-bit file size limit)"
+
+private:
+	FILE *fp;
+	char *name;
+};
+
Index: /tags/v2.0.0_beta_2/Serial_Server/library/FlatImage.h
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/FlatImage.h	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/FlatImage.h	(revision 464)
@@ -0,0 +1,96 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        FlatImage.h - Header file for basic flat disk image support
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include "library.h"
+
+class FlatImage : public Image
+{
+private:
+	class FileAccess fp;
+
+public:
+	FlatImage( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS )   :   Image( name, p_readOnly, p_drive, p_create, p_cyl, p_head, p_sect, p_useCHS )
+	{
+		long filesize;
+
+		if( p_create )
+		{
+			char buff[512];
+			unsigned long size;
+			double sizef;
+			FileAccess cf;
+			char sizeChar;
+
+			size = (unsigned long) p_cyl * (unsigned long) p_sect * (unsigned long) p_head;
+			if( size > cf.MaxSectors )
+				log( -1, "'%s', can't create flat file with size greater than %lu 512-byte sectors", name, cf.MaxSectors );
+			sizef = size / 2048.0;   // 512 byte sectors -> MB
+			sizeChar = 'M';
+			if( sizef < 1 ) 
+			{
+				sizef *= 1024;
+				sizeChar = 'K';
+			}
+
+			if( cf.Create( name ) )
+			{
+				memset( &buff[0], 0, 512 );
+				while( size-- )
+					cf.Write( &buff[0], 512 );
+				
+				if( p_cyl > 1024 )
+					log( 0, "Created file '%s', size %.2lf %cB", name, sizef, sizeChar );
+				else
+					log( 0, "Created file '%s', geometry %u:%u:%u, size %.2lf %cB", name, p_cyl, p_head, p_sect, sizef, sizeChar );
+				cf.Close();
+			}
+		}
+
+		fp.Open( name );
+
+		totallba = fp.SizeSectors();
+
+		init( name, p_readOnly, p_drive, p_cyl, p_head, p_sect, p_useCHS );
+	}
+
+	FlatImage::~FlatImage()
+	{
+		fp.Close();
+	}
+
+	void seekSector( unsigned long lba )
+	{
+		fp.SeekSectors( lba );
+	}
+
+	void writeSector( void *buff )
+	{
+		fp.Write( buff, 512 );
+	}
+
+	void readSector( void *buff )
+	{
+		fp.Read( buff, 512 );
+	}
+};
+
Index: /tags/v2.0.0_beta_2/Serial_Server/library/Image.cpp
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/Image.cpp	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/Image.cpp	(revision 464)
@@ -0,0 +1,330 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        image.cpp - Abstract base class for disk image support
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include "library.h"
+#include <memory.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+struct floppyInfo floppyInfos[] = 
+{
+	{ 1, 2949120 / 512, 6, 80, 2, 36 },   		// 2.88MB 3.5"
+	{ 0, 2867200 / 512, 6, 80, 2, 36 },   		// 2.88MB 3.5" (alternate spelling with 2.8)
+	{ 0, 2969600 / 512, 6, 80, 2, 36 },   		// 2.88MB 3.5" (alternate spelling with 2.9)
+	{ 1, 1474560 / 512, 4, 80, 2, 18 },         // 1.44MB 3.5"
+	{ 0, 1433600 / 512, 4, 80, 2, 18 },         // 1.44MB 3.5" (alternate spelling with 1.4)
+	{ 1, 1228800 / 512, 2, 80, 2, 15 },     	// 1.2MB 5.25"
+	{ 1, 737280 / 512, 3, 80, 1, 18 },    		// 720KB 3.5"
+	{ 1, 368640 / 512, 1, 40, 2, 9 }, 			// 360KB 5.25"
+	{ 1, 327680 / 512, 0, 40, 2, 8 }, 			// 320KB 5.25"
+	{ 1, 184320 / 512, 0, 40, 1, 9 }, 			// 180KB 5.25" single sided
+	{ 1, 163840 / 512, 0, 40, 1, 8 }, 			// 160KB 5.25" single sided
+	{ 0, 0, 0, 0, 0, 0 }
+};
+
+struct floppyInfo *FindFloppyInfoBySize( double size )
+{
+	struct floppyInfo *fi;
+
+	for( fi = floppyInfos; fi->size != 0 && !(size+5 > fi->size && size-5 < fi->size); fi++ ) ;
+
+	if( fi->size == 0 )
+		fi = NULL;
+
+	return( fi );
+}
+
+void flipEndian( unsigned short *buff, unsigned int len )
+{
+	for( unsigned int t = 0; t < len/2; t++ )
+		buff[t] = (buff[t] & 0xff) << 8 | (buff[t] & 0xff00) >> 8;
+}
+
+Image::Image( char *name, int p_readOnly, int p_drive )
+{
+}
+
+Image::Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_lba )
+{
+}
+
+Image::Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS )
+{
+}
+
+void Image::init( char *name, int p_readOnly, int p_drive, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS )
+{
+	double sizef;
+	char sizeChar;
+	struct floppyInfo *f;
+
+	for( char *c = shortFileName = name; *c; c++ )
+		if( *c == '\\' || *c == '/' || *c == ':' )
+			shortFileName = c+1;
+
+	if( *(shortFileName) == 0 )
+	{
+		log( 1, "Can't parse '%s' for short file name\n\n", name );
+		shortFileName = "SerDrive";
+	}
+  
+	readOnly = p_readOnly;
+	drive = p_drive;
+
+	if( totallba > 0xfffffff )     // lba28 limit - 28 bits
+		log( -1, "'%s', Image size larger than LBA28 maximum of 137,438,952,960 bytes, %lu", name, totallba );
+
+	if( totallba == 0 )
+		log( -1, "'%s', Image size zero?" );
+
+	floppy = 0;
+	for( f = floppyInfos; f->size && !(f->size == totallba && f->real); f++ ) ;
+	if( f->size )
+	{
+		floppy = 1;
+		floppyType = f->type;
+		p_useCHS = 1;
+		p_cyl = f->cylinders;
+		p_head = f->heads;
+		p_sect = f->sectors;
+		totallba = p_cyl * p_head * p_sect;
+	}
+
+	if( p_cyl )
+	{
+		if( (p_sect > 255 || p_sect < 1) || (p_head > 16 || p_head < 1) || (p_cyl > 65536 || p_cyl < 1) )
+			log( -1, "'%s', parts of the CHS geometry (%lu:%lu:%lu) are out of the range (1-65536:1-16:1-255)", name, p_cyl, p_head, p_sect );
+		else if( totallba != (p_sect * p_head * p_cyl) )
+			log( -1, "'%s', file size does not match geometry", name );
+		sect = p_sect;
+		head = p_head;
+		cyl = p_cyl;
+	}
+	else
+	{
+		if( totallba > 65536*16*63 )
+		{
+			log( 0, "'%s': Warning: Image size is greater than derived standard CHS maximum, limiting CHS to 65535:16:63, consider using -g to specify geometry", name );
+			cyl = 65536;
+			head = 16;
+			sect = 63;
+		}
+		else if( (totallba % 16) != 0 || ((totallba/16) % 63) != 0 )
+		{
+			log( -1, "'%s', file size does not match standard CHS geometry (x:16:63), please specify geometry explicitly with -g", name );
+		}
+		else 
+		{
+			sect = 63;
+			head = 16;
+			cyl = (totallba / sect / head);
+			if( cyl > 65536 )
+			{
+				log( -1, "'%s', derived standard CHS geometry of %lu:16:63 is has more cylinders than 65536, please specify geometry explicitly with -g", name, cyl, head, sect );
+			}
+		}
+	}
+
+	useCHS = p_useCHS;
+
+	sizef = totallba/2048.0;
+	sizeChar = 'M';
+	if( sizef < 1 ) 
+	{
+		sizef *= 1024;
+		sizeChar = 'K';
+	}
+	if( useCHS )
+		log( 0, "%s: %s with CHS geometry %u:%u:%u, size %.2lf %cB",
+			 name, (floppy ? "Floppy Disk" : "Hard Disk"), cyl, head, sect, sizef, sizeChar );
+	else
+		log( 0, "%s: %s with %lu LBA sectors, size %.2lf %cB (CHS geometry %u:%u:%u)", 
+			 name, (floppy ? "Floppy Disk" : "Hard Disk"), totallba, sizef, sizeChar, cyl, head, sect );
+}
+
+int Image::parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_head, unsigned long *p_sect )
+{
+	char *c, *s, *h;
+	unsigned long cyl, sect, head;
+
+	c = str;
+	for( h = c; *h && *h != ':' && *h != 'x' && *h != 'X'; h++ ) ;
+	if( !*h )
+		return( 0 );
+
+	*h = '\0';
+	h++;
+	for( s = h+1; *s && *s != ':' && *s != 'x' && *s != 'X'; s++ ) ; 
+	if( !*s )
+		return( 0 );
+
+	*s = '\0';
+	s++;
+
+	cyl = atol(c);
+	head = atol(h);
+	sect = atol(s);
+
+	if( cyl == 0 || sect == 0 || head == 0 )
+		return( 0 );
+
+	*p_cyl = cyl;
+	*p_head = head;
+	*p_sect = sect;
+
+	return( 1 );
+}
+
+#define ATA_wGenCfg 0
+#define ATA_wCylCnt 1
+#define ATA_wHeadCnt 3
+#define ATA_wBpTrck 4
+#define ATA_wBpSect 5
+#define ATA_wSPT 6
+
+#define ATA_strSerial 10
+#define ATA_strSerial_Length 20
+
+#define ATA_strFirmware 23
+#define ATA_strFirmware_Length 8
+
+#define ATA_strModel 27
+#define ATA_strModel_Length 40                 // Maximum allowable length of the string according to the ATA spec
+#define XTIDEBIOS_strModel_Length 30           // Maximum length copied out of the ATA information by the BIOS
+
+#define ATA_wCaps 49
+#define ATA_wCurCyls 54
+#define ATA_wCurHeads 55
+#define ATA_wCurSPT 56
+#define ATA_dwCurSCnt 57
+#define ATA_dwLBACnt 60
+
+// Words carved out of the vendor specific area for our use
+//
+#define ATA_wSerialServerVersion 157
+#define ATA_wSerialDriveFlags 158
+#define ATA_wSerialPortAndBaud 159
+
+// Defines used in the words above
+//
+#define ATA_wCaps_LBA 0x200
+
+#define ATA_wGenCfg_FIXED 0x40
+
+// These are all shifted by 1 bit to the right, so that SerialDPT_Finalize can shift them into proper position
+// and shift the high order bit into the carry flag to indicate a floppy drive is present.
+//
+#define ATA_wSerialDriveFlags_Floppy    0x88
+#define ATA_wSerialDriveFlags_Present   0x02
+#define ATA_wSerialDriveFlags_FloppyType_FieldPosition   4
+
+struct comPorts {
+	unsigned long port;
+	unsigned char com;
+};
+struct comPorts supportedComPorts[] = 
+{ 
+  { 0x3f8, '1' }, 
+  { 0x2f8, '2' }, 
+  { 0x3e8, '3' }, 
+  { 0x2e8, '4' }, 
+  { 0x2f0, '5' }, 
+  { 0x3e0, '6' }, 
+  { 0x2e0, '7' }, 
+  { 0x260, '8' },
+  { 0x368, '9' },
+  { 0x268, 'A' },
+  { 0x360, 'B' },
+  { 0x270, 'C' },
+  { 0, 0 } 
+};
+
+void Image::respondInquire( unsigned short *buff, unsigned short originalPortAndBaud, struct baudRate *baudRate, unsigned short port, unsigned char scan )
+{
+	char formatBuff[ 128 ];
+	char speedBuff[ 128 ];
+
+	memset( &buff[0], 0, 514 );
+
+	if( scan )
+	{
+		unsigned short comPort = 0;
+		struct comPorts *cp;
+
+		if( port )
+		{
+			for( cp = supportedComPorts; cp->port && cp->port != port; cp++ ) ;
+			if( cp->port )
+				comPort = cp->com;
+		}
+
+		if( comPort )
+			sprintf( speedBuff, " (COM%c/%s)", comPort, baudRate->display );
+		else
+			sprintf( speedBuff, " (%s baud)", shortFileName, baudRate->display );
+
+		sprintf( formatBuff, "%.*s%s ", XTIDEBIOS_strModel_Length - strlen(speedBuff), shortFileName, speedBuff );
+	}
+	else
+		sprintf( formatBuff, "%.*s ", XTIDEBIOS_strModel_Length, shortFileName );
+	strncpy( (char *) &buff[ATA_strModel], formatBuff, ATA_strModel_Length );
+	flipEndian( &buff[ATA_strModel], ATA_strModel_Length );
+
+	strncpy( (char *) &buff[ATA_strSerial], "SerialDrive ", ATA_strSerial_Length );
+	flipEndian( &buff[ATA_strSerial], ATA_strSerial_Length );
+
+	sprintf( formatBuff, "%d.%d ", SERIAL_SERVER_MAJORVERSION, SERIAL_SERVER_MINORVERSION );
+	strncpy( (char *) &buff[ATA_strFirmware], formatBuff, ATA_strFirmware_Length );
+	flipEndian( &buff[ATA_strFirmware], ATA_strFirmware_Length );
+
+	buff[ ATA_wCylCnt ] = cyl;
+	buff[ ATA_wHeadCnt ] = head;
+	buff[ ATA_wSPT ] = sect;
+
+	if( !useCHS )
+	{
+		buff[ ATA_wCaps ] = ATA_wCaps_LBA;
+		buff[ ATA_dwLBACnt ] = (unsigned short) (totallba & 0xffff);
+		buff[ ATA_dwLBACnt+1 ] = (unsigned short) (totallba >> 16);
+	}
+
+	// We echo back the port and baud that we were called on from the client, 
+	// the client then uses this value to finalize the DPT.
+	//
+	buff[ ATA_wSerialPortAndBaud ] = originalPortAndBaud;
+
+	// In case the client requires a specific server version...
+	//
+	buff[ ATA_wSerialServerVersion ] = (SERIAL_SERVER_MAJORVERSION << 8) | SERIAL_SERVER_MINORVERSION;
+
+	buff[ ATA_wSerialDriveFlags ] = ATA_wSerialDriveFlags_Present;
+	if( floppy )
+		buff[ ATA_wSerialDriveFlags ] |= 
+			ATA_wSerialDriveFlags_Floppy | (floppyType << ATA_wSerialDriveFlags_FloppyType_FieldPosition);
+
+	// we always set this, so that the bulk of the BIOS will consider this disk as a hard disk
+	//
+	buff[ ATA_wGenCfg ] = ATA_wGenCfg_FIXED;
+}
+
Index: /tags/v2.0.0_beta_2/Serial_Server/library/Library.h
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/Library.h	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/Library.h	(revision 464)
@@ -0,0 +1,102 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        library.h - Include file for users of the library
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#ifndef LIBRARY_H_INCLUDED
+#define LIBRARY_H_INCLUDED
+
+#define SERIAL_SERVER_MAJORVERSION 1
+#define SERIAL_SERVER_MINORVERSION 0
+
+void log( int level, char *message, ... );
+
+unsigned long GetTime(void);
+unsigned long GetTime_Timeout(void);
+
+unsigned short checksum( unsigned short *wbuff, int wlen );
+
+struct floppyInfo {
+	unsigned char real;
+	unsigned long size;
+	unsigned char type;
+	unsigned char cylinders;
+	unsigned char heads;
+	unsigned char sectors;
+};
+
+struct floppyInfo *FindFloppyInfoBySize( double size );
+
+class Image
+{
+public:
+	virtual void seekSector( unsigned long lba ) = 0;
+
+	virtual void writeSector( void *buff ) = 0;
+
+	virtual void readSector( void *buff ) = 0;
+
+	Image( char *name, int p_readOnly, int p_drive );
+	Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_lba );
+	Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS );
+
+	virtual ~Image() {};
+
+	unsigned long cyl, sect, head;
+	unsigned char floppy, floppyType;
+	int useCHS;
+
+	unsigned long totallba;
+
+	char *shortFileName;
+	int readOnly;
+	int drive;
+
+	static int parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_head, unsigned long *p_sect );
+
+	void respondInquire( unsigned short *buff, unsigned short originalPortAndBaud, struct baudRate *baudRate, unsigned short port, unsigned char scan );
+
+	void init( char *name, int p_readOnly, int p_drive, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS );
+};
+
+struct baudRate {
+	unsigned long rate;
+	unsigned char divisor;
+	char *display;
+};
+struct baudRate *baudRateMatchString( char *str );
+struct baudRate *baudRateMatchDivisor( unsigned char divisor );
+
+#ifdef WIN32
+#include "../win32/win32serial.h"
+#else
+// there is no standard way to read/write and configure the serial port, OS specific only
+#endif
+
+#ifdef WIN32
+#include "../win32/win32file.h"
+#else
+#include "file.h"
+#endif
+
+void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel );
+
+#endif
Index: /tags/v2.0.0_beta_2/Serial_Server/library/Process.cpp
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/Process.cpp	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/Process.cpp	(revision 464)
@@ -0,0 +1,404 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        process.cpp - Processes commands received over the serial port
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include "library.h"
+#include <memory.h>
+#include <string.h>
+#include <stdio.h>
+
+union _buff {
+	struct {
+		unsigned char command;
+		unsigned char driveAndHead;
+		unsigned char count;
+		unsigned char sector;
+		unsigned short cylinder;
+	} chs;
+	struct {
+		unsigned char command;
+		unsigned char bits24;
+		unsigned char count;
+		unsigned char bits00;
+		unsigned char bits08;
+		unsigned char bits16;
+	} lba;
+	struct {
+		unsigned char command;
+		unsigned char driveAndHead;
+		unsigned char count;
+		unsigned char scan;
+		unsigned char port;
+		unsigned char baud;
+	} inquire;
+	struct {
+		unsigned char command;
+		unsigned char driveAndHead;
+		unsigned char count;
+		unsigned char scan;
+		unsigned short PackedPortAndBaud;
+	} inquirePacked;
+	unsigned char b[514];
+	unsigned short w[257];
+} buff;
+
+#define SERIAL_COMMAND_HEADER 0xa0
+
+#define SERIAL_COMMAND_WRITE 1
+#define SERIAL_COMMAND_READWRITE 2
+#define SERIAL_COMMAND_RWMASK 3
+#define SERIAL_COMMAND_INQUIRE 0
+
+#define SERIAL_COMMAND_MASK 0xe3
+#define SERIAL_COMMAND_HEADERMASK 0xe0
+
+#define ATA_COMMAND_LBA 0x40
+#define ATA_COMMAND_HEADMASK 0xf
+
+#define ATA_DriveAndHead_Drive 0x10
+
+void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
+{
+	char logBuff[ 514*9 + 10 ];
+	int logCount;
+
+	if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
+	{
+		if( verboseLevel == 3 && buffoffset > 11 )
+			logCount = 11;
+		else
+			logCount = buffoffset;
+
+		for( int t = 0; t < logCount; t++ )
+			sprintf( &logBuff[t*9], "[%3d:%02x] ", t, buff.b[t] );
+		if( logCount != buffoffset )
+			sprintf( &logBuff[logCount*9], "... " );
+
+		log( 3, "%s%s", message, logBuff );
+	}
+}
+
+void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
+{
+	unsigned char workCommand;
+	int workOffset, workCount;
+
+	unsigned long mylba;
+	unsigned long readto;
+	unsigned long buffoffset;
+	unsigned long lasttick;
+	unsigned short crc;
+	unsigned long GetTime_Timeout_Local;
+	unsigned long len;
+	Image *img;
+	unsigned long cyl, sect, head;
+	unsigned long perfTimer;
+	unsigned char lastScan;
+
+	GetTime_Timeout_Local = GetTime_Timeout();
+
+	buffoffset = 0;
+	readto = 0;
+	workCount = workOffset = workCommand = 0;
+	lastScan = 0;
+
+	//
+	// Floppy disks must come after any hard disks
+	//
+	if( (image0 && image0->floppy) && (image1 && !image1->floppy) )
+	{
+		img = image0;
+		image0 = image1;
+		image1 = img;
+	}
+
+	lasttick = GetTime();
+
+	while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
+	{
+		buffoffset += len;
+
+		//
+		// For debugging, look at the incoming packet
+		//
+		if( verboseLevel >= 3 )
+			logBuff( "    Received: ", buffoffset, readto, verboseLevel );
+
+		if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
+		{
+			log( 1, "Timeout waiting on data from client, aborting previous command" );
+
+			workCount = workOffset = workCommand = 0;
+			readto = 0;
+
+			if( len <= 8 && (buff.b[buffoffset-len] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
+			{
+				// assume that we are at the front of a new command
+				//
+				memcpy( &buff.b[0], &buff.b[buffoffset-len], len );
+				buffoffset = len;
+				readto = 8;
+				// fall through to normal processing
+			}
+			else if( len == 1 )
+			{
+				// one new character, treat it like any other new character received, discarding the buffer
+				//
+				buff.b[0] = buff.b[buffoffset-1];
+				buffoffset = 1;
+				// fall through to normal processing
+			}
+			else
+			{
+				// discard even the newly received data and start listening anew
+				//
+				buffoffset = 0;
+				continue;
+			}
+		}
+
+		lasttick = GetTime();
+
+		// 
+		// No work currently to do, look at each character as they come in...
+		//
+		if( !readto )
+		{
+			if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
+			{
+				//
+				// Found our command header byte to start a commnad sequence, read the next 7 and evaluate
+				//
+				readto = 8;
+				continue;
+			}
+			else
+			{
+				//
+				// Spurious characters, discard
+				//
+				if( verboseLevel >= 2 )
+				{
+					if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
+						log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
+					else
+						log( 2, "Spurious: [%d]", buff.b[0] );
+				}
+				buffoffset = 0;
+				continue;
+			}
+		}
+
+		//
+		// Partial packet received, keep reading...
+		//
+		if( readto && buffoffset < readto )
+			continue;
+
+		//
+		// Read 512 bytes from serial port, only one command reads that many characters: Write Sector
+		//
+		if( buffoffset == readto && readto == 514 )
+		{
+			buffoffset = readto = 0;
+			if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
+			{
+				log( 0, "Bad Write Sector Checksum" );
+				continue;
+			}
+
+			if( img->readOnly )
+			{
+				log( 1, "Attempt to write to read-only image" );
+				continue;
+			}
+
+			img->seekSector( mylba + workOffset );
+			img->writeSector( &buff.w[0] );
+
+			//
+			// Echo back the CRC
+			//
+			if( !serial->writeCharacters( &buff.w[256], 2 ) )
+				break;
+
+			workOffset++;
+			workCount--;
+
+			if( workCount )
+				readto = 1;           // looking for continuation ACK
+		}
+
+		//
+		// 8 byte command received, or a continuation of the previous command
+		//
+		else if( (buffoffset == readto && readto == 8) ||
+				 (buffoffset == readto && readto == 1 && workCount) )
+		{
+			buffoffset = readto = 0;
+			if( workCount )
+			{
+				if( verboseLevel > 1 )
+					log( 2, "    Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
+
+				//
+				// Continuation...
+				//
+				if( buff.b[0] != (workCount-0) )
+				{
+					log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
+					workCount = 0;
+					continue;
+				}
+			}
+			else
+			{
+				//
+				// New Command...
+				//
+				if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
+				{
+					log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
+						 buff.b[0], buff.b[1], buff.b[2], buff.b[3], buff.b[4], buff.b[5], buff.b[6], buff.b[7], crc);
+					continue;
+				}
+
+				img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
+
+				workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
+
+				if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
+				{
+					mylba = ((((unsigned long) buff.lba.bits24) & ATA_COMMAND_HEADMASK) << 24) 
+						| (((unsigned long) buff.lba.bits16) << 16) 
+						| (((unsigned long) buff.lba.bits08) << 8) 
+						| ((unsigned long) buff.lba.bits00);
+				}
+				else
+				{
+					cyl = buff.chs.cylinder;
+					sect = buff.chs.sector;
+					head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK);
+					mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
+				}
+
+				workOffset = 0;
+				workCount = buff.chs.count;
+
+				if( verboseLevel > 0 )
+				{
+					char *comStr = (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read");
+
+					if( workCommand == SERIAL_COMMAND_INQUIRE )
+						log( 1, "Inquire %d: Client Port=0x%x, Client Baud=%s", img == image0 ? 0 : 1,
+							 ((unsigned short) buff.inquire.port) << 2,
+							 baudRateMatchDivisor( buff.inquire.baud )->display );
+					else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
+						log( 1, "%s %d: LBA=%u, Count=%u", comStr, img == image0 ? 0 : 1,
+							 mylba, workCount );
+					else
+						log( 1, "%s %d: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", comStr, img == image0 ? 0 : 1,
+							 cyl, sect, head, workCount, mylba );
+				}
+
+				if( !img )
+				{
+					log( 1, "    No slave drive provided" );
+					workCount = 0;
+					continue;
+				}
+
+				if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
+				{
+					log( 1, "    Write attempt to Read Only disk" );
+					workCount = 0;
+					continue;
+				}
+
+				if( verboseLevel > 0 && workCount > 100 )
+					perfTimer = GetTime();
+			}
+
+			if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
+			{
+				//
+				// Write command...   Setup to receive a sector
+				//
+				readto = 514;
+			}
+			else 
+			{
+				//
+				// Inquire command...
+				//
+				if( workCommand == SERIAL_COMMAND_INQUIRE )
+				{
+					unsigned char localScan;
+
+					if( serial->speedEmulation && 
+						buff.inquire.baud != serial->baudRate->divisor )
+					{
+						log( 1, "    Ignoring Inquire with wrong baud rate" );
+						workCount = 0;
+						continue;
+					}
+
+					localScan = buff.inquire.scan;         // need to do this before the call to 
+					                                       // img->respondInquire, as it will clear the buff
+					img->respondInquire( &buff.w[0], buff.inquirePacked.PackedPortAndBaud, 
+										 serial->baudRate, 
+										 ((unsigned short) buff.inquire.port) << 2, 
+										 (img == image1 && lastScan) || buff.inquire.scan );
+					lastScan = localScan;
+				}
+				//
+				// Read command...
+				//
+				else
+				{
+					img->seekSector( mylba + workOffset );
+					img->readSector( &buff.w[0] );
+					lastScan = 0;
+				}
+
+				buff.w[256] = checksum( &buff.w[0], 256 );
+
+				if( !serial->writeCharacters( &buff.w[0], 514 ) )
+					break;
+
+				if( verboseLevel >= 3 )
+					logBuff( "    Sending: ", 514, 514, verboseLevel );
+
+				workCount--;
+				workOffset++;
+
+				if( workCount )
+					readto = 1;           // looking for continuation ACK
+			}
+		}
+
+		if( workCount == 0 && workOffset > 100 )
+			log( 1, "    Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
+	}
+}
+
+
Index: /tags/v2.0.0_beta_2/Serial_Server/library/Serial.cpp
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/library/Serial.cpp	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/library/Serial.cpp	(revision 464)
@@ -0,0 +1,70 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Serial.cpp - Generic functions for dealing with serial communications
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include "library.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct baudRate supportedBaudRates[] = 
+{ 
+	{   2400,  0x30,    "2400" },
+	{   4800,  0x18,    "4800" },
+	{   9600,   0xc,    "9600" },
+	{  19200,  0xff,   "19.2K" },
+	{  28800,   0x4,   "28.8K" },
+	{  38400,  0xff,   "38.4K" },
+	{  57600,   0x2,   "57.6K" },
+	{  76800,  0xff,   "76.8K" },
+	{ 115200,   0x1,  "115.2K" },
+	{ 153600,  0xff,  "153.6K" },
+	{ 230400,  0xff,  "230.4K" },
+	{ 460800,  0xff,  "460.8K" },
+	{      0,     0, "Unknown" },
+};
+
+struct baudRate *baudRateMatchString( char *str )
+{
+	struct baudRate *b;
+  
+	unsigned long a = atol( str );
+	if( a )
+	{
+		for( b = supportedBaudRates; b->rate; b++ )
+			if( b->rate == a || (b->rate / 1000) == a || ((b->rate + 500) / 1000) == a )
+				return( b );
+	}
+
+	return( b );
+}
+
+struct baudRate *baudRateMatchDivisor( unsigned char divisor )
+{
+	struct baudRate *b;
+
+	for( b = supportedBaudRates; b->rate && b->divisor != divisor; b++ ) 
+		;
+
+	return( b );
+}
+
+
Index: /tags/v2.0.0_beta_2/Serial_Server/makefile
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/makefile	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/makefile	(revision 464)
@@ -0,0 +1,50 @@
+######################################################################
+#
+# Project:     XTIDE Universal BIOS, Serial Port Server
+#
+# File:        makefile
+#
+# Use with GNU Make or Microsoft Nmake
+# Build with Microsoft Visual C++ 2010 or Windows SDK v7.1
+#
+# Also works with Open Watcom C/C++ Version 1.9
+#
+
+HEADERS = library/library.h win32/win32file.h win32/win32serial.h library/file.h library/flatimage.h
+
+CXX = cl
+CXXFLAGS = /Ox /DWIN32
+
+WIN32OBJS = build/win32.obj build/checksum.obj build/serial.obj build/process.obj build/image.obj
+
+build/serdrive.exe:	$(WIN32OBJS)
+	@$(CXX) /Febuild/serdrive.exe $(WIN32OBJS)
+
+build/win32.obj:	win32/win32.cpp $(HEADERS)
+	@$(CXX) /c $(CXXFLAGS) win32/win32.cpp /Fobuild/win32.obj
+
+build/checksum.obj:	library/checksum.cpp $(HEADERS)
+	@$(CXX) /c $(CXXFLAGS) library/checksum.cpp /Fobuild/checksum.obj
+
+build/serial.obj:	library/serial.cpp $(HEADERS)
+	@$(CXX) /c $(CXXFLAGS) library/serial.cpp /Fobuild/serial.obj
+
+build/process.obj:	library/process.cpp $(HEADERS)
+	@$(CXX) /c $(CXXFLAGS) library/process.cpp /Fobuild/process.obj
+
+build/image.obj:	library/image.cpp $(HEADERS)
+	@$(CXX) /c $(CXXFLAGS) library/image.cpp /Fobuild/image.obj
+
+
+release:	build/serdrive.exe
+	@echo Compressing with UPX...
+	@upx -qq --ultra-brute build/serdrive.exe
+	@echo Done!
+
+clean:
+	@del /q build\*.*
+
+
+build/checksum_test.exe:	library/checksum.cpp
+	@$(CXX) /Febuild/checksum_test.exe /Ox library/checksum.cpp /Fobuild/checksum_test.obj -D CHECKSUM_TEST
+
Index: /tags/v2.0.0_beta_2/Serial_Server/win32/Win32.cpp
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/win32/Win32.cpp	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/win32/Win32.cpp	(revision 464)
@@ -0,0 +1,318 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Win32.cpp - Microsoft Windows 32-bit application
+//
+// This file contains the entry point for the Win32 version of the server.
+// It also handles log reporting, timers, and command line parameter parsing.
+// 
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "../library/library.h"
+#include "../library/flatimage.h"
+
+#include "../../XTIDE_Universal_BIOS/inc/version.inc"
+
+char *bannerStrings[] = {
+	"SerDrive - XTIDE Universal BIOS Serial Drive Server",
+	"Copyright (C) 2012 by XTIDE Universal BIOS Team",
+	"Released under GNU GPL v2, with ABSOLUTELY NO WARRANTY",
+	ROM_VERSION_STRING,
+	"", 
+	NULL };
+
+char *usageStrings[] = {
+	"This is free software, and you are welcome to redistribute it under certain",
+	"conditions.  For more license details, see the LICENSE.TXT file included with",
+	"this distribution, visit the XTIDE Universal BIOS wiki (address below), or",
+ 	"http://www.gnu.org/licenses/gpl-2.0.html",
+	"",
+	"Visit the wiki on http://code.google.com/p/xtideuniversalbios for detailed",
+	"serial drive usage directions.",
+	"",
+	"Usage: SerDrive [options] imagefile [[slave-options] slave-imagefile]",
+	"",
+	"  -g [cyl:head:sect]  Geometry in cylinders, sectors per cylinder, and heads",
+	"                      -g also implies CHS addressing mode (default is LBA28)",
+	"",
+	"  -n [megabytes]      Create new disk with given size or use -g geometry",
+	"                      Maximum size is " USAGE_MAXSECTORS, 
+	"                      Floppy images can also be created, such as \"360K\"",
+	"                      (default is a 32 MB disk, with CHS geometry 65:16:63)",
+	"",
+	"  -p [pipename]       Named Pipe mode for emulators",
+	"                      (must begin with \"\\\\\", default is \"" PIPENAME "\")",
+	"",
+	"  -c COMPortNumber    COM Port to use (default is first found)",
+	"                      Available COM ports on this system are:",
+ "COM                          ",
+	"",
+	"  -b BaudRate         Baud rate to use on the COM port, with client machine",
+	"                      rate multiplier in effect:",
+	"                          None:  2400,  4800,  9600,  28.8K,  57.6K, 115.2K",
+	"                          2x:    4800,  9600, 19200,  57.6K, 115.2K, 230.4K",
+	"                          4x:    9600, 19200, 38400, 115.2K, 230.4K, 460.8K",
+	"                          and for completeness:               76.8K, 153.6K",
+	"                      (default is 9600, 115.2K when in named pipe mode)",
+	"",
+	"  -t                  Disable timeout, useful for long delays when debugging",
+	"",
+	"  -r                  Read Only disk, do not allow writes",
+	"",
+	"  -v [level]          Reporting level 1-6, with increasing information",
+	"",
+	"On the client computer, a serial port can be configured for use as a hard disk",
+	"with xtidecfg.com.  Or one can hold down the ALT key at the end of the normal",
+	"IDE hard disk scan and the XTIDE Universal BIOS will scan COM1-7, at each of",
+	"the six speeds given above for BaudRate.  Note that hardware rate multipliers",
+	"must be taken into account on the server end, but are invisible on the client.",
+	"",
+	"Floppy images may also be used.  Image size must be exactly the same size",
+	"as a 2.88MB, 1.44MB, 1.2MB, 720KB, 360KB, 320KB, 180KB, or 160KB disk.",
+	"Floppy images must be the last disks discovered by the BIOS, and only",
+	"two floppy drives are supported by the BIOS at a time.",
+	NULL };
+
+void usagePrint( char *strings[] )
+{
+	for( int t = 0; strings[t]; t++ )
+	{
+		if( !strncmp( strings[t], "COM", 3 ) )
+		{
+			char logbuff[ 1024 ];
+
+			SerialAccess::EnumerateCOMPorts( logbuff, 1024 );
+			fprintf( stderr, "%s%s\n", strings[t]+3, logbuff );
+		}
+		else
+			fprintf( stderr, "%s\n", strings[t] );
+	}
+}
+
+#define usage() { usagePrint( usageStrings ); exit(1); }
+
+int verbose = 0;
+
+int main(int argc, char* argv[])
+{
+	DWORD len;
+
+	unsigned long check;
+	unsigned char w;
+
+	unsigned short wbuff[256];
+
+	SerialAccess serial;
+	Image *img;
+	struct baudRate *baudRate = NULL;
+
+	int timeoutEnabled = 1;
+
+	char *ComPort = NULL, ComPortBuff[20];
+
+	_fmode = _O_BINARY;
+
+	unsigned long cyl = 0, sect = 0, head = 0;
+	int readOnly = 0, createFile = 0;
+	int useCHS = 0;
+
+	int imagecount = 0;
+	Image *images[2] = { NULL, NULL };
+
+	usagePrint( bannerStrings );
+
+	for( int t = 1; t < argc; t++ )
+	{
+		char *next = (t+1 < argc ? argv[t+1] : NULL );
+
+		if( argv[t][0] == '/' || argv[t][0] == '-' )
+		{
+		    char *c;
+			unsigned long a;
+			for( c = &argv[t][1]; *c && !isdigit( *c ); c++ ) 
+				;
+			a = atol(c);
+
+			switch( argv[t][1] )
+			{
+			case 'c': case 'C':
+				if( !next )
+					usage();
+				t++;
+				a = atol( next );
+				if( a < 1 )
+					usage();
+				sprintf( ComPortBuff, "COM%d", a );
+				ComPort = &ComPortBuff[0];
+				break;
+			case 'v': case 'V':
+			    if( next && atol(next) != 0 )
+				{
+					t++;
+					verbose = atol(next);
+				}
+				else
+					verbose = 1;
+				break;
+			case 'r': case 'R':
+				readOnly = 1;
+				break;
+			case 'p': case 'P':
+				if( next && next[0] == '\\' && next[1] == '\\' )
+				{
+					t++;
+					ComPort = next;
+				}
+				else
+					ComPort = PIPENAME;
+				if( !baudRate )
+					baudRate = baudRateMatchString( "115200" );
+				break;			  
+			case 'g': case 'G':
+				if( next && atol(next) != 0 )
+				{
+					t++;
+					if( !Image::parseGeometry( next, &cyl, &head, &sect ) )
+						usage();
+				}
+				useCHS = 1;
+				break;
+			case 'h': case 'H': case '?':
+				usage();
+				break;
+			case 'n': case 'N':
+				createFile = 1;
+				if( next && atol(next) != 0 )
+				{
+					double size = atof(next);
+					struct floppyInfo *fi;
+					char *c;
+
+					t++;
+
+					size *= 2;
+					for( c = argv[t]; *c && *c != 'k' && *c != 'K'; c++ ) ;
+					if( !(*c) )
+						size *= 1000;
+
+					if( (fi = FindFloppyInfoBySize( size )) )
+					{
+						sect = fi->sectors;
+						head = fi->heads;
+						cyl = fi->cylinders;
+					}
+					else
+					{
+						sect = 63;
+						head = 16;
+						cyl = size / (16*63);
+					}
+				}
+				break;
+			case 't': case 'T':
+				timeoutEnabled = 0;
+				break;
+			case 'b': case 'B':
+				if( !next )
+					usage();
+				t++;
+				if( !(baudRate = baudRateMatchString( next )) || !baudRate->rate )
+					log( -2, "Unknown Baud Rate \"%s\"", next );
+				break;
+			default:
+				log( -2, "Unknown Option: \"%s\"", argv[t] );
+			}
+		}
+		else if( imagecount < 2 )
+		{
+			if( createFile && cyl == 0 )
+			{
+				cyl = 65;
+				sect = 63;
+				head = 16;
+			}
+			images[imagecount] = new FlatImage( argv[t], readOnly, imagecount, createFile, cyl, head, sect, useCHS );
+			imagecount++;
+			createFile = readOnly = cyl = sect = head = useCHS = 0;
+		}
+		else
+			usage();
+	}
+
+	if( imagecount == 0 )
+		usage();
+
+	if( !baudRate )
+		baudRate = baudRateMatchString( "9600" );
+
+	do
+	{
+		serial.Connect( ComPort, baudRate );
+
+		processRequests( &serial, images[0], images[1], timeoutEnabled, verbose );
+
+		serial.Disconnect();
+
+		if( serial.resetConnection )
+			log( 0, "Serial Connection closed, reset..." );
+	}
+	while( serial.resetConnection );
+}
+
+void log( int level, char *message, ... )
+{
+	va_list args;
+
+	va_start( args, message );
+
+	if( level < 0 )
+	{
+		fprintf( stderr, "ERROR: " );
+		vfprintf( stderr, message, args );
+		fprintf( stderr, "\n" );
+		if( level < -1 )
+		{
+			fprintf( stderr, "\n" );
+			usage();
+		}
+		exit( 1 );
+	}
+	else if( verbose >= level )
+	{
+		vprintf( message, args );
+		printf( "\n" );
+	}
+
+	va_end( args );
+}
+
+unsigned long GetTime(void)
+{
+	return( GetTickCount() );
+}
+
+unsigned long GetTime_Timeout(void)
+{
+	return( 1000 );
+}
Index: /tags/v2.0.0_beta_2/Serial_Server/win32/Win32File.h
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/win32/Win32File.h	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/win32/Win32File.h	(revision 464)
@@ -0,0 +1,135 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Win32File.h - Microsoft Windows file system access.
+//
+// Routines for accessing the file system under Win32.  It's important
+// to use these direct Win32 calls for large files, since FILE * routines,
+// in particular ftell() and fseek(), are limites to signed 32-bits (2 GB).
+// These are also likely faster since they are more direct.
+// 
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include <windows.h>
+#include <stdio.h>
+#include "../library/library.h"
+
+class FileAccess
+{
+public:
+	int Create( char *p_name )
+	{
+		fp = CreateFileA( p_name, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
+
+		if( fp == INVALID_HANDLE_VALUE )
+		{
+			if( GetLastError() == ERROR_FILE_EXISTS )
+			{
+				log( 0, "'%s', file already exists", p_name );
+				return( 0 );
+			}
+			else
+				log( -1, "'%s', could not create file", p_name );
+		}
+
+		name = p_name;
+
+		return( 1 );
+	}
+
+	void Open( char *p_name )
+	{
+		fp = CreateFileA( p_name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+
+		if( fp == INVALID_HANDLE_VALUE )
+			log( -1, "'%s', could not open file", p_name );
+
+		name = p_name;
+	}
+
+	void Close()
+	{
+		if( fp )
+		{
+			if( !CloseHandle( fp ) )
+				log( 0, "'%s', could not close file handle", name ? name : "unknown" );			
+		}
+	}
+
+	unsigned long SizeSectors(void)
+	{
+		LARGE_INTEGER li;
+		unsigned long i;
+
+		if( !GetFileSizeEx( fp, &li ) )
+			log( -1, "'%s', could not retrieve file size (error %ul)", name, GetLastError() );
+
+		if( li.LowPart & 0x1ff )
+			log( -1, "'%s', file size is not a multiple of 512 byte sectors", name );
+
+		if( li.HighPart > 0x1f )
+			log( -1, "'%s', file size greater than LBA28 limit of 137,438,952,960 bytes", name );
+
+		i = ((li.HighPart << 23 ) & 0xff800000) | ((li.LowPart >> 9) & 0x7fffff);
+
+		return( (unsigned long) i );
+	}
+
+	void SeekSectors( unsigned long lba )
+	{
+		LARGE_INTEGER dist;
+
+		dist.HighPart = lba >> 23;
+		dist.LowPart = lba << 9;
+
+		if( !SetFilePointerEx( fp, dist, NULL, FILE_BEGIN ) )
+			log( -1, "'%s', Failed to seek to lba=%lu", name, lba );
+	}
+
+	void Read( void *buff, unsigned long len )
+	{
+		unsigned long out_len;
+
+		if( !ReadFile( fp, buff, len, &out_len, NULL ) || len != out_len )
+			log( -1, "'%s', ReadFile failed", name );
+	}
+
+	void Write( void *buff, unsigned long len )
+	{
+		unsigned long out_len;
+
+		if( !WriteFile( fp, buff, len, &out_len, NULL ) || len != out_len )
+			log( -1, "'%s', WriteFile failed", name );
+	}
+
+	FileAccess()
+	{
+		fp = NULL;
+		name = NULL;
+	}
+
+    // LBA 28 limit - 28-bits (could be 1 more, but not worth pushing it)
+	const static unsigned long MaxSectors = 0xfffffff; 
+#define USAGE_MAXSECTORS "137438 MB (LBA28 limit)"
+
+private:
+	HANDLE fp;
+	char *name;
+};
+
Index: /tags/v2.0.0_beta_2/Serial_Server/win32/Win32Serial.h
===================================================================
--- /tags/v2.0.0_beta_2/Serial_Server/win32/Win32Serial.h	(revision 464)
+++ /tags/v2.0.0_beta_2/Serial_Server/win32/Win32Serial.h	(revision 464)
@@ -0,0 +1,207 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Win32Serial.h - Microsoft Windows serial code
+//
+
+//
+// XTIDE Universal BIOS and Associated Tools 
+// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+//
+// 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.		
+// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+//
+
+#include <stdio.h>
+#include "windows.h"
+#include "../library/library.h"
+
+#define PIPENAME "\\\\.\\pipe\\xtide"
+
+class SerialAccess
+{
+public:
+	void Connect( char *name, struct baudRate *p_baudRate )
+	{
+		char buff1[20], buff2[1024];
+
+		baudRate = p_baudRate;
+
+		pipe = NULL;
+
+		if( !name )
+		{
+			for( int t = 1; t <= 30 && !name; t++ )
+			{
+				sprintf( buff1, "COM%d", t );
+				if( QueryDosDeviceA( buff1, buff2, sizeof(buff2) ) )
+					name = buff1;
+			}
+			if( !name )
+				log( -1, "No physical COM ports found" );
+		}
+
+		if( name[0] == '\\' && name[1] == '\\' )
+		{
+			log( 0, "Opening named pipe %s (simulating %s baud)", name, baudRate->display );
+
+			pipe = CreateNamedPipeA( name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_REJECT_REMOTE_CLIENTS, 2, 1024, 1024, 0, NULL );
+			if( pipe == INVALID_HANDLE_VALUE )
+				log( -1, "Could not CreateNamedPipe " PIPENAME );
+
+			if( !ConnectNamedPipe( pipe, NULL ) )
+				log( -1, "Could not ConnectNamedPipe" );
+
+			if( baudRate->divisor > 0x80 )
+				log( -1, "Cannot simulate baud rates with hardware multipliers" );
+
+			speedEmulation = 1;
+			resetConnection = 1;
+		}
+		else
+		{
+			if( QueryDosDeviceA( name, buff2, sizeof(buff2) ) )
+			{
+				COMMTIMEOUTS timeouts;
+				DCB dcb;
+
+				log( 0, "Opening %s (%s baud)", name, baudRate->display );
+
+				pipe = CreateFileA( name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+				if( pipe == INVALID_HANDLE_VALUE )
+					log( -1, "Could not Open \"%s\"", name );
+
+				FillMemory(&dcb, sizeof(dcb), 0);
+				FillMemory(&timeouts, sizeof(timeouts), 0);
+
+				dcb.DCBlength = sizeof(dcb);
+				dcb.BaudRate = baudRate->rate;
+				dcb.ByteSize = 8;
+				dcb.StopBits = ONESTOPBIT;
+				dcb.Parity = NOPARITY;
+				if( !SetCommState( pipe, &dcb ) )
+				{
+					char *msg = "";
+					COMMPROP comProp;
+
+					if( GetCommProperties( pipe, &comProp ) )
+					{
+						if( comProp.dwMaxBaud != BAUD_USER )
+							msg = "\n    On this COM port, baud rate is limited to 115.2K";
+					}
+					log( -1, "Could not SetCommState: baud rate selected may not be available%s", msg );
+				}
+
+				if( !SetCommTimeouts( pipe, &timeouts ) )
+					log( -1, "Could not SetCommTimeouts" );
+			}
+			else
+			{
+				char logbuff[ 1024 ];
+
+				EnumerateCOMPorts( logbuff, 1024 );
+
+				log( -1, "Serial port '%s' not found, detected COM ports: %s", name, logbuff );
+			}
+		}
+	}
+
+	static void EnumerateCOMPorts( char *logbuff, int logbuffLen )
+	{
+		int found = 0;
+		char buff1[20], buff2[1024];
+
+		logbuff[0] = 0;
+
+		for( int t = 1; t <= 40 && strlen(logbuff) < (logbuffLen - 40); t++ )
+		{
+			sprintf( buff1, "COM%d", t );
+			if( QueryDosDeviceA( buff1, buff2, sizeof(buff2) ) )
+			{
+				if( found )
+					strcat( logbuff, ", " );
+				strcat( logbuff, buff1 );
+				found = 1;
+			}
+		}
+
+		if( !found )
+			strcat( logbuff, "(none)" );
+	}
+
+	void Disconnect()
+	{
+		if( pipe )
+		{
+			CloseHandle( pipe );
+			pipe = NULL;
+		}
+	}
+
+	unsigned long readCharacters( void *buff, unsigned long len )
+	{
+		unsigned long readLen;
+		int ret;
+
+		ret = ReadFile( pipe, buff, len, &readLen, NULL );
+
+		if( !ret || readLen == 0 )
+		{
+			if( GetLastError() == ERROR_BROKEN_PIPE )
+				return( 0 );
+		    else
+				log( -1, "read serial failed (error code %d)", GetLastError() );
+		}
+
+		return( readLen );
+	}
+
+	int writeCharacters( void *buff, unsigned long len )
+	{
+		unsigned long writeLen;
+		int ret;
+
+		ret = WriteFile( pipe, buff, len, &writeLen, NULL );
+
+		if( !ret || len != writeLen )
+		{
+			if( GetLastError() == ERROR_BROKEN_PIPE )
+				return( 0 );
+			else
+				log( -1, "write serial failed (error code %d)", GetLastError() );
+		}
+
+		return( 1 );
+	}
+
+	SerialAccess()
+	{
+		pipe = NULL;
+		speedEmulation = 0;
+		resetConnection = 0;
+		baudRate = NULL;
+	}
+
+	~SerialAccess()
+	{
+		Disconnect();
+	}
+
+	int speedEmulation;
+	int resetConnection;
+
+	struct baudRate *baudRate;
+
+private:
+	HANDLE pipe;
+};
+
