STATIC WORD getbpb(ddt * pddt) { ULONG count; bpb *pbpbarray = &pddt->ddt_bpb; unsigned secs_per_cyl; WORD ret; /* pddt->ddt_descflags |= DF_NOACCESS; * disabled for now - problems with FORMAT ?? */ /* set drive to not accessible and changed */ if (diskchange(pddt) != M_NOT_CHANGED) pddt->ddt_descflags |= DF_DISKCHANGE; ret = RWzero(pddt, LBA_READ); if (ret != 0) return (dskerr(ret)); pbpbarray->bpb_nbyte = getword(&DiskTransferBuffer[BT_BPB]); if (DiskTransferBuffer[0x1fe] != 0x55 || DiskTransferBuffer[0x1ff] != 0xaa || pbpbarray->bpb_nbyte % 512) { /* copy default bpb to be sure that there is no bogus data */ memcpy(pbpbarray, &pddt->ddt_defbpb, sizeof(bpb)); return S_DONE; } pddt->ddt_descflags &= ~DF_NOACCESS; /* set drive to accessible */ /*TE ~ 200 bytes*/ memcpy(pbpbarray, &DiskTransferBuffer[BT_BPB], sizeof(bpb)); /*?? */ /* 2b is fat16 volume label. if memcmp, then offset 0x36. if (fstrncmp((BYTE *) & DiskTransferBuffer[0x36], "FAT16",5) == 0 || fstrncmp((BYTE *) & DiskTransferBuffer[0x36], "FAT12",5) == 0) { TE: I'm not sure, what the _real_ decision point is, however MSDN 'A_BF_BPB_SectorsPerFAT The number of sectors per FAT. Note: This member will always be zero in a FAT32 BPB. Use the values from A_BF_BPB_BigSectorsPerFat... */ { struct FS_info *fs = (struct FS_info *)&DiskTransferBuffer[0x27]; register BYTE extended_BPB_signature; #ifdef WITHFAT32 if (pbpbarray->bpb_nfsect == 0) { /* FAT32 boot sector */ fs = (struct FS_info *)&DiskTransferBuffer[0x43]; /* Extended BPB signature, offset differs for FAT32 vs FAT12/16 */ extended_BPB_signature = DiskTransferBuffer[0x42]; } else #endif extended_BPB_signature = DiskTransferBuffer[0x26]; /* 0x29 is usual signature value for serial#,vol label,& fstype; 0x28 older EBPB signature indicating only serial# is valid */ if ((extended_BPB_signature == 0x29) || (extended_BPB_signature == 0x28)) { pddt->ddt_serialno = getlong(&fs->serialno); } else { /* short BPB, no serial # available */ pddt->ddt_serialno = 0; } if (extended_BPB_signature == 0x29) { fmemcpy(pddt->ddt_volume, fs->volume, sizeof fs->volume); fmemcpy(pddt->ddt_fstype, fs->fstype, sizeof fs->fstype); } else { /* earlier extended BPB or short BPB, fields not available */ fmemcpy(pddt->ddt_volume, "NO NAME ", 11); fmemcpy(pddt->ddt_fstype, "FAT?? ", 8); } } #ifdef DSK_DEBUG printf("BPB_NBYTE = %04x\n", pbpbarray->bpb_nbyte); printf("BPB_NSECTOR = %02x\n", pbpbarray->bpb_nsector); printf("BPB_NRESERVED = %04x\n", pbpbarray->bpb_nreserved); printf("BPB_NFAT = %02x\n", pbpbarray->bpb_nfat); printf("BPB_NDIRENT = %04x\n", pbpbarray->bpb_ndirent); printf("BPB_NSIZE = %04x\n", pbpbarray->bpb_nsize); printf("BPB_MDESC = %02x\n", pbpbarray->bpb_mdesc); printf("BPB_NFSECT = %04x\n", pbpbarray->bpb_nfsect); #endif count = pbpbarray->bpb_nsize == 0 ? pbpbarray->bpb_huge : pbpbarray->bpb_nsize; secs_per_cyl = pbpbarray->bpb_nheads * pbpbarray->bpb_nsecs; if (secs_per_cyl == 0) { tmark(pddt); return failure(E_FAILURE); } /* this field is problematic for partitions > 65535 cylinders, in general > 512 GiB. However: we are not using it ourselves. */ pddt->ddt_ncyl = (UWORD)((count + (secs_per_cyl - 1)) / secs_per_cyl); tmark(pddt); #ifdef DSK_DEBUG printf("BPB_NSECS = %04x\n", pbpbarray->bpb_nsecs); printf("BPB_NHEADS = %04x\n", pbpbarray->bpb_nheads); printf("BPB_HIDDEN = %08lx\n", pbpbarray->bpb_hidden); printf("BPB_HUGE = %08lx\n", pbpbarray->bpb_huge); #endif return 0; }
STATIC WORD Genblkdev(rqptr rp, ddt * pddt) { int ret; unsigned descflags = pddt->ddt_descflags; #ifdef WITHFAT32 int extended = 0; if (rp->r_cat == 0x48) extended = 1; else #endif if (rp->r_cat != 8) return failure(E_CMD); switch (rp->r_fun) { case 0x40: /* set device parameters */ { struct gblkio FAR *gblp = rp->r_io; bpb *pbpb; pddt->ddt_type = gblp->gbio_devtype; pddt->ddt_descflags = (descflags & ~3) | (gblp->gbio_devattrib & 3) | (DF_DPCHANGED | DF_REFORMAT); pddt->ddt_ncyl = gblp->gbio_ncyl; /* use default dpb or current bpb? */ pbpb = (gblp->gbio_spcfunbit & 0x01) == 0 ? &pddt->ddt_defbpb : &pddt->ddt_bpb; #ifdef WITHFAT32 fmemcpy(pbpb, &gblp->gbio_bpb, extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); #else fmemcpy(pbpb, &gblp->gbio_bpb, sizeof(gblp->gbio_bpb)); #endif /*pbpb->bpb_nsector = gblp->gbio_nsecs; */ break; } case 0x41: /* write track */ { struct gblkrw FAR *rw = rp->r_rw; ret = Genblockio(pddt, LBA_WRITE, rw->gbrw_head, rw->gbrw_cyl, rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); if (ret != 0) return dskerr(ret); } break; case 0x42: /* format/verify track */ { struct gblkfv FAR *fv = rp->r_fv; COUNT tracks; struct thst { UBYTE track, head, sector, type; } *addrfield, afentry; pddt->ddt_descflags &= ~DF_DPCHANGED; if (hd(descflags)) { /* XXX no low-level formatting for hard disks implemented */ fv->gbfv_spcfunbit = 1; /* "not supported by bios" */ return S_DONE; } if (descflags & DF_DPCHANGED) { /* first try newer setmediatype function */ ret = fl_setmediatype(pddt->ddt_driveno, pddt->ddt_ncyl, pddt->ddt_bpb.bpb_nsecs); if (ret == 0xc) { /* specified tracks, sectors/track not allowed for drive */ fv->gbfv_spcfunbit = 2; return dskerr(ret); } else if (ret == 0x80) { fv->gbfv_spcfunbit = 3; /* no disk in drive */ return dskerr(ret); } else if (ret != 0) /* otherwise, setdisktype */ { unsigned char type; unsigned tracks, secs; if ((fv->gbfv_spcfunbit & 1) && (ret = fl_read(pddt->ddt_driveno, 0, 0, 1, 1, DiskTransferBuffer)) != 0) { fv->gbfv_spcfunbit = 3; /* no disk in drive */ return dskerr(ret); } /* type 1: 320/360K disk in 360K drive */ /* type 2: 320/360K disk in 1.2M drive */ tracks = pddt->ddt_ncyl; secs = pddt->ddt_bpb.bpb_nsecs; type = pddt->ddt_type + 1; if (!(tracks == 40 && (secs == 9 || secs == 8) && type < 3)) { /* type 3: 1.2M disk in 1.2M drive */ /* type 4: 720kb disk in 1.44M or 720kb drive */ type++; if (type == 9) /* 1.44M drive */ type = 4; if (!(tracks == 80 && ((secs == 15 && type == 3) || (secs == 9 && type == 4)))) { /* specified tracks, sectors/track not allowed for drive */ fv->gbfv_spcfunbit = 2; return dskerr(0xc); } } fl_setdisktype(pddt->ddt_driveno, type); } } if (fv->gbfv_spcfunbit & 1) return S_DONE; afentry.type = 2; /* 512 byte sectors */ afentry.track = fv->gbfv_cyl; afentry.head = fv->gbfv_head; for (tracks = fv->gbfv_spcfunbit & 2 ? fv->gbfv_ntracks : 1; tracks > 0; tracks--) { addrfield = (struct thst *)DiskTransferBuffer; if (afentry.track > pddt->ddt_ncyl) return failure(E_FAILURE); for (afentry.sector = 1; afentry.sector <= pddt->ddt_bpb.bpb_nsecs; afentry.sector++) memcpy(addrfield++, &afentry, sizeof(afentry)); ret = Genblockio(pddt, LBA_FORMAT, afentry.head, afentry.track, 0, pddt->ddt_bpb.bpb_nsecs, DiskTransferBuffer); if (ret != 0) return dskerr(ret); } afentry.head++; if (afentry.head >= pddt->ddt_bpb.bpb_nheads) { afentry.head = 0; afentry.track++; } } /* fall through to verify */ case 0x62: /* verify track */ { struct gblkfv FAR *fv = rp->r_fv; ret = Genblockio(pddt, LBA_VERIFY, fv->gbfv_head, fv->gbfv_cyl, 0, (fv->gbfv_spcfunbit ? fv->gbfv_ntracks * pddt->ddt_defbpb.bpb_nsecs : pddt->ddt_defbpb.bpb_nsecs), DiskTransferBuffer); if (ret != 0) return dskerr(ret); fv->gbfv_spcfunbit = 0; /* success */ } break; case 0x46: /* set volume serial number */ { struct Gioc_media FAR *gioc = rp->r_gioc; struct FS_info *fs; ret = getbpb(pddt); if (ret != 0) return (ret); fs = (struct FS_info *)&DiskTransferBuffer [(pddt->ddt_bpb.bpb_nfsect != 0 ? 0x27 : 0x43)]; fs->serialno = gioc->ioc_serialno; pddt->ddt_serialno = fs->serialno; ret = RWzero(pddt, LBA_WRITE); if (ret != 0) return (dskerr(ret)); } break; case 0x47: /* set access flag */ { struct Access_info FAR *ai = rp->r_ai; pddt->ddt_descflags = (descflags & ~DF_NOACCESS) | (ai->AI_Flag ? 0 : DF_NOACCESS); } break; case 0x60: /* get device parameters */ { struct gblkio FAR *gblp = rp->r_io; bpb *pbpb; gblp->gbio_devtype = pddt->ddt_type; gblp->gbio_devattrib = descflags & 3; /* 360 kb disk in 1.2 MB drive */ gblp->gbio_media = (pddt->ddt_type == 1) && (pddt->ddt_ncyl == 40); gblp->gbio_ncyl = pddt->ddt_ncyl; /* use default dpb or current bpb? */ pbpb = (gblp->gbio_spcfunbit & 0x01) == 0 ? &pddt->ddt_defbpb : &pddt->ddt_bpb; #ifdef WITHFAT32 fmemcpy(&gblp->gbio_bpb, pbpb, extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); #else fmemcpy(&gblp->gbio_bpb, pbpb, sizeof(gblp->gbio_bpb)); #endif /*gblp->gbio_nsecs = pbpb->bpb_nsector; */ break; } case 0x61: /* read track */ { struct gblkrw FAR *rw = rp->r_rw; ret = Genblockio(pddt, LBA_READ, rw->gbrw_head, rw->gbrw_cyl, rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); if (ret != 0) return dskerr(ret); } break; case 0x66: /* get volume serial number */ { struct Gioc_media FAR *gioc = rp->r_gioc; ret = getbpb(pddt); if (ret != 0) return (ret); gioc->ioc_serialno = pddt->ddt_serialno; fmemcpy(gioc->ioc_volume, pddt->ddt_volume, 11); fmemcpy(gioc->ioc_fstype, pddt->ddt_fstype, 8); } break; case 0x67: /* get access flag */ { struct Access_info FAR *ai = rp->r_ai; ai->AI_Flag = descflags & DF_NOACCESS ? 0 : 1; /* bit 9 */ } break; default: return failure(E_CMD); } return S_DONE; }