/* 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; }