From 9e41edbc48b85663236009cba2391df165dd1ee4 Mon Sep 17 00:00:00 2001 From: Jeff Armstrong Date: Wed, 5 Apr 2017 08:24:53 -0400 Subject: Initial import --- rbfloppy.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100755 rbfloppy.c (limited to 'rbfloppy.c') diff --git a/rbfloppy.c b/rbfloppy.c new file mode 100755 index 0000000..3202e27 --- /dev/null +++ b/rbfloppy.c @@ -0,0 +1,175 @@ +/* Rainbow Image Utilities + * Copyright © 2008 Jeffrey Armstrong + * http://jeff.rainbow-100.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 . + */ + +/* rbfloppy.obj - A collection of direct disk access routines + * by Jeff Armstrong + */ + +#include +#include "rbfloppy.h" +#include + +/* Structure that represents the block of data needed to call interrupt + * 0x65, which allows direct disk access. The order here is very + * important. + */ +struct dsk_bios_block { + unsigned char command; + unsigned char drive_id; + unsigned char sector; + unsigned char phys_unit; + unsigned int track; + unsigned int sector_count; + unsigned int data; + unsigned int segment; +}; + +/* The map that is used to skew/deskew sector addresses */ +static int skew[11] = {0,1,6,2,7,3,8,4,9,5,10}; + +/* The current program addressing mode */ +static int current_mode = MODE_PHYSICAL; + +/* An internal method to unskew a given sector number */ +int unskew(int sector); + +/* Writes a given sector using the data in buffer */ +int write_sector(int unit, int track, int sector, char *buffer) +{ + return access_sector(CMD_WRITE_VERIFY, unit, track, sector, buffer); +} + +/* Reads a specified sector from disk into buffer */ +int read_sector(int unit, int track, int sector, char *buffer) +{ + return access_sector(CMD_READ, unit, track, sector, buffer); +} + +/* Internal routine that performs all actual disk access through calls + * to interrupt 0x65. Some command ints are already #defined, but + * a few more exist that aren't listed here. + */ +int access_sector(int command, int unit, int track, int sector, char *buffer) +{ +struct dsk_bios_block write; +struct SREGS segregs; +union REGS r; + +char *pt; + + /* Sectors are numbered 1 to 10 */ + if(sector > 10) + return ERROR_BAD_SECTOR; + + /* The current data segment is needed for the interrupt call */ + segread(&segregs); + + write.command = (unsigned char)command; + write.drive_id = (unsigned char)0xFF; + write.track = (unsigned int)track; + + /* Determine the sector if skewing is necessary */ + if(track > 1 && get_mode() == MODE_PHYSICAL) + write.sector = (unsigned char)unskew(sector); + else + write.sector = (unsigned char)sector; + + write.sector_count = (unsigned int)1; + write.phys_unit = (unsigned char)(0+unit*16); + + write.data = (unsigned int)buffer; + write.segment = segregs.ds; + + /* Only for debugging */ + pt = &write; + +#ifdef DEBUG + printf("Sz: %d: 0:%d 1:%d 2:%d 3:%d 4:%d 5:%d 6:%d 7:%d of:%d ds%d\n", + sizeof(write),pt[0],pt[1],pt[2],pt[3],pt[4]+pt[5]*256, + pt[6]+pt[7]*256,pt[8]+pt[9]*256,pt[10]+pt[11]*256, + &buffer[0],segregs.ds); +#endif + + r.x.bx = &write; + + int86(FLOPPY_INTR,&r,&r); + + if(r.h.al == 0) + return OK; + else + return ERROR_FROM_BIOS; +} + +/* Determines the unit number for access_sector() from a given character. + * Expects a drive letter or a number. Returns -1 on error. + */ +int drive_id(char id) +{ +int drv; + + switch(id) { + case 'A': + case 'a': + case 0: + case '0': + drv = 0; + break; + case 'B': + case 'b': + case 1: + case '1': + drv = 1; + break; + case 'C': + case 'c': + case 2: + case '2': + drv = 2; + break; + case 'D': + case 'd': + case 3: + case '3': + drv = 3; + break; + default: + drv = -1; + } + + return drv; +} + +/* Returns an unskewed sector number from a skewed address */ +int unskew(int sector) { + return sector <= 10 && sector > 0 ? skew[sector] : 1; +} + +/* Sets the mode of the sector addressing to either physical or + * logical by assigning a static variable. + */ +void set_mode(int mode) +{ + if(mode == MODE_PHYSICAL || mode == MODE_LOGICAL) + current_mode = mode; +} + +/* Returns the current addressing mode */ +int get_mode() +{ + return current_mode; +} \ No newline at end of file -- cgit v1.2.3