// Stop the 1 second timer if necessary
if (dx->StopTimer) {
IoStopTimer(fdo);
dx->StopTimer = false;
}
NTSTATUS status = STATUS_SUCCESS;
// Switch on the IRP major function code
switch(IrpStack->MajorFunction) {
//////////////////////////////////////////////////////////////////////
case IRP_MJ_DEVICE_CONTROL:
{
ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
ULONG InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(ControlCode) {
////////////////////////////////////////////////////////////////////
case IOCTL_PHDIO_RUN_CMDS:
DebugPrint( 'WdmIoStartIo: Run Cmds %s', dx->ConnectedToInterrupt?'(synchronised)':'');
// Run the commands, synchronized with interrupt if necessary
if (dx->ConnectedToInterrupt) {
if (!KeSynchronizeExecution(dx->InterruptObject, (PKSYNCHRONIZE_ROUTINE)RunCmdsSynch, (PVOID)fdo))
status = STATUS_UNSUCCESSFUL;
} else if (!RunCmds(fdo, true)) status = STATUS_UNSUCCESSFUL;
break;
////////////////////////////////////////////////////////////////////
case IOCTL_PHDIO_CMDS_FOR_READ:
DebugPrintMsg( 'WdmIoStartIo: Store cmds for read');
status = StoreCmds(&dx->ReadCmds, &dx->ReadCmdsLen, InputLength, Buffer);
break;
////////////////////////////////////////////////////////////////////
case IOCTL_PHDIO_CMDS_FOR_READ_START:
DebugPrintMsg('WdmIoStartIo: Store cmds for read start');
status = StoreCmds(&dx->StartReadCmds, &dx->StartReadCmdsLen, InputLength, Buffer);
break;
////////////////////////////////////////////////////////////////////
case IOCTL_PHDIO_CMDS_FOR_WRITE:
DebugPrintMsg('WdmIoStartIo: Store cmds for write');
status = StoreCmds(&dx->WriteCmds, &dx->WriteCmdsLen, InputLength, Buffer);
break;
////////////////////////////////////////////////////////////////////
case IOCTL_PHDIO_GET_RW_RESULTS:
// Copy cmd output first
dx->CmdOutputCount = dx->TxCmdOutputCount;
if (dx->CmdOutputCount>OutputLength) dx->CmdOutputCount = OutputLength;
RtlCopyMemory(Buffer, dx->TxResult, dx->CmdOutputCount);
// Then add on last interrupt reg value
if (dx->CmdOutputCount+1<=OutputLength) Buffer[dx->CmdOutputCount++] = dx->TxLastIntReg;
DebugPrint('WdmIoStartIo: Get RW Results: %d bytes', dx->CmdOutputCount);
break;
////////////////////////////////////////////////////////////////////
default:
status = STATUS_NOT_SUPPORTED;
}
break;
}
//////////////////////////////////////////////////////////////////////
case IRP_MJ_WRITE:
// …
case IRP_MJ_READ:
// …
default:
status = STATUS_NOT_SUPPORTED;
break;
}
//////////////////////////////////////////////////////////////////////
// Complete this IRP
if (Irp->Cancel) status = STATUS_CANCELLED;
// Remove cancel routine KIRQL OldIrql;
IoAcquireCancelSpinLock(&OldIrql);
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(OldIrql);
// Unlock device, complete IRP and start next UnlockDevice(dx);
DebugPrint('WdmIoStartIo: CmdOutputCount %d', dx->CmdOutputCount);
CompleteIrp(Irp, status, dx->CmdOutputCount);
IoStartNextPacket(fdo, TRUE);
}
Processing Commands
The IOCTL_PHDIO_RUN_CMDS IOCTL is used to run a set of commands straightaway. Eventually the
However, there are a couple of hurdles to overcome before IOCTL_PHDIO_RUN_CMDS can call
The first hurdle is that the IOCTL input and output buffers use the same block of memory. While this is a jolly useful technique for saving memory in the first stage of IOCTL processing, it