summaryrefslogtreecommitdiff
path: root/src/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/disk.c')
-rw-r--r--src/disk.c610
1 files changed, 610 insertions, 0 deletions
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 */