diff options
author | Ian C <ianc@noddybox.co.uk> | 2007-05-07 02:05:54 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2007-05-07 02:05:54 +0000 |
commit | 024f069d1f0feb3ecb2eea6b1443536defb01f35 (patch) | |
tree | fd108ce1dcc82fe14029db250f4505ea7f4321ff /src/disk.c | |
parent | c657944c91fae5f581839912cb0a55bee84c9278 (diff) |
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'src/disk.c')
-rw-r--r-- | src/disk.c | 610 |
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 */ |