📄 ide.c
字号:
//
// And set the Status and Infomration fields
//
Irp->IoStatus.Information = tempSize;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
//
// Free the buffer holding the partition table information
// allocated by IoReadPartitionTable()
//
ExFreePool(partitionList);
}
}
break ;
//
// Update the disk with new partition information.
//
case IOCTL_DISK_SET_DRIVE_LAYOUT:
//
// For this sample, we assume a single partition and no
// alterations... Sorry!
//
#if DBG
DbgPrint("IdeDispatchDeviceControl: IOCTL_DISK_SET_DRIVE_LAYOUT unsupported\n");
#endif
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
//
// Is this disk writable?
//
case IOCTL_DISK_IS_WRITABLE:
//
// SURE it is!
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
//
// Here's another request that class driver's get.
// Is the media removable from this device?
//
case IOCTL_DISK_MEDIA_REMOVAL:
//
// No, it is not.
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
default:
//
// The supplied operation is not supported by this driver
//
#if DBG
DbgPrint("IdeDispatchDeviceControl: Unrecognized IOCTL %x\n",
ioStack->Parameters.DeviceIoControl.IoControlCode);
#endif
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Finish up and complete the IRP
//
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(ntStatus);
}
///////////////////////////////////////////////////////////////////////////////
//
// IdeDispatchReadWrite
//
// This is the dispatch entry point for IRP_MJ_READ and IRP_MJ_WRITE requests.
// All we do here is validate the IRP, and if it's valid mark it pending
// and call IoStartPacket() to start the request on the device.
//
//
// INPUTS:
//
// DeviceObject - pointer to our device object
// Irp - pointer to the IRP
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_PENDING, otherwise STATUS_INVALID_PARAMETER
//
// IRQL:
//
// IRQL_PASSIVE_LEVEL
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
IdeDispatchReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PPARTITION_DATA partitionData = (PPARTITION_DATA)DeviceObject->DeviceExtension;
PIDE_DEV_EXT devExt = partitionData->Partition0;
PIO_STACK_LOCATION ioStack;
ULONG firstSectorOfRequest;
LONGLONG byteOffset;
LONGLONG partitionLength;
ULONG transferLength;
partitionLength = partitionData->Pi.PartitionLength.QuadPart;
//
// Get a pointer to the current I/O stack location
//
ioStack = IoGetCurrentIrpStackLocation(Irp);
//
// Pick up some handy parameters from the current I/O Stack.
// NOTE that although we access the parameters from the READ union,
// we could be processing EITHER a READ or a WRITE operation. The parameters
// are at the same locations in both I/O Stacks.
//
byteOffset = ioStack->Parameters.Read.ByteOffset.QuadPart;
transferLength = ioStack->Parameters.Read.Length;
//
// Validate the IRP
//
// Here we check to see if the parameters are valid with respect to the
// device. Specifically:
//
// - The transfer size must not be zero.
// - The transfer size must not be > MAXIMUM_TRANSFER_LENGTH bytes
// - The transfer must be entirely within one disk partition
// - The transfer size must be an even multiple of the sector size
//
if ((transferLength == 0) ||
(transferLength > MAXIMUM_TRANSFER_LENGTH) ||
((byteOffset + transferLength) > partitionLength) ||
(transferLength % devExt->BytesPerSector)) {
//
// One of the parameters is not valid
//
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
#if DBG
DbgPrint("DispatchReadWrite: Invalid Parameter!\n");
DbgPrint("Major Func = 0x%0x\n", ioStack->MajorFunction);
DbgPrint("\t\tLength = %d.\n", transferLength);
DbgPrint("\t\tPartition Length = %d.\n", partitionLength);
#endif
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_INVALID_PARAMETER);
}
//
// The IRP is valid. We will therefore be returning with the IRP
// pending.
//
IoMarkIrpPending(Irp);
//
// Convert the partition-relative request to one relative to the
// start of the disk, and store it back in the IRP for later use.
//
byteOffset += partitionData->Pi.StartingOffset.QuadPart;
ioStack->Parameters.Read.ByteOffset.QuadPart = byteOffset;
//
// Determine the sector at which the request starts
//
firstSectorOfRequest = (ULONG)(byteOffset >> devExt->ByteShiftToSector);
//
// Attempt to start the request.
//
// NOTE that we sort the queue of IRPs based on the starting sector
// of the request. Since requests are processed quickly on the disk,
// we do not make them cancellable.
//
IoStartPacket(devExt->DeviceObject,
Irp,
&firstSectorOfRequest,
NULL);
//
// Return with the request queued
//
return(STATUS_PENDING);
}
///////////////////////////////////////////////////////////////////////////////
//
// IdeStartIo
//
// This routine is called to start processing the next packet.
//
// INPUTS:
//
// DeviceObject - pointer to our device object
// Irp - pointer to the IRP
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS
//
// IRQL:
//
// IRQL_DISPATCH_LEVEL
//
// NOTES:
//
// Since we have a single controller and disk, access to the
// devExt is allowed, but NOT to the controllerData structure
//
//
///////////////////////////////////////////////////////////////////////////////
VOID
IdeStartIo(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIDE_DEV_EXT devExt = (PIDE_DEV_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack;
//
// Get a pointer to the current I/O Stack Location
//
ioStack = IoGetCurrentIrpStackLocation(Irp);
//
// Set up the major function, length and starting sector of the transfer
// in the device extension. They'll be quicker to get at from the ISR
// in the devExt than if we leave them in the IRP.
//
devExt->OperationType = ioStack->MajorFunction;
devExt->RemainingTransferLength = ioStack->Parameters.Read.Length;
devExt->FirstSectorOfRequest =
(ULONG)(ioStack->Parameters.Read.ByteOffset.QuadPart >>
devExt->ByteShiftToSector);
//
// Check if we're retrying this irp.
//
if (devExt->PacketIsBeingRetried) {
#if DBG
DbgPrint("IdeStartIo: Retrying IRP: %x\n", Irp);
#endif
devExt->PacketIsBeingRetried = FALSE;
//
// Increment the retry count. The DpcForIsr limits the number
// of retries
//
devExt->IrpRetryCount++;
} else {
devExt->IrpRetryCount = 0;
}
//
// This driver uses Direct I/O for transfer operations.
// Map the requestor's buffer into system address space.
//
ASSERT(Irp->MdlAddress);
devExt->CurrentAddress = MmGetSystemAddressForMdl(Irp->MdlAddress);
//
// let folks know of our intent
//
#if DBG
DbgPrint("IdeStartIo: Irp: 0x%0x, Func: 0x%0x VA: 0x%0x, Length: 0x%0x\n",
Irp,
ioStack->MajorFunction,
devExt->CurrentAddress,
devExt->RemainingTransferLength);
#endif
//
// We start the request on this device at DIRQL so seralize
// access to the data structures and the HW registers
//
(VOID)KeSynchronizeExecution(devExt->ControllerData->InterruptObject,
IdeStartThisRequestOnDevice,
devExt);
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// IdeStartThisRequestOnDevice
//
// This routine is will start the specified request on the device
//
// INPUTS:
//
// Context - actually, the devExt structure
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// TRUE, unless the hardware fails
//
// IRQL:
//
// DIRQL
//
// NOTES:
//
// Because this is called at DIRQL, we have access to all structures
// in the devExt and controllerData and we can actually touch the
// registers
//
///////////////////////////////////////////////////////////////////////////////
BOOLEAN
IdeStartThisRequestOnDevice(IN OUT PVOID Context)
{
PIDE_DEV_EXT devExt;
PCONTROLLER_DATA controllerData;
NTSTATUS ntStatus;
UCHAR controllerStatus;
UCHAR sectorCount, sectorNumber, cylinderLow, cylinderHigh, driveHead;
//
// set some locals
//
devExt = Context;
controllerData = devExt->ControllerData;
//
// get the current state of the controller
//
controllerStatus =
READ_PORT_UCHAR(devExt->ControllerData->ControllerAddress + STATUS_REGISTER);
//
// We will soon cause an interrupt that will require servicing by
// the DPC, so set the flag to note that we require a DPC.
//
controllerData->InterruptRequiresDpc = TRUE;
//
// Determine the parameters for the controller
//
sectorCount = (UCHAR)(devExt->RemainingTransferLength / devExt->BytesPerSector);
sectorNumber = (UCHAR)((devExt->FirstSectorOfRequest %
devExt->SectorsPerTrack) + 1);
cylinderLow = (UCHAR)(devExt->FirstSectorOfRequest /
(devExt->SectorsPerTrack *
devExt->TracksPerCylinder)) & 0xff;
cylinderHigh = (UCHAR)(devExt->FirstSectorOfRequest /
(devExt->SectorsPerTrack *
devExt->TracksPerCylinder) >> 8);
driveHead = (UCHAR) (((devExt->FirstSectorOfRequest /
devExt->SectorsPerTrack) %
devExt->TracksPerCylinder) |
devExt->DeviceUnit);
#if DBG
DbgPrint(
"IdeStartThisRequestOnDevice: sectorCount %x sectorNumber %x cylinderLow %x high %x driveHead %x\n",
sectorCount, sectorNumber, cylinderLow, cylinderHigh, driveHead);
#endif
//
// Give the controller the cylinder and head of the start of the transfer.
// Also tell it how many sectors we want to transfer.
//
WRITE_PORT_UCHAR(controllerData->ControllerAddress + SECTOR_COUNT_REGISTER,
sectorCount);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + SECTOR_NUMBER_REGISTER,
sectorNumber);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + CYLINDER_LOW_REGISTER,
cylinderLow);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + CYLINDER_HIGH_REGISTER,
cylinderHigh);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + DRIVE_HEAD_REGISTER,
driveHead);
//
// Actually start the request, based on the direction of the transfer.
// Note that we've already stored that length and starting VA of
// the transfer in the device extension (in the StartIo routine).
//
switch (devExt->OperationType) {
case IRP_MJ_READ:
#if DBG
DbgPrint("Starting a READ\n");
#endif
//
// Tell the controller to do a read.
//
// The controller will interrupt when it has a complete sector
// of data for us to retrieve from it.
//
WRITE_PORT_UCHAR(controllerData->ControllerAddress + COMMAND_REGISTER,
devExt->ReadCommand);
break;
case IRP_MJ_WRITE:
#if DBG
DbgPrint("Starting a WRITE\n");
#endif
//
// Set the write precomp -- Like it matters?
//
WRITE_PORT_UCHAR(
controllerData->ControllerAddress + WRITE_PRECOMP_REGISTER,
(UCHAR)(devExt->WritePrecomp));
//
// Give the controller the WRITE command
//
WRITE_PORT_UCHAR(controllerData->ControllerAddress + COMMAND_REGISTER,
devExt->WriteCommand);
//
// The way writes work is that afer giving the controller the WRITE
// command, we stuff a sector's worth of data into it. BUT, before
// we can start stuffing, the controller has to drop it's BUSY
// status, and assert DATA_REQUEST_STATUS. That's our signal to
// load 'er up!
//
ntStatus = IdeWaitControllerReady(controllerData, 10, 5000);
if (!NT_SUCCESS(ntStatus)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -