621 lines
15 KiB
C
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;
|
|
}
|