/****************************************************************/ /* */ /* dsk.c */ /* */ /* Copyright (c) 1995 */ /* Pasquale J. Villani */ /* All Rights Reserved */ /* */ /* This file is part of DOS-C. */ /* */ /* DOS-C 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, or (at your option) any later version. */ /* */ /* DOS-C 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 DOS-C; see the file COPYING. If not, */ /* write to the Free Software Foundation, 675 Mass Ave, */ /* Cambridge, MA 02139, USA. */ /****************************************************************/ #include "portab.h" #include "globals.h" #ifdef VERSION_STRINGS static BYTE *dskRcsId = "$Id$"; #endif /* * $Log$ * Revision 1.2 2000/05/08 04:29:59 jimtabor * Update CVS to 2020 * * Revision 1.6 2000/04/29 05:13:16 jtabor * Added new functions and clean up code * * Revision 1.5 2000/03/09 06:07:11 kernel * 2017f updates by James Tabor * * Revision 1.4 1999/08/10 18:07:57 jprice * ror4 2011-04 patch * * Revision 1.3 1999/04/16 21:43:40 jprice * ror4 multi-sector IO * * Revision 1.2 1999/04/16 00:53:32 jprice * Optimized FAT handling * * Revision 1.1.1.1 1999/03/29 15:40:51 jprice * New version without IPL.SYS * * Revision 1.5 1999/02/14 04:26:46 jprice * Changed check media so that it checks if a floppy disk has been changed. * * Revision 1.4 1999/02/08 05:55:57 jprice * Added Pat's 1937 kernel patches * * Revision 1.3 1999/02/01 01:48:41 jprice * Clean up; Now you can use hex numbers in config.sys. added config.sys screen function to change screen mode (28 or 43/50 lines) * * Revision 1.2 1999/01/22 04:13:25 jprice * Formating * * Revision 1.1.1.1 1999/01/20 05:51:01 jprice * Imported sources * * * Rev 1.7 06 Dec 1998 8:45:18 patv * Changed due to new I/O subsystem. * * Rev 1.6 04 Jan 1998 23:15:16 patv * Changed Log for strip utility * * Rev 1.5 10 Jan 1997 5:41:48 patv * Modified for extended partition support * * Rev 1.4 29 May 1996 21:03:32 patv * bug fixes for v0.91a * * Rev 1.3 19 Feb 1996 3:21:36 patv * Added NLS, int2f and config.sys processing * * Rev 1.2 01 Sep 1995 17:54:18 patv * First GPL release. * * Rev 1.1 30 Jul 1995 20:52:00 patv * Eliminated version strings in ipl * * Rev 1.0 02 Jul 1995 8:32:42 patv * Initial revision. */ #ifdef PROTO BOOL fl_reset(WORD); COUNT fl_readdasd(WORD); COUNT fl_diskchanged(WORD); COUNT fl_rd_status(WORD); COUNT fl_read(WORD, WORD, WORD, WORD, WORD, BYTE FAR *); COUNT fl_write(WORD, WORD, WORD, WORD, WORD, BYTE FAR *); COUNT fl_verify(WORD, WORD, WORD, WORD, WORD, BYTE FAR *); BOOL fl_format(WORD, BYTE FAR *); #else BOOL fl_reset(); COUNT fl_readdasd(); COUNT fl_diskchanged(); COUNT fl_rd_status(); COUNT fl_read(); COUNT fl_write(); COUNT fl_verify(); BOOL fl_format(); #endif #define NDEV 8 /* only one for demo */ #define SEC_SIZE 512 /* size of sector in bytes */ #define N_RETRY 5 /* number of retries permitted */ #define NENTRY 25 /* total size of dispatch table */ union { BYTE bytes[2 * SEC_SIZE]; boot boot_sector; } buffer; static struct media_info { ULONG mi_size; /* physical sector count */ UWORD mi_heads; /* number of heads (sides) */ UWORD mi_cyls; /* number of cyl/drive */ UWORD mi_sectors; /* number of sectors/cyl */ ULONG mi_offset; /* relative partition offset */ BYTE mi_drive; /* BIOS drive number */ COUNT mi_partidx; /* Index to partition array */ }; static struct media_info miarray[NDEV]; /* Internal media info structs */ static bpb bpbarray[NDEV]; /* BIOS parameter blocks */ static bpb *bpbptrs[NDEV]; /* pointers to bpbs */ #define N_PART 4 /* number of partitions per table partition */ static WORD head, track, sector, ret; /* globals for blockio */ static WORD count; static COUNT nUnits; /* number of returned units */ static COUNT nPartitions; /* number of DOS partitions */ #define PARTOFF 0x1be static struct { BYTE peDrive; /* BIOS drive number */ BYTE peBootable; BYTE peBeginHead; BYTE peBeginSector; UWORD peBeginCylinder; BYTE peFileSystem; BYTE peEndHead; BYTE peEndSector; UWORD peEndCylinder; LONG peStartSector; LONG peSectors; LONG peAbsStart; /* Absolute sector start */ } dos_partition[NDEV - 2]; #ifdef PROTO WORD init(rqptr), mediachk(rqptr), bldbpb(rqptr), blockio(rqptr), Genblkdev(rqptr), blk_error(rqptr); COUNT ltop(WORD *, WORD *, WORD *, COUNT, COUNT, LONG, byteptr); WORD dskerr(COUNT); COUNT processtable(COUNT ptDrive, BYTE ptHead, UWORD ptCylinder, BYTE ptSector, LONG ptAccuOff); #else WORD init(), mediachk(), bldbpb(), blockio(), blk_error(); WORD dskerr(); COUNT processtable(); #endif /* */ /* the function dispatch table */ /* */ #ifdef PROTO static WORD(*dispatch[NENTRY]) (rqptr) = #else static WORD(*dispatch[NENTRY]) () = #endif { init, /* Initialize */ mediachk, /* Media Check */ bldbpb, /* Build BPB */ blk_error, /* Ioctl In */ blockio, /* Input (Read) */ blk_error, /* Non-destructive Read */ blk_error, /* Input Status */ blk_error, /* Input Flush */ blockio, /* Output (Write) */ blockio, /* Output with verify */ blk_error, /* Output Status */ blk_error, /* Output Flush */ blk_error, /* Ioctl Out */ blk_error, /* Device Open */ blk_error, /* Device Close */ blk_error, /* Removable Media */ blk_error, /* Output till busy */ blk_error, /* undefined */ blk_error, /* undefined */ Genblkdev, /* Generic Ioctl */ blk_error, /* undefined */ blk_error, /* undefined */ blk_error, /* undefined */ blk_error, /* Get Logical Device */ blk_error /* Set Logical Device */ }; #define SIZEOF_PARTENT 16 #define FAT12 0x01 #define FAT16SMALL 0x04 #define EXTENDED 0x05 #define FAT16LARGE 0x06 #define hd(x) ((x) & 0x80) COUNT processtable(COUNT ptDrive, BYTE ptHead, UWORD ptCylinder, BYTE ptSector, LONG ptAccuOff) { struct /* Temporary partition table */ { BYTE peBootable; BYTE peBeginHead; BYTE peBeginSector; UWORD peBeginCylinder; BYTE peFileSystem; BYTE peEndHead; BYTE peEndSector; UWORD peEndCylinder; LONG peStartSector; LONG peSectors; } temp_part[N_PART]; REG retry = N_RETRY; UBYTE packed_byte, pb1; COUNT Part; /* Read partition table */ do { ret = fl_read((WORD) ptDrive, (WORD) ptHead, (WORD) ptCylinder, (WORD) ptSector, (WORD) 1, (byteptr) & buffer); } while (ret != 0 && --retry > 0); if (ret != 0) return FALSE; /* Read each partition into temporary array */ for (Part = 0; Part < N_PART; Part++) { REG BYTE *p = (BYTE *) & buffer.bytes[PARTOFF + (Part * SIZEOF_PARTENT)]; getbyte((VOID *) p, &temp_part[Part].peBootable); ++p; getbyte((VOID *) p, &temp_part[Part].peBeginHead); ++p; getbyte((VOID *) p, &packed_byte); temp_part[Part].peBeginSector = packed_byte & 0x3f; ++p; getbyte((VOID *) p, &pb1); ++p; temp_part[Part].peBeginCylinder = pb1 + ((UWORD) (0xc0 & packed_byte) << 2); getbyte((VOID *) p, &temp_part[Part].peFileSystem); ++p; getbyte((VOID *) p, &temp_part[Part].peEndHead); ++p; getbyte((VOID *) p, &packed_byte); temp_part[Part].peEndSector = packed_byte & 0x3f; ++p; getbyte((VOID *) p, &pb1); ++p; temp_part[Part].peEndCylinder = pb1 + ((UWORD) (0xc0 & packed_byte) << 2); getlong((VOID *) p, &temp_part[Part].peStartSector); p += sizeof(LONG); getlong((VOID *) p, &temp_part[Part].peSectors); }; /* Walk through the table, add DOS partitions to global array and process extended partitions */ for (Part = 0; Part < N_PART && nUnits < NDEV; Part++) { if (temp_part[Part].peFileSystem == FAT12 || temp_part[Part].peFileSystem == FAT16SMALL || temp_part[Part].peFileSystem == FAT16LARGE) { miarray[nUnits].mi_offset = temp_part[Part].peStartSector + ptAccuOff; miarray[nUnits].mi_drive = ptDrive; miarray[nUnits].mi_partidx = nPartitions; nUnits++; dos_partition[nPartitions].peDrive = ptDrive; dos_partition[nPartitions].peBootable = temp_part[Part].peBootable; dos_partition[nPartitions].peBeginHead = temp_part[Part].peBeginHead; dos_partition[nPartitions].peBeginSector = temp_part[Part].peBeginSector; dos_partition[nPartitions].peBeginCylinder = temp_part[Part].peBeginCylinder; dos_partition[nPartitions].peFileSystem = temp_part[Part].peFileSystem; dos_partition[nPartitions].peEndHead = temp_part[Part].peEndHead; dos_partition[nPartitions].peEndSector = temp_part[Part].peEndSector; dos_partition[nPartitions].peEndCylinder = temp_part[Part].peEndCylinder; dos_partition[nPartitions].peStartSector = temp_part[Part].peStartSector; dos_partition[nPartitions].peSectors = temp_part[Part].peSectors; dos_partition[nPartitions].peAbsStart = temp_part[Part].peStartSector + ptAccuOff; nPartitions++; } else if (temp_part[Part].peFileSystem == EXTENDED) { /* call again to process extended part table */ processtable(ptDrive, temp_part[Part].peBeginHead, temp_part[Part].peBeginCylinder, temp_part[Part].peBeginSector, temp_part[Part].peStartSector + ptAccuOff); }; }; return TRUE; } COUNT blk_driver(rqptr rp) { if (rp->r_unit >= nUnits && rp->r_command != C_INIT) return failure(E_UNIT); if (rp->r_command > NENTRY) { return failure(E_FAILURE); /* general failure */ } else return ((*dispatch[rp->r_command]) (rp)); } static WORD init(rqptr rp) { extern COUNT fl_nrdrives(VOID); COUNT HardDrive, nHardDisk, Unit; /* Reset the drives */ fl_reset(0x80); /* Initial number of disk units */ nUnits = 2; /* Initial number of DOS partitions */ nPartitions = 0; /* Setup media info and BPBs arrays */ for (Unit = 0; Unit < NDEV; Unit++) { miarray[Unit].mi_size = 720l; miarray[Unit].mi_heads = 2; miarray[Unit].mi_cyls = 40; miarray[Unit].mi_sectors = 9; miarray[Unit].mi_offset = 0l; miarray[Unit].mi_drive = Unit; bpbarray[Unit].bpb_nbyte = SEC_SIZE; bpbarray[Unit].bpb_nsector = 2; bpbarray[Unit].bpb_nreserved = 1; bpbarray[Unit].bpb_nfat = 2; bpbarray[Unit].bpb_ndirent = 112; bpbarray[Unit].bpb_nsize = 720l; bpbarray[Unit].bpb_mdesc = 0xfd; bpbarray[Unit].bpb_nfsect = 2; bpbptrs[Unit] = &bpbarray[Unit]; }; nHardDisk = fl_nrdrives(); for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) { /* Process primary partition table */ if (!processtable((HardDrive | 0x80), 0, 0l, 1, 0l)) /* Exit if no hard drive */ break; }; rp->r_nunits = nUnits; rp->r_bpbptr = bpbptrs; rp->r_endaddr = device_end(); return S_DONE; } static WORD mediachk(rqptr rp) { COUNT drive = miarray[rp->r_unit].mi_drive; COUNT result; /* if it's a hard drive, media never changes */ if (hd(drive)) rp->r_mcretcode = M_NOT_CHANGED; else /* else, check floppy status */ { if ((result = fl_readdasd(drive)) == 2) /* if we can detect a change ... */ { if ((result = fl_diskchanged(drive)) == 1) /* check if it has changed... */ rp->r_mcretcode = M_CHANGED; else if (result == 0) rp->r_mcretcode = M_NOT_CHANGED; else rp->r_mcretcode = tdelay((LONG) 37) ? M_DONT_KNOW : M_NOT_CHANGED; } else if (result == 3) /* if it's a fixed disk, then no change */ rp->r_mcretcode = M_NOT_CHANGED; else /* can not detect or error... */ rp->r_mcretcode = tdelay((LONG) 37) ? M_DONT_KNOW : M_NOT_CHANGED; } return S_DONE; } static WORD bldbpb(rqptr rp) { REG retry = N_RETRY; ULONG count; byteptr trans; WORD local_word; if (hd(miarray[rp->r_unit].mi_drive)) { COUNT partidx = miarray[rp->r_unit].mi_partidx; head = dos_partition[partidx].peBeginHead; sector = dos_partition[partidx].peBeginSector; track = dos_partition[partidx].peBeginCylinder; } else { head = 0; sector = 1; track = 0; } do { ret = fl_read((WORD) miarray[rp->r_unit].mi_drive, (WORD) head, (WORD) track, (WORD) sector, (WORD) 1, (byteptr) & buffer); } while (ret != 0 && --retry > 0); if (ret != 0) return (dskerr(ret)); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NBYTE]), &bpbarray[rp->r_unit].bpb_nbyte); getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSECTOR]), &bpbarray[rp->r_unit].bpb_nsector); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NRESERVED]), &bpbarray[rp->r_unit].bpb_nreserved); getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NFAT]), &bpbarray[rp->r_unit].bpb_nfat); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NDIRENT]), &bpbarray[rp->r_unit].bpb_ndirent); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSIZE]), &bpbarray[rp->r_unit].bpb_nsize); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSIZE]), &bpbarray[rp->r_unit].bpb_nsize); getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_MDESC]), &bpbarray[rp->r_unit].bpb_mdesc); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NFSECT]), &bpbarray[rp->r_unit].bpb_nfsect); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSECS]), &bpbarray[rp->r_unit].bpb_nsecs); getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NHEADS]), &bpbarray[rp->r_unit].bpb_nheads); getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HIDDEN])), &bpbarray[rp->r_unit].bpb_hidden); getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HUGE])), &bpbarray[rp->r_unit].bpb_huge); #ifdef DSK_DEBUG printf("BPB_NBYTE = %04x\n", bpbarray[rp->r_unit].bpb_nbyte); printf("BPB_NSECTOR = %02x\n", bpbarray[rp->r_unit].bpb_nsector); printf("BPB_NRESERVED = %04x\n", bpbarray[rp->r_unit].bpb_nreserved); printf("BPB_NFAT = %02x\n", bpbarray[rp->r_unit].bpb_nfat); printf("BPB_NDIRENT = %04x\n", bpbarray[rp->r_unit].bpb_ndirent); printf("BPB_NSIZE = %04x\n", bpbarray[rp->r_unit].bpb_nsize); printf("BPB_MDESC = %02x\n", bpbarray[rp->r_unit].bpb_mdesc); printf("BPB_NFSECT = %04x\n", bpbarray[rp->r_unit].bpb_nfsect); #endif rp->r_bpptr = &bpbarray[rp->r_unit]; count = miarray[rp->r_unit].mi_size = bpbarray[rp->r_unit].bpb_nsize == 0 ? bpbarray[rp->r_unit].bpb_huge : bpbarray[rp->r_unit].bpb_nsize; getword((&(((BYTE *) & buffer.bytes[BT_BPB])[BPB_NHEADS])), &miarray[rp->r_unit].mi_heads); head = miarray[rp->r_unit].mi_heads; getword((&(((BYTE *) & buffer.bytes[BT_BPB])[BPB_NSECS])), &miarray[rp->r_unit].mi_sectors); if (miarray[rp->r_unit].mi_size == 0) getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HUGE])), &miarray[rp->r_unit].mi_size); sector = miarray[rp->r_unit].mi_sectors; if (head == 0 || sector == 0) { tmark(); return failure(E_FAILURE); } miarray[rp->r_unit].mi_cyls = count / (head * sector); tmark(); #ifdef DSK_DEBUG printf("BPB_NSECS = %04x\n", sector); printf("BPB_NHEADS = %04x\n", head); printf("BPB_HIDDEN = %08lx\n", bpbarray[rp->r_unit].bpb_hidden); printf("BPB_HUGE = %08lx\n", bpbarray[rp->r_unit].bpb_huge); #endif return S_DONE; } static COUNT write_and_verify(WORD drive, WORD head, WORD track, WORD sector, WORD count, BYTE FAR * buffer) { REG COUNT ret; ret = fl_write(drive, head, track, sector, count, buffer); if (ret != 0) return ret; return fl_verify(drive, head, track, sector, count, buffer); } static WORD Genblkdev(rqptr rp) { UWORD cmd = rp->r_count; switch(cmd){ case 0x0860: { struct gblkio FAR * gblp = rp->r_trans; gblp->gbio_devtype = 0x05; gblp->gbio_devattrib = 0x01; gblp->gbio_ncyl = miarray[rp->r_unit].mi_cyls; gblp->gbio_media = 0; gblp->gbio_bpb = bpbarray[rp->r_unit]; gblp->gbio_nsecs = bpbarray[rp->r_unit].bpb_nsector; printf("GenBlkIO = %08lx\n", rp->r_trans); printf("GenBlkIO = %08lx\n", gblp); break; } case 0x0866: break; } return S_DONE; } static WORD blockio(rqptr rp) { REG retry = N_RETRY, remaining; UWORD cmd, total; ULONG start; byteptr trans; COUNT(*action) (WORD, WORD, WORD, WORD, WORD, BYTE FAR *); cmd = rp->r_command; total = 0; trans = rp->r_trans; tmark(); for ( remaining = rp->r_count, start = (rp->r_start != HUGECOUNT ? rp->r_start : rp->r_huge) + miarray[rp->r_unit].mi_offset; remaining > 0; remaining -= count, trans += count * SEC_SIZE, start += count ) { count = ltop(&track, §or, &head, rp->r_unit, remaining, start, trans); do { switch (cmd) { case C_INPUT: action = fl_read; break; case C_OUTPUT: action = fl_write; break; case C_OUTVFY: action = write_and_verify; break; default: return failure(E_FAILURE); } if (count) ret = action((WORD) miarray[rp->r_unit].mi_drive, head, track, sector, count, trans); else { count = 1; /* buffer crosses DMA boundary, use scratchpad */ if (cmd != C_INPUT) fbcopy(trans, dma_scratch, SEC_SIZE); ret = action((WORD) miarray[rp->r_unit].mi_drive, head, track, sector, 1, dma_scratch); if (cmd == C_INPUT) fbcopy(dma_scratch, trans, SEC_SIZE); } if (ret != 0) fl_reset((WORD) miarray[rp->r_unit].mi_drive); } while (ret != 0 && --retry > 0); if (ret != 0) { rp->r_count = total; return dskerr(ret); } total += count; } rp->r_count = total; return S_DONE; } static WORD blk_error(rqptr rp) { rp->r_count = 0; return failure(E_FAILURE); /* general failure */ } static WORD dskerr(COUNT code) { /* printf("diskette error:\nhead = %d\ntrack = %d\nsector = %d\ncount = %d\n", head, track, sector, count); */ switch (code & 0x03) { case 1: /* invalid command - general failure */ if (code & 0x08) return (E_FAILURE); else return failure(E_CMD); case 2: /* address mark not found - general failure */ return failure(E_FAILURE); case 3: /* write protect */ return failure(E_WRPRT); default: if (code & 0x80) /* time-out */ return failure(E_NOTRDY); else if (code & 0x40) /* seek error */ return failure(E_SEEK); else if (code & 0x10) /* CRC error */ return failure(E_CRC); else if (code & 0x04) return failure(E_NOTFND); else return failure(E_FAILURE); } } /* */ /* Do logical block number to physical head/track/sector mapping */ /* */ static COUNT ltop(WORD * trackp, WORD * sectorp, WORD * headp, REG COUNT unit, COUNT count, LONG strt_sect, byteptr strt_addr) { #ifdef I86 ULONG ltemp; #endif REG ls, ps; #ifdef I86 /* Adjust for segmented architecture */ ltemp = (((ULONG) mk_segment(strt_addr) << 4) + mk_offset(strt_addr)) & 0xffff; /* Test for 64K boundary crossing and return count large */ /* enough not to exceed the threshold. */ count = (((ltemp + SEC_SIZE * count) & 0xffff0000l) != 0l) ? (0xffffl - ltemp) / SEC_SIZE : count; #endif *trackp = strt_sect / (miarray[unit].mi_heads * miarray[unit].mi_sectors); *sectorp = strt_sect % miarray[unit].mi_sectors + 1; *headp = (strt_sect % (miarray[unit].mi_sectors * miarray[unit].mi_heads)) / miarray[unit].mi_sectors; if (*sectorp + count > miarray[unit].mi_sectors + 1) count = miarray[unit].mi_sectors + 1 - *sectorp; return count; }