Index: /trunk/Serial_Server/library/Checksum.cpp
===================================================================
--- /trunk/Serial_Server/library/Checksum.cpp	(revision 209)
+++ /trunk/Serial_Server/library/Checksum.cpp	(revision 209)
@@ -0,0 +1,355 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        checksum.cpp - Checksum function and test routines
+//
+// 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: /trunk/Serial_Server/library/FlatImage.cpp
===================================================================
--- /trunk/Serial_Server/library/FlatImage.cpp	(revision 209)
+++ /trunk/Serial_Server/library/FlatImage.cpp	(revision 209)
@@ -0,0 +1,117 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        FlatImage.cpp - Basic flat disk image file support
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "FlatImage.h"
+
+FlatImage::FlatImage( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_sect, unsigned long p_head )   :   Image( name, p_readOnly, p_drive, p_create, p_cyl, p_sect, p_head )
+{
+	double sizef;
+
+	if( p_create )
+	{
+		char buff[512];
+		unsigned long size;
+		unsigned long size2;
+		double sizef;
+
+		fp = fopen( name, "r" );
+		if( fp )
+			log( 0, "Create Failure: '%s' already exists", name );
+		
+		if( !(fp = fopen( name, "w" )) )
+			log( 0, "Could not create file '%s'", name );
+
+		memset( &buff[0], 0, 512 );
+		size2 = size = (unsigned long) p_cyl * (unsigned long) p_sect * (unsigned long) p_head;
+		while( size-- )
+		{
+			if( fwrite( &buff[0], 1, 512, fp ) != 512 )
+				log( 0, "Create write black sector error" );
+		}
+		fclose( fp );
+		
+		sizef = size2/2048.0;
+		log( 1, "Created file '%s' with geometry %u:%u:%u, size %.1lf megabytes\n", name, p_cyl, p_sect, p_head, sizef );
+	}
+
+	fp = fopen( name, "r+" );
+	if( !fp )
+		log( 0, "Could not Open %s", name );
+
+	log( 1, "Opening disk image '%s'", name );
+
+	fseek( fp, 0, SEEK_END );
+	totallba = ftell( fp );
+
+	if( !totallba )
+		log( 0, "Could not get file size" );
+
+	if( totallba & 0x1ff )
+		log( 0, "File not made up of 512 byte sectors" );
+
+	totallba >>= 9;
+	if( totallba != (p_sect * p_head * p_cyl) )
+	{
+		if( p_sect || p_head || p_cyl )
+			log( 0, "File size does not match geometry" );
+		else if( (totallba % 16) != 0 || ((totallba/16) % 63) != 0 )
+			log( 0, "File size does not match standard geometry (x:16:63), please give explicitly with -g" );
+		else
+		{
+			sect = 63;
+			head = 16;
+			cyl = (totallba / sect / head);
+		}
+	}
+	else
+	{
+		sect = p_sect;
+		head = p_head;
+		cyl = p_cyl;
+	}
+
+	sizef = totallba/2048.0;
+	log( 1, "Using geometry %u:%u:%u, total size %.1lf megabytes", cyl, sect, head, sizef );
+}
+
+int FlatImage::seekSector( unsigned long cyl, unsigned long sect, unsigned long head )
+{
+	return( 0 );
+}
+
+int FlatImage::seekSector( unsigned long lba )
+{
+	return( fseek( fp, lba * 512, SEEK_SET ) );
+}
+
+int FlatImage::writeSector( void *buff )
+{
+	int r;
+
+	r = fwrite( buff, 1, 512, fp );
+	fflush( fp );
+	
+	return( r == 512 ? 0 : 1 );
+}
+
+int FlatImage::readSector( void *buff )
+{
+	return( fread( buff, 1, 512, fp ) == 512 ? 0 : 1 );
+}
+
+FlatImage::~FlatImage()
+{
+	if( fp )
+		fclose( fp );
+	fp = NULL;
+}
+
+
Index: /trunk/Serial_Server/library/FlatImage.h
===================================================================
--- /trunk/Serial_Server/library/FlatImage.h	(revision 209)
+++ /trunk/Serial_Server/library/FlatImage.h	(revision 209)
@@ -0,0 +1,25 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        FlatImage.h - Header file for basic flat disk image support
+//
+
+#include <stdio.h>
+#include "library.h"
+
+class FlatImage : public Image
+{
+private:
+	FILE *fp;
+
+public:
+	FlatImage( char *name, int p_readOnly, int p_drive, int create, unsigned long cyl, unsigned long sect, unsigned long head );
+	~FlatImage();
+
+	int seekSector( unsigned long cyl, unsigned long sect, unsigned long head );
+	int seekSector( unsigned long lba );
+	int writeSector( void *buff );
+	int readSector( void *buff );
+};
+
Index: /trunk/Serial_Server/library/Image.cpp
===================================================================
--- /trunk/Serial_Server/library/Image.cpp	(revision 209)
+++ /trunk/Serial_Server/library/Image.cpp	(revision 209)
@@ -0,0 +1,157 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        image.cpp - Abstract base class for disk image support
+//
+
+#include "library.h"
+#include <memory.h>
+#include <stdlib.h>
+#include <string.h>
+
+Image::Image( char *name, int p_readOnly, int p_drive )
+{
+	init( name, p_readOnly, p_drive );
+}
+
+Image::Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_lba )
+{
+	init( name, p_readOnly, p_drive );
+}
+
+Image::Image( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_sect, unsigned long p_head )
+{
+	init( name, p_readOnly, p_drive );
+}
+
+void Image::init( char *name, int p_readOnly, int p_drive )
+{
+	for( char *c = shortFileName = name; *c; c++ )
+		if( *c == '\\' || *c == '/' || *c == ':' )
+			shortFileName = c+1;
+
+	if( *(shortFileName) == 0 )
+		log( 0, "Can't parse %s\n\n", name );
+  
+	readOnly = p_readOnly;
+	drive = p_drive;
+}
+
+int Image::parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_sect, unsigned long *p_head )
+{
+	char *c, *s, *h;
+	unsigned long cyl, sect, head;
+
+	c = str;
+	for( s = c; *s && *s != ':' && *s != 'x' && *s != 'X'; s++ ) ;
+	if( !*s )
+		return( 0 );
+
+	*s = '\0';
+	s++;
+	for( h = s+1; *h && *h != ':' && *h != 'x' && *h != 'X'; h++ ) ; 
+	if( !*h )
+		return( 0 );
+
+	*h = '\0';
+	h++;
+
+	cyl = atol(c);
+	sect = atol(s);
+	head = atol(h);
+
+	if( cyl == 0 || sect == 0 || head == 0 )
+		return( 0 );
+
+	*p_cyl = cyl;
+	*p_sect = sect;
+	*p_head = head;
+
+	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_strFirmware 23
+#define ATA_strModel 27
+#define ATA_wCaps 49
+#define ATA_wCurCyls 54
+#define ATA_wCurHeads 55
+#define ATA_wCurSPT 56
+#define ATA_dwCurSCnt 57
+#define ATA_dwLBACnt 60
+
+#define ATA_VendorSpecific_ReturnPortBaud 158
+
+#define ATA_wCaps_LBA 0x200
+
+#define ATA_wGenCfg_FIXED 0x40
+
+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, struct baudRate *baudRate, unsigned char portAndBaud )
+{
+	unsigned short comPort = 0;
+	struct comPorts *cp;
+
+	if( portAndBaud )
+	{
+		for( cp = supportedComPorts; cp->port && cp->port != ((portAndBaud << 3) + 0x260); cp++ ) ;
+		if( cp->port )
+			comPort = cp->com;
+	}
+	  
+	memset( &buff[0], 0, 514 );
+
+	if( comPort )
+		sprintf( (char *) &buff[ATA_strModel], "%.20s (COM%d/%s)", shortFileName, comPort, baudRate->display );
+	else
+		sprintf( (char *) &buff[ATA_strModel], "%.30s (%s baud)", shortFileName, baudRate->display );
+
+	// strncpy( (char *) &buff[ATA_strModel], img->shortFileName, 40 );
+
+	strncpy( (char *) &buff[ATA_strSerial], "serial", 20 );
+	strncpy( (char *) &buff[ATA_strFirmware], "firmw", 8 );
+
+	for( int t = ATA_strModel; t < ATA_strModel+40; t++ )
+		buff[t] = (buff[t] >> 8) | (buff[t] << 8);
+
+#if 1
+	buff[ ATA_wCylCnt ] = cyl;
+	buff[ ATA_wHeadCnt ] = head;
+	buff[ ATA_wSPT ] = sect;
+#endif
+	buff[ ATA_wGenCfg ] = ATA_wGenCfg_FIXED;
+	//					buff[ ATA_VendorSpecific_ReturnPortBaud ] = retWord;
+#if 0
+	buff[ ATA_wCaps ] = ATA_wCaps_LBA;
+  
+	buff[ ATA_dwLBACnt ] = (unsigned short) (totallba & 0xffff);
+	buff[ ATA_dwLBACnt+1 ] = (unsigned short) (totallba >> 16);
+#endif
+}
Index: /trunk/Serial_Server/library/Library.h
===================================================================
--- /trunk/Serial_Server/library/Library.h	(revision 209)
+++ /trunk/Serial_Server/library/Library.h	(revision 209)
@@ -0,0 +1,89 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        library.h - Include file for users of the library
+//
+
+#ifndef LIBRARY_H_INCLUDED
+#define LIBRARY_H_INCLUDED
+
+#include "stdio.h"
+
+void log( int level, char *message, ... );
+unsigned long GetTime(void);
+unsigned long GetTime_Timeout(void);
+
+unsigned short checksum( unsigned short *wbuff, int wlen );
+
+class Image
+{
+public:
+	virtual int seekSector( unsigned long cyl, unsigned long sect, unsigned long head ) = 0;
+	virtual int seekSector( unsigned long lba ) = 0;
+
+	virtual int writeSector( void *buff ) = 0;
+	
+	virtual int 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_sect, unsigned long p_head );
+
+	virtual ~Image() {};
+
+	unsigned long cyl, sect, head;
+
+	unsigned long totallba;
+	
+	char *shortFileName;
+	int readOnly;
+	int drive;
+
+	static int parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_sect, unsigned long *p_head );
+
+	void respondInquire( unsigned short *buff, struct baudRate *baudRate, unsigned char portAndBaud );
+
+private:
+	void init( char *name, int p_readOnly, int p_drive );
+};
+
+struct baudRate {
+	unsigned long rate;
+	unsigned char divisor;
+	char *display;
+	char *altSelection;
+};
+struct baudRate *baudRateMatchString( char *str );
+struct baudRate *baudRateMatchDivisor( unsigned char divisor );
+
+class Serial
+{
+public:
+	virtual unsigned long readCharacters( void *buff, unsigned long len ) = 0;
+
+	virtual unsigned long writeCharacters( void *buff, unsigned long len ) = 0;
+
+	Serial( char *name, struct baudRate *p_baudRate ) 
+	{
+		speedEmulation = 0;
+		resetConnection = 0;
+		baudRate = p_baudRate;
+	};
+
+	virtual ~Serial() {};
+
+	int speedEmulation;
+	int resetConnection;
+
+	struct baudRate *baudRate;
+};
+
+void processRequests( Serial *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel );
+
+#define ATA_COMMAND_LBA 0x40
+#define ATA_COMMAND_HEADMASK 0xf
+
+#define ATA_DriveAndHead_Drive 0x10
+
+#endif
Index: /trunk/Serial_Server/library/Process.cpp
===================================================================
--- /trunk/Serial_Server/library/Process.cpp	(revision 209)
+++ /trunk/Serial_Server/library/Process.cpp	(revision 209)
@@ -0,0 +1,298 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        process.cpp - Processes commands received over the serial port
+//
+
+#include "library.h"
+#include <memory.h>
+#include <string.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 undefined1;
+		unsigned char portAndBaud;
+		unsigned char undefined2;
+	} inquire;
+	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 SERIAL_INQUIRE_PORTANDBAUD_BAUD 3
+#define SERIAL_INQUIRE_PORTANDBAUD_PORT 0xfc
+
+void processRequests( Serial *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
+{
+	unsigned char workCommand;
+	int workOffset, workCount;
+
+	int vtype;
+
+	unsigned long mylba;
+	unsigned long readto;
+	unsigned long buffoffset;
+	int timeout;
+	unsigned long lasttick;
+	unsigned short crc;
+	unsigned long GetTime_Timeout_Local;
+	unsigned long len;
+	Image *img;
+	unsigned long cyl, sect, head;
+
+	GetTime_Timeout_Local = GetTime_Timeout();
+
+	buffoffset = 0;
+	readto = 0;
+	timeout = 0;
+	workCount = workOffset = workCommand = 0;
+	lasttick = GetTime();
+
+	while( timeout || (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
+	{
+		buffoffset += len;
+
+		if( verboseLevel >= 4 )
+		{
+			char logBuff[ 514*9 + 10 ];
+			int logCount;
+
+			if( verboseLevel == 6 || buffoffset == readto )
+			{
+				if( verboseLevel == 4 && 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( 4, logBuff );
+			}
+		}
+
+		timeout = 0;
+
+		if( buffoffset != 1 && (timeoutEnabled && GetTime() > lasttick + GetTime_Timeout_Local) )
+		{
+			timeout = 1;
+			buff.b[0] = buff.b[buffoffset];
+			buffoffset = 0;
+			len = 1;
+			workCount = 0;
+			log( 2, "Timeout waiting on command" );
+			continue;
+		}
+
+		lasttick = GetTime();
+
+		if( buffoffset == 1 && !readto )
+		{
+			if( workCount )
+			{
+				readto = 1;
+			}
+			else if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
+			{
+				readto = 8;
+			}
+			else
+			{
+				if( verboseLevel >= 2 )
+				{
+					if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
+						log( 3, "[%d:%c]", buff.b[0], buff.b[0] );
+					else
+						log( 3, "[%d]", buff.b[0] );
+				}
+				buffoffset = 0;
+				continue;
+			}
+		}
+
+		// read 512 bytes from serial port - only one reason for that size: Write Sector
+		//
+		if( buffoffset == readto && readto == 514 )
+		{
+			buffoffset = readto = 0;
+			if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
+			{
+				log( 1, "Bad Write Sector Checksum" );
+				continue;
+			}
+
+			if( img->readOnly )
+			{
+				log( 2, "Attempt to write to read-only image" );
+				continue;
+			}
+
+			img->seekSector( mylba + workOffset );
+			img->writeSector( &buff.w[0] );
+
+			if( serial->writeCharacters( &buff.w[256], 2 ) != 2 )
+				log( 1, "Serial Port Write Error" );
+
+			workOffset++;
+			workCount--;
+		}
+
+		// 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( buff.b[0] != (workCount-0) )
+				{
+					log( 1, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
+					workCount = 0;
+					continue;
+				}
+			}
+			else
+			{
+				if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
+				{
+					log( 1, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%02x",
+						 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;
+				}
+
+				if( (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) )
+				{
+					if( !image1 )
+					{
+						log( 2, "slave drive selected when not supplied" );
+						continue;
+					}
+					img = NULL;
+				}
+				else
+					img = image0;
+
+				workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
+
+				if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.command & 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);
+					vtype = 1;
+				}
+				else
+				{
+					cyl = buff.chs.cylinder;
+					sect = buff.chs.sector;
+					head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK);
+					mylba = (((cyl*img->head + head)*img->sect) + sect-1);
+					vtype = 2;
+				}
+
+				if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
+				{
+					log( 2, "Write attempt to Read Only disk" );
+					continue;
+				}
+
+				workOffset = 0;
+				workCount = buff.chs.count;
+			}
+
+			if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
+			{
+				readto = 514;
+			}
+			else 
+			{
+				if( workCommand == SERIAL_COMMAND_INQUIRE )
+				{
+					log( 2, "Inquire Disk Information, Drive=%d", 
+						 (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) >> 4 );
+
+					if( serial->speedEmulation && 
+						(buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUD) != serial->baudRate->divisor )
+					{
+						struct baudRate *br;
+
+						br = baudRateMatchDivisor( buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUD );
+
+						if( br )
+							log( 2, "    Ignoring Inquire with Baud Rate=%d", br->rate );
+						else
+							log( 2, "    Ignoring Inquire with Unknown Baud Rate (portAndBaud=%d)", buff.inquire.portAndBaud );
+						workCount = 0;
+						continue;
+					}
+
+					img->respondInquire( &buff.w[0], serial->baudRate, buff.inquire.portAndBaud );
+				}
+				else
+				{
+					img->seekSector( mylba + workOffset );
+					img->readSector( &buff.w[0] );
+				}
+
+				buff.w[256] = checksum( &buff.w[0], 256 );
+
+				if( serial->writeCharacters( &buff.w[0], 514 ) != 514 )
+				{
+					log( 1, "Serial Port Write Error" );
+				}
+
+				workCount--;
+				workOffset++;
+			}
+
+			if( verboseLevel > 1 )
+			{
+				if( vtype == 1 )
+					log( 2, "%s: LBA=%u, Count=%u", 
+						 (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read"),
+						 mylba, workCount );
+				else if( vtype == 2 )
+					log( 2, "%s: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", 
+						 (workCommand & SERIAL_COMMAND_WRITE ? "Write" : (workCommand & SERIAL_COMMAND_READWRITE ? "Read" : "Inquire")),
+						 cyl, sect, head, workCount, mylba );
+
+				vtype = 0;		  
+
+				if( workOffset > 1 )
+					log( 3, "       Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );				  
+			}
+		}
+	}
+}
Index: /trunk/Serial_Server/library/Serial.cpp
===================================================================
--- /trunk/Serial_Server/library/Serial.cpp	(revision 209)
+++ /trunk/Serial_Server/library/Serial.cpp	(revision 209)
@@ -0,0 +1,54 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Serial.cpp - Generic functions for dealing with serial communications
+//
+
+#include "library.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct baudRate supportedBaudRates[] = 
+{ 
+	{   2400,  0x0,   "2400",   NULL }, 
+	{   4800, 0xff,   "4800",   NULL }, 
+	{   9600,  0x1,   "9600",   NULL }, 
+	{  19200, 0xff,  "19.2K",  "19K" }, 
+	{  38400,  0x2,  "38.4K",  "38K" }, 
+	{ 115200,  0x3, "115.2K", "115K" }, 
+	{ 230400, 0xff, "230.4K", "230K" }, 
+	{ 460800,  0x1, "460.8K", "460K" }, 
+	{      0,    0,     NULL,   NULL } 
+};
+
+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 )
+				return( b );
+	}
+
+	for( b = supportedBaudRates; b->rate; b++ )
+		if( !stricmp( str, b->display ) || (b->altSelection && !stricmp( str, b->altSelection )) )
+			return( b );
+
+	return( NULL );
+}
+
+struct baudRate *baudRateMatchDivisor( unsigned char divisor )
+{
+	struct baudRate *b;
+
+	for( b = supportedBaudRates; b->rate && b->divisor != divisor; b++ ) 
+		;
+
+	return( b->rate ? b : NULL );
+}
+
+
Index: /trunk/Serial_Server/makefile
===================================================================
--- /trunk/Serial_Server/makefile	(revision 209)
+++ /trunk/Serial_Server/makefile	(revision 209)
@@ -0,0 +1,31 @@
+######################################################################
+#
+# Project:     XTIDE Universal BIOS, Serial Port Server
+#
+# File:        makefile
+#
+# Use with GNU Make and Microsoft Visual C++ 2010
+#
+
+CL = cl
+CLFLAGS = /Ox
+
+WIN32OBJS = build/win32.obj build/win32serial.obj build/checksum.obj build/serial.obj build/flatimage.obj build/process.obj build/image.obj
+
+build/serserve.exe:	$(WIN32OBJS)
+	$(CL) /Febuild/serserve.exe $(WIN32OBJS)
+
+build/%.obj:	win32/%.cpp
+	$(CL) /c $(CLFLAGS) $< /Fo$@
+
+build/%.obj:	library/%.cpp
+	$(CL) /c $(CLFLAGS) $< /Fo$@
+
+$(WIN32OBJS):	library/library.h
+
+build/checksum_test.exe:	library/checksum.cpp
+	$(CL) /Febuild/checksum_test.exe /Ox library/checksum.cpp /Fobuild/checksum_test.obj -D CHECKSUM_TEST
+
+clean:	
+	del /q build\*.*
+
Index: /trunk/Serial_Server/win32/Win32.cpp
===================================================================
--- /trunk/Serial_Server/win32/Win32.cpp	(revision 209)
+++ /trunk/Serial_Server/win32/Win32.cpp	(revision 209)
@@ -0,0 +1,194 @@
+//======================================================================
+//
+// 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.
+// 
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "../library/library.h"
+#include "../library/flatimage.h"
+#include "Win32Serial.h"
+
+void usage(void)
+{
+	char *usageStrings[] = {
+		"usage: SerServe [options] master-imagefile [[slave-options] slave-imagefile]",
+		"  -g cyl:sect:head  Geometry in cylinders, sectors per cylinder, and heads",
+		"                    (default is 65:63:16 for a 32 MB disk)",
+		"  -n [megabytes]    New, Create new disk with given size or use -g geometry",
+		"  -p                Named pipe mode for emulators (pipe is " PIPENAME ")",
+		"  -c PortNumber     COM Port to use (default is first found)",
+		"  -b BaudRate       Baud rate to use on the COM port ",
+		"                    9600, 38400, 115200, 230400, or 460800",   
+		"                    (default 9600, 115200 in pipe mode)",
+		"  -t                Disable timeout, useful for long delays when debugging",
+		"  -r                Read Only disk",
+		"  -v [level]        Reporting level 1-6, increasing information",
+		NULL };
+
+	for( int t = 0; usageStrings[t]; t++ )
+		fprintf( stderr, "%s\n", usageStrings[t] );
+
+	exit( 1 );
+}
+
+int verbose = 1;
+
+int main(int argc, char* argv[])
+{
+	DWORD len;
+
+	unsigned long check;
+	unsigned char w;
+
+	unsigned short wbuff[256];
+
+	Serial *serial;
+	Image *img;
+	struct baudRate *baudRate;
+
+	int timeoutEnabled = 1;
+
+	char *ComPort = NULL, ComPortBuff[20];
+
+	_fmode = _O_BINARY;
+
+	unsigned long cyl = 0, sect = 0, head = 0;
+	int readOnly = 0, createFile = 0, explicitGeometry = 0;
+
+	int imagecount = 0;
+	Image *images[2] = { NULL, NULL };
+
+	baudRate = baudRateMatchString( "9600" );
+
+	for( int t = 1; t < argc; t++ )
+	{
+		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':
+				a = atol( argv[++t] );
+				if( a < 1 )
+					usage();
+				sprintf( ComPortBuff, "COM%d", a );
+				ComPort = &ComPortBuff[0];
+				break;
+			case 'v': case 'V':
+			    if( atol(argv[t+1]) != 0 )
+					verbose = atol(argv[++t]);
+				else
+					verbose = 2;
+				break;
+			case 'r': case 'R':
+				readOnly = 1;
+				break;
+			case 'p': case 'P':
+				ComPort = "PIPE";
+				baudRate = baudRateMatchString( "115200" );
+				break;			  
+			case 'g': case 'G':
+				if( !Image::parseGeometry( argv[++t], &cyl, &sect, &head ) )
+					usage();
+				explicitGeometry = 1;
+				break;
+			case 'h': case 'H': case '?':
+				usage();
+				break;
+			case 'n': case 'N':
+				createFile = 1;
+				if( atol(argv[t+1]) != 0 )
+				{
+					unsigned long size = atol(argv[++t]);
+					sect = 63;
+					head = 16;
+					cyl = (size*1024*2) / (16*63);
+					explicitGeometry = 1;
+				}
+				break;
+			case 't': case 'T':
+				timeoutEnabled = 0;
+				break;
+			case 'b': case 'B':
+				if( !(baudRate = baudRateMatchString( argv[++t] )) )
+				{
+						fprintf( stderr, "Unknown Baud Rate %s\n\n", argv[t] );
+						usage();
+				}
+				break;
+			default:
+				fprintf( stderr, "Unknown Option: %s\n\n", argv[t] );
+				usage();
+			}
+		}
+		else if( imagecount < 2 )
+		{
+			images[imagecount] = new FlatImage( argv[t], readOnly, imagecount, createFile, cyl, sect, head );
+			imagecount++;
+			createFile = readOnly = cyl = sect = head = 0;
+		}
+		else
+			usage();
+	}
+
+	if( imagecount == 0 )
+		usage();
+
+	do
+	{
+		serial = new Win32Serial( ComPort, baudRate );
+
+		processRequests( serial, images[0], images[1], timeoutEnabled, verbose );
+
+		delete serial;
+
+		if( serial->resetConnection )
+			log( 1, "==== Resetting Connection ====" );
+	}
+	while( serial->resetConnection );
+}
+
+void log( int level, char *message, ... )
+{
+	va_list args;
+
+	va_start( args, message );
+
+	if( level == 0 )
+	{
+	  vfprintf( stderr, message, args );
+	  fprintf( stderr, "\n" );
+	  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: /trunk/Serial_Server/win32/Win32Serial.cpp
===================================================================
--- /trunk/Serial_Server/win32/Win32Serial.cpp	(revision 209)
+++ /trunk/Serial_Server/win32/Win32Serial.cpp	(revision 209)
@@ -0,0 +1,124 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Win32Serial.cpp - Microsoft Windows serial code
+//
+// Support for the serial port under Win32.
+// 
+
+#include <stdio.h>
+
+#include "..\library\library.h"
+#include "Win32Serial.h"
+
+COMMTIMEOUTS timeouts;
+
+DCB dcb;
+
+Win32Serial::~Win32Serial()
+{
+	if( pipe )
+		CloseHandle( pipe );
+
+	pipe = NULL;
+}
+
+Win32Serial::Win32Serial( char *name, struct baudRate *baudRate ) : Serial( name, baudRate )
+{
+	char buff1[20], buff2[1024];
+
+	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( 0, "No Physical COM Ports Found" );
+	}
+
+	if( !strcmp( name, "PIPE" ) )
+	{
+		log( 1, "Opening named pipe %s (simulating %lu baud)", PIPENAME, baudRate->rate );
+		
+		pipe = CreateNamedPipeA( PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_REJECT_REMOTE_CLIENTS, 2, 1024, 1024, 0, NULL );
+		if( !pipe )
+			log( 0, "Could not CreateNamedPipe " PIPENAME );
+		
+		if( !ConnectNamedPipe( pipe, NULL ) )
+			log( 0, "Could not ConnectNamedPipe" );
+
+		speedEmulation = 1;
+		resetConnection = 1;
+	}
+	else
+	{
+		if( QueryDosDeviceA( name, buff2, sizeof(buff2) ) )
+		{
+			log( 1, "Opening %s (%lu baud)", name, baudRate->rate );
+			
+			pipe = CreateFileA( name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+			if( !pipe )
+				log( 0, "Could not Open \"%s\"", name );
+			
+			FillMemory(&dcb, sizeof(dcb), 0);
+			dcb.DCBlength = sizeof(dcb);
+			dcb.BaudRate = baudRate->rate;
+			dcb.ByteSize = 8;
+			dcb.StopBits = ONESTOPBIT;
+			dcb.Parity = NOPARITY;
+			if( !SetCommState( pipe, &dcb ) )
+				log( 0, "Could not SetCommState" );
+
+			if( !SetCommTimeouts( pipe, &timeouts ) )
+				log( 0, "Could not SetCommTimeouts" );
+		}
+		else
+		{
+			int first = 1;
+			char logbuff[ 1024 ];
+			sprintf( logbuff, "Serial Port Not Found \"%s\", Available: ", name );
+			for( int t = 1; t <= 30 && !name; t++ )
+			{
+				sprintf( buff1, "COM%d", t );
+				if( QueryDosDeviceA( buff1, buff2, sizeof(buff2) ) )
+				{
+					if( !first )
+						strcat( logbuff, ", " );
+					else
+						first = 0;
+					strcat( logbuff, buff1 );
+				}
+			}
+			log( 0, logbuff );
+		}
+	}
+}
+
+unsigned long Win32Serial::readCharacters( void *buff, unsigned long len )
+{
+	unsigned long readLen;
+	int ret;
+	ret = ReadFile( pipe, buff, len, &readLen, NULL );
+	return( ret ? readLen : 0 );
+}
+
+unsigned long Win32Serial::writeCharacters( void *buff, unsigned long len )
+{
+	unsigned long writeLen;
+	int ret;
+	ret = WriteFile( pipe, buff, len, &writeLen, NULL );
+	return( ret ? writeLen : 0 );
+}
+
+
+
+
+
+
+
Index: /trunk/Serial_Server/win32/Win32Serial.h
===================================================================
--- /trunk/Serial_Server/win32/Win32Serial.h	(revision 209)
+++ /trunk/Serial_Server/win32/Win32Serial.h	(revision 209)
@@ -0,0 +1,25 @@
+//======================================================================
+//
+// Project:     XTIDE Universal BIOS, Serial Port Server
+//
+// File:        Win32Serial.h - Microsoft Windows serial code
+//
+
+#include "windows.h"
+#include "../library/library.h"
+
+#define PIPENAME "\\\\.\\pipe\\xtide"
+
+class Win32Serial : public Serial
+{
+public:
+	Win32Serial( char *name, struct baudRate *baudRate );
+	~Win32Serial();
+
+	unsigned long readCharacters( void *buff, unsigned long len );
+	unsigned long writeCharacters( void *buff, unsigned long len );
+
+private:
+	HANDLE pipe;
+};
+
