windows-nt/Source/XPSP1/NT/base/mvdm/dos/dem/demioctl.c
2020-09-26 16:20:57 +08:00

621 lines
15 KiB
C

/* demioctl.c - SVC handlers for DOS IOCTL calls
*
* demIOCTL
*
* Modification History:
*
* Sudeepb 23-Apr-1991 Created
*
*/
#include "dem.h"
#include "demmsg.h"
#include <softpc.h>
#include <winbase.h>
#include "demdasd.h"
PFNSVC apfnSVCIoctl [] = {
demIoctlInvalid, // IOCTL_GET_DEVICE_INFO 0
demIoctlInvalid, // IOCTL_SET_DEVICE_INFO 1
demIoctlInvalid, // IOCTL_READ_HANDLE 2
demIoctlInvalid, // IOCTL_WRITE_HANDLE 3
demIoctlInvalid, // IOCTL_READ_DRIVE 4
demIoctlInvalid, // IOCTL_WRITE_DRIVE 5
demIoctlInvalid, // IOCTL_GET_INPUT_STATUS 6
demIoctlInvalid, // IOCTL_GET_OUTPUT_STATUS 7
demIoctlChangeable, // IOCTL_CHANGEABLE 8
demIoctlChangeable, // IOCTL_DeviceLocOrRem 9
demIoctlInvalid, // IOCTL_HandleLocOrRem a
demIoctlInvalid, // IOCTL_SHARING_RETRY b
demIoctlInvalid, // GENERIC_IOCTL_HANDLE c
demIoctlDiskGeneric, // GENERIC_IOCTL d
demIoctlInvalid, // IOCTL_GET_DRIVE_MAP e
demIoctlInvalid, // IOCTL_SET_DRIVE_MAP f
demIoctlInvalid, // IOCTL_QUERY_HANDLE 10
demIoctlDiskQuery, // IOCTL_QUERY_BLOCK 11
demIoctlInvalid
};
MEDIA_TYPE MediaForFormat;
#define MAX_IOCTL_INDEX (sizeof (apfnSVCIoctl) / sizeof (PFNSVC))
/* demIOCTL - DOS IOCTLS
*
*
* Entry - depends on the subfunction. See dos\ioctl.asm
*
* Exit
* SUCCESS
* Client (CY) = 0
* for other registers see the corresponding function header
*
* FAILURE
* Client (CY) = 1
* for other registers see the corresponding function header
*/
VOID demIOCTL (VOID)
{
ULONG iIoctl;
iIoctl = (ULONG) getAL();
#if DBG
if (iIoctl >= MAX_IOCTL_INDEX){
setAX((USHORT) ERROR_INVALID_FUNCTION);
setCF(1);
return;
}
#endif
(apfnSVCIoctl [iIoctl])();
return;
}
/* demIoctlChangeable - Is drive removeable (subfunc 8) or remote (subfunc 9)
*
*
* Entry - Client (AL) - subfunc
* Client (BL) - drive number (a=0,b=1 etc)
*
* Exit
* SUCCESS
* Client (CY) = 0
* if subfunc 8
* AX = 0 if removeable media
* AX = 1 otherwise
* if subfunc 9
* DX = 0 if not remote
* DX = 1000 if remote
*
* FAILURE
* Client (CY) = 1
* Client (AX) = error code
*
* CDROM drives are considered remote drives with write protection
* by dos. (full support requires a VDD)
*/
VOID demIoctlChangeable (VOID)
{
ULONG ulSubFunc;
CHAR RootPathName[] = "?:\\";
DWORD DriveType;
UCHAR DriveNum;
ulSubFunc = getAL();
// Form Root path
DriveNum = getBL();
DriveType = demGetPhysicalDriveType(DriveNum);
if (DriveType == DRIVE_UNKNOWN) {
RootPathName[0] = (CHAR)('A' + DriveNum);
DriveType = GetDriveTypeOem(RootPathName);
}
if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){
setAX (ERROR_INVALID_DRIVE);
setCF(1);
return;
}
if (ulSubFunc == IOCTL_CHANGEABLE){
#ifdef JAPAN
/* For MS-WORKS 2.5 */
if (DriveType == DRIVE_REMOTE || DriveType == DRIVE_CDROM){
setCF(1);
setAX(0x000f);
return;
}
#endif // JAPAN
if(DriveType == DRIVE_REMOVABLE)
setAX(0);
else
setAX(1); // includes CDROM drives
}
else {
setAL(0);
if (DriveType == DRIVE_REMOTE || DriveType == DRIVE_CDROM)
#ifdef JAPAN
/* For ICHITARO Ver.4 */
setDH(0x10);
else
setDH(0);
#else // !JAPAN
setDX(0x1000);
else
// We have to return 800 rather then 0 as Dos Based Quatrro pro
// behaves very badly if this bit is not set. sudeepb 15-Jun-1994
setDX(0x800);
#endif // !JAPAN
}
setCF(0);
return;
}
/* demIoctlDiskGeneric - Block device generic ioctl
*
*
* Entry - Client (BL) = drive number (a=0;b=1 etc)
* (CL) = subfucntion code
* (SI:DX) pointer to parameter block.
* Exit
* SUCCESS
* Client (CY) = 0
* (AX) = 0
* parameter block updated
* FAILURE
* Client (CY) = 1
* (AX) = error code
*/
VOID demIoctlDiskGeneric (VOID)
{
BYTE Code, Drive;
PDEVICE_PARAMETERS pdms;
PMID pmid;
PRW_BLOCK pRW;
PFMT_BLOCK pfmt;
PBDS pbds;
DWORD Head, Cylinder;
DWORD TrackSize;
DWORD Sectors, StartSector;
BYTE BootSector[BYTES_PER_SECTOR];
PBOOTSECTOR pbs;
PBPB pBPB;
PACCESSCTRL pAccessCtrl;
WORD SectorSize, ClusterSize, TotalClusters, FreeClusters;
Code = getCL();
Drive = getBL();
if (Code == IOCTL_GETMEDIA) {
pmid = (PMID) GetVDMAddr(getSI(), getDX());
if (!GetMediaId(Drive, (PVOLINFO)pmid)) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
}
else {
setAX(0);
setCF(0);
}
return;
}
#ifdef JAPAN
/* For Ichitaro Ver.4 */
if (!demIsDriveFloppy(Drive) && Code==IOCTL_GETDPM){
CHAR RootPathName[] = "?:\\";
DWORD dwDriveType;
RootPathName[0] = (CHAR)('A' + getBL());
dwDriveType = GetDriveTypeOem(RootPathName);
if (dwDriveType == DRIVE_FIXED){
pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
pdms->DeviceType = 5;
pdms->DeviceAttrs = NON_REMOVABLE;
}
}
#endif // JAPAN
// if we don't know the drive, bail out
if((pbds = demGetBDS(Drive)) == NULL && Code != IOCTL_GETDPM) {
#if defined(NEC_98)
setAX(DOS_FILE_NOT_FOUND);
#else // !NEC_98
if (!demIsDriveFloppy(Drive))
host_direct_access_error(NOSUPPORT_HARDDISK);
setAX(DOS_FILE_NOT_FOUND);
#endif // !NEC_98
setCF(1);
return;
}
switch (Code) {
case IOCTL_SETDPM:
pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
if (!(pdms->Functions & ONLY_SET_TRACKLAYOUT)) {
pbds->FormFactor = pdms->DeviceType;
pbds->Cylinders = pdms->Cylinders;
pbds->Flags = pdms->DeviceAttrs;
pbds->MediaType = pdms->MediaType;
if (pdms->Functions & INSTALL_FAKE_BPB) {
pbds->Flags |= RETURN_FAKE_BPB;
pbds->bpb = pdms->bpb;
// update the total sectors, we need it
// for verification
pbds->TotalSectors = (pbds->bpb.Sectors) ?
pbds->bpb.Sectors :
pbds->bpb.BigSectors;
}
else {
pbds->Flags &= ~RETURN_FAKE_BPB;
pbds->rbpb = pdms->bpb;
}
}
MediaForFormat = Unknown;
if (!(pbds->Flags & NON_REMOVABLE)){
nt_floppy_close(pbds->DrivePhys);
}
else {
nt_fdisk_close(pbds->DrivePhys);
}
break;
case IOCTL_WRITETRACK:
pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX());
Sectors = pRW->Sectors;
StartSector = pRW->StartSector;
StartSector += pbds->bpb.TrackSize *
(pRW->Cylinder * pbds->bpb.Heads + pRW->Head);
Sectors = demDasdWrite(pbds,
StartSector,
Sectors,
pRW->BufferOff,
pRW->BufferSeg
);
if (Sectors != pRW->Sectors) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
break;
case IOCTL_FORMATTRACK:
pfmt = (PFMT_BLOCK)GetVDMAddr(getSI(), getDX());
Head = pfmt->Head;
Cylinder = pfmt->Cylinder;
if ((pbds->Flags & NON_REMOVABLE) &&
pfmt->Head < pbds->bpb.Heads &&
pfmt->Cylinder < pbds->Cylinders)
{
if (pfmt->Functions == STATUS_FOR_FORMAT){
pfmt->Functions = 0;
setCF(0);
return;
}
if (!demDasdFormat(pbds, Head, Cylinder, NULL)) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
}
else {
if (MediaForFormat == Unknown) {
demDasdFormat(pbds,
Head,
Cylinder,
&MediaForFormat
);
}
if (pfmt->Functions & STATUS_FOR_FORMAT){
if (MediaForFormat == Unknown)
pfmt->Functions = 2; // illegal combination
else
pfmt->Functions = 0;
break;
}
if (MediaForFormat == Unknown ||
!demDasdFormat(pbds, Head, Cylinder, &MediaForFormat)) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
}
break;
case IOCTL_SETMEDIA:
pmid = (PMID) GetVDMAddr(getSI(), getDX());
if (pbds->Flags & NON_REMOVABLE) {
Sectors = nt_fdisk_read(pbds->DrivePhys,
0,
BYTES_PER_SECTOR,
BootSector
);
}
else {
if (demGetBPB(pbds))
Sectors = nt_floppy_read(pbds->DrivePhys,
0,
BYTES_PER_SECTOR,
BootSector
);
else
Sectors = 0;
}
pbs = (PBOOTSECTOR) BootSector;
if (Sectors != BYTES_PER_SECTOR ||
pbs->ExtBootSig != EXT_BOOTSECT_SIG)
{
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
pbs->SerialNum = pmid->SerialNum;
pbs->Label = pmid->Label;
pbs->FileSysType = pmid->FileSysType;
if (pbds->Flags & NON_REMOVABLE) {
Sectors = nt_fdisk_write(pbds->DrivePhys,
0,
BYTES_PER_SECTOR,
(PBYTE)pbs
);
nt_fdisk_close(pbds->DrivePhys);
}
else {
Sectors = nt_floppy_write(pbds->DrivePhys,
0,
BYTES_PER_SECTOR,
(PBYTE) pbs
);
nt_floppy_close(pbds->DrivePhys);
}
if (Sectors != BYTES_PER_SECTOR) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
break;
// ioctl get device parameters
case IOCTL_GETDPM:
pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
// if we couldn't find the bds, fake one
if (pbds == NULL) {
HANDLE hVolume;
CHAR achRoot[]="\\\\.\\?:";
DISK_GEOMETRY DiskGM;
DWORD SizeReturned;
if (!demGetDiskFreeSpace(Drive,
&SectorSize,
&ClusterSize,
&TotalClusters,
&FreeClusters
)){
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
achRoot[4] = Drive + 'A';
hVolume = CreateFileA(achRoot,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hVolume == INVALID_HANDLE_VALUE) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
if (!DeviceIoControl(hVolume,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGM,
sizeof(DISK_GEOMETRY),
&SizeReturned,
NULL
)) {
CloseHandle(hVolume);
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
CloseHandle(hVolume);
Sectors = DiskGM.Cylinders.LowPart *
DiskGM.TracksPerCylinder *
DiskGM.SectorsPerTrack;
pdms->DeviceType = FF_FDISK;
pdms->DeviceAttrs = NON_REMOVABLE;
pdms->MediaType = 0;
pdms->bpb.SectorSize = SectorSize;
pdms->bpb.ClusterSize = (BYTE) ClusterSize;
pdms->bpb.ReservedSectors = 1;
pdms->bpb.FATs = 2;
pdms->bpb.RootDirs = (Sectors > 32680) ? 512 : 64;
pdms->bpb.MediaID = 0xF8;
pdms->bpb.TrackSize = (WORD) DiskGM.SectorsPerTrack;
pdms->bpb.Heads = (WORD) DiskGM.TracksPerCylinder;
pdms->Cylinders = (WORD) DiskGM.Cylinders.LowPart;
if (Sectors >= 40000) {
TrackSize = 256 * ClusterSize + 2;
pdms->bpb.FATSize = (WORD) ((Sectors - pdms->bpb.ReservedSectors
- pdms->bpb.RootDirs * 32 / 512 +
TrackSize - 1 ) / TrackSize);
}
else {
pdms->bpb.FATSize = (WORD) (((Sectors / ClusterSize) * 3 / 2) /
512 + 1);
}
pdms->bpb.HiddenSectors = Sectors;
Sectors = TotalClusters * ClusterSize;
if (Sectors >= 0x10000) {
pdms->bpb.Sectors = 0;
pdms->bpb.BigSectors = Sectors;
}
else {
pdms->bpb.Sectors = (WORD) Sectors;
pdms->bpb.BigSectors = 0;
}
pdms->bpb.HiddenSectors -= Sectors;
break;
}
pdms->DeviceType = pbds->FormFactor;
pdms->DeviceAttrs = pbds->Flags & ~(HAS_CHANGELINE);
pdms->Cylinders = pbds->Cylinders;
pdms->MediaType = 0;
if (pdms->Functions & BUILD_DEVICE_BPB){
if (!(pbds->Flags & NON_REMOVABLE) &&
!demGetBPB(pbds)) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
pBPB = &pbds->bpb;
}
else
// copy recommended bpb
pBPB = &pbds->rbpb;
pdms->bpb = *pBPB;
break;
case IOCTL_READTRACK:
pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX());
Sectors = pRW->Sectors;
StartSector = pRW->StartSector;
StartSector += pbds->bpb.TrackSize *
(pRW->Cylinder * pbds->bpb.Heads + pRW->Head);
Sectors = demDasdRead(pbds,
StartSector,
Sectors,
pRW->BufferOff,
pRW->BufferSeg
);
if (Sectors != pRW->Sectors) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
break;
case IOCTL_VERIFYTRACK:
pfmt = (PFMT_BLOCK) GetVDMAddr(getSI(), getDX());
if(!demDasdVerify(pbds, pfmt->Head, pfmt->Cylinder)) {
setAX(demWinErrorToDosError(GetLastError()));
setCF(1);
return;
}
break;
case IOCTL_GETACCESS:
pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX());
pAccessCtrl->AccessFlag = (pbds->Flags & UNFORMATTED_MEDIA) ?
0 : 1;
break;
case IOCTL_SETACCESS:
pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX());
pbds->Flags &= ~(UNFORMATTED_MEDIA);
if (pAccessCtrl->AccessFlag == 0)
#if defined(NEC_98)
pbds->Flags |= UNFORMATTED_MEDIA;
#else // !NEC_98
pAccessCtrl->AccessFlag |= UNFORMATTED_MEDIA;
#endif // !NEC_98
break;
default:
setAX(DOS_INVALID_FUNCTION);
setCF(1);
return;
}
setAX(0);
setCF(0);
}
/* demIoctlDiskQuery - Query block device generic ioctl capability
*
*
* Entry - Client (BL) = drive number (a=0;b=1 etc)
* (CL) = generic ioctl subfuntion to be queried
* Exit
* SUCCESS
* Client (CY) = 0
* The specific ioctl is supported
* FAILURE
* Client (CY) = 1
* The given ioctl is not supported
*/
VOID demIoctlDiskQuery (VOID)
{
BYTE Code, Drive;
Code = getCL();
Drive = getBL();
if (demGetBDS(Drive) == NULL) {
setAX(DOS_FILE_NOT_FOUND);
setCF(1);
return;
}
switch (Code) {
case IOCTL_SETDPM:
case IOCTL_WRITETRACK:
case IOCTL_FORMATTRACK:
case IOCTL_SETMEDIA:
case IOCTL_GETDPM:
case IOCTL_READTRACK:
case IOCTL_VERIFYTRACK:
case IOCTL_GETMEDIA:
// case IOCTL_GETACCESS:
// case IOCTL_SETACCESS:
setAX(0);
setCF(0);
break;
default:
setAX(DOS_ACCESS_DENIED);
setCF(1);
break;
}
}
/* demIoctlInvalid - For those subfunctions which may be implemented later
*
*
* Entry -
*
* Exit
* Client (CY) = 1
* Client (AX) = error_invalid_function
*/
VOID demIoctlInvalid (VOID)
{
setCF(1);
setAX(ERROR_INVALID_FUNCTION);
return;
}