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 ); }