summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile113
-rw-r--r--src/config.c222
-rw-r--r--src/config.h68
-rw-r--r--src/disk.c610
-rw-r--r--src/disk.h39
-rw-r--r--src/diskimg.c263
-rw-r--r--src/diskimg.h99
-rw-r--r--src/main.c140
-rw-r--r--src/serial.c472
-rw-r--r--src/serial.h134
-rw-r--r--src/siorc.example17
-rw-r--r--src/tmpbin0 -> 92176 bytes
-rw-r--r--src/token.c257
-rw-r--r--src/token.h71
-rw-r--r--src/util.c165
-rw-r--r--src/util.h82
16 files changed, 2752 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..639860c
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,113 @@
+# atarisio - A UNIX back end for an Atari SIO2PC lead.
+#
+# Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -------------------------------------------------------------------------
+#
+# $Id: Makefile,v 1.1.1.1 2007-05-07 02:05:54 ianc Exp $
+#
+
+
+# This CFLAGS assumes that gcc is being used.
+# Simply comment out if not, and replace as needed.
+#
+# Note that the -pthread is *IMPORTANT* - this is a FreeBSD extension
+# that links with the appropriate libc for pthreads. Consult your OS
+# documentation on what to do on other systems.
+#
+#
+CFLAGS = -g -Wall -Werror -pthread
+
+TARGET = atarisio
+
+SOURCE = main.c \
+ token.c \
+ config.c \
+ serial.c \
+ disk.c \
+ diskimg.c \
+ util.c
+
+OBJECTS = main.o \
+ token.o \
+ serial.o \
+ config.o \
+ disk.o \
+ diskimg.o \
+ util.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
+
+clean:
+ rm -f $(TARGET) $(OBJECTS) core
+
+depend:
+ makedepend -- $(CFLAGS) -- $(SOURCE)
+ if test -e Makefile ; then rm -f Makefile.bak ; fi
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
+
+main.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+main.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+main.o: /usr/include/limits.h /usr/include/sys/limits.h
+main.o: /usr/include/machine/_limits.h /usr/include/sys/syslimits.h
+main.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+main.o: /usr/include/errno.h /usr/include/unistd.h /usr/include/sys/types.h
+main.o: /usr/include/machine/endian.h /usr/include/sys/select.h
+main.o: /usr/include/sys/_sigset.h /usr/include/sys/_timeval.h
+main.o: /usr/include/sys/timespec.h /usr/include/sys/unistd.h
+main.o: /usr/include/fcntl.h serial.h util.h disk.h config.h token.h
+token.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+token.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+token.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+token.o: /usr/include/ctype.h /usr/include/runetype.h token.h util.h
+config.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+config.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+config.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+config.o: config.h util.h token.h
+serial.o: /usr/include/pthread.h /usr/include/sys/cdefs.h
+serial.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+serial.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+serial.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+serial.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+serial.o: /usr/include/sys/time.h /usr/include/time.h
+serial.o: /usr/include/sys/signal.h /usr/include/machine/signal.h
+serial.o: /usr/include/machine/trap.h /usr/include/limits.h
+serial.o: /usr/include/sys/limits.h /usr/include/machine/_limits.h
+serial.o: /usr/include/sys/syslimits.h /usr/include/sched.h
+serial.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+serial.o: /usr/include/ctype.h /usr/include/runetype.h /usr/include/unistd.h
+serial.o: /usr/include/sys/unistd.h /usr/include/termios.h
+serial.o: /usr/include/sys/ttycom.h /usr/include/sys/ioccom.h
+serial.o: /usr/include/sys/ttydefaults.h /usr/include/fcntl.h
+serial.o: /usr/include/errno.h serial.h /usr/include/stdlib.h util.h
+disk.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+disk.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+disk.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+disk.o: /usr/include/ctype.h /usr/include/runetype.h disk.h util.h diskimg.h
+disk.o: config.h token.h serial.h
+diskimg.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+diskimg.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+diskimg.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+diskimg.o: diskimg.h util.h
+util.o: /usr/include/stdio.h /usr/include/sys/cdefs.h
+util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+util.o: /usr/include/string.h /usr/include/strings.h /usr/include/ctype.h
+util.o: /usr/include/runetype.h util.h /usr/include/stdlib.h
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..6d05005
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,222 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Config file
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "token.h"
+
+static const char ident_h[]=ATARIOSIO_CONFIG_H;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/* ---------------------------------------- CONFIG
+*/
+static char *serial_path=NULL;
+static char *prompt=NULL;
+
+static const struct
+{
+ const char *name;
+ void *var;
+ int is_int;
+} config[]= {
+ {"device", &serial_path, FALSE},
+ {"prompt", &prompt, FALSE},
+ {NULL, NULL, FALSE}
+ };
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Parse(FILE *fp)
+{
+ char buff[1024];
+
+ while(fgets(buff,sizeof buff,fp))
+ {
+ size_t l;
+
+ l=strlen(buff);
+
+ if (buff[l-1]=='\n')
+ buff[--l]=0;
+
+ if (l>0 && buff[0]!='#')
+ TokenRun(buff);
+ }
+}
+
+
+static void Set(int argc, char *argv[])
+{
+ int f;
+
+ for(f=0;config[f].name;f++)
+ {
+ if (strcmp(config[f].name,argv[1])==0)
+ {
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ *i=atoi(argv[2]);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+
+ if (*p)
+ free(*p);
+
+ *p=StrCopy(argv[2]);
+ }
+ }
+ }
+}
+
+
+static void Show(int argc, char *argv[])
+{
+ int f;
+
+ if (argc==2)
+ {
+ for(f=0;config[f].name;f++)
+ {
+ if (strcmp(config[f].name,argv[1])==0)
+ {
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ printf("%s = %d\n",argv[1],*i);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+ printf("%s = %s\n",argv[1],*p ? *p:"undefined");
+ }
+ }
+ }
+ }
+ else
+ {
+ for(f=0;config[f].name;f++)
+ {
+ printf("%s = ",config[f].name);
+
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ printf("%d\n",*i);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+ printf("%s\n",*p ? *p:"undefined");
+ }
+ }
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+int ConfigRead(void)
+{
+ static Command cmd[2]=
+ {
+ {"set",3,3,"set variable value","Set a variable",Set},
+ {"show",1,2,"show [variable]","Show variables",Show}
+ };
+
+ FILE *fp;
+ char path[FILENAME_MAX]={0};
+
+ serial_path=StrCopy("/dev/cuaa0");
+ prompt=StrCopy("SIO% ");
+
+ if (getenv("HOME"))
+ strcpy(path,getenv("HOME"));
+
+ strcat(path,"/.siorc");
+
+ if (!(fp=fopen(path,"r")))
+ return FALSE;
+
+ TokenRegister(2,cmd);
+
+ Parse(fp);
+ fclose(fp);
+
+ return TRUE;
+}
+
+
+int IConfig(IConfigVar v)
+{
+ static const int *vars[]=
+ {
+ NULL
+ };
+
+ return *vars[v];
+}
+
+
+const char *SConfig(SConfigVar v)
+{
+ static char **vars[]=
+ {
+ &serial_path,
+ &prompt
+ };
+
+ return (const char *)*vars[v];
+}
+
+
+/* END OF FILE */
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..8e58514
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,68 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Config file
+
+*/
+
+#ifndef ATARIOSIO_CONFIG_H
+#define ATARIOSIO_CONFIG_H "$Id$"
+
+#include "util.h"
+
+
+/* Integer settings
+*/
+typedef enum
+{
+ CONF_NONE
+} IConfigVar;
+
+
+/* String settings
+*/
+typedef enum
+{
+ CONF_DEVICE,
+ CONF_PROMPT
+} SConfigVar;
+
+
+/* Read config file
+*/
+int ConfigRead(void);
+
+
+/* Get integer setting
+*/
+int IConfig(IConfigVar v);
+
+
+/* Get string setting
+*/
+const char *SConfig(SConfigVar v);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/disk.c b/src/disk.c
new file mode 100644
index 0000000..d058154
--- /dev/null
+++ b/src/disk.c
@@ -0,0 +1,610 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "disk.h"
+#include "diskimg.h"
+#include "config.h"
+#include "token.h"
+#include "serial.h"
+
+static const char ident_h[]=ATARIOSIO_DISK_H;
+
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define HEX_DUMP_LINE 16
+
+#define MAX_DRIVE 8
+
+
+/* ---------------------------------------- STATICS
+*/
+static DiskImg drive[MAX_DRIVE]={0};
+static DiskInfo info[MAX_DRIVE];
+static uchar *buff[MAX_DRIVE]={0};
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static int Word(uchar lo, uchar hi)
+{
+ return ((int)hi<<8)|(int)lo;
+}
+
+
+static int ParseDrive(const char *p)
+{
+ int d;
+
+ if (*p++!='d')
+ return -1;
+
+ d=(*p-'0')-1;
+
+ if (d<0 || d>=MAX_DRIVE)
+ return -1;
+
+ return d;
+}
+
+
+
+static void DoMount(int d, const char *p)
+{
+ drive[d]=DiskImgLoad(p);
+
+ if (!drive[d])
+ printf("Disk image error: %s\n",DiskImgError());
+ else
+ {
+ DiskImgInfo(drive[d],info+d);
+ buff[d]=Malloc(info[d].bytes_per_sector);
+ }
+}
+
+
+static void DoUnmount(int d)
+{
+ if (drive[d])
+ DiskImgFree(drive[d]);
+
+ drive[d]=NULL;
+ free(buff[d]);
+}
+
+
+static void ShowDir(const uchar *p, unsigned len)
+{
+ unsigned f;
+
+ if (!p)
+ return;
+
+ f=0;
+
+ while(f<len)
+ {
+ uchar flag;
+
+ flag=p[f];
+
+ if (flag&0x40)
+ {
+ int secs;
+ int i;
+
+ secs=Word(p[f+1],p[f+2]);
+
+ for(i=5;i<16;i++)
+ {
+ putchar(p[f+i]);
+ }
+
+ printf(" %4d sectors\n",secs);
+ }
+
+ f+=16;
+ }
+}
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static void Mount(int argc, char *argv[])
+{
+ int d;
+
+ if (argc==1)
+ {
+ for(d=0;d<MAX_DRIVE;d++)
+ if (drive[d])
+ printf("d%d %s\n",d+1,DiskImgPath(drive[d]));
+ }
+ else if (argc==3)
+ {
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (drive[d])
+ {
+ printf("Disk already mounted\n");
+ return;
+ }
+
+ DoMount(d,argv[2]);
+ }
+ else
+ {
+ printf("Invalid arguments\n");
+ }
+}
+
+
+static void Unmount(int argc, char *argv[])
+{
+ int d;
+
+ if (argc==1)
+ {
+ for(d=0;d<MAX_DRIVE;d++)
+ {
+ if (drive[d])
+ {
+ printf("Unmounting %s from d%d\n",DiskImgPath(drive[d]),d+1);
+ DoUnmount(d);
+ }
+ }
+ }
+ else
+ {
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ DoUnmount(d);
+ }
+}
+
+
+static void ReadOnly(int argc, char *argv[])
+{
+ int d;
+ int flag;
+
+ if (!YesNo(argv[2],&flag))
+ {
+ printf("Invalid parameter\n");
+ return;
+ }
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+}
+
+
+static void Info(int argc, char *argv[])
+{
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ printf("Sectors : %d\n",info[d].sectors);
+ printf("Bytes per sector: %d\n",info[d].bytes_per_sector);
+ printf("Write protect : %s\n",info[d].write_protect ? "ON":"OFF");
+}
+
+
+static void Sector(int argc, char *argv[])
+{
+ const uchar *p;
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ if (!(p=DiskImgGetSector(drive[d],GetInt(argv[2]))))
+ {
+ printf("Invalid sector\n");
+ return;
+ }
+
+ HexDump(p,info[d].bytes_per_sector);
+}
+
+
+static void New(int argc, char *argv[])
+{
+ DiskImg img;
+ DiskInfo inf;
+
+ img=DiskImgNew(GetInt(argv[2]),GetInt(argv[3]));
+
+ if (!img)
+ {
+ printf("Failed to create image\n");
+ return;
+ }
+
+ DiskImgInfo(img,&inf);
+
+ if (argc==5)
+ {
+ uchar *buff;
+ FILE *fp;
+ int rd;
+ unsigned sec;
+
+ buff=Malloc(inf.bytes_per_sector);
+
+ if (!(fp=fopen(argv[4],"rb")))
+ {
+ printf("Failed to open %s\n",argv[4]);
+ DiskImgFree(img);
+ free(buff);
+ return;
+ }
+
+ sec=0;
+
+ do
+ {
+ rd=fread(buff,1,inf.bytes_per_sector,fp);
+
+ if (rd>0)
+ {
+ DiskImgPutSector(img,sec++,buff);
+ }
+ } while(rd==inf.bytes_per_sector);
+
+ fclose(fp);
+
+ free(buff);
+ }
+
+ if (!DiskImgSave(img,argv[1]))
+ {
+ printf("Failed to save image\n");
+ }
+
+ DiskImgFree(img);
+}
+
+
+static void Ls(int argc, char *argv[])
+{
+ int d;
+ unsigned f;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ for(f=360;f<368;f++)
+ ShowDir(DiskImgGetSector(drive[d],f),info[d].bytes_per_sector);
+}
+
+
+static void Save(int argc, char *argv[])
+{
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ if (argc==2)
+ DiskImgSave(drive[d],NULL);
+ else
+ DiskImgSave(drive[d],argv[2]);
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static Command cmd[]=
+{
+ {
+ "mount",
+ 1,3,
+ "mount [dN file]",
+ "Mount a disk image",
+ Mount
+ },
+ {
+ "umount",
+ 1,2,
+ "unmount [dN]",
+ "Unmount a disk image",
+ Unmount
+ },
+ {
+ "readonly",
+ 3,3,
+ "readonly dN on|off",
+ "Set a disk read only/writeable",
+ ReadOnly
+ },
+ {
+ "info",
+ 2,2,
+ "info dN",
+ "Returns info on a mounted disk",
+ Info
+ },
+ {
+ "sector",
+ 3,3,
+ "sector dN sector",
+ "Hex dumps supplied sector",
+ Sector
+ },
+ {
+ "new",
+ 4,5,
+ "new path sectors secsize [file]",
+ "Creates a new disk file, with optional data",
+ New
+ },
+ {
+ "ls",
+ 2,2,
+ "ls dN",
+ "Lists directory on disk",
+ Ls
+ },
+ {
+ "save",
+ 2,3,
+ "save dN [file]",
+ "Saves a disk back to, er, disk",
+ Save
+ }
+};
+
+
+/* ---------------------------------------- SIO HANDLER
+*/
+static void StatusHandler(int d, const SIOCommand *cmd)
+{
+ static uchar status[4]={0x00, 0x00, 0x01, 0x00};
+
+ usleep(TIME_ACK);
+
+ if (!drive[d])
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ cmd->putchar(SIO_ACK);
+
+ if (info[d].bytes_per_sector==128)
+ {
+ if (info[d].sectors>720)
+ status[0]=0x80;
+ else
+ status[0]=0x10;
+ }
+ else
+ status[0]=0x60;
+
+ if (info[d].write_protect)
+ status[0]|=8;
+ else
+ status[0]&=~8;
+
+ usleep(TIME_ACK_TO_COMPLETE);
+ cmd->putchar(SIO_COMPLETE);
+ usleep(TIME_COMPLETE_TO_DATA);
+ cmd->write(status,4);
+}
+
+
+static void PutHandler(int d, const SIOCommand *cmd)
+{
+ int sec;
+ size_t len;
+
+ sec=Word(cmd->aux1,cmd->aux2);
+
+ usleep(TIME_ACK);
+
+ if (!drive[d] || info[d].write_protect || sec>info[d].sectors)
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ if (sec<3)
+ len=128;
+ else
+ len=info[d].bytes_per_sector;
+
+ sec--;
+
+ cmd->putchar(SIO_ACK);
+ if (cmd->read(buff[d],len))
+ {
+ cmd->putchar(SIO_ACK);
+ cmd->putchar(SIO_COMPLETE);
+ }
+ else
+ {
+ cmd->putchar(SIO_NACK);
+ }
+}
+
+
+static void GetHandler(int d, const SIOCommand *cmd)
+{
+ int sec;
+ size_t len;
+
+ sec=Word(cmd->aux1,cmd->aux2);
+
+ usleep(TIME_ACK);
+
+ if (!drive[d] || info[d].write_protect || sec>info[d].sectors)
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ if (sec<3)
+ len=128;
+ else
+ len=info[d].bytes_per_sector;
+
+ sec--;
+
+ cmd->putchar(SIO_ACK);
+ usleep(TIME_ACK_TO_COMPLETE);
+ cmd->putchar(SIO_COMPLETE);
+ usleep(TIME_COMPLETE_TO_DATA);
+
+ cmd->write(DiskImgGetSector(drive[d],sec),len);
+}
+
+
+static void SIOHandler(const SIOCommand *cmd)
+{
+ switch(cmd->cmd)
+ {
+ case eRead:
+ GetHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eWrite:
+ PutHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eStatus:
+ StatusHandler(cmd->device-0x31,cmd);
+ break;
+
+ case ePut:
+ PutHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eFormat:
+ break;
+
+ case eVerifySec:
+ break;
+
+ case eDownload:
+ case eReadAddr:
+ case eReadSpin:
+ case eMotorOn:
+ break;
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void DiskInit(void)
+{
+ int f;
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+
+ for(f=0x31;f<0x31+MAX_DRIVE;f++)
+ SerialRegister(f,SIOHandler);
+}
+
+
+/* END OF FILE */
diff --git a/src/disk.h b/src/disk.h
new file mode 100644
index 0000000..952f6ba
--- /dev/null
+++ b/src/disk.h
@@ -0,0 +1,39 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+
+#ifndef ATARIOSIO_DISK_H
+#define ATARIOSIO_DISK_H "$Id$"
+
+#include "util.h"
+
+/* Initialise disk routines
+*/
+void DiskInit(void);
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/diskimg.c b/src/diskimg.c
new file mode 100644
index 0000000..74e0243
--- /dev/null
+++ b/src/diskimg.c
@@ -0,0 +1,263 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "diskimg.h"
+
+static const char ident_h[]=ATARIOSIO_DISKIMG_H;
+
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAGIC ('N'+'I'+'C'+'K'+'A'+'T'+'A'+'R'+'I')
+
+#define WRITE_PROTECT 0x01
+
+
+/* ---------------------------------------- TYPES
+*/
+struct sDiskImg
+{
+ char *path;
+ unsigned sectors;
+ unsigned bps;
+ int flags;
+ uchar *data;
+};
+
+
+/* ---------------------------------------- STATICS
+*/
+static char error[256];
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static unsigned GetWord(FILE *fp)
+{
+ unsigned w;
+ int i;
+
+ if ((i=getc(fp))==EOF)
+ return 0;
+
+ w=i;
+
+ if ((i=getc(fp))==EOF)
+ return 0;
+
+ w|=i<<8;
+
+ return w;
+}
+
+
+static void PutWord(FILE *fp,int w)
+{
+ uchar c;
+
+ c=(w&0xff);
+
+ putc(c,fp);
+
+ c=(w>>8);
+
+ putc(c,fp);
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+DiskImg DiskImgLoad(const char *path)
+{
+ FILE *fp;
+ DiskImg img;
+ unsigned long hi,lo;
+ int f;
+
+ if (!(fp=fopen(path,"rb")))
+ {
+ strcpy(error,"Disk file does not exist");
+ return NULL;
+ }
+
+ if (GetWord(fp)!=MAGIC)
+ {
+ strcpy(error,"Not an ATR disk file");
+ return NULL;
+ }
+
+ img=Malloc(sizeof *img);
+
+ img->path=StrCopy(path);
+
+ lo=GetWord(fp);
+
+ img->bps=GetWord(fp);
+
+ img->flags=getc(fp);
+
+ hi=GetWord(fp);
+
+ hi=(hi<<16)|lo;
+
+ img->sectors=(hi*16)/img->bps;
+
+ img->data=Malloc(img->sectors*img->bps);
+
+ for(f=0;f<7;f++)
+ getc(fp);
+
+ for(f=0;f<img->sectors*img->bps;f++)
+ {
+ int i;
+
+ if ((i=getc(fp))==EOF)
+ {
+ free(img->path);
+ free(img->data);
+ free(img);
+ strcpy(error,"Corrupt disk file - too short");
+ return NULL;
+ }
+
+ img->data[f]=i;
+ }
+
+ return img;
+}
+
+
+const char *DiskImgError(void)
+{
+ return error;
+}
+
+
+const uchar *DiskImgGetSector(DiskImg img, unsigned sector)
+{
+ if (sector>=img->sectors)
+ return NULL;
+
+ return img->data+sector*img->bps;
+}
+
+
+int DiskImgPutSector(DiskImg img, unsigned sector, const uchar *data)
+{
+ if (sector>=img->sectors)
+ return FALSE;
+
+ memcpy(img->data+sector*img->bps,data,img->bps);
+
+ return TRUE;
+}
+
+DiskImg DiskImgNew(unsigned sectors, unsigned bytes_per_sector)
+{
+ DiskImg img;
+
+ img=Malloc(sizeof *img);
+
+ img->path=StrCopy("blank.atr");
+ img->sectors=sectors;
+ img->bps=bytes_per_sector;
+ img->flags=0;
+ img->data=Malloc(sectors*bytes_per_sector);
+
+ return img;
+}
+
+
+int DiskImgSave(DiskImg img, const char *path)
+{
+ unsigned long l;
+ FILE *fp;
+ int f;
+
+ if (path)
+ fp=fopen(path,"wb");
+ else
+ fp=fopen(img->path,"wb");
+
+ if (!fp)
+ return FALSE;
+
+ l=(img->sectors/img->bps)/16;
+
+ PutWord(fp,MAGIC);
+ PutWord(fp,l&0xffff);
+ PutWord(fp,img->bps);
+ putc(0,fp);
+ PutWord(fp,l>>16);
+
+ for(f=0;f<7;f++)
+ putc(0,fp);
+
+ for(f=0;f<img->sectors*img->bps;f++)
+ {
+ putc(img->data[f],fp);
+ }
+
+ return TRUE;
+}
+
+
+void DiskImgFree(DiskImg img)
+{
+ free(img->path);
+ free(img->data);
+ free(img);
+}
+
+
+void DiskImgInfo(DiskImg img, DiskInfo *info)
+{
+ info->sectors=img->sectors;
+ info->bytes_per_sector=img->bps;
+ info->write_protect=img->flags&WRITE_PROTECT;
+}
+
+
+const char *DiskImgPath(DiskImg img)
+{
+ return img->path;
+}
+
+
+/* END OF FILE */
diff --git a/src/diskimg.h b/src/diskimg.h
new file mode 100644
index 0000000..f355c50
--- /dev/null
+++ b/src/diskimg.h
@@ -0,0 +1,99 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+
+#ifndef ATARIOSIO_DISKIMG_H
+#define ATARIOSIO_DISKIMG_H "$Id$"
+
+#include "util.h"
+
+
+/* Type representing a disk
+*/
+struct sDiskImg;
+typedef struct sDiskImg *DiskImg;
+
+
+/* Type representing disk config
+*/
+typedef struct
+{
+ unsigned sectors;
+ unsigned bytes_per_sector;
+ int write_protect;
+} DiskInfo;
+
+
+/* Load a disk - returns NULL for error.
+*/
+DiskImg DiskImgLoad(const char *path);
+
+
+/* Why the last operation failed
+*/
+const char *DiskImgError(void);
+
+
+/* Read a sector (NULL if invalid sector)
+*/
+const uchar *DiskImgGetSector(DiskImg img, unsigned sector);
+
+
+/* Write a sector (returns FALSE for invalid sector)
+*/
+int DiskImgPutSector(DiskImg img, unsigned sector,
+ const uchar *data);
+
+
+/* Create a blank disk
+*/
+DiskImg DiskImgNew(unsigned sectors, unsigned bytes_per_sector);
+
+
+/* Write a disk image - silently ignored for read only disks. Returns TRUE
+ for success. If path is NULL then the path the file was loaded from is used.
+*/
+int DiskImgSave(DiskImg img, const char *path);
+
+
+/* Free up a disk image
+*/
+void DiskImgFree(DiskImg img);
+
+
+/* Returns info on a disk
+*/
+void DiskImgInfo(DiskImg img, DiskInfo *info);
+
+
+/* Returns path to a disk
+*/
+const char *DiskImgPath(DiskImg img);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..3c9ef78
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,140 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "serial.h"
+#include "disk.h"
+#include "config.h"
+#include "token.h"
+#include "util.h"
+
+
+/* ---------------------------------------- MACROS
+*/
+#define TRUE 1
+#define FALSE 0
+
+
+/* ---------------------------------------- STATIC
+*/
+static int quit=FALSE;
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+
+static void Quit(int argc, char *argv[])
+{
+ quit=TRUE;
+}
+
+
+static void Start(int argc, char *argv[])
+{
+ SerialOpen(SConfig(CONF_DEVICE));
+}
+
+
+static void Stop(int argc, char *argv[])
+{
+ SerialClose();
+}
+
+
+static void Debug(int argc, char *argv[])
+{
+ int flag;
+
+ if (YesNo(argv[1],&flag))
+ {
+ SerialDebug(flag);
+ }
+ else
+ {
+ printf("Invalid argument\n");
+ }
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+
+static Command cmd[]=
+{
+ {"quit", 1,1, "quit", "Exit atarisio", Quit},
+ {"start", 1,1, "start", "Start emulation", Start},
+ {"stop", 1,1, "stop", "Stop emulation", Stop},
+ {"debug", 2,2, "debug on|off", "Switch debug on/off", Debug}
+};
+
+
+/* ---------------------------------------- MAIN
+*/
+int main(int argc, char *argv[])
+{
+ char buff[1024];
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+ SerialInit();
+ DiskInit();
+
+ printf("atarsio, Copyright (C) 2004 Ian Cowburn\n");
+ printf("atarsio comes with with ABSOLUTELY NO WARRANTY.\n");
+
+ if (!ConfigRead())
+ {
+ fprintf(stderr,"Failed to read ~/.siorc\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!quit)
+ {
+ printf("%s",SConfig(CONF_PROMPT));
+ fflush(stdout);
+
+ while(fgets(buff,sizeof buff,stdin))
+ {
+ TokenRun(buff);
+
+ if (quit)
+ break;
+
+ printf("%s",SConfig(CONF_PROMPT));
+ fflush(stdout);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+/* END OF FILE */
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000..6f25892
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,472 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Serial wrappers.
+
+*/
+static const char ident[]="$Id$";
+
+#include <pthread.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+
+#include "serial.h"
+#include "token.h"
+
+static const char ident_h[]=ATARISIO_SERIAL_H;
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define WHICH (pthread_equal(pthread_self(),thread) ? "READ":"MAIN")
+
+/* Just as I'm always forgetting how many...
+*/
+#define MILLI2MICRO(x) ((x)*1000)
+
+
+/* ---------------------------------------- EXTERN
+*/
+const uchar SIO_ACK=0x41;
+const uchar SIO_NACK=0x4e;
+const uchar SIO_COMPLETE=0x43;
+const uchar SIO_ERROR=0x45;
+
+
+/* ---------------------------------------- STATICS
+*/
+static int fd=-1;
+static SIOCallback devtable[256]={0};
+static int debug=FALSE;
+static int thread_created=FALSE;
+
+static int do_debug;
+
+static pthread_mutex_t mutex;
+static pthread_t thread;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Error(const char *p)
+{
+ perror(p);
+
+ if (fd!=-1)
+ {
+ if (pthread_equal(pthread_self(),thread))
+ {
+ printf("WARNING: Reader thread exiting - "
+ "serial port is still open\n");
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ else
+ {
+ printf("Trying to closing serial device\n");
+ SerialClose();
+ }
+ }
+}
+
+
+static void Fatal(const char *p)
+{
+ fprintf(stderr,"FATAL: ");
+ perror(p);
+ exit(EXIT_FAILURE);
+}
+
+
+static void Lock(void)
+{
+ /* printf("[LOCK %s]\n",WHICH); */
+ pthread_mutex_lock(&mutex);
+}
+
+
+static void Unlock(void)
+{
+ /* printf("[UNLOCK %s]\n",WHICH); */
+ pthread_mutex_unlock(&mutex);
+}
+
+
+void SerialPutchar(uchar c)
+{
+ if (do_debug)
+ printf("PUTCHAR: %2.2x (%c)\n",c,isprint(c) ? c:'?');
+
+ if (write(fd,&c,1)==-1)
+ {
+ Error("write:");
+ return;
+ }
+}
+
+
+void SerialWrite(const uchar *p, size_t len)
+{
+ uchar csum;
+
+ if (do_debug)
+ {
+ printf("SENDING:\n");
+ HexDump(p,len);
+ }
+
+ csum=Checksum(p,len);
+
+ while(len>0)
+ {
+ ssize_t w;
+
+ w=write(fd,p,len);
+
+ if (w==-1)
+ {
+ Error("write:");
+ return;
+ }
+
+ p+=w;
+ len-=w;
+ }
+
+ write(fd,&csum,1);
+
+ if (do_debug)
+ printf("CHECKSUM: %2.2x\n",csum);
+}
+
+
+int SerialRead(uchar *p, size_t len)
+{
+ uchar *orig;
+ uchar csum;
+
+ orig=p;
+
+ while(len>0)
+ {
+ ssize_t r;
+
+ r=read(fd,p,len);
+
+ if (r==-1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ p+=r;
+ len-=r;
+ }
+
+ if (read(fd,&csum,1)!=1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ return Checksum(orig,len)==csum;
+}
+
+
+/* ---------------------------------------- READER
+*/
+static void *ReaderThread(void *p)
+{
+ SIOCommand cmd;
+ time_t start;
+ int st;
+ int no;
+ uchar frame[5];
+ uchar c;
+ uchar csum;
+
+ cmd.putchar=SerialPutchar;
+ cmd.write=SerialWrite;
+ cmd.read=SerialRead;
+
+ while(TRUE)
+ {
+ Lock();
+ do_debug=debug;
+ Unlock();
+
+ no=0;
+
+ while(no<5)
+ {
+ if (read(fd,&c,1)==-1)
+ Error("read");
+
+ if (ioctl(fd,TIOCMGET,&st)==-1)
+ Error("ioctl(TIOCMGET)");
+
+ if (st&TIOCM_RNG)
+ {
+ if (do_debug)
+ printf("Got byte %d (%c) and RNG set\n",
+ c,isprint(c) ? c:'?');
+
+ if (no==0)
+ start=time(NULL);
+
+ frame[no++]=c;
+ }
+ else if (do_debug)
+ {
+ printf("Got byte %d (%c) and RNG *NOT* set\n",
+ c,isprint(c) ? c:'?');
+ }
+ }
+
+ if ((time(NULL)-start)>1)
+ {
+ printf("Reader: Got 5 bytes, but too slowly - ignored\n");
+ }
+ else
+ {
+ Lock();
+
+ csum=Checksum(frame,4);
+
+ if (csum==frame[4])
+ {
+ if (do_debug)
+ {
+ printf("Frame:\n");
+ HexDump(frame,5);
+ }
+
+ if (devtable[frame[0]])
+ {
+ /* Fill up the command structure
+ */
+ cmd.device=frame[0];
+ cmd.cmd=frame[1];
+ cmd.aux1=frame[2];
+ cmd.aux2=frame[3];
+
+ /* Let the device do its work
+ */
+ if (do_debug)
+ printf("Calling handler for device %2.2x\n",cmd.device);
+
+ devtable[cmd.device](&cmd);
+ }
+ }
+ else
+ {
+ printf("Reader: Bad checksum, expected %2.2x. Frame:\n",csum);
+ HexDump(frame,5);
+ }
+
+ Unlock();
+ }
+ }
+}
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static void Register(int argc, char *argv[])
+{
+ int f;
+
+ for(f=0;f<256;f++)
+ if (devtable[f])
+ printf("Device %2.2x regsitered\n",f);
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static Command cmd[]=
+{
+ {
+ "register",
+ 1,1,
+ "register",
+ "Show registered devices",
+ Register
+ }
+};
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void SerialInit(void)
+{
+ if (pthread_mutex_init(&mutex,NULL)==-1)
+ Fatal("pthread_mutex_init");
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+}
+
+
+void SerialOpen(const char *path)
+{
+ struct termios ios;
+
+ if (fd!=-1)
+ {
+ printf("Serial device already open\n");
+ return;
+ }
+
+ fd=open(path,O_RDWR|O_NOCTTY|O_NDELAY);
+
+ if (fd==-1)
+ {
+ Error(path);
+ return;
+ }
+
+ if (fcntl(fd,F_SETFL,0)==-1)
+ {
+ Error("fcntl(F_SETFL,0)");
+ return;
+ }
+
+ if (tcgetattr(fd,&ios)==-1)
+ {
+ Error("tcgetattr");
+ return;
+ }
+
+ cfsetispeed(&ios,B19200);
+ cfsetospeed(&ios,B19200);
+
+ ios.c_cflag|=(CLOCAL|CREAD);
+
+ ios.c_cflag&=~PARENB;
+ ios.c_cflag&=~CSTOPB;
+ ios.c_cflag&=~CSIZE;
+ ios.c_cflag|=CS8;
+
+ /* Not that it'll work if we can't disable it...
+ */
+#ifdef CRTSCTS
+ ios.c_cflag&=~CRTSCTS;
+#endif
+
+ ios.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
+
+ ios.c_iflag&=~(IXON|IXOFF|IXANY);
+
+ ios.c_oflag&=~OPOST;
+
+ if (tcsetattr(fd,TCSANOW,&ios))
+ {
+ Error("tcsetattr");
+ return;
+ }
+
+ if (pthread_create(&thread,NULL,ReaderThread,NULL)==-1)
+ Fatal("pthread_create");
+
+ thread_created=TRUE;
+}
+
+
+void SerialRegister(int device, SIOCallback func)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d registered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=func;
+ Unlock();
+}
+
+
+void SerialDeregister(int device)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d deregistered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=NULL;
+ Unlock();
+}
+
+
+void SerialDebug(int mode)
+{
+ Lock();
+ debug=mode;
+ Unlock();
+}
+
+
+void SerialClose(void)
+{
+ if (fd==-1)
+ {
+ printf("Serial not open\n");
+ }
+
+ Lock();
+
+ if (thread_created)
+ {
+ printf("Cancelling reader thread...");
+ fflush(stdout);
+ pthread_cancel(thread);
+ pthread_join(thread,NULL);
+ printf("Done\n");
+ }
+
+ Unlock();
+
+ close(fd);
+
+ fd=-1;
+ thread_created=FALSE;
+}
+
+
+/* END OF FILE */
diff --git a/src/serial.h b/src/serial.h
new file mode 100644
index 0000000..740bed7
--- /dev/null
+++ b/src/serial.h
@@ -0,0 +1,134 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Serial wrappers.
+
+*/
+
+#ifndef ATARISIO_SERIAL_H
+#define ATARISIO_SERIAL_H "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+
+/* Private callbacks furnished to registered devices to read/write serial
+ data. On errors these will not return. Note that SWrite appends the sent
+ data with its checksum. SRead reads len+1, the last byte being the checksum.
+ It returns TRUE if the checksum matches.
+*/
+typedef void (*SPutchar)(uchar c);
+typedef void (*SWrite)(const uchar *p, size_t len);
+typedef int (*SRead)(uchar *p, size_t len);
+
+
+/* Constants (usable with SWrite) for Atari ACK, COMPLETE and ERROR repsonses
+*/
+extern const uchar SIO_ACK;
+extern const uchar SIO_NACK;
+extern const uchar SIO_COMPLETE;
+extern const uchar SIO_ERROR;
+
+
+/* Microsecond timings
+*/
+#define TIME_ACK 85
+#define TIME_ACK_TO_COMPLETE 255
+#define TIME_COMPLETE_TO_DATA 425
+
+
+/* A command from the Atari
+*/
+typedef enum
+{
+ eRead = 0x52,
+ eWrite = 0x57,
+ eStatus = 0x53,
+ ePut = 0x50,
+ eFormat = 0x21,
+ eDownload = 0x20,
+ eReadAddr = 0x54,
+ eReadSpin = 0x51,
+ eMotorOn = 0x55,
+ eVerifySec = 0x56
+} ESIOCmdType;
+
+
+typedef struct
+{
+ uchar device; /* The device ID */
+ ESIOCmdType cmd; /* The command frame type */
+ uchar aux1; /* Data */
+ uchar aux2; /* Data */
+ SPutchar putchar; /* To write a char to the serial port */
+ SWrite write; /* To write to the serial port */
+ SRead read; /* To read from the serial port */
+} SIOCommand;
+
+
+/* Interface for recieving SIO commands. Note that this interface is expected
+ to all serial IO responses, including the initial ACK (in case the device
+ wants to NACK instead).
+*/
+typedef void (*SIOCallback)(const SIOCommand* cmd);
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Initialise the serial routines. Must be called first.
+*/
+void SerialInit(void);
+
+
+/* Opens the passed serial device and configures it for SIO2PC usage.
+*/
+void SerialOpen(const char *path);
+
+
+/* Registers a command handler
+*/
+void SerialRegister(int device, SIOCallback func);
+
+
+/* Deregisters a command handler
+*/
+void SerialDeregister(int device);
+
+
+/* Switch debug mode on/off
+*/
+void SerialDebug(int mode);
+
+
+/* Close the serial device
+*/
+void SerialClose(void);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/siorc.example b/src/siorc.example
new file mode 100644
index 0000000..e1d4217
--- /dev/null
+++ b/src/siorc.example
@@ -0,0 +1,17 @@
+# Example rc file
+#
+# $Id: siorc.example,v 1.1.1.1 2007-05-07 02:05:54 ianc Exp $
+#
+
+# Path to the serial device
+#
+set device /dev/cuaa0
+
+# Load up initial disks
+#
+mount d1 /files/atari/dosdisk
+
+
+# Open up the device
+#
+start
diff --git a/src/tmp b/src/tmp
new file mode 100644
index 0000000..05bd099
--- /dev/null
+++ b/src/tmp
Binary files differ
diff --git a/src/token.c b/src/token.c
new file mode 100644
index 0000000..b71a6cb
--- /dev/null
+++ b/src/token.c
@@ -0,0 +1,257 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Command parsing and execution
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "token.h"
+
+static const char ident_h[]=ATARIOSIO_TOKEN_H;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_ARGS 128
+
+
+/* ---------------------------------------- STATICS
+*/
+
+static int no_cmds=0;
+static Command *cmd_table=NULL;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static int QCompare(const void *a, const void *b)
+{
+ const Command *ca;
+ const Command *cb;
+
+ ca=a;
+ cb=b;
+
+ return strcmp(ca->cmd,cb->cmd);
+}
+
+
+static int BCompare(const void *a, const void *b)
+{
+ const Command *cb;
+
+ cb=b;
+
+ return strcmp(a,cb->cmd);
+}
+
+
+static char *GetToken(char **ptr)
+{
+ char qu=0;
+ char *tok;
+ char *p;
+
+ p=*ptr;
+
+ while(*p && isspace(*p))
+ p++;
+
+ if (!*p)
+ return NULL;
+
+ if (*p=='\'' || *p=='"')
+ qu=*p++;
+
+ tok=p;
+
+ if (qu)
+ {
+ while(*p && *p!=qu)
+ p++;
+
+ if (*p)
+ *p++=0;
+ else
+ printf("Warning: unterminated quotes\n");
+ }
+ else
+ {
+ while(*p && !isspace(*p))
+ p++;
+
+ if (*p)
+ *p++=0;
+ }
+
+ *ptr=p;
+
+ return tok;
+}
+
+static int Split(char *p, char **argv)
+{
+ int argc=0;
+
+ while((argv[argc]=GetToken(&p)))
+ {
+ if (argc==MAX_ARGS)
+ {
+ argv[argc]=0;
+ return argc;
+ }
+
+ argc++;
+ }
+
+ return argc;
+}
+
+
+static void ShowHelp(const char *usage, const char *help)
+{
+ int l;
+
+ printf("%s ",usage);
+
+ for(l=strlen(usage);l<35;l++)
+ putchar('.');
+
+ printf(" %s\n",help);
+}
+
+
+static void HelpCommand(int argc, char *argv[])
+{
+ if (argc==1)
+ {
+ int f;
+
+ for(f=0;f<no_cmds;f++)
+ ShowHelp(cmd_table[f].usage,cmd_table[f].help);
+ }
+ else
+ {
+ Command *cmd;
+
+ cmd=bsearch(argv[1],cmd_table,no_cmds,sizeof *cmd_table,BCompare);
+
+ if (!cmd)
+ printf("Unknown command: %s\n",argv[1]);
+ else
+ ShowHelp(cmd->usage,cmd->help);
+ }
+}
+
+
+static void Init(void)
+{
+ static Command cmd[]=
+ {
+ {"help",1,2,"help [command]","Get help on commands",HelpCommand}
+ };
+
+ static int init=FALSE;
+
+ if (!init)
+ {
+ init=TRUE;
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void TokenRegister(int no, const Command *cmds)
+{
+ Init();
+
+ cmd_table=Realloc(cmd_table,sizeof(*cmds)*(no+no_cmds));
+ memcpy(cmd_table+no_cmds,cmds,sizeof(*cmds)*no);
+ no_cmds+=no;
+ qsort(cmd_table,no_cmds,sizeof *cmd_table,QCompare);
+}
+
+
+int TokenRun(const char *line)
+{
+ char *p;
+ char *argv[MAX_ARGS];
+ int argc;
+ int res;
+ int l;
+
+ if (!(l=strlen(line)))
+ return FALSE;
+
+ res=FALSE;
+
+ p=StrCopy(line);
+
+ if (p[l-1]=='\n')
+ p[--l]=0;
+
+ argc=Split(p,argv);
+
+ if (argc)
+ {
+ Command *cmd;
+
+ cmd=bsearch(argv[0],cmd_table,no_cmds,sizeof *cmd_table,BCompare);
+
+ if (cmd)
+ {
+ if (argc>=cmd->min_args && argc<=cmd->max_args)
+ {
+ res=TRUE;
+ cmd->func(argc,argv);
+ }
+ else
+ {
+ printf("usage: %s\n",cmd->usage);
+ }
+ }
+ else
+ {
+ printf("Unrecognised command %s\n",argv[0]);
+ }
+ }
+
+ free(p);
+
+ return res;
+}
+
+
+/* END OF FILE */
diff --git a/src/token.h b/src/token.h
new file mode 100644
index 0000000..b143aa5
--- /dev/null
+++ b/src/token.h
@@ -0,0 +1,71 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Command parsing and execution
+
+*/
+
+#ifndef ATARIOSIO_TOKEN_H
+#define ATARIOSIO_TOKEN_H "$Id$"
+
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+
+/* A command callback (note argv[0] is the command itself)
+*/
+typedef void (*TokenHandler)(int argc, char *argv[]);
+
+
+/* A command. min and max args have to include the command itself.
+*/
+typedef struct
+{
+ const char *cmd;
+ int min_args;
+ int max_args;
+ const char *usage;
+ const char *help;
+ TokenHandler func;
+} Command;
+
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Register commands
+*/
+void TokenRegister(int no, const Command *cmds);
+
+
+/* Parse a command line. Returns TRUE if command parsed and run.
+*/
+int TokenRun(const char *line);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..9ea5749
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,165 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Global utilities and types
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include "util.h"
+
+static const char ident_h[]=ATARISIO_UTIL_H;
+
+#define HEX_DUMP_LINE 16
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void *Malloc(size_t size)
+{
+ void *new=malloc(size);
+
+ if (!new)
+ {
+ fprintf(stderr,"malloc failed for %lu bytes\n",(unsigned long)size);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+void *Realloc(void *p, size_t size)
+{
+ void *new=realloc(p,size);
+
+ if (!new)
+ {
+ fprintf(stderr,"realloc failed for %lu bytes\n",(unsigned long)size);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+char *StrCopy(const char *source)
+{
+ return strcpy(Malloc(strlen(source)+1),source);
+}
+
+
+int YesNo(const char *str, int *flag)
+{
+ if (strcasecmp(str,"on")==0 ||
+ strcasecmp(str,"yes")==0 ||
+ strcasecmp(str,"1")==0)
+ {
+ *flag=1;
+ return 1;
+ }
+
+ if (strcasecmp(str,"off")==0 ||
+ strcasecmp(str,"no")==0 ||
+ strcasecmp(str,"0")==0)
+ {
+ *flag=0;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void HexDump(const uchar *p, size_t len)
+{
+ char asc[HEX_DUMP_LINE+1];
+ size_t f;
+
+ f=0;
+
+ while(f<len)
+ {
+ if ((f%HEX_DUMP_LINE)==0)
+ printf("%4.4x: ",f);
+
+ printf(" %2.2x",p[f]);
+
+ if (isprint(p[f]))
+ asc[f%HEX_DUMP_LINE]=p[f];
+ else
+ asc[f%HEX_DUMP_LINE]='.';
+
+ asc[(f%HEX_DUMP_LINE)+1]=0;
+
+ f++;
+
+ if ((f%HEX_DUMP_LINE)==0)
+ printf(" %s\n",asc);
+ }
+
+ if (f%HEX_DUMP_LINE)
+ {
+ while(f%HEX_DUMP_LINE)
+ {
+ printf(" ");
+ f++;
+ }
+
+ printf(" %s\n",asc);
+ }
+}
+
+
+int GetInt(const char *p)
+{
+ long l;
+
+ l=strtol(p,NULL,0);
+
+ return l;
+}
+
+
+uchar Checksum(const uchar *p, size_t len)
+{
+ int sum;
+ size_t f;
+
+ sum=0;
+
+ for(f=0;f<len;f++)
+ {
+ sum+=p[f];
+ sum=(sum&0xff)+(sum>>8);
+ }
+
+ return (uchar)(sum&0xff);
+}
+
+
+
+/* END OF FILE */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..304e02f
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,82 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Global utilities and types
+
+*/
+
+#ifndef ATARISIO_UTIL_H
+#define ATARISIO_UTIL_H "$Id$"
+
+#include <stdlib.h>
+
+/* ---------------------------------------- TYPES
+*/
+
+typedef unsigned char uchar;
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Returns result from malloc(size), calling exit() if it fails.
+*/
+void *Malloc(size_t size);
+
+
+/* Returns result from realloc(p,size), calling exit() if it fails.
+*/
+void *Realloc(void *p, size_t size);
+
+
+/* Copies a string. The result must be freed.
+*/
+char *StrCopy(const char *source);
+
+
+/* Set flag TRUE/FALSE depending on the contents of str.
+ 'on', 'yes' and '1' are TRUE, 'off', 'no' and '0' false.
+
+ Returns FALSE is str is invalid.
+*/
+int YesNo(const char *str, int *flag);
+
+
+/* Hex dump to stdout
+*/
+void HexDump(const uchar *p, size_t len);
+
+
+/* Get an integer from a string
+*/
+int GetInt(const char *p);
+
+
+/* Returns an Atari serial style checksum.
+*/
+uchar Checksum(const uchar *p, size_t len);
+
+
+#endif
+
+
+/* END OF FILE */