/* demioctl.c - SVC handlers for DOS IOCTL calls * * demIOCTL * * Modification History: * * Sudeepb 23-Apr-1991 Created * */ #include "dem.h" #include "demmsg.h" #include #include #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; }