User can mount the disk image file such as raw dd image file,
then it will appear the Disk Managerment MMC interface.
It works fine, but i don't how to make it read-only.
//This is caret physical device object.
// Set DeviceType
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetExclusive(DeviceInit, TRUE);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetCharacteristics(DeviceInit,
FILE_DEVICE_SECURE_OPEN
//| FILE_READ_ONLY_DEVICE
/*| FILE_REMOVABLE_MEDIA*/
| FILE_CHARACTERISTIC_PNP_DEVICE, TRUE);
WdfDeviceInitSetDeviceClass(DeviceInit, &GUID_DEVCLASS_DISKDRIVE);
// Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId
ntStatus = WdfPdoInitAssignDeviceID(DeviceInit, &deviceID);
ntStatus = WdfPdoInitAddHardwareID(DeviceInit, &hardwareID);
ntStatus = WdfPdoInitAddCompatibleID(DeviceInit, &compatibleID);
ntStatus = RtlUnicodeStringPrintf(&buffer, L"VDBusDisk%02d", SerialNo);
ntStatus = WdfPdoInitAssignInstanceID(DeviceInit, &buffer);
ntStatus = RtlUnicodeStringPrintf(&buffer, L"VDBUS Disk %02d", SerialNo);
ntStatus = WdfPdoInitAddDeviceText(DeviceInit, &buffer, &deviceLocation,
0x409);
WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);
// Initialize WDF_PDO_EVENT_CALLBACKS structure to fill the
// dispatch table for a bus driver's event callbacks. We use
// this callback to provide a fake I/O port resource.
WDF_PDO_EVENT_CALLBACKS_INIT(&pdoCallbacks);
WdfPdoInitSetEventCallbacks(DeviceInit, &pdoCallbacks);
// Mark a PDO as raw.
WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_DISKDRIVE);
// Initialize the attributes to specify the size of PDO device extension.
// All the state information private to the PDO will be tracked here.
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdo_Attributes, PDO_DEVICE_DATA);
pdo_Attributes.SynchronizationScope =
WdfSynchronizationScopeInheritFromParent;
pdo_Attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent;
ntStatus = WdfDeviceCreate(&DeviceInit, &pdo_Attributes, &hChild);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
WdfIoQueueDispatchParallel);
queueConfig.PowerManaged = WdfFalse;
queueConfig.AllowZeroLengthRequests = TRUE;
queueConfig.EvtIoDeviceControl = BusPDO_EvtIoDeviceControl;
queueConfig.EvtIoDefault = BusPDO_EvtIoDefault;
queueConfig.EvtIoRead = BusPDO_EvtIoRead;
queueConfig.EvtIoWrite = BusPDO_EvtIoWrite;
//DEL queueConfig.EvtIoInternalDeviceControl =
BusPDO_EvtIoInternalDeviceControl;
queueConfig.EvtIoStop = BusPDO_EvtIoStop;
queueConfig.EvtIoResume = BusPDO_EvtIoResume;
queueConfig.EvtIoCanceledOnQueue = BusPDO_EvtIoCanceledOnQueue;
// Set POWER properties for the child device.
WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
powerCaps.DeviceWake = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
WdfDeviceSetPowerCapabilities(hChild, &powerCaps);
ntStatus = WdfDeviceCreateDeviceInterface(hChild, &GUID_DEVCLASS_DISKDRIVE,
NULL);
//////////////////////////////////////////////////////////////////////////////////////////////
// this code is handle the default request for SCSI request
VOID
BusPDO_EvtIoDefault(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest)
{
WDF_REQUEST_PARAMETERS sReqParams;
PAGED_CODE ();
WDF_REQUEST_PARAMETERS_INIT(&sReqParams);
WdfRequestGetParameters(hRequest, &sReqParams);
switch (sReqParams.Type)
{
case WdfRequestTypeDeviceControlInternal: // IRP_MJ_SCSI
// Handle IRP_MJ_SCSI request.
BusPDO_InternalSCSI(hQueue, hRequest);
break;
default:
tst_TRC_m(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"Unknown EvtIoDefault(0x%x,0x%x).",
sReqParams.Type, sReqParams.MinorFunction));
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
};
};
// then the internal scsi request handler
//============================================================================//
VOID
BusPDO_InternalSCSI(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest)
{
WDF_REQUEST_PARAMETERS sReqParams;
PSCSI_REQUEST_BLOCK pSrb;
ULONG ulIoctl;
PAGED_CODE();
tst_FUNCIN_m();
tst_INP_ASSERT_m(NULL != hQueue, __LINE__, 0, 0, 0);
tst_INP_ASSERT_m(NULL != hRequest, __LINE__, 0, 0, 0);
WDF_REQUEST_PARAMETERS_INIT(&sReqParams);
WdfRequestGetParameters(hRequest, &sReqParams);
pSrb = (PSCSI_REQUEST_BLOCK) sReqParams.Parameters.Others.Arg1;
ulIoctl = sReqParams.Parameters.Others.IoControlCode;
//Dump all SRB members.
tst_TRC_m(tst_DBG_SRB_d, (tst_TRC_PARAMS_d,
"Dump SRB. Len=%d Function=0x%x SrbStatus=0x%x ScsiStatus=0x%x
PathId=%d TargetId=%d Lun=%d "
"QueueTag=0x%x QueueAction=0x%x QueueSortKey=0x%x TimeOutValue=%d
SrbFlags=0x%x"
"DataTransferLength=%d DataBuffer=0x%x SenseInfoBufferLength=%d
SenseInfoBuffer=0x%x "
"OriginalRequest=0x%x SrbExtension=0x%x NextSrb=0x%x CdbLength=%d
Cdb[0]=0x%x",
pSrb->Length, pSrb->Function, pSrb->SrbStatus, pSrb->ScsiStatus,
pSrb->PathId, pSrb->TargetId, pSrb->Lun,
pSrb->QueueTag, pSrb->QueueAction, pSrb->QueueSortKey,
pSrb->TimeOutValue, pSrb->SrbFlags,
pSrb->DataTransferLength, pSrb->DataBuffer,
pSrb->SenseInfoBufferLength, pSrb->SenseInfoBuffer,
pSrb->OriginalRequest, pSrb->SrbExtension, pSrb->NextSrb,
pSrb->CdbLength, pSrb->Cdb[0]));
switch (ulIoctl)
{
case IOCTL_SCSI_EXECUTE_NONE:
switch (pSrb->Function)
{
case SRB_FUNCTION_CLAIM_DEVICE:
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;
case SRB_FUNCTION_EXECUTE_SCSI:
//Really?
BusPDO_ScsiRequest(hQueue, hRequest, pSrb);
break;
default:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest,
STATUS_INVALID_DEVICE_REQUEST);
break;
};
break;
case IOCTL_SCSI_EXECUTE_IN:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
case IOCTL_SCSI_EXECUTE_OUT:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
default: // It is IRP_MJ_SCSI.
BusPDO_ScsiRequest(hQueue, hRequest, pSrb);
break;
};
tst_FUNCOUT_m();
};
//--------------------------------------------------------------------
VOID
BusPDO_ScsiRequest(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest,
IN PSCSI_REQUEST_BLOCK pSrb)
{
PCDB pCdb;
PSRB_IO_CONTROL pSio;
PAGED_CODE();
switch (pSrb->Function)
{
case SRB_FUNCTION_EXECUTE_SCSI:
pCdb = (PCDB) pSrb->Cdb;
switch (pCdb->CDB6GENERIC.OperationCode)
{
case SCSIOP_READ_CAPACITY:
BusPDO_SrbReadCapacity(hQueue, hRequest, pSrb);
break;
case SCSIOP_READ:
BusPDO_SrbRead(hQueue, hRequest, pSrb);
break;
case SCSIOP_WRITE:
BusPDO_SrbWrite(hQueue, hRequest, pSrb);
break;
// If i refuse this request, Windows will not make the Virtual Disk Device
available.
/*case SCSIOP_WRITE:
tst_TRC_m(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"-- UNIMPLEMENTED. SCSIOP_WRITE CDB(%d,0x%x).",
pSrb->CdbLength, pCdb->CDB6GENERIC.OperationCode));
pSrb->ScsiStatus = SRB_STATUS_BAD_FUNCTION;
pSrb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
WdfRequestComplete(hRequest, STATUS_MEDIA_WRITE_PROTECTED);
break;*/
case SCSIOP_MODE_SENSE:
BusPDO_SrbModeSense(hQueue, hRequest, pSrb);
break;
case SCSIOP_TEST_UNIT_READY:
BusPDO_SrbTestUnitReady(hQueue, hRequest, pSrb);
break;
case SCSIOP_VERIFY:
BusPDO_SrbVerify(hQueue, hRequest, pSrb);
break;
case SCSIOP_MEDIUM_REMOVAL:
BusPDO_SrbMediumRemoval(hQueue, hRequest, pSrb);
break;
case SCSIOP_LOAD_UNLOAD:
BusPDO_SrbLoadUnload(hQueue, hRequest, pSrb);
break;
default: // Unknown SRB operation code.
myTraceMessage(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"UNIMPLEMENTED. SRB_FUNCTION_EXECUTE_SCSI
CDB(%d,0x%x).",
pSrb->CdbLength, pCdb->CDB6GENERIC.OperationCode));
pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_ERROR;
WdfRequestComplete(hRequest,
STATUS_INVALID_DEVICE_REQUEST);
break;
};
break;
case SRB_FUNCTION_IO_CONTROL:
pSio = (PSRB_IO_CONTROL) pSrb->DataBuffer;
myTraceMessage(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"UNIMPLEMENTED. SRB_FUNCTION_IO_CONTROL SIO(%d,0x%x,%d).",
pSrb->DataTransferLength, pSio->ControlCode, pSio->Length));
// This way comes in some SMART disk IOCTLs
// e.g. IOCTL_SCSI_MINIPORT_IDENTIFY send from
DiskPerformSmartCommand (disk.c).
// Success request.
// pSio->ReturnCode = STATUS_SUCCESS;
// pSRB->SrbStatus = SRB_STATUS_SUCCESS;
// *pulLen = pSio->Length;
//TODO IOCTL_SCSI_MINIPORT_IDENTIFY:
// UNIMPLEMENTED. SRB_FUNCTION_IO_CONTROL
SIO(572,0x1b0501,544)
pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
case SRB_FUNCTION_FLUSH:
// Success request.
pSrb->SrbStatus = SRB_STATUS_SUCCESS;
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;
case SRB_FUNCTION_SHUTDOWN:
// Success request.
pSrb->SrbStatus = SRB_STATUS_SUCCESS;
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;
default: // Unknown SRB function.
pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
};
};
I can't refuse SCSIOP_WRITE request. it will make mount image failed.
Dose someone can give me some cure? I can't post all the code on here, due
to the size limitation.
So if someone can help me to fix this problem, i could share with my code.
Thank u!
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply
"sa_sa_Jerry" <sa_sa...@hotmail.com> wrote in message
news:OZhyMuoo...@TK2MSFTNGP04.phx.gbl...