851eb99b63
git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@176 6ac86273-5f31-0410-b378-82cca8765d1b
1242 lines
40 KiB
C
1242 lines
40 KiB
C
/****************************************************************/
|
|
/* */
|
|
/* 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.12 2001/03/24 22:13:05 bartoldeman
|
|
* See history.txt: dsk.c changes, warning removal and int21 entry handling.
|
|
*
|
|
* Revision 1.11 2001/03/21 02:56:25 bartoldeman
|
|
* See history.txt for changes. Bug fixes and HMA support are the main ones.
|
|
*
|
|
* Revision 1.9 2001/03/08 21:15:00 bartoldeman
|
|
* Space saving fixes from Tom Ehlert
|
|
*
|
|
* Revision 1.8 2000/06/21 18:16:46 jimtabor
|
|
* Add UMB code, patch, and code fixes
|
|
*
|
|
* Revision 1.7 2000/06/01 06:37:38 jimtabor
|
|
* Read History for Changes
|
|
*
|
|
* Revision 1.6 2000/05/26 19:25:19 jimtabor
|
|
* Read History file for Change info
|
|
*
|
|
* Revision 1.5 2000/05/25 20:56:21 jimtabor
|
|
* Fixed project history
|
|
*
|
|
* Revision 1.4 2000/05/17 19:15:12 jimtabor
|
|
* Cleanup, add and fix source.
|
|
*
|
|
* Revision 1.3 2000/05/11 04:26:26 jimtabor
|
|
* Added code for DOS FN 69 & 6C
|
|
*
|
|
* Revision 1.2 2000/05/08 04:29:59 jimtabor
|
|
* Update CVS to 2020
|
|
*
|
|
* Revision 1.1.1.1 2000/05/06 19:34:53 jhall1
|
|
* The FreeDOS Kernel. A DOS kernel that aims to be 100% compatible with
|
|
* MS-DOS. Distributed under the GNU GPL.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#if defined(DEBUG)
|
|
#define PartCodePrintf(x) printf x
|
|
#else
|
|
#define PartCodePrintf(x)
|
|
#endif
|
|
|
|
#define STATIC
|
|
|
|
|
|
|
|
|
|
#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 26 /* total size of dispatch table */
|
|
|
|
extern BYTE FAR nblk_rel;
|
|
|
|
union
|
|
{
|
|
BYTE bytes[1 * SEC_SIZE];
|
|
boot boot_sector;
|
|
} buffer;
|
|
|
|
/* if the buffer above is good enough for booting
|
|
it's also good enough for DMA input */
|
|
BYTE /* scratchpad used for working around */
|
|
FAR * dma_scratch_buffer = (BYTE FAR *)&buffer; /* DMA transfers during disk I/O */
|
|
|
|
|
|
|
|
|
|
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 */
|
|
ULONG mi_FileOC; /* Count of Open files on Drv */
|
|
};
|
|
|
|
static struct FS_info
|
|
{
|
|
ULONG fs_serialno;
|
|
BYTE fs_volume[11];
|
|
BYTE fs_fstype[8];
|
|
};
|
|
|
|
static struct Access_info
|
|
{
|
|
BYTE AI_spec;
|
|
BYTE AI_Flag;
|
|
};
|
|
|
|
STATIC struct media_info miarray[NDEV]; /* Internal media info structs */
|
|
STATIC struct FS_info fsarray[NDEV];
|
|
STATIC bpb bpbarray[NDEV]; /* BIOS parameter blocks */
|
|
STATIC bpb *bpbptrs[NDEV]; /* pointers to bpbs */
|
|
|
|
/*TE - array access functions */
|
|
struct media_info *getPMiarray(int dev) { return &miarray[dev];}
|
|
bpb *getPBpbarray(unsigned dev){ return &bpbarray[dev];}
|
|
|
|
#define N_PART 4 /* number of partitions per
|
|
table partition */
|
|
|
|
STATIC COUNT nUnits; /* number of returned units */
|
|
STATIC COUNT nPartitions; /* number of DOS partitions */
|
|
|
|
#define PARTOFF 0x1be
|
|
|
|
STATIC struct dos_partitionS
|
|
{
|
|
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 _dsk_init(rqptr),
|
|
mediachk(rqptr),
|
|
bldbpb(rqptr),
|
|
blockio(rqptr),
|
|
IoctlQueblk(rqptr),
|
|
Genblkdev(rqptr),
|
|
Getlogdev(rqptr),
|
|
Setlogdev(rqptr),
|
|
blk_Open(rqptr),
|
|
blk_Close(rqptr),
|
|
blk_Media(rqptr),
|
|
blk_noerr(rqptr),
|
|
blk_nondr(rqptr),
|
|
blk_error(rqptr);
|
|
COUNT ltop(WORD *, WORD *, WORD *, COUNT, COUNT, ULONG, byteptr);
|
|
WORD dskerr(COUNT);
|
|
COUNT processtable(int table_type,COUNT ptDrive, BYTE ptHead, UWORD ptCylinder, BYTE ptSector, LONG ptAccuOff, UWORD PartitionDone);
|
|
#else
|
|
WORD _dsk_init(),
|
|
mediachk(),
|
|
bldbpb(),
|
|
blockio(),
|
|
IoctlQueblk(),
|
|
Genblkdev(),
|
|
Getlogdev(),
|
|
Setlogdev(),
|
|
blk_Open(),
|
|
blk_Close(),
|
|
blk_Media(),
|
|
blk_noerr(),
|
|
blk_nondr(),
|
|
blk_error();
|
|
WORD dskerr();
|
|
COUNT processtable();
|
|
#endif
|
|
|
|
/* */
|
|
/* the function dispatch table */
|
|
/* */
|
|
|
|
#ifdef PROTO
|
|
static WORD(*dispatch[NENTRY]) (rqptr) =
|
|
#else
|
|
static WORD(*dispatch[NENTRY]) () =
|
|
#endif
|
|
{
|
|
_dsk_init, /* Initialize */
|
|
mediachk, /* Media Check */
|
|
bldbpb, /* Build BPB */
|
|
blk_error, /* Ioctl In */
|
|
blockio, /* Input (Read) */
|
|
blk_nondr, /* Non-destructive Read */
|
|
blk_noerr, /* Input Status */
|
|
blk_noerr, /* Input Flush */
|
|
blockio, /* Output (Write) */
|
|
blockio, /* Output with verify */
|
|
blk_noerr, /* Output Status */
|
|
blk_noerr, /* Output Flush */
|
|
blk_error, /* Ioctl Out */
|
|
blk_Open, /* Device Open */
|
|
blk_Close, /* Device Close */
|
|
blk_Media, /* Removable Media */
|
|
blk_noerr, /* Output till busy */
|
|
blk_error, /* undefined */
|
|
blk_error, /* undefined */
|
|
Genblkdev, /* Generic Ioctl Call */
|
|
blk_error, /* undefined */
|
|
blk_error, /* undefined */
|
|
blk_error, /* undefined */
|
|
Getlogdev, /* Get Logical Device */
|
|
Setlogdev, /* Set Logical Device */
|
|
IoctlQueblk /* Ioctl Query */
|
|
};
|
|
|
|
#define SIZEOF_PARTENT 16
|
|
|
|
#define PRIMARY 0x01
|
|
#define PRIMARY2 0x02
|
|
|
|
#define FAT12 0x01
|
|
#define FAT16SMALL 0x04
|
|
#define EXTENDED 0x05
|
|
#define FAT16LARGE 0x06
|
|
#define EXTENDED_INT32 0x0f /* like 0x05, but uses extended INT32 */
|
|
|
|
#define hd(x) ((x) & 0x80)
|
|
|
|
|
|
|
|
ULONG StartSector(WORD ptDrive, unsigned BeginCylinder,
|
|
unsigned BeginSector,
|
|
unsigned BeginHead,
|
|
ULONG peStartSector,
|
|
ULONG ptAccuOff)
|
|
{
|
|
iregs regs;
|
|
|
|
unsigned cylinders,heads,sectors;
|
|
ULONG startPos;
|
|
ULONG oldStartPos;
|
|
|
|
regs.a.x = 0x0800; /* get drive parameters */
|
|
regs.d.x = ptDrive;
|
|
intr(0x13, ®s);
|
|
|
|
if ((regs.a.x & 0xff) != 0)
|
|
{
|
|
PartCodePrintf(("error getting drive parameters for drive %x\n", ptDrive));
|
|
return peStartSector+ptAccuOff;
|
|
}
|
|
|
|
/* cylinders = (regs.c.x >>8) | ((regs.c.x & 0x0c) << 2); */
|
|
heads = (regs.d.x >> 8) + 1;
|
|
sectors = regs.c.x & 0x3f;
|
|
|
|
startPos = ((ULONG)BeginCylinder * heads + BeginHead) * sectors + BeginSector - 1;
|
|
|
|
PartCodePrintf((" CHS %x %x %x (%d %d %d) --> %lx ( %ld)\n",
|
|
BeginCylinder, BeginHead, BeginSector,
|
|
BeginCylinder, BeginHead, BeginSector,
|
|
startPos, startPos));
|
|
|
|
|
|
oldStartPos = peStartSector + ptAccuOff;
|
|
|
|
PartCodePrintf(("oldStartPos = %lx - ", oldStartPos));
|
|
|
|
|
|
if (startPos != oldStartPos)
|
|
{
|
|
printf("PART TABLE mismatch for drive %x, CHS=%d %d %d, startsec %d, offset %ld\n",
|
|
ptDrive, BeginCylinder, BeginHead,BeginSector,
|
|
peStartSector, ptAccuOff);
|
|
|
|
printf(" old startpos = %ld, new startpos = %ld, using new\n",
|
|
oldStartPos, startPos);
|
|
}
|
|
|
|
return startPos;
|
|
}
|
|
|
|
/*
|
|
thats what MSDN says:
|
|
|
|
How Windows 2000 Assigns, Reserves, and Stores Drive Letters
|
|
ID: q234048
|
|
|
|
BASIC Disk - Drive Letter Assignment Rules
|
|
The following are the basic disk drive letter assignment rules for Windows 2000:
|
|
Scan all fixed hard disks as they are enumerated, assign drive letters
|
|
starting with any active primary partitions (if there is one), otherwise,
|
|
scan the first primary partition on each drive. Assign next available
|
|
letter starting with C:
|
|
|
|
|
|
Repeat scan for all fixed hard disks and removable (JAZ, MO) disks
|
|
and assign drive letters to all logical drives in an extended partition,
|
|
or the removable disk(s) as enumerated. Assign next available letter
|
|
starting with C:
|
|
|
|
|
|
Finally, repeat scan for all fixed hard disk drives, and assign drive
|
|
letters to all remaining primary partitions. Assign next available letter
|
|
starting with C:
|
|
|
|
Floppy drives. Assign letter starting with A:
|
|
|
|
CD-ROM drives. Assign next available letter starting with D:
|
|
|
|
*************************************************************************
|
|
Order in Which MS-DOS and Windows Assign Drive Letters
|
|
ID: q51978
|
|
|
|
MORE INFORMATION
|
|
The following occurs at startup:
|
|
|
|
MS-DOS checks all installed disk devices, assigning the drive letter A
|
|
to the first physical floppy disk drive that is found.
|
|
|
|
If a second physical floppy disk drive is present, it is assigned drive letter B. If it is not present, a logical drive B is created that uses the first physical floppy disk drive.
|
|
|
|
|
|
Regardless of whether a second floppy disk drive is present,
|
|
MS-DOS then assigns the drive letter C to the primary MS-DOS
|
|
partition on the first physical hard disk, and then goes on
|
|
to check for a second hard disk.
|
|
|
|
|
|
If a second physical hard disk is found, and a primary partition exists
|
|
on the second physical drive, the primary MS-DOS partition on the second
|
|
physical hard drive is assigned the letter D. MS-DOS version 5.0, which
|
|
supports up to eight physical drives, will continue to search for more
|
|
physical hard disk drives at this point. For example, if a third physical
|
|
hard disk is found, and a primary partition exists on the third physical
|
|
drive, the primary MS-DOS partition on the third physical hard drive is
|
|
assigned the letter E.
|
|
|
|
|
|
MS-DOS returns to the first physical hard disk drive and assigns drive
|
|
letters to any additional logical drives (in extended MS-DOS partitions)
|
|
on that drive in sequence.
|
|
|
|
|
|
MS-DOS repeats this process for the second physical hard disk drive,
|
|
if present. MS-DOS 5.0 will repeat this process for up to eight physical
|
|
hard drives, if present. After all logical drives (in extended MS-DOS
|
|
partitions) have been assigned drive letters, MS-DOS 5.0 returns to
|
|
the first physical drive and assigns drive letters to any other primary
|
|
MS-DOS partitions that exist, then searches other physical drives for
|
|
additional primary MS-DOS partitions. This support for multiple primary
|
|
MS-DOS partitions was added to version 5.0 for backward compatibility
|
|
with the previous OEM MS-DOS versions that support multiple primary partitions.
|
|
|
|
|
|
After all logical drives on the hard disk(s) have been assigned drive
|
|
letters, drive letters are assigned to drives installed using DRIVER.SYS
|
|
or created using RAMDRIVE.SYS in the order in which the drivers are loaded
|
|
in the CONFIG.SYS file. Which drive letters are assigned to which devices
|
|
can be influenced by changing the order of the device drivers or, if necessary,
|
|
by creating "dummy" drive letters with DRIVER.SYS.
|
|
|
|
********************************************************
|
|
|
|
I don't know, if I did it right, but I tried to do it that way. TE
|
|
|
|
*/
|
|
COUNT processtable(int table_type,COUNT ptDrive, BYTE ptHead, UWORD ptCylinder,
|
|
BYTE ptSector, LONG ptAccuOff, UWORD PartitionDone )
|
|
{
|
|
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],
|
|
*ptemp_part; /*TE*/
|
|
|
|
int retry;
|
|
UBYTE packed_byte,
|
|
pb1;
|
|
BYTE *p;
|
|
int partition_chain = 0;
|
|
int ret;
|
|
ULONG newStartPos;
|
|
UWORD partMask;
|
|
int loop;
|
|
|
|
restart: /* yes, it's a GOTO >:-) */
|
|
|
|
/* if someone has a circular linked
|
|
extended partition list, stop it sooner or later */
|
|
if (partition_chain > 64)
|
|
return PartitionDone;
|
|
|
|
|
|
PartCodePrintf(("searching partition table at %x %x %x %x %lx\n",
|
|
ptDrive, ptCylinder, ptHead, ptSector, ptAccuOff));
|
|
|
|
/* Read partition table */
|
|
for ( retry = N_RETRY; --retry >= 0; )
|
|
{
|
|
ret = fl_read((WORD) ptDrive, (WORD) ptHead, (WORD) ptCylinder,
|
|
(WORD) ptSector, (WORD) 1, (byteptr) & buffer);
|
|
if (ret == 0)
|
|
break;
|
|
}
|
|
if (ret != 0)
|
|
return PartitionDone;
|
|
|
|
/* Read each partition into temporary array */
|
|
|
|
p = (BYTE *) & buffer.bytes[PARTOFF];
|
|
|
|
for (ptemp_part = &temp_part[0];
|
|
ptemp_part < &temp_part[N_PART]; ptemp_part++)
|
|
{
|
|
|
|
getbyte((VOID *) (p+0), &ptemp_part->peBootable);
|
|
getbyte((VOID *) (p+1), &ptemp_part->peBeginHead);
|
|
getbyte((VOID *) (p+2), &packed_byte);
|
|
ptemp_part->peBeginSector = packed_byte & 0x3f;
|
|
getbyte((VOID *) (p+3), &pb1);
|
|
ptemp_part->peBeginCylinder = pb1 + ((UWORD) (0xc0 & packed_byte) << 2);
|
|
getbyte((VOID *) (p+4), &ptemp_part->peFileSystem);
|
|
getbyte((VOID *) (p+5), &ptemp_part->peEndHead);
|
|
getbyte((VOID *) (p+6), &packed_byte);
|
|
ptemp_part->peEndSector = packed_byte & 0x3f;
|
|
getbyte((VOID *) (p+7), &pb1);
|
|
ptemp_part->peEndCylinder = pb1 + ((UWORD) (0xc0 & packed_byte) << 2);
|
|
getlong((VOID *) (p+8), &ptemp_part->peStartSector);
|
|
getlong((VOID *) (p+12), &ptemp_part->peSectors);
|
|
|
|
p += SIZEOF_PARTENT; /* == 16 */
|
|
}
|
|
|
|
/* Walk through the table, add DOS partitions to global
|
|
array and process extended partitions */
|
|
|
|
/* when searching the EXT chain,
|
|
must skip primary partitions */
|
|
if ( table_type==PRIMARY ||
|
|
table_type==PRIMARY2 ||
|
|
partition_chain!=0 )
|
|
{
|
|
/* do this for
|
|
0) all active partitions
|
|
1) the first primary partition
|
|
*/
|
|
for (loop = 0; loop < 2; loop++)
|
|
{
|
|
for (ptemp_part = &temp_part[0], partMask = 1;
|
|
ptemp_part < &temp_part[N_PART] && nUnits < NDEV;
|
|
partMask <<= 1,ptemp_part++)
|
|
{
|
|
|
|
|
|
if (loop == 0 && /* scan for only for active */
|
|
!ptemp_part->peBootable)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (PartitionDone & partMask) /* don't reassign partitions */
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( ptemp_part->peFileSystem == FAT12 ||
|
|
ptemp_part->peFileSystem == FAT16SMALL ||
|
|
ptemp_part->peFileSystem == FAT16LARGE )
|
|
{
|
|
struct dos_partitionS *pdos_partition;
|
|
|
|
struct media_info *pmiarray = getPMiarray(nUnits);
|
|
|
|
pmiarray->mi_drive = ptDrive;
|
|
pmiarray->mi_partidx = nPartitions;
|
|
|
|
pmiarray->mi_offset = StartSector(ptDrive,
|
|
ptemp_part->peBeginCylinder,
|
|
ptemp_part->peBeginHead,
|
|
ptemp_part->peBeginSector,
|
|
ptemp_part->peStartSector,
|
|
ptAccuOff);
|
|
|
|
nUnits++;
|
|
|
|
pdos_partition = &dos_partition[nPartitions];
|
|
|
|
pdos_partition->peDrive = ptDrive;
|
|
pdos_partition->peBootable = ptemp_part->peBootable;
|
|
pdos_partition->peBeginHead = ptemp_part->peBeginHead;
|
|
pdos_partition->peBeginSector = ptemp_part->peBeginSector;
|
|
pdos_partition->peBeginCylinder=ptemp_part->peBeginCylinder;
|
|
pdos_partition->peFileSystem =ptemp_part->peFileSystem;
|
|
pdos_partition->peEndHead =ptemp_part->peEndHead;
|
|
pdos_partition->peEndSector =ptemp_part->peEndSector;
|
|
pdos_partition->peEndCylinder =ptemp_part->peEndCylinder;
|
|
pdos_partition->peStartSector =ptemp_part->peStartSector;
|
|
pdos_partition->peSectors =ptemp_part->peSectors;
|
|
pdos_partition->peAbsStart =ptemp_part->peStartSector + ptAccuOff;
|
|
|
|
PartCodePrintf(("DOS PARTITION drive %x CHS %x-%x-%x %x-%x-%x %lx %lx %lx FS %x\n",
|
|
pdos_partition->peDrive,
|
|
pdos_partition->peBeginCylinder,pdos_partition->peBeginHead ,pdos_partition->peBeginSector ,
|
|
pdos_partition->peEndCylinder ,pdos_partition->peEndHead ,pdos_partition->peEndSector ,
|
|
pdos_partition->peStartSector ,
|
|
pdos_partition->peSectors ,
|
|
pdos_partition->peAbsStart ,
|
|
pdos_partition->peFileSystem
|
|
));
|
|
|
|
nPartitions++;
|
|
|
|
PartitionDone |= partMask;
|
|
|
|
if ( table_type==PRIMARY )
|
|
{
|
|
return PartitionDone; /* we are done */
|
|
}
|
|
|
|
} /* end FAT16 detected */
|
|
} /* end PArtitionentry 0..3 */
|
|
} /* end of loop 0..1 for active, nonactive */
|
|
} /* if ( table_type==PRIMARY ) */
|
|
|
|
/* search for EXT partitions only on 2. run */
|
|
if (table_type==EXTENDED)
|
|
{
|
|
for (ptemp_part = &temp_part[0];
|
|
ptemp_part < &temp_part[N_PART] && nUnits < NDEV; ptemp_part++)
|
|
{
|
|
if ( (ptemp_part->peFileSystem == EXTENDED ||
|
|
ptemp_part->peFileSystem == EXTENDED_INT32 ) )
|
|
{
|
|
/* restart with new extended part table, don't recurs */
|
|
partition_chain++;
|
|
|
|
ptHead = ptemp_part->peBeginHead;
|
|
ptCylinder = ptemp_part->peBeginCylinder;
|
|
ptSector = ptemp_part->peBeginSector;
|
|
ptAccuOff = ptemp_part->peStartSector + ptAccuOff;
|
|
|
|
PartitionDone = 0; /* not important for EXTENDED */
|
|
|
|
goto restart;
|
|
}
|
|
}
|
|
}
|
|
|
|
return PartitionDone;
|
|
}
|
|
|
|
COUNT FAR init_call_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));
|
|
}
|
|
|
|
WORD _dsk_init(rqptr rp)
|
|
{
|
|
extern COUNT fl_nrdrives(VOID);
|
|
COUNT HardDrive,
|
|
nHardDisk,
|
|
Unit;
|
|
struct media_info *pmiarray;
|
|
bpb *pbpbarray;
|
|
UBYTE foundPartitions[16];
|
|
|
|
|
|
/* 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++)
|
|
{
|
|
pmiarray = getPMiarray(Unit);
|
|
|
|
pmiarray->mi_size = 720l;
|
|
pmiarray->mi_heads = 2;
|
|
pmiarray->mi_cyls = 40;
|
|
pmiarray->mi_sectors = 9;
|
|
pmiarray->mi_offset = 0l;
|
|
pmiarray->mi_drive = Unit;
|
|
|
|
fsarray[Unit].fs_serialno = 0x12345678;
|
|
|
|
pbpbarray = getPBpbarray(Unit);
|
|
|
|
pbpbarray->bpb_nbyte = SEC_SIZE;
|
|
pbpbarray->bpb_nsector = 2;
|
|
pbpbarray->bpb_nreserved = 1;
|
|
pbpbarray->bpb_nfat = 2;
|
|
pbpbarray->bpb_ndirent = 112;
|
|
pbpbarray->bpb_nsize = 720l;
|
|
pbpbarray->bpb_mdesc = 0xfd;
|
|
pbpbarray->bpb_nfsect = 2;
|
|
|
|
bpbptrs[Unit] = pbpbarray;
|
|
}
|
|
|
|
nHardDisk = fl_nrdrives();
|
|
|
|
nHardDisk = min(nHardDisk,sizeof(foundPartitions));
|
|
|
|
/* as rather well documented, DOS searches 1st) 1 primary patitions on
|
|
all drives, 2nd) all extended partitions. that
|
|
makes many people (including me) unhappy, as all DRIVES D:,E:...
|
|
on 1st disk will move up/down, if other disk with
|
|
primary partitions are added/removed, but
|
|
thats the way it is (hope I got it right)
|
|
TE (with a little help from my friends)
|
|
see also above for WIN2000,DOS,MSDN */
|
|
|
|
PartCodePrintf(("DSK init: found %d disk drives\n",nHardDisk));
|
|
|
|
|
|
/* Process primary partition table 1 partition only */
|
|
for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++)
|
|
{
|
|
foundPartitions[HardDrive] =
|
|
processtable(PRIMARY, (HardDrive | 0x80), 0, 0l, 1, 0l,0);
|
|
}
|
|
/* Process extended partition table */
|
|
for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++)
|
|
{
|
|
processtable(EXTENDED, (HardDrive | 0x80), 0, 0l, 1, 0l,0);
|
|
}
|
|
|
|
/* Process primary a 2nd time */
|
|
for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++)
|
|
{
|
|
processtable(PRIMARY, (HardDrive | 0x80), 0, 0l, 1, 0l,foundPartitions[HardDrive]);
|
|
}
|
|
|
|
rp->r_nunits = nUnits;
|
|
rp->r_bpbptr = bpbptrs;
|
|
rp->r_endaddr = device_end();
|
|
nblk_rel = nUnits; /* make device header reflect units */
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Read Write Sector Zero or Hard Drive Dos Bpb
|
|
*/
|
|
STATIC WORD RWzero(rqptr rp, WORD t)
|
|
{
|
|
REG retry = N_RETRY;
|
|
WORD head,track,sector,ret;
|
|
|
|
|
|
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
|
|
{
|
|
if (!t) /* 0 == Read */
|
|
{
|
|
ret = fl_read((WORD) miarray[rp->r_unit].mi_drive,
|
|
(WORD) head, (WORD) track, (WORD) sector, (WORD) 1, (byteptr) & buffer);
|
|
}
|
|
else
|
|
{
|
|
ret = fl_write((WORD) miarray[rp->r_unit].mi_drive,
|
|
(WORD) head, (WORD) track, (WORD) sector, (WORD) 1, (byteptr) & buffer);
|
|
}
|
|
}
|
|
while (ret != 0 && --retry > 0);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
0 if not set, 1 = a, 2 = b, etc, assume set.
|
|
page 424 MS Programmer's Ref.
|
|
*/
|
|
static WORD Getlogdev(rqptr rp)
|
|
{
|
|
BYTE x = rp->r_unit;
|
|
x++;
|
|
if( x > nblk_rel )
|
|
return failure(E_UNIT);
|
|
|
|
rp->r_unit = x;
|
|
return S_DONE;
|
|
}
|
|
|
|
static WORD Setlogdev(rqptr rp)
|
|
{
|
|
UNREFERENCED_PARAMETER(rp);
|
|
return S_DONE;
|
|
}
|
|
|
|
static WORD blk_Open(rqptr rp)
|
|
{
|
|
miarray[rp->r_unit].mi_FileOC++;
|
|
return S_DONE;
|
|
}
|
|
|
|
static WORD blk_Close(rqptr rp)
|
|
{
|
|
miarray[rp->r_unit].mi_FileOC--;
|
|
return S_DONE;
|
|
}
|
|
|
|
static WORD blk_nondr(rqptr rp)
|
|
{
|
|
UNREFERENCED_PARAMETER(rp);
|
|
return S_BUSY|S_DONE;
|
|
}
|
|
|
|
static WORD blk_Media(rqptr rp)
|
|
{
|
|
if (hd( miarray[rp->r_unit].mi_drive))
|
|
return S_BUSY|S_DONE; /* Hard Drive */
|
|
else
|
|
return S_DONE; /* Floppy */
|
|
}
|
|
|
|
STATIC WORD bldbpb(rqptr rp)
|
|
{
|
|
ULONG count, i;
|
|
byteptr trans;
|
|
WORD local_word;
|
|
/*TE*/
|
|
bpb *pbpbarray;
|
|
struct media_info *pmiarray;
|
|
WORD head,track,sector,ret;
|
|
|
|
ret = RWzero( rp, 0);
|
|
|
|
if (ret != 0)
|
|
return (dskerr(ret));
|
|
|
|
/*TE ~ 200 bytes*/
|
|
pbpbarray = getPBpbarray(rp->r_unit);
|
|
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NBYTE]), &pbpbarray->bpb_nbyte);
|
|
getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSECTOR]), &pbpbarray->bpb_nsector);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NRESERVED]), &pbpbarray->bpb_nreserved);
|
|
getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NFAT]), &pbpbarray->bpb_nfat);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NDIRENT]), &pbpbarray->bpb_ndirent);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSIZE]), &pbpbarray->bpb_nsize);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSIZE]), &pbpbarray->bpb_nsize);
|
|
getbyte(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_MDESC]), &pbpbarray->bpb_mdesc);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NFSECT]), &pbpbarray->bpb_nfsect);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NSECS]), &pbpbarray->bpb_nsecs);
|
|
getword(&((((BYTE *) & buffer.bytes[BT_BPB]))[BPB_NHEADS]), &pbpbarray->bpb_nheads);
|
|
getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HIDDEN])), &pbpbarray->bpb_hidden);
|
|
getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HUGE])), &pbpbarray->bpb_huge);
|
|
|
|
/* Needs fat32 offset code */
|
|
|
|
getlong(&((((BYTE *) & buffer.bytes[0x27])[0])), &fsarray[rp->r_unit].fs_serialno);
|
|
/*TE
|
|
for(i = 0; i < 11 ;i++ )
|
|
fsarray[rp->r_unit].fs_volume[i] = buffer.bytes[0x2B + i];
|
|
for(i = 0; i < 8; i++ )
|
|
fsarray[rp->r_unit].fs_fstype[i] = buffer.bytes[0x36 + i];
|
|
*/
|
|
memcpy(fsarray[rp->r_unit].fs_volume,&buffer.bytes[0x2B], 11);
|
|
memcpy(fsarray[rp->r_unit].fs_fstype,&buffer.bytes[0x36], 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
|
|
rp->r_bpptr = pbpbarray;
|
|
|
|
pmiarray = getPMiarray(rp->r_unit);
|
|
|
|
count = pmiarray->mi_size =
|
|
pbpbarray->bpb_nsize == 0 ?
|
|
pbpbarray->bpb_huge :
|
|
pbpbarray->bpb_nsize;
|
|
getword((&(((BYTE *) & buffer.bytes[BT_BPB])[BPB_NHEADS])), &pmiarray->mi_heads);
|
|
head = pmiarray->mi_heads;
|
|
getword((&(((BYTE *) & buffer.bytes[BT_BPB])[BPB_NSECS])), &pmiarray->mi_sectors);
|
|
if (pmiarray->mi_size == 0)
|
|
getlong(&((((BYTE *) & buffer.bytes[BT_BPB])[BPB_HUGE])), &pmiarray->mi_size);
|
|
sector = pmiarray->mi_sectors;
|
|
|
|
if (head == 0 || sector == 0)
|
|
{
|
|
tmark();
|
|
return failure(E_FAILURE);
|
|
}
|
|
pmiarray->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", pbpbarray->bpb_hidden);
|
|
printf("BPB_HUGE = %08lx\n", pbpbarray->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 IoctlQueblk(rqptr rp)
|
|
{
|
|
switch(rp->r_count){
|
|
case 0x0846:
|
|
case 0x0847:
|
|
case 0x0860:
|
|
case 0x0866:
|
|
case 0x0867:
|
|
break;
|
|
default:
|
|
return failure(E_CMD);
|
|
}
|
|
return S_DONE;
|
|
|
|
}
|
|
|
|
static WORD Genblkdev(rqptr rp)
|
|
{
|
|
int ret;
|
|
switch(rp->r_count){
|
|
case 0x0860: /* get device parameters */
|
|
{
|
|
struct gblkio FAR * gblp = (struct gblkio FAR *) rp->r_trans;
|
|
REG COUNT x = 5,y = 1,z = 0;
|
|
|
|
if (!hd(miarray[rp->r_unit].mi_drive)){
|
|
y = 2;
|
|
switch(miarray[rp->r_unit].mi_size)
|
|
{
|
|
case 640l:
|
|
case 720l: /* 320-360 */
|
|
x = 0;
|
|
z = 1;
|
|
break;
|
|
case 1440l: /* 720 */
|
|
x = 2;
|
|
break;
|
|
case 2400l: /* 1.2 */
|
|
x = 1;
|
|
break;
|
|
case 2880l: /* 1.44 */
|
|
x = 7;
|
|
break;
|
|
case 5760l: /* 2.88 almost forgot this one*/
|
|
x = 9;
|
|
break;
|
|
default:
|
|
x = 8; /* any odd ball drives return this */
|
|
}
|
|
}
|
|
gblp->gbio_devtype = (UBYTE) x;
|
|
gblp->gbio_devattrib = (UWORD) y;
|
|
gblp->gbio_media = (UBYTE) z;
|
|
gblp->gbio_ncyl = miarray[rp->r_unit].mi_cyls;
|
|
gblp->gbio_bpb = bpbarray[rp->r_unit];
|
|
gblp->gbio_nsecs = bpbarray[rp->r_unit].bpb_nsector;
|
|
break;
|
|
}
|
|
case 0x0866: /* get volume serial number */
|
|
{
|
|
struct Gioc_media FAR * gioc = (struct Gioc_media FAR *) rp->r_trans;
|
|
struct FS_info FAR * fs = &fsarray[rp->r_unit];
|
|
|
|
gioc->ioc_serialno = fs->fs_serialno;
|
|
fmemcpy(gioc->ioc_volume,fs->fs_volume,11);
|
|
fmemcpy(gioc->ioc_fstype, fs->fs_fstype,8);
|
|
}
|
|
break;
|
|
case 0x0846: /* set volume serial number */
|
|
{
|
|
struct Gioc_media FAR * gioc = (struct Gioc_media FAR *) rp->r_trans;
|
|
struct FS_info FAR * fs = (struct FS_info FAR *) &buffer.bytes[0x27];
|
|
|
|
ret = RWzero( rp, 0);
|
|
if (ret != 0)
|
|
return (dskerr(ret));
|
|
|
|
fs->fs_serialno = gioc->ioc_serialno;
|
|
fsarray[rp->r_unit].fs_serialno = fs->fs_serialno;
|
|
|
|
ret = RWzero( rp, 1);
|
|
if (ret != 0)
|
|
return (dskerr(ret));
|
|
}
|
|
break;
|
|
case 0x0867: /* get access flag, always on*/
|
|
{
|
|
struct Access_info FAR * ai = (struct Access_info FAR *) rp->r_trans;
|
|
ai->AI_Flag = 1;
|
|
}
|
|
break;
|
|
case 0x0847: /* set access flag, no real use*/
|
|
break;
|
|
default:
|
|
return failure(E_CMD);
|
|
}
|
|
return S_DONE;
|
|
}
|
|
|
|
WORD blockio(rqptr rp)
|
|
{
|
|
REG retry = N_RETRY,
|
|
remaining;
|
|
UWORD cmd,
|
|
total;
|
|
ULONG start;
|
|
byteptr trans;
|
|
WORD head,track,sector,ret,count;
|
|
|
|
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);
|
|
|
|
/*printf("dskAction %02x THS=%x-%x-%x block=%lx\n", rp->r_unit,track, head, sector, start);*/
|
|
|
|
|
|
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 && FP_SEG(trans) != 0xffff)
|
|
{
|
|
ret = action((WORD) miarray[rp->r_unit].mi_drive, head, track, sector,
|
|
count, trans);
|
|
}
|
|
else
|
|
{
|
|
count = 1;
|
|
/* buffer crosses DMA boundary, use scratchpad */
|
|
/* use scratchpad also, if going to HIGH memory */
|
|
|
|
if (cmd != C_INPUT)
|
|
fbcopy(trans, dma_scratch_buffer, SEC_SIZE);
|
|
ret = action((WORD) miarray[rp->r_unit].mi_drive, head, track, sector,
|
|
1, dma_scratch_buffer);
|
|
if (cmd == C_INPUT)
|
|
fbcopy(dma_scratch_buffer, 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 blk_noerr(rqptr rp)
|
|
{
|
|
UNREFERENCED_PARAMETER(rp);
|
|
return S_DONE;
|
|
}
|
|
|
|
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 */
|
|
/* */
|
|
COUNT ltop(WORD * trackp, WORD * sectorp, WORD * headp, COUNT unit, COUNT count, ULONG strt_sect, byteptr strt_addr)
|
|
{
|
|
#ifdef I86
|
|
UWORD utemp;
|
|
#endif
|
|
struct media_info *pmiarray;
|
|
|
|
|
|
#ifdef I86
|
|
/*TE*/
|
|
/* Adjust for segmented architecture */
|
|
utemp = (((UWORD) mk_segment(strt_addr) << 4) + mk_offset(strt_addr));
|
|
/* Test for 64K boundary crossing and return count large */
|
|
/* enough not to exceed the threshold. */
|
|
|
|
#define SEC_SHIFT 9 /* = 0x200 = 512 */
|
|
|
|
utemp >>= SEC_SHIFT;
|
|
|
|
if (count > (0xffff >> SEC_SHIFT) - utemp)
|
|
{
|
|
count = (0xffff >> SEC_SHIFT) - utemp;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*TE*/
|
|
pmiarray = getPMiarray(unit);
|
|
|
|
*trackp = strt_sect / (pmiarray->mi_heads * pmiarray->mi_sectors);
|
|
*sectorp = strt_sect % pmiarray->mi_sectors + 1;
|
|
*headp = (strt_sect % (pmiarray->mi_heads * pmiarray->mi_sectors))
|
|
/ pmiarray->mi_sectors;
|
|
if (*sectorp + count > pmiarray->mi_sectors + 1)
|
|
count = pmiarray->mi_sectors + 1 - *sectorp;
|
|
return count;
|
|
}
|
|
|