www.pudn.com > SmartFDISK.zip > harddrv.cpp


/**************************************************************************** 
 * 
 * Smart FDISK 
 * 
 * This program is a powerful Harddisk Partitioning Tool including a 
 * easy-to-use Boot Manager. 
 * 
 * 
 *     Copyright (C) 1999 Suzhe (suzhe@263.net) 
 * 
 * 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 2 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, write to the Free Software Foundation, 
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 * 
 ****************************************************************************/ 
/* 
 * harddrv.cpp : Source file for Class THardDrive 
 */ 
 
#define Uses_HardDrive 
#define Uses_DataType 
 
#include "Kernel.H" 
#include  
 
#define API_EXTCHECK		0x41 
#define API_EXTREAD			0x42 
#define API_EXTWRITE		0x43 
#define API_VERIFY			0x44 
#define API_EXTSEEK			0x47 
#define API_GETPARAM		0x48 
#define API_LOCK			0x45 
#define API_EJECT			0x46 
#define API_GETEXTCHGSTAT	0x49 
 
int32 THardDrive::ParamBufSelector=0; 
int32 THardDrive::ParamBufSeg=0; 
int32 THardDrive::ParamBufOff=0; 
 
int32 THardDrive::DataBufSelector=0; 
int32 THardDrive::DataBufSeg=0; 
int32 THardDrive::DataBufOff=0; 
int32 THardDrive::BufferUseCount=0; 
 
int32 THardDrive::AllocBuffers() 
{ 
	BufferUseCount ++; 
    if( ParamBufSeg == 0 ) 
    { 
    	ParamBufSeg = __dpmi_allocate_dos_memory( (MAXPARAMBUFSIZE+15)/16, & ParamBufSelector ); 
        ParamBufOff = 0; 
    } 
	if( ParamBufSeg == -1 ) 
    { 
    	ParamBufSeg = 0; 
        return 0x400;			//No Enough Memory 
    } 
 
    if( DataBufSeg == 0 ) 
    { 
		DataBufSeg = __dpmi_allocate_dos_memory( (MAXDATABUFSIZE+15)/16, & DataBufSelector ); 
        DataBufOff = 0; 
    } 
    if( DataBufSeg == -1 ) 
    { 
    	DataBufSeg = 0; 
        return 0x400; 
    } 
 
    return 0; 
} 
 
void THardDrive::FreeBuffers() 
{ 
    BufferUseCount --; 
    if( BufferUseCount > 0 ) return; 
 
    if( ParamBufSeg != 0 ) 
    { 
    	__dpmi_free_dos_memory( ParamBufSelector ); 
        ParamBufSeg = ParamBufSelector = 0; 
    } 
 
    if( DataBufSeg != 0 ) 
    { 
    	__dpmi_free_dos_memory( DataBufSelector ); 
        DataBufSelector = DataBufSeg = 0; 
    } 
} 
 
THardDrive::THardDrive() 
{ 
	PreInit(); 
} 
 
THardDrive::THardDrive( int32 dn ) 
{ 
	if( dn > MINDRIVENUM ) dn -= MINDRIVENUM; 
	Initialize(dn, True); 
} 
 
THardDrive::THardDrive( int32 dn ,Boolean UseInt13Ext) 
{ 
	if( dn > MINDRIVENUM ) dn -= MINDRIVENUM; 
	Initialize(dn, UseInt13Ext); 
} 
 
void THardDrive::PreInit() 
{ 
	DriveNumber				   =0; 
 
	DriveParam.InfoSize        = sizeof( TInt13ExtDriveParam ); 
	DriveParam.Flags           = 0; 
	DriveParam.Cylinders       = 0; 
	DriveParam.Heads           = 0; 
	DriveParam.SectorsPerTrack = 0; 
	DriveParam.Sectors         = 0; 
	DriveParam.SectorSize      = 0; 
 
	DiskGeometry.Cylinders      = 0; 
	DiskGeometry.Heads          = 0; 
	DiskGeometry.SectorsPerTrack= 0; 
 
	Useable                     = False; 
	Int13ExtPresent             = False; 
	UseInt13Ext					= False; 
 
} 
 
void THardDrive::ShutDown() 
{ 
	if( IsUseable() && IsLockable() ) 
	{ 
		Unlock(); 
	} 
	PreInit(); 
    FreeBuffers(); 
} 
 
Boolean THardDrive::CheckInt13Ext() 
{ 
	__dpmi_regs regs; 
 
	regs.h.ah = API_EXTCHECK; 
	regs.x.bx = 0x55aa; 
	regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
 
	__dpmi_int(0x13,®s); 
 
	if( (regs.x.flags & 0x01) !=0 || regs.x.bx!=0xaa55 || (regs.x.cx & 0x01) == 0) 
		return False; 
 
	return True; 
} 
 
int32 THardDrive::Initialize( int32 dn, Boolean UseExt ) 
{ 
	DWORD temp; 
    int32 errno; 
	__dpmi_regs regs; 
 
	PreInit(); 
 
	if( dn< 0 ) return 0x101; 
 
    if( (errno = AllocBuffers()) !=0 ) 
    	return errno; 
 
	UseInt13Ext = UseExt; 
 
	DriveNumber = dn + MINDRIVENUM; 
	Int13ExtPresent = CheckInt13Ext(); 
 
	ResetDrive(); 
 
	if( Int13ExtPresent && UseInt13Ext ) 
	{ 
		regs.h.ah = API_GETPARAM; 
		regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
		regs.x.si = ParamBufOff; 
		regs.x.ds = ParamBufSeg; 
		__dpmi_int( 0x13, ®s ); 
 
		dosmemget( ParamBufSeg * 16 + ParamBufOff, sizeof( DriveParam ), &DriveParam ); 
 
		if( (regs.x.flags & 0x01) != 0 ) 
			return (int32) regs.h.ah; 
		else 
		{ 
			Useable=True; 
			DetectLBAGeometry( DiskGeometry ); 
		} 
	} 
	else 
	{ 
		regs.h.ah=0x08; 
		regs.h.dl=DriveNumber; 
		__dpmi_int(0x13, ®s); 
		if( (regs.x.flags & 0x01) != 0 ) return regs.h.ah; 
		else 
		{ 
			Useable=True; 
			DiskGeometry.SectorsPerTrack 	= regs.h.cl & 0x3f; 
			DiskGeometry.Heads 			 	= regs.h.dh+1; 
			DiskGeometry.Cylinders			= ((WORD)regs.h.ch | 
											  ( ((WORD)regs.h.cl)<<2) & 0x300 ) + 1; 
			DiskGeometry.SectorsPerCylinder	= DiskGeometry.Heads * 
											  DiskGeometry.SectorsPerTrack; 
			DriveParam.Flags			= CHSINFOVALID; 
			DriveParam.Cylinders		= DiskGeometry.Cylinders; 
			DriveParam.Heads			= DiskGeometry.Heads; 
			DriveParam.SectorsPerTrack	= DiskGeometry.SectorsPerTrack; 
			DriveParam.Sectors			= (QWORD)DriveParam.Cylinders * 
										  (QWORD)DriveParam.Heads * 
										  (QWORD)DriveParam.SectorsPerTrack; 
			DriveParam.SectorSize		= DEFSECTORSIZE; 
		} 
	} 
	temp = 1048576uL / DriveParam.SectorSize; 
	SizeInMega = DriveParam.Sectors / temp; 
	if( DriveParam.Sectors % temp >= temp / 2 ) 
		SizeInMega ++; 
	if( IsLockable() ) Lock(); 
	return 0; 
} 
 
int32 THardDrive::Read( QWORD BlockNum, WORD BlockCount, void * Buffer ) 
{ 
	TInt13ExtData ReadParam; 
	__dpmi_regs regs; 
	int32 errno; 
	int i; 
 
	if( Buffer==NULL ) return 0x401; 
	if( !Useable ) return 0x102; 
    if( BlockCount * DriveParam.SectorSize > 32768u ) return 0x01; 
 
	if( !Int13ExtPresent || !UseInt13Ext ) 
	{ 
		for( i=0; i<2; i++ ) 
		{ 
			if( (errno=OldRead( (DWORD) BlockNum, BlockCount, Buffer )) == 0 ) 
				return 0; 
			ResetDrive(); 
		} 
		return errno; 
	} 
 
	for( i=0; i<2; i++ ) 
	{ 
		ReadParam.PackageSize = sizeof( TInt13ExtData ); 
		ReadParam.Reserved    = 0; 
		ReadParam.BlockCount  = BlockCount; 
		ReadParam.BufferAddr  = ( (((DWORD) DataBufSeg) << (sizeof(WORD) * 8) ) & 0xffff0000 ) | 
								( ( (DWORD) DataBufOff ) & 0x0000ffff ); 
		ReadParam.BlockNum    = BlockNum; 
 
		regs.h.ah = API_EXTREAD; 
		regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
		regs.x.si = ParamBufOff; 
		regs.x.ds = ParamBufSeg; 
 
        dosmemput( &ReadParam, sizeof(ReadParam), ParamBufSeg * 16 + ParamBufOff ); 
 
		__dpmi_int( 0x13, ®s ); 
 
		if( (regs.x.flags & 0x01) == 0 ) 
		{ 
			BlockCount = ReadParam.BlockCount; 
            dosmemget( DataBufSeg * 16 + DataBufOff, BlockCount * DriveParam.SectorSize, Buffer ); 
			return 0; 
		} 
		ResetDrive(); 
	} 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::Write( QWORD BlockNum, WORD BlockCount, void * Buffer ) 
{ 
 
	TInt13ExtData WriteParam; 
	__dpmi_regs regs; 
	int32 errno; 
	int i; 
 
	if( Buffer==NULL ) return 0x401; 
	if( !Useable ) return 0x102; 
    if( BlockCount * DriveParam.SectorSize > 32768u ) return 0x01; 
 
	if( !Int13ExtPresent || !UseInt13Ext ) 
	{ 
		for( i=0; i<2; i++ ) 
		{ 
			if( (errno=OldWrite( (DWORD)BlockNum, BlockCount, Buffer )) == 0 ) 
				return 0; 
			ResetDrive(); 
		} 
		return errno; 
	} 
 
	dosmemput( Buffer, BlockCount * DriveParam.SectorSize, DataBufSeg * 16 + DataBufOff ); 
	for( i=0; i<2; i++ ) 
	{ 
		WriteParam.PackageSize = sizeof( TInt13ExtData ); 
		WriteParam.Reserved    = 0; 
		WriteParam.BlockCount  = BlockCount; 
		WriteParam.BufferAddr  =( (((DWORD) DataBufSeg) << (sizeof(WORD) * 8) ) & 0xffff0000 ) | 
								( ( (DWORD) DataBufOff ) & 0x0000ffff ); 
		WriteParam.BlockNum    = BlockNum; 
 
		regs.h.ah = API_EXTWRITE; 
		regs.h.al = (( DriveParam.Flags & WRITEVERIFYOK ) == 0) ? 0 : 1; 
		regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
		regs.x.si = ParamBufOff; 
		regs.x.ds = ParamBufSeg; 
 
        dosmemput( &WriteParam, sizeof(WriteParam), ParamBufSeg * 16 + ParamBufOff ); 
 
		__dpmi_int( 0x13, ®s ); 
 
		if( ( regs.x.flags & 0x01 ) == 0 ) 
		{ 
			BlockCount = WriteParam.BlockCount; 
			return 0; 
		} 
		ResetDrive(); 
	} 
	return (int32) regs.h.ah; 
 
} 
 
int32 THardDrive::Verify( QWORD BlockNum, WORD BlockCount ) 
{ 
	TInt13ExtData VerifyParam; 
	__dpmi_regs regs; 
	int32 errno; 
	int i; 
 
	if( !Useable ) return 0x102; 
 
	if( !Int13ExtPresent || !UseInt13Ext ) 
	{ 
		for( i=0; i<2; i++ ) 
		{ 
			if( (errno=OldVerify( (DWORD) BlockNum, BlockCount )) == 0 ) 
				return 0; 
			ResetDrive(); 
		} 
		return errno; 
	} 
 
	for( i=0; i<2; i++ ) 
	{ 
		VerifyParam.PackageSize = sizeof( TInt13ExtData ); 
		VerifyParam.Reserved    = 0; 
		VerifyParam.BlockCount  = BlockCount; 
		VerifyParam.BufferAddr  = 0; 
		VerifyParam.BlockNum    = BlockNum; 
 
		regs.h.ah = API_VERIFY; 
		regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
		regs.x.si = ParamBufOff; 
		regs.x.ds = ParamBufSeg; 
 
        dosmemput( &VerifyParam, sizeof(VerifyParam), ParamBufSeg * 16 + ParamBufOff ); 
 
		__dpmi_int( 0x13, ®s ); 
 
		if( ( regs.x.flags & 0x01 ) == 0 ) 
		{ 
			BlockCount = VerifyParam.BlockCount; 
			return 0; 
		} 
		ResetDrive(); 
	} 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::Seek( QWORD BlockNum ) 
{ 
	TInt13ExtData SeekParam; 
	__dpmi_regs regs; 
 
	if( !Useable ) return 0x102; 
	if( !Int13ExtPresent ) return 0x100; 
 
	for( int i=0; i<2; i++ ) 
	{ 
		SeekParam.PackageSize = sizeof( TInt13ExtData ); 
		SeekParam.Reserved    = 0; 
		SeekParam.BlockCount  = 0; 
		SeekParam.BufferAddr  = 0; 
		SeekParam.BlockNum    = BlockNum; 
 
		regs.h.ah = API_EXTSEEK; 
		regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
		regs.x.si = ParamBufOff; 
		regs.x.ds = ParamBufSeg; 
 
        dosmemput( &SeekParam, sizeof(SeekParam), ParamBufSeg * 16 + ParamBufOff ); 
 
		__dpmi_int( 0x13, ®s ); 
		if( ( regs.x.flags & 0x01 ) == 0 ) 
			return 0; 
		ResetDrive(); 
	} 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::Lock() 
{ 
	__dpmi_regs regs; 
 
	if( !IsLockable() ) return 0x103; 
	if( !Int13ExtPresent ) return 0x100; 
 
	regs.h.ah = API_LOCK; 
	regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
	regs.h.al = 0; 
 
	__dpmi_int( 0x13, ®s ); 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::Unlock() 
{ 
	__dpmi_regs regs; 
 
	if( !IsLockable() ) return 0x103; 
	if( !Int13ExtPresent ) return 0x100; 
 
	regs.h.ah = API_LOCK; 
	regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
	regs.h.al = 1; 
 
	__dpmi_int( 0x13, ®s ); 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::GetLockStatus(int32 & status) 
{ 
	__dpmi_regs regs; 
 
	if( !IsLockable() ) return 0x103; 
	if( !Int13ExtPresent ) return 0x100; 
 
	regs.h.ah = API_LOCK; 
	regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
	regs.h.al = 2; 
 
	__dpmi_int( 0x13, ®s ); 
	status = regs.h.al; 
 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::Eject() 
{ 
	__dpmi_regs regs; 
 
	if( !IsRemovable() ) return 0x104; 
	if( !Int13ExtPresent ) return 0x100; 
 
	regs.h.ah = API_EJECT; 
	regs.h.dl = (BYTE) (DriveNumber & 0x00ff); 
	regs.h.al = 0; 
 
	__dpmi_int( 0x13, ®s ); 
	return (int32) regs.h.ah; 
} 
 
int32 THardDrive::GetDriveParam( TInt13ExtDriveParam & dp ) 
{ 
	if( !Useable ) return 0x102; 
	else 
	{ 
		dp = DriveParam; 
		return 0; 
	} 
} 
 
int32 THardDrive::GetGeometry( TDiskGeometry & Geometry ) 
{ 
	if( !Useable ) return 0x102; 
	else 
	{ 
		Geometry = DiskGeometry; 
		return 0; 
	} 
} 
 
int32 THardDrive::SetGeometry( TDiskGeometry & Geometry ) 
{ 
	if( !Useable ) return 0x102; 
	if( Geometry.Cylinders == 0 || 
		Geometry.Heads == 0 || 
		Geometry.SectorsPerTrack == 0 ) 
		return 1; 
	DiskGeometry = Geometry; 
	return 0; 
} 
 
int32 THardDrive::DetectLBAGeometry( TDiskGeometry & Geometry ) 
{ 
	__dpmi_regs regs; 
	if( !Useable ) return 0x102; 
 
	regs.h.ah=0x08; 
	regs.h.dl=DriveNumber; 
 
	__dpmi_int(0x13, ®s); 
 
	if( ( regs.x.flags & 0x01 )!=0 ) return regs.h.ah; 
	else 
	{ 
		Geometry.SectorsPerTrack = regs.h.cl & 0x3f; 
		Geometry.Heads = regs.h.dh+1; 
		Geometry.Cylinders = 
			DriveParam.Sectors / ( Geometry.SectorsPerTrack * Geometry.Heads ); 
		Geometry.SectorsPerCylinder = Geometry.SectorsPerTrack * Geometry.Heads; 
		return 0; 
	} 
} 
 
int32 THardDrive::LBAtoCHS 
	( QWORD BlockNum, WORD & cylinder, WORD & head, WORD & sector ) 
{ 
	if( DiskGeometry.Cylinders == 0 || 
		DiskGeometry.Heads == 0 || 
		DiskGeometry.SectorsPerTrack == 0 ) 
		return 0x102; 
 
	cylinder = BlockNum / DiskGeometry.SectorsPerCylinder; 
	BlockNum %= DiskGeometry.SectorsPerCylinder; 
	head = BlockNum / DiskGeometry.SectorsPerTrack; 
	BlockNum %= DiskGeometry.SectorsPerTrack; 
	sector = BlockNum + 1; 
	return 0; 
} 
 
int32 THardDrive::CHStoLBA 
	( WORD cylinder, WORD head, WORD sector, QWORD & BlockNum ) 
{ 
	if( DiskGeometry.Cylinders == 0 || 
		DiskGeometry.Heads == 0 || 
		DiskGeometry.SectorsPerTrack == 0 ) 
		return 0x102; 
 
	BlockNum = ( ((QWORD)cylinder) * ((QWORD)DiskGeometry.Heads) + 
			   ((QWORD)head) ) * ((QWORD)DiskGeometry.SectorsPerTrack) + 
			   (QWORD)sector - 1L; 
	return 0; 
} 
 
 
int32 THardDrive::OldBiosDisk(int cmd, int drive, int head, int track, 
	int sector, int nsects, void *buffer) 
{ 
	int32 seg=0, before=0, xfer = 0; 
	__dpmi_regs r; 
 
    if( DataBufSeg == 0 ) return 0x400; 
 
	switch (cmd) 
	{ 
		case 2: 
			xfer = DriveParam.SectorSize * nsects; 
			before = 0; 
			break; 
		case 3: 
			xfer = DriveParam.SectorSize * nsects; 
			before = 1; 
			break; 
		case 5: 
			xfer = 2 * 256; 
			before = 1; 
			break; 
		case 0x0a: 
			xfer = (DriveParam.SectorSize+7) * nsects; 
			before = 0; 
			break; 
		case 0x0b: 
			xfer = (DriveParam.SectorSize+7) * nsects; 
			before = 1; 
			break; 
		case 0x0e: 
			xfer = DriveParam.SectorSize; 
			before = 0; 
			break; 
		case 0x0f: 
			xfer = DriveParam.SectorSize; 
		    before = 1; 
			break; 
	} 
 
	r.h.ah = cmd; 
	r.h.al = nsects; 
	r.x.es = DataBufSeg; 
	r.x.bx = DataBufOff; 
	r.h.ch = track & 0xff; 
	r.h.cl = sector | ((track >> 2) & 0xc0); 
	r.h.dh = head; 
	r.h.dl = drive; 
 
    if (xfer && before) 
    dosmemput(buffer, xfer, DataBufSeg * 16 + DataBufOff); 
 
    __dpmi_int(0x13, &r); 
 
    if (xfer && !before) 
    dosmemget(DataBufSeg * 16 + DataBufOff, xfer, buffer); 
 
    if (cmd == 0x08) 
	{ 
	    ((short *)buffer)[0] = r.x.cx; 
    	((short *)buffer)[1] = r.x.dx; 
	} 
	return r.h.ah; 
} 
 
 
 
int32 THardDrive::OldRead  ( DWORD BlockNum, WORD BlockCount, void * Buffer ) 
{ 
	WORD cylinder, sector, head; 
	WORD toRead,addr; 
 
	int32 errno; 
	if( (errno=LBAtoCHS( BlockNum, cylinder, head, sector ))!=0 ) 
		return errno; 
	addr = 0; 
	while( BlockCount > 0 ) 
	{ 
		toRead = ((DiskGeometry.SectorsPerTrack - sector +1) > BlockCount)? 
				BlockCount:(DiskGeometry.SectorsPerTrack - sector +1); 
		if( (errno= OldBiosDisk( 2, DriveNumber, head,	cylinder, sector, toRead, 
			((char*)Buffer) + addr * GetSectorSize()) )  != 0 ) 
			return errno; 
 
		BlockCount -= toRead; 
		addr +=toRead; 
		sector += toRead; 
		if( sector > DiskGeometry.SectorsPerTrack ) 
		{ 
			head++; 
			sector -= DiskGeometry.SectorsPerTrack; 
		} 
		if( head >= DiskGeometry.Heads ) 
		{ 
			cylinder++; 
			head -= DiskGeometry.Heads; 
		} 
	} 
	return 0; 
} 
 
int32 THardDrive::OldWrite ( DWORD BlockNum, WORD BlockCount, void * Buffer ) 
{ 
	WORD cylinder, sector, head; 
	WORD toWrite,addr; 
 
	int32 errno; 
	if( (errno=LBAtoCHS( BlockNum, cylinder, head, sector ))!=0 ) 
		return errno; 
	addr = 0; 
	while( BlockCount > 0 ) 
	{ 
		toWrite = ((DiskGeometry.SectorsPerTrack - sector +1) > BlockCount)? 
				BlockCount:(DiskGeometry.SectorsPerTrack - sector +1); 
		if( (errno= OldBiosDisk( 3, DriveNumber, head,	cylinder, sector, toWrite, 
			((char*)Buffer) + addr * GetSectorSize()) ) != 0 ) 
			return errno; 
 
		BlockCount -= toWrite; 
		addr +=toWrite; 
		sector += toWrite; 
		if( sector > DiskGeometry.SectorsPerTrack ) 
		{ 
			head++; 
			sector -= DiskGeometry.SectorsPerTrack; 
		} 
		if( head >= DiskGeometry.Heads ) 
		{ 
			cylinder++; 
			head -= DiskGeometry.Heads; 
		} 
	} 
	return 0; 
} 
 
int32 THardDrive::OldVerify( DWORD BlockNum, WORD BlockCount ) 
{ 
	WORD cylinder, sector, head; 
	WORD toVerify,addr; 
 
	int32 errno; 
	if( (errno=LBAtoCHS( BlockNum, cylinder, head, sector ))!=0 ) 
		return errno; 
	addr = 0; 
	while( BlockCount > 0 ) 
	{ 
		toVerify = ((DiskGeometry.SectorsPerTrack - sector +1) > BlockCount)? 
				BlockCount:(DiskGeometry.SectorsPerTrack - sector +1); 
		if( (errno= OldBiosDisk( 4, DriveNumber, head,	cylinder, sector, toVerify, 
			NULL) ) != 0 ) 
			return errno; 
		BlockCount -= toVerify; 
		addr +=toVerify; 
		sector += toVerify; 
		if( sector > DiskGeometry.SectorsPerTrack ) 
		{ 
			head++; 
			sector -= DiskGeometry.SectorsPerTrack; 
		} 
		if( head >= DiskGeometry.Heads ) 
		{ 
			cylinder++; 
			head -= DiskGeometry.Heads; 
		} 
	} 
	return 0; 
} 
 
int32 GetHDNumber(void) 
{ 
    WORD number1, number2; 
 
	__dpmi_regs regs; 
	regs.h.ah=0x08; 
	regs.h.dl=MINDRIVENUM; 
	__dpmi_int(0x13,®s); 
	if( ( regs.x.flags & 0x01 ) != 0 ) 
		number1=0; 
	else 
		number1=(WORD) regs.h.dl; 
 
    number2=0; 
    for( int i=0; i< 32; i++ ) 
    { 
        regs.h.ah=0x15; 
        regs.h.dl=MINDRIVENUM+i; 
        __dpmi_int(0x13,®s); 
        if( ( regs.x.flags & 0x01) != 0 || regs.h.ah == 0 ) 
        	break; 
        number2++; 
    } 
 
    return ( number2 > number1 ) ? number2 : number1; 
} 
 
void THardDrive::ResetDrive() 
{ 
	__dpmi_regs regs; 
	regs.h.ah = 0; 
	regs.h.dl = DriveNumber; 
	__dpmi_int( 0x13, ®s ); 
}