diff -Nur orig/Makefile new/Makefile
--- orig/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ new/Makefile	2011-03-06 19:35:59.000000000 +0100
@@ -0,0 +1,55 @@
+# **************************************************************************
+#    TI-99/4A read and write floppy images
+#
+#    Copyright (C) 2008 Michael Zapf (Michael.Zapf@mizapf.de)
+#    Copyright (C) 2011 Gerhard Wiesinger (gerhard@wiesinger.com)
+#
+#    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 3 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, see <http://www.gnu.org/licenses/>.
+#
+# **************************************************************************
+
+CC=gcc
+CCFLAGS=-g -Wall -pedantic -std=c99
+LDFLAGS=-g
+
+MAKEFILE=Makefile
+TARGET1=readti
+OBJS1=readti.o
+TARGET2=writeti
+OBJS2=writeti.o
+
+ORIGDIR=orig
+NEWDIR=new
+PATCHFILE=ti99.patch
+
+.c.o: 
+	$(CC) -c $(CCFLAGS) $< 
+
+all: $(TARGET1) $(TARGET2) $(PATCHFILE)
+
+$(TARGET1): $(OBJS1)
+	$(CC) $(LDFLAGS) -o $(TARGET1) $(OBJS1)
+#	strip $(TARGET1)
+
+$(TARGET2): $(OBJS2)
+	$(CC) $(LDFLAGS) -o $(TARGET2) $(OBJS2)
+#	strip $(TARGET2)
+
+$(PATCHFILE): $(MAKEFILE) $(TARGET1).c $(TARGET2).c
+	mkdir -p $(NEWDIR)
+	cp $(MAKEFILE) $(TARGET1).c $(TARGET2).c $(NEWDIR)
+	diff -Nur $(ORIGDIR) $(NEWDIR) > $(PATCHFILE); exit 0
+
+clean:
+	rm -f $(TARGET1) $(OBJS1) $(TARGET2) $(OBJS2) $(PATCHFILE)
diff -Nur orig/readti.c new/readti.c
--- orig/readti.c	2011-03-05 20:17:25.000000000 +0100
+++ new/readti.c	2011-03-06 19:35:59.000000000 +0100
@@ -4,6 +4,7 @@
               and Geneve computer family
     
     Copyright (C) 2008 Michael Zapf (Michael.Zapf@mizapf.de)
+    Copyright (C) 2011 Gerhard Wiesinger (gerhard@wiesinger.com)
 
     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 
@@ -24,13 +25,14 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <linux/fd.h>
 #include <linux/fdreg.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <wchar.h>
+#include <getopt.h>
 
 #define COMMAND 0
 #define PHEAD 1
@@ -47,6 +49,11 @@
 #define SINGLE 1
 #define DOUBLE 2
 
+#define SECTOR_SIZE (0x100)
+
+// Reply interrupt code (2 status bits, bits 7,6)
+#define REPLY_STATUS_MASK (0xC0)
+
 struct geometry_t 
 {
 	int tracks;
@@ -57,10 +64,109 @@
 	int stepping;
 } geometry;
 
+int disk_analysis;
+int command_display;
+int debug;
 int verbose;
+int recalibrate_on_error;
+int reply_display;
+int sectorwise_read;
 
 struct floppy_raw_cmd raw_cmd;
 
+void print_command()
+{
+	unsigned int i = 0;
+	printf("command: flags=0x%08X, rate=0x%02X, track=%d, len=%ld, command_count=%d, command[hex]=", 
+		raw_cmd.flags, (int)raw_cmd.rate, raw_cmd.track, raw_cmd.length, (int)raw_cmd.cmd_count);
+	for (i=0; i < raw_cmd.cmd_count; ++i)
+		printf("%02X ", (unsigned int)raw_cmd.cmd[i]);
+
+	printf("\n");
+	fflush(stdout);
+}
+
+int is_reply_error_byte(unsigned char* reply)
+{
+	return ((reply[0] & REPLY_STATUS_MASK) != 0);
+}
+
+int is_reply_error(struct floppy_raw_cmd* cmd)
+{
+	if (cmd->reply_count < 7)
+	{
+		printf("Got no valid reply with length >=7");
+		exit(1);
+	}
+	return is_reply_error_byte(&(cmd->reply[0]));
+}
+
+void print_reply()
+{
+	unsigned int i = 0;
+	printf("reply_count=%d, reply[hex]=", (int)raw_cmd.reply_count);
+	for (i=0; i < raw_cmd.reply_count; ++i)
+		printf("%02X ", (unsigned int)raw_cmd.reply[i]);
+
+	printf("\n");
+	fflush(stdout);
+}
+
+int fileout_seek(FILE* fout, int track, int sector, int head)
+{
+	int error = 0;
+	long offset = 0;
+	if (geometry.sides == 2 && head == 1)
+	{
+		// Second side: starting with half offset of file and tracks geometry.tracks-1 downto 0
+		offset = SECTOR_SIZE * (sector + geometry.sectors * (geometry.tracks + (geometry.tracks-1) - track));
+	}
+	else
+	{
+		// First side: starting with 0 offset of file and tracks 0 to geometry.tracks-1
+		offset = SECTOR_SIZE * (sector + geometry.sectors * track);
+	}
+	if (debug) printf("Seek to file position %ld\n", offset);
+	error = fseek(fout, offset, SEEK_SET);
+	if (error) printf("Can't seek to file position %ld\n", offset);
+	return error;
+}
+
+int write_initial_file(FILE* fout)
+{
+	wchar_t* buffer = NULL;
+	long offset = 0;
+	int size = 0;
+	int error = fseek(fout, 0, SEEK_SET);
+        if (error)
+	{
+		printf("Can't seek to file position %ld\n", offset);
+		return error;
+	}
+
+	size = SECTOR_SIZE * geometry.sides * geometry.sectors * geometry.tracks;
+
+	if (verbose) printf("Allocating file with filesize of %d bytes\n", size);
+
+	buffer = malloc(size);
+	if (buffer == NULL)
+	{
+		printf("Can't allocate %d bytes\n", size);
+		return 1;
+	}
+	wmemset(buffer, 0xaddeadde, size/sizeof(wchar_t));
+	fwrite(buffer, size, 1, fout);	
+	free(buffer);
+
+	error = fseek(fout, 0, SEEK_SET);
+        if (error)
+	{
+		printf("Can't seek to file position %ld\n", offset);
+		return error;
+	}
+	return 0;
+}
+
 void recalibrate(int fd)
 {
 	int tmp, size;
@@ -70,7 +176,7 @@
 	raw_cmd.cmd[PHEAD] = head*4;  // 0 and 4 are the sides
 	raw_cmd.cmd[LHEAD] = head;
 	raw_cmd.cmd_count = 2;
-	raw_cmd.length = 0x100;
+	raw_cmd.length = SECTOR_SIZE;
 	size = raw_cmd.length;    
 
 	raw_cmd.rate = geometry.rate;
@@ -82,6 +188,8 @@
 	raw_cmd.cmd[LCYL] = track;
 	raw_cmd.track = raw_cmd.cmd[LCYL]*geometry.stepping;
 
+	if (debug || command_display) print_command();
+
 	tmp = ioctl( fd, FDRAWCMD, &raw_cmd );
 	if (verbose) printf("Recalibrate...\n"); 
 	if ( tmp < 0 ){
@@ -90,7 +198,7 @@
 	}
 }
 
-void loadsector(int fd, int fdout, int track, int sector, int head)
+void loadsector(int fd, FILE* fout, int track, int sector, int head)
 {
 	int tmp, size;
 	
@@ -105,7 +213,7 @@
 	raw_cmd.cmd[GAP] = 0x1b;     // not needed, default
 	raw_cmd.cmd[SIZE2] = 0xff;   // not needed, default
 	raw_cmd.cmd_count = 9;
-	raw_cmd.length = 0x100;
+	raw_cmd.length = SECTOR_SIZE;
 	size = raw_cmd.length;    
 
 	raw_cmd.rate = geometry.rate;
@@ -117,26 +225,40 @@
 	raw_cmd.cmd[LCYL] = track;
 	raw_cmd.track = raw_cmd.cmd[LCYL]*geometry.stepping;
 
+	if (debug || command_display) print_command();
+
 	tmp = ioctl( fd, FDRAWCMD, &raw_cmd );
-//	printf("Reading track %d, head %d, status %2x\n", track, head, raw_cmd.reply[0]); 
+	if (verbose) printf("Read sector: track %d, sector=%d, head=%d, reply_count=%d, status=0x%02X\n", track, sector, head, (int)raw_cmd.reply_count, (int)raw_cmd.reply[0]); 
 	if ( tmp < 0 ){
 		perror("error executing command");
 		exit(1);
 	}
-	if (raw_cmd.reply[0] > 0x07) 
+	if (debug || reply_display) print_reply();
+	if (is_reply_error(&raw_cmd))
 	{
 		printf("Read error reading sector %d on track %d, side %d. Filling with 0xdead.\n", sector, track, head+1);
-		wmemset(buffer, 0xaddeadde, size/4);
+		wmemset((wchar_t*)buffer, 0xaddeadde, size/sizeof(wchar_t));
 	}
-	write(fdout, buffer, size );
+	(void)fileout_seek(fout, track, sector, head);
+	fwrite(buffer, size, 1, fout);
 }
 
-void loadtrack(int fd, int fdout, int track, int head)
+void loadtrack(int fd, FILE* fout, int track, int head)
 {
 	int tmp, size;
 	
 	char buffer[ 512 * 2 * 24 ];
 
+	if (sectorwise_read)
+	{
+		int sector;
+		for (sector=0; sector < geometry.sectors; sector++)
+		{
+			loadsector(fd, fout, track, sector, head);
+		}
+		return;	
+	}
+
 	raw_cmd.data = buffer;
 	raw_cmd.cmd[PHEAD] = head*4;  // 0 and 4 are the sides
 	raw_cmd.cmd[LHEAD] = head;
@@ -146,7 +268,7 @@
 	raw_cmd.cmd[GAP] = 0x1b;     // not needed, default
 	raw_cmd.cmd[SIZE2] = 0xff;   // not needed, default
 	raw_cmd.cmd_count = 9;
-	raw_cmd.length = 0x100 * geometry.sectors;
+	raw_cmd.length = SECTOR_SIZE * geometry.sectors;
 	size = raw_cmd.length;    
 
 	raw_cmd.rate = geometry.rate;
@@ -158,29 +280,35 @@
 	raw_cmd.cmd[LCYL] = track;
 	raw_cmd.track = raw_cmd.cmd[LCYL]*geometry.stepping;
 
+	if (debug || command_display) print_command();
+
 	tmp = ioctl( fd, FDRAWCMD, &raw_cmd );
-//	printf("Reading track %d, head %d, status %2x\n", track, head, raw_cmd.reply[0]); 
+	if (verbose) printf("Read track: track=%d, head=%d, reply_count=%d, status=0x%02X\n", track, head, (int)raw_cmd.reply_count, (int)raw_cmd.reply[0]); 
 	if ( tmp < 0 ){
 		perror("error executing command");
 		exit(1);
 	}
-	if (raw_cmd.reply[0] > 0x07) 
+	if (debug || reply_display) print_reply();
+	if (is_reply_error(&raw_cmd))
 	{
 		int sector;
 		if (verbose) printf("Read error reading track %d, side %d. Trying to read separate sectors.\n", track, head+1);
-		recalibrate(fd);
+		if (recalibrate_on_error) recalibrate(fd);
 		for (sector=0; sector < geometry.sectors; sector++)
 		{
-			loadsector(fd, fdout, track, sector, head);
+			loadsector(fd, fout, track, sector, head);
 		}
 	}
 	else
-		write(fdout, buffer, size );
+	{
+		(void)fileout_seek(fout, track, 0, head);
+		fwrite(buffer, size, 1, fout);
+	}
 }
 
 unsigned char *try_readid(int fd, int rate, int head, int track, int single_density)
 {
-	int tmp, size;
+	int tmp;
 	int need_seek = 1;
 
 	raw_cmd.cmd[COMMAND] = FD_READID;
@@ -194,12 +322,16 @@
 	
 	if (single_density) raw_cmd.cmd[0] &= ~0x40;
 
+	if (debug || command_display) print_command();
+
 	tmp = ioctl( fd, FDRAWCMD, &raw_cmd );
 		
 	if ( tmp < 0 ){
 		perror("error executing command");
 		exit(1);
 	}
+
+	if (debug) print_reply();
 	
 	return raw_cmd.reply;
 }
@@ -211,25 +343,28 @@
 void analyze_disk(int fd)
 {
 	// fdrawcmd readid 0 rate=0 need_seek track=0
-	char *status;
+	unsigned char *status;
 	// Determine rate  
 	int rate, density;
 	int sectors, i, heads, stepping, tracks;
+	int min_sector = 100000;
 	density = MFM;
 	
+	if (debug) printf("Detecting rate ...\n");
 	for (rate=0; rate < 4; rate++) 
 	{
 		status = try_readid(fd, rate, 0, 0, density);
-		if (status[0] < 0x08) break;
+		if (!is_reply_error_byte(status)) break;
 	}
 	if (rate==4)
 	{
+		if (debug) printf("Trying single density ...\n");
 		// Try single density
 		density = FM;
 		for (rate=0; rate < 4; rate++) 
 		{
 			status = try_readid(fd, rate, 0, 0, density);
-			if (status[0] < 0x08) break;
+			if (!is_reply_error_byte(status)) break;
 		}
 		if (rate==4)
 		{
@@ -238,35 +373,49 @@
 		}
 	}
 
+	if (debug) printf("Rate=%d\n", rate);
+
+	if (debug) printf("Detecting number of sides ...\n");
 	// Determine number of sides
 	status = try_readid(fd, rate, 1, 0, density);
-	if (status[0] < 0x08) heads = 2;
+	if (!is_reply_error_byte(status)) heads = 2;
 	else {
 		// Try another track
+		if (debug) printf("Recalibrating ...\n");
 		recalibrate(fd);
+		if (debug) printf("Reading track 18 for side detection ...\n");
 		status = try_readid(fd, rate, 1, 18, density);
-		if (status[0] < 0x08) heads = 2;
+		if (!is_reply_error_byte(status)) heads = 2;
 		else 
 			heads = 1;
 	}
+	if (debug) printf("Heads=%d\n", heads);
 
+	if (debug) printf("Detecting number of sectors ...\n");
 	// Determine number of sectors per track
+	// Heuristic: Statistical analysis of reading same track e.g. 200 (was 50) sectors and determining the maximum
 	sectors = 0;
-	for (i=0; i < 50; i++)
+	for (i=0; i < 200; i++)
 	{
+		if (debug) printf("Read track attempt number %d\n", i);
 		status = try_readid(fd, rate, 0, 0, density);
-		if (status[0] > 0x08) 
+		if (is_reply_error_byte(status)) 
 		{
 			printf("Error ... could not read a sector. Bad floppy disk?\n");
 			exit(1);
 		}
-		if (status[5] > sectors) sectors = status[5]; 
+		if (status[5] > sectors) sectors = status[5];
+		if (status[5] < min_sector) min_sector = status[5];
 	}
+	if (debug) printf("min_sector=%d\n", min_sector);
+	if (debug) printf("max_sector=%d\n", sectors);
 	sectors = sectors+1;
+	if (debug) printf("Sectors=%d\n", sectors);
 
+	if (debug) printf("Detecting single or double stepping ...\n");
 	// Determine single or double stepping
 	status = try_readid(fd, rate, 0, 2, density);
-	if (status[0] > 0x08) 
+	if (is_reply_error_byte(status)) 
 	{
 		printf("Error ... could not read a sector. Bad floppy disk?\n");
 		exit(1);
@@ -287,26 +436,28 @@
 			exit(1);
 		}
 	}	
-	
+	if (debug) printf("Stepping=%d\n", stepping);
+
+	if (debug) printf("Detecting number of tracks ...\n");
 	// Determine number of tracks
 	// Heuristic: 80 tracks/40 tracks, or 70 tracks/35 tracks
 	// Double stepping means a maximum of 40 or 35 tracks.
 	tracks = 80;
 	if (stepping==1) {
 		status = try_readid(fd, rate, 0, tracks-1, density);
-		if (status[0] > 0x08) 
+		if (is_reply_error_byte(status)) 
 		{
 			tracks = 70;
 			status = try_readid(fd, rate, 0, tracks-1, density);
-			if (status[0] > 0x08)
+			if (is_reply_error_byte(status))
 			{
 				tracks = 40;
 				status = try_readid(fd, rate, 0, tracks-1, density);
-				if (status[0] > 0x08)
+				if (is_reply_error_byte(status))
 				{
 					tracks = 35;
 					status = try_readid(fd, rate, 0, tracks-1, density);
-					if (status[0] > 0x08)
+					if (is_reply_error_byte(status))
 					{
 						printf("Cannot determine last track. Bad floppy disk?\n");
 						exit(1);
@@ -319,17 +470,18 @@
 	{ // double stepping; 40 or 35
 		tracks = 40;
 		status = try_readid(fd, rate, 0, 2*(tracks-1), density);
-		if (status[0] > 0x08)
+		if (is_reply_error_byte(status))
 		{
 			tracks = 35;
 			status = try_readid(fd, rate, 0, 2*(tracks-1), density);
-			if (status[0] > 0x08)
+			if (is_reply_error_byte(status))
 			{
 				printf("Cannot determine last track. Bad floppy disk?\n");
 				exit(1);
 			}
 		}
 	}
+	if (debug) printf("Tracks=%d\n", tracks);
 	
 	geometry.rate = rate;
 	geometry.density = density;
@@ -338,66 +490,106 @@
 	geometry.stepping = stepping;
 	geometry.tracks = tracks;
 	
-	if (verbose)
+	if (verbose || disk_analysis)
 	{
 		printf("Rate = %d\n", rate);	
 		printf("Single density = %d\n", density);
 		printf("Sectors = %d\n", sectors);
 		printf("Heads = %d\n", heads);
-		printf("physical/logical tracks = %d\n", stepping);
+		printf("Stepping(physical/logical tracks) = %d\n", stepping);
 		printf("Logical tracks = %d\n", tracks);
 	}
 }
 
+void usage()
+{
+	printf("Usage: readti [-a] [-c] [-d] [-e] [-r] [-s] [-v] device (=/dev/fd0) outfile\n");
+	printf("  Must be done on a 80 track capable floppy drive (typically no TI ones)\n");
+	printf("  -a print disk analysis\n");
+	printf("  -c display commands\n");
+	printf("  -d debug\n");
+	printf("  -e display rEply\n");
+	printf("  -r no recalibration beetween track mode read error and sector reading\n");
+	printf("  -s read tracks sector wise and not a whole track (doesn't work on some machines otherwise)\n");
+	printf("  -v verbose\n");
+	exit(1);
+}
+
 int main(int argc, char **argv)
 {
-	int fd, fdout, i;
-	int index=1;
+	FILE* fout = NULL;
+	int fd, i;
+	char c;
+	disk_analysis = 0;
+	command_display = 0;
+	debug = 0;
+	reply_display = 0;
+	recalibrate_on_error = 1;
+	sectorwise_read = 0;
 	verbose = 0;
+
+	if (argc < 3) usage();
 	
-	if (argc < 3)
-	{
-		printf("Usage: readti [-v] device (=/dev/fd0) outfile\n");
-		exit(1);
-	}
-	if (strcmp(argv[index],"-v")==0)
+	while ((c = getopt (argc, argv, "acdersv")) != -1) 
 	{
-		verbose = 1;
-		index++;
-		if (argc < 4)
+		switch (c)
 		{
-			printf("Usage: readti [-v] device (=/dev/fd0) outfile\n");
-			exit(1);
+		case 'a': 
+			disk_analysis = 1;
+			break;
+		case 'c': 
+			command_display = 1;
+			break;
+		case 'd': 
+			debug = 1;
+			break;
+		case 'e': 
+			reply_display = 1;
+			break;
+		case 'r': // no recalibrate on error
+			recalibrate_on_error = 0;
+			break;
+		case 's': // Read track sectorwise
+			sectorwise_read = 1;
+			break;
+		case 'v': 
+			verbose = 1;
+			break;
+		default:
+			usage();
+			break;
 		}
 	}
-	
-	fd = open(argv[index++], O_ACCMODE | O_NDELAY);
+
+	// 2 arguments must be left
+	if (argc - optind < 2) usage();
+
+	fd = open(argv[optind++], O_ACCMODE | O_NDELAY);
 	if ( fd < 0 ){
 		perror("error opening floppy");
 		exit(1);
 	}
 
-	fdout = open(argv[index++], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-	if ( fdout < 0 ){
+	fout = fopen(argv[optind++], "w");
+	if ( fout == NULL ){
 		perror("error opening output file");
 		exit(1);
 	}
 
 	analyze_disk(fd);
+
+	(void)write_initial_file(fout);
 	
 	for (i=0; i < geometry.tracks; i++)
 	{
-		loadtrack(fd, fdout, i, 0);
-	}		
-	if (geometry.sides==2)
-	{
-		for (i=geometry.tracks-1; i >=0; i--)
+		loadtrack(fd, fout, i, 0);
+		if (geometry.sides==2)
 		{
-			loadtrack(fd, fdout, i, 1);
+			loadtrack(fd, fout, i, 1);
 		}
 	}		
 
 	if (close(fd)) perror("close error for input file");
-	if (close(fdout)) perror("close error for output file");
+	if (fclose(fout)) perror("close error for output file");
 	return 0;
 }
diff -Nur orig/writeti.c new/writeti.c
--- orig/writeti.c	2011-03-05 20:17:25.000000000 +0100
+++ new/writeti.c	2011-03-06 19:35:59.000000000 +0100
@@ -4,6 +4,7 @@
                TI-99/4A and Geneve computer family
     
     Copyright (C) 2009 Michael Zapf (Michael.Zapf@mizapf.de)
+    Copyright (C) 2011 Gerhard Wiesinger (gerhard@wiesinger.com)
 
     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 
@@ -24,13 +25,13 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <linux/fd.h>
 #include <linux/fdreg.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <getopt.h>
 
 #define COMMAND 0
 #define PHEAD 1
@@ -213,7 +214,6 @@
 int main(int argc, char **argv)
 {
 	int fdflop, fdfile, i;
-	int index=1;
 	verbose = 0;
 	char c;
 	char *buffer;
