📄 class.c
字号:
// then enable the once per second timer.
//
// NOTE: This assumes that ClassInitializeMediaChangeDetection is always
// called in the context of the ClassInitDevice callback. If called
// after then this check will have already been made and the
// once a second timer will not have been enabled.
//
if ((isFdo) &&
((initData->ClassTick != NULL) ||
(fdoExtension->MediaChangeDetectionInfo != NULL) ||
((fdoExtension->FailurePredictionInfo != NULL) &&
(fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone))))
{
ClasspEnableTimer(DeviceObject);
timerStarted = TRUE;
}
//
// NOTE: the timer looks at commonExtension->CurrentState now
// to prevent Media Change Notification code from running
// until the device is started, but allows the device
// specific tick handler to run. therefore it is imperative
// that commonExtension->CurrentState not be updated until
// the device specific startdevice handler has finished.
//
status = devInfo->ClassStartDevice(DeviceObject);
if (NT_SUCCESS(status)){
commonExtension->CurrentState = IRP_MN_START_DEVICE;
if((isFdo) && (initData->ClassEnumerateDevice != NULL)) {
isMountedDevice = FALSE;
}
if((DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
(DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) {
isMountedDevice = FALSE;
}
if(isMountedDevice) {
ClasspRegisterMountedDeviceInterface(DeviceObject);
}
if((commonExtension->IsFdo) &&
(devInfo->ClassWmiInfo.GuidRegInfo != NULL)) {
IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER);
}
}
else {
if (timerStarted) {
ClasspDisableTimer(DeviceObject);
}
}
return status;
}
/*++////////////////////////////////////////////////////////////////////////////
ClassReadWrite()
Routine Description:
This is the system entry point for read and write requests. The
device-specific handler is invoked to perform any validation necessary.
If the device object is a PDO (partition object) then the request will
simply be adjusted for Partition0 and issued to the lower device driver.
IF the device object is an FDO (paritition 0 object), the number of bytes
in the request are checked against the maximum byte counts that the adapter
supports and requests are broken up into
smaller sizes if necessary.
Arguments:
DeviceObject - a pointer to the device object for this request
Irp - IO request
Return Value:
NT Status
--*/
NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
ULONG isRemoved;
NTSTATUS status;
/*
* Grab the remove lock. If we can't acquire it, bail out.
*/
isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
if (isRemoved) {
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
status = STATUS_DEVICE_DOES_NOT_EXIST;
}
else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) &&
(currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) &&
!TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){
/*
* DO_VERIFY_VOLUME is set for the device object,
* but this request is not itself a verify request.
* So fail this request.
*/
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
Irp->IoStatus.Information = 0;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, 0);
status = STATUS_VERIFY_REQUIRED;
}
else {
/*
* Since we've bypassed the verify-required tests we don't need to repeat
* them with this IRP - in particular we don't want to worry about
* hitting them at the partition 0 level if the request has come through
* a non-zero partition.
*/
currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED;
/*
* Call the miniport driver's pre-pass filter to check if we
* should continue with this transfer.
*/
ASSERT(commonExtension->DevInfo->ClassReadWriteVerification);
status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp);
if (!NT_SUCCESS(status)){
ASSERT(Irp->IoStatus.Status == status);
ASSERT(status != STATUS_INSUFFICIENT_RESOURCES);
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT);
}
else if (status == STATUS_PENDING){
/*
* ClassReadWriteVerification queued this request.
* So don't touch the irp anymore.
*/
}
else {
if (transferByteCount == 0) {
/*
* Several parts of the code turn 0 into 0xffffffff,
* so don't process a zero-length request any further.
*/
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
status = STATUS_SUCCESS;
}
else {
/*
* If the driver has its own StartIo routine, call it.
*/
if (commonExtension->DriverExtension->InitData.ClassStartIo) {
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
status = STATUS_PENDING;
}
else {
/*
* The driver does not have its own StartIo routine.
* So process this request ourselves.
*/
/*
* Add partition byte offset to make starting byte relative to
* beginning of disk.
*/
currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
commonExtension->StartingOffset.QuadPart;
if (commonExtension->IsFdo){
/*
* Add in any skew for the disk manager software.
*/
currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
commonExtension->PartitionZeroExtension->DMByteSkew;
/*
* Perform the actual transfer(s) on the hardware
* to service this request.
*/
status = ServiceTransferRequest(DeviceObject, Irp);
}
else {
/*
* This is a child PDO enumerated for our FDO by e.g. disk.sys
* and owned by e.g. partmgr. Send it down to the next device
* and the same irp will come back to us for the FDO.
*/
IoCopyCurrentIrpStackLocationToNext(Irp);
ClassReleaseRemoveLock(DeviceObject, Irp);
status = IoCallDriver(lowerDeviceObject, Irp);
}
}
}
}
}
return status;
}
VOID InterpretCapacityData(PDEVICE_OBJECT Fdo, PREAD_CAPACITY_DATA_EX ReadCapacityData)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
ULONG cylinderSize;
ULONG bytesPerSector;
ULONG tmp;
LARGE_INTEGER lastSector;
LARGE_INTEGER largeInt;
/*
* Read the bytesPerSector value, which is big-endian in the returned buffer.
* Default to the standard 512 bytes.
*/
tmp = ReadCapacityData->BytesPerBlock;
((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
if (bytesPerSector == 0) {
bytesPerSector = 512;
}
else {
/*
* Clear all but the highest set bit.
* That will give us a bytesPerSector value that is a power of 2.
*/
if (bytesPerSector & (bytesPerSector-1)){
DBGWARN(("FDO %ph has non-standard sector size 0x%x.", Fdo, bytesPerSector));
do {
bytesPerSector &= bytesPerSector-1;
}
while (bytesPerSector & (bytesPerSector-1));
}
}
fdoExt->DiskGeometry.BytesPerSector = bytesPerSector;
WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift);
/*
* LogicalBlockAddress is the last sector of the logical drive, in big-endian.
* It tells us the size of the drive (#sectors is lastSector+1).
*/
largeInt = ReadCapacityData->LogicalBlockAddress;
REVERSE_BYTES_QUAD(&lastSector, &largeInt);
if (fdoExt->DMActive){
DebugPrint((1, "ClassReadDriveCapacity: reducing number of sectors by %d\n", fdoExt->DMSkew));
lastSector.QuadPart -= fdoExt->DMSkew;
}
/*
* Check to see if we have a geometry we should be using already.
* If not, we set part of the disk geometry to garbage values that will be filled in by the caller (e.g. disk.sys).
*
* So the first call to ClassReadDriveCapacity always sets a meaningless geometry.
* TracksPerCylinder and SectorsPerTrack are kind of meaningless anyway wrt I/O,
* because I/O is always targeted to a logical sector number.
* All that really matters is BytesPerSector and the number of sectors.
*/
cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
if (cylinderSize == 0){
fdoExt->DiskGeometry.TracksPerCylinder = 0xff;
fdoExt->DiskGeometry.SectorsPerTrack = 0x3f;
cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
}
/*
* Calculate number of cylinders.
* If there are zero cylinders, then the device lied AND it's
* smaller than 0xff*0x3f (about 16k sectors, usually 8 meg)
* this can fit into a single LONGLONG, so create another usable
* geometry, even if it's unusual looking.
* This allows small, non-standard devices, such as Sony's Memory Stick, to show up as having a partition.
*/
fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector.QuadPart + 1)/cylinderSize);
if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) {
fdoExt->DiskGeometry.SectorsPerTrack = 1;
fdoExt->DiskGeometry.TracksPerCylinder = 1;
fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector.QuadPart + 1;
}
/*
* Calculate media capacity in bytes.
* For this purpose we treat the entire LUN as is if it is one partition. Disk will deal with actual partitioning.
*/
fdoExt->CommonExtension.PartitionLength.QuadPart =
((LONGLONG)(lastSector.QuadPart + 1)) << fdoExt->SectorShift;
/*
* Is this removable or fixed media
*/
if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
fdoExt->DiskGeometry.MediaType = RemovableMedia;
}
else {
fdoExt->DiskGeometry.MediaType = FixedMedia;
}
}
/*++////////////////////////////////////////////////////////////////////////////
ClassReadDriveCapacity()
Routine Description:
This routine sends a READ CAPACITY to the requested device, updates
the geometry information in the device object and returns
when it is complete. This routine is synchronous.
This routine must be called with the remove lock held or some other
assurance that the Fdo will not be removed while processing.
Arguments:
DeviceObject - Supplies a pointer to the device object that represents
the device whose capacity is to be read.
Return Value:
Status is returned.
--*/
NTSTATUS ClassReadDriveCapacity(IN PDEVICE_OBJECT Fdo)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
READ_CAPACITY_DATA_EX PTRALIGN readCapacityData = {0};
PTRANSFER_PACKET pkt;
NTSTATUS status;
PMDL driveCapMdl;
KEVENT event;
NTSTATUS pktStatus;
IRP pseudoIrp = {0};
ULONG readCapacityDataSize;
BOOLEAN use16ByteCdb;
BOOLEAN match = TRUE;
use16ByteCdb = TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB);
//
// Use the larger read capacity buffer for allocating the MDL
//
driveCapMdl = BuildDeviceInputMdl(&readCapacityData, sizeof(READ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -