/* 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 #include #include #include #include #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(f0) { 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 */