/****************************************************************/ /* */ /* 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 "../../hdr/portab.h" #include "globals.h" /* $Logfile: C:/dos-c/src/kernel/dsk.c_v $ */ #ifndef IPL static BYTE *dskRcsId = "$Header: C:/dos-c/src/kernel/dsk.c_v 1.2 01 Sep 1995 17:54:18 patv $"; #endif /* * $Log: C:/dos-c/src/kernel/dsk.c_v $ * * 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(VOID); 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 *); BOOL fl_verify(WORD, WORD, WORD, WORD, WORD, BYTE FAR *); BOOL fl_format(WORD, BYTE FAR *); #else BOOL fl_reset(); COUNT fl_rd_status(); COUNT fl_read(); COUNT fl_write(); BOOL fl_verify(); BOOL fl_format(); #endif #define NDEV 4 /* 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 */ #define dsk_unit(x) ((x)>=2?(((x)-2)|0x80):(x)) #define hd(x) ((x)>=2) union { BYTE bytes[2 * SEC_SIZE]; boot boot_sector; } buffer; static struct media_info { ULONG mi_size; /* physical sector size */ 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 */ }; static struct media_info miarray[NDEV] = { {720l, 2, 40, 9, 0l}, {720l, 2, 40, 9, 0l}, {720l, 2, 40, 9, 0l}, {720l, 2, 40, 9, 0l} }; static bpb bpbarray[NDEV] = { { SEC_SIZE, /* Physical sector size */ 2, /* Sectors/cluster */ 1, /* reserved sectors */ 2, /* # FAT's */ 112, /* # dir entries */ 720, /* # sectors on disk */ 0xfd, /* media descriptor byte */ 2 /* # FAT sectors */ }, { SEC_SIZE, /* Physical sector size */ 2, /* Sectors/cluster */ 1, /* reserved sectors */ 2, /* # FAT's */ 112, /* # dir entries */ 720, /* # sectors on disk */ 0xfd, /* media descriptor byte */ 2 /* # FAT sectors */ }, { SEC_SIZE, /* Physical sector size */ 2, /* Sectors/cluster */ 1, /* reserved sectors */ 2, /* # FAT's */ 112, /* # dir entries */ 720, /* # sectors on disk */ 0xfd, /* media descriptor byte */ 2 /* # FAT sectors */ }, { SEC_SIZE, /* Physical sector size */ 2, /* Sectors/cluster */ 1, /* reserved sectors */ 2, /* # FAT's */ 112, /* # dir entries */ 720, /* # sectors on disk */ 0xfd, /* media descriptor byte */ 2 /* # FAT sectors */ } }; static bpb *bpbptrs[NDEV] = { &bpbarray[0], &bpbarray[1], &bpbarray[2], &bpbarray[3] }; #define N_PART 4 static COUNT part_map[N_PART]; static WORD head, track, sector, ret; static WORD count; static COUNT nDevices; #define PARTOFF 0x1be static struct { BYTE peBootable; BYTE peBeginHead; BYTE peBeginSector; UWORD peBeginCylinder; BYTE peFileSystem; BYTE peEndHead; BYTE peEndSector; UWORD peEndCylinder; LONG peStartSector; LONG peSectors; } partition[4]; #ifdef PROTO WORD init(rqptr), mediachk(rqptr), bldbpb(rqptr), blockio(rqptr), blk_error(rqptr); COUNT ltop(WORD *, WORD *, WORD *, COUNT, COUNT, LONG, byteptr); WORD dskerr(COUNT); COUNT get_part(COUNT drive, COUNT idx); #else WORD init(), mediachk(), bldbpb(), blockio(), blk_error(); WORD dskerr(); COUNT get_part(); #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 */ blk_error, /* 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 COUNT get_part (COUNT drive, COUNT idx) { REG retry = N_RETRY; REG BYTE *p = (BYTE *)&buffer.bytes[PARTOFF + (idx * SIZEOF_PARTENT)]; BYTE packed_byte, pb1; do { ret = fl_read((WORD)dsk_unit(drive), (WORD)0, (WORD)0, (WORD)1, (WORD)1, (byteptr)&buffer); } while (ret != 0 && --retry > 0); if(ret != 0) return FALSE; getbyte((VOID *)p, &partition[idx].peBootable); ++p; getbyte((VOID *)p, &partition[idx].peBeginHead); ++p; getbyte((VOID *)p, &packed_byte); partition[idx].peBeginSector = packed_byte & 0x3f; ++p; getbyte((VOID *)p, &pb1); ++p; partition[idx].peBeginCylinder = pb1 + ((0xc0 & packed_byte) << 2); getbyte((VOID *)p, &partition[idx].peFileSystem); ++p; getbyte((VOID *)p, &partition[idx].peEndHead); ++p; getbyte((VOID *)p, &packed_byte); partition[idx].peEndSector = packed_byte & 0x3f; ++p; getbyte((VOID *)p, &pb1); ++p; partition[idx].peEndCylinder = pb1 + ((0xc0 & packed_byte) << 2); getlong((VOID *)p, &partition[idx].peStartSector); p += sizeof(LONG); getlong((VOID *)p, &partition[idx].peSectors); return TRUE; } COUNT blk_driver (rqptr rp) { if(rp -> r_unit >= NDEV) 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) { REG COUNT idx, off = 0; COUNT Drive; /* Reset the drives */ fl_reset(); nDevices = 2; for(Drive = 2; Drive < NDEV; Drive++) { COUNT RetCode; /* Retrieve all the partition information */ for(RetCode = TRUE, idx = 0; RetCode && (idx < N_PART); idx++) RetCode = get_part(Drive, idx); if(!RetCode) break; else ++nDevices; /* Search for the first DOS partition and start */ /* building the map for the hard drive */ for(idx = 0; idx < N_PART; idx++) { if(partition[idx].peFileSystem == FAT12 || partition[idx].peFileSystem == FAT16SMALL || partition[idx].peFileSystem == FAT16LARGE) { miarray[Drive+ off].mi_offset = partition[idx].peStartSector; part_map[off++] = idx; break; } } /* Then search for the remaing DOS extended partitions */ /* and finish building the map for the hard drive */ for(idx = 0; idx < N_PART; idx++) { if(partition[idx].peFileSystem == EXTENDED) { miarray[Drive + off].mi_offset = partition[idx].peStartSector; part_map[off++] = idx; break; } } } rp -> r_nunits = nDevices; rp -> r_bpbptr = bpbptrs; rp -> r_endaddr = device_end(); return S_DONE; } static WORD mediachk (rqptr rp) { if(hd(rp -> r_unit)) rp -> r_mcretcode = M_NOT_CHANGED; else 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(rp -> r_unit)) { head = partition[part_map[rp -> r_unit - 2]].peBeginHead; sector = partition[part_map[rp -> r_unit - 2]].peBeginSector; track = partition[part_map[rp -> r_unit - 2]].peBeginCylinder; } else { head = 0; sector = 1; track = 0; } do { ret = fl_read((WORD)dsk_unit(rp -> r_unit), (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 WORD blockio (rqptr rp) { REG retry = N_RETRY, remaining; UWORD cmd, total; ULONG start; byteptr trans; 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 ) { if(ltop(&track, §or, &head, rp -> r_unit, 1, start, trans) != 1) { /* printf("split sector at 0x%lx", trans);*/ } count = ltop(&track, §or, &head, rp -> r_unit, remaining, start, trans); total += count; do { switch(cmd) { case C_INPUT: ret = fl_read((WORD)dsk_unit(rp -> r_unit), (WORD)head, (WORD)track, (WORD)sector, (WORD)count, trans); break; case C_OUTPUT: case C_OUTVFY: ret = fl_write((WORD)dsk_unit(rp -> r_unit), (WORD)head, (WORD)track, (WORD)sector, (WORD)count, trans); break; default: return failure(E_FAILURE); } } while (ret != 0 && --retry > 0); if(ret != 0) { rp -> r_count = 0; return dskerr(ret); } if(cmd == C_OUTVFY) { ret = fl_verify((WORD)dsk_unit(rp -> r_unit), (WORD)head, (WORD)track, (WORD)sector, (WORD)count, rp -> r_trans); if(ret != 0) { rp -> r_count = 0; return dskerr(ret); } } } 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(((ls = *headp * miarray[unit].mi_sectors + *sectorp - 1) + count) > (ps = miarray[unit].mi_heads * miarray[unit].mi_sectors)) count = ps - ls; return count; }