📄 io.c
字号:
--*/
//
// Just flag that we've seen it and complete the
// request
//
DeviceData->HandshakeAccepted = TRUE;
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("IrHandshake: Handshake from class arrived"));
WdfRequestComplete(Request, STATUS_SUCCESS);
return;
}
VOID
IrReceive(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request,
SIZE_T OutputBufferLength
) {
/*++
Routine Description.
This request is sent exclusively from IRCLASS and receives Run Length Coded
(RLC) IR data when the device is not running in priority mode. When running
in priority mode, these requests remain queued but receive no data.
An IOCTL_IR_RECEIVE request remains pending until one of two events occurs:
1) The data buffer provided in the request has been completely filled
with RLC IR data.
2) An IR timeout occurs. In the case of an IR timeout, the DataEnd
member of the output structure is set to TRUE.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_RECEIVE request
OutputBufferLength - Size of a variable length IR_RECEIVE_PARAMS structure
--*/
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
ULONG amountData;
PUCHAR callersBuffer;
PIR_RECEIVE_PARAMS receiveParams;
BOOLEAN dataEnd;
ULONG capturedByteCount;
PIO_STATUS_BLOCK ioStatus;
//
// Make sure the user is supplying a big enough buffer...
//
if (OutputBufferLength < sizeof(IR_RECEIVE_PARAMS)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrReceive: Buffer size must be at least 0x%x bytes",
sizeof(IR_RECEIVE_PARAMS)));
WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
return;
}
status = WdfRequestRetrieveOutputBuffer(Request,
OutputBufferLength,
&receiveParams,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrReceive: WdfRequestRetrieveOutputBuffer failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
ASSERT(receiveParams);
//
// Because the receiveParams are mapped via MDL, the user
// still has the ability to modify the buffer contents
// from underneath us. This means that we need to capture
// the input values and only use the captured value from
// then on.
//
//
// Case to ULONG is OK, max transfer size in Windows
// is ULONG bytes, the ULONG_PTR is only for alignment
// purposes.
//
capturedByteCount = (ULONG)receiveParams->ByteCount;
//
// Make sure we check the byte count against the overall
// buffer length first to avoid getting tricked into
// an overflow (i.e. 0xFFFFFFFF + sizeof())
//
if (capturedByteCount >
(OutputBufferLength - sizeof(IR_RECEIVE_PARAMS))) {
//
// Tricky user...
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrReceive: Buffer size specified in structure is too large. "\
"Buffer Size: 0x%x - Overall buffer size: 0x%Ix",
capturedByteCount, OutputBufferLength));
WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
return;
}
//
// Setup the caller's buffer...
//
callersBuffer = (PUCHAR)&receiveParams->Data[0];
KeAcquireSpinLock(&DeviceData->Receiver.ListSpinLock, &oldIrql);
//
// If we don't have a current IR receive, set this up
// to be it...
//
if (DeviceData->Receiver.CurrentIrReceiveRequest == NULL) {
//
// If we're not in PRIORITY mode, we can see
// if there is some data to process. If we are in
// priority mode we need to be hands off...
//
amountData = 0;
if (!DeviceData->InPriorityMode) {
//
// Any data out there?
//
amountData = SmscIrDequeueRLCData(&DeviceData->Receiver,
callersBuffer,
capturedByteCount,
&dataEnd);
if (dataEnd ||
(amountData == capturedByteCount)){
//
// Filled the user's buffer already or we copied up to
// a data end event. Complete the request.
//
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_RECEIVE_INFO,
("IrReceive: Data was waiting. Completing request."));
KeReleaseSpinLock(&DeviceData->Receiver.ListSpinLock, oldIrql);
//
// Get the IO_STATUS_BLOCK for the underlying IRP. This is
// ehere we'll be filling in the number of bytes
// transferred.
//
ioStatus = &WdfRequestWdmGetIrp(Request)->IoStatus;
ioStatus->Information
= FIELD_OFFSET(IR_RECEIVE_PARAMS, Data) + amountData;
receiveParams->DataEnd = dataEnd;
WdfRequestComplete(Request, STATUS_SUCCESS);
return;
}
}
//
// Otherwise we're out of here, we'll complete the
// request when we see all of the data.
//
DeviceData->Receiver.CurrentIrReceiveRequest = Request;
DeviceData->Receiver.ReceiveBuffer = callersBuffer;
DeviceData->Receiver.ReceiveBufferSize = capturedByteCount;
DeviceData->Receiver.ReceiveCurrentOffset = amountData;
DeviceData->Receiver.ReceiveParams = receiveParams;
//
// This request is going to hang out there, and may stay
// there indefinitely. We need to be able to cancel this
// request if the user wants to disable the device,
// so we need a cancel routine...
//
WdfRequestMarkCancelable(Request, IrReceiveInProgressCancel);
} else {
//
// Put the request in the queue.
//
status = WdfRequestForwardToIoQueue(
Request,
DeviceData->Receiver.PendingReceiveQueue);
if(!NT_SUCCESS(status)) {
KeReleaseSpinLock(&DeviceData->Receiver.ListSpinLock, oldIrql);
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrReceive: WdfRequestForwardToIoQueue failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
}
KeReleaseSpinLock(&DeviceData->Receiver.ListSpinLock, oldIrql);
return;
}
VOID
IrReceiveInProgressCancel(
IN WDFREQUEST Request
) {
/*++
Routine Description.
Cancel routine set for the in progress
receive request.
Arguments:
Request - An IOCTL_IR_RECEIVE request
--*/
PSMSCIR_DATA deviceData;
WDFQUEUE ioQueue;
KIRQL oldIrql;
BOOLEAN completeRequest;
WDFREQUEST failedRequest = NULL;
NTSTATUS status;
NTSTATUS failureStatus;
ioQueue = WdfRequestGetIoQueue(Request);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrReceiveInProgressCancel: Entered"));
deviceData = (PSMSCIR_DATA)GetIrData(WdfIoQueueGetDevice(ioQueue));
KeAcquireSpinLock(&deviceData->Receiver.ListSpinLock, &oldIrql);
//
// We're here first. NULL out the current request
// in the extension - the completion side will
// never see this request.
//
deviceData->Receiver.CurrentIrReceiveRequest = NULL;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_RECEIVE_INFO,
("IrReceiveInProgressCancel: Request 0x%p is the currently "\
"active receive request.",
Request));
//
// Need to get the next request active.
//
status = IrSetupNextRequest(&deviceData->Receiver,
&failedRequest,
&failureStatus);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrReceiveInProgressCancel: IrSetupNextRequest failed - 0x%x",
status));
}
KeReleaseSpinLock(&deviceData->Receiver.ListSpinLock, oldIrql);
WdfRequestComplete(Request, STATUS_CANCELLED);
if (failedRequest) {
WdfRequestComplete(failedRequest, failureStatus);
}
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrReceiveInProgressCancel: Exited"));
}
VOID
IrPriorityReceive(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request,
SIZE_T OutputBufferLength
) {
/*++
Routine Description.
This request is sent from user mode to receive RLC IR data for the
purpose of learning. If the device is not already in priority mode,
initiated by an IOCTL_ENTER_PRIORITY_RECEIVE, the request is failed
immediately. If in priority mode, the request will remain pending until
one of two events occurs:
1) The data buffer provided in the request has been completely
filled with priority IR data.
2) An IR timeout occurs. The length of time required for the IR
timeout was specified when entering priority mode.
While in priority mode and processing IOCTL_IR_PRIORITY_RECEIVE requests,
IOCTL_IR_RECEIVE requests remain pending and are not filled with IR data.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_PRIORITY_RECEIVE request
OutputBufferLength - Size of a variable length IR_PRIORITY_RECEIVE_PARAMS
structure
--*/
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
ULONG amountData;
PUCHAR callersBuffer;
PIR_PRIORITY_RECEIVE_PARAMS receiveParams = NULL;
BOOLEAN dataEnd;
ULONG capturedByteCount;
PIO_STATUS_BLOCK ioStatus;
//
// If we're not in priority mode, there's nothing to do here.
//
if (!DeviceData->InPriorityMode) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: Device is NOT in priority mode. "\
"Failing PRIORITY receive"));
WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
return;
}
if (OutputBufferLength < sizeof(IR_PRIORITY_RECEIVE_PARAMS)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: Buffer size must be at least 0x%x",
sizeof(IR_PRIORITY_RECEIVE_PARAMS)));
//
// Work around for the current version of WDF Verifier, which
// checks the amount of data to be returned before setting
// the status in the IRP (the default status in the IRP is
// SUCCESS, so if we don't do this it believes we're going to
// copy sizeof(IR_PRIORITY_RECEIVE_PARAMS) into a user buffer
// that is < sizeof(IR_PRIORITY_RECEIVE_PARAMS)
//
WdfRequestWdmGetIrp(Request)->IoStatus.Status
= STATUS_BUFFER_TOO_SMALL;
WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_TOO_SMALL,
sizeof(IR_PRIORITY_RECEIVE_PARAMS));
return;
}
status = WdfRequestRetrieveOutputBuffer(Request,
OutputBufferLength,
&receiveParams,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: "\
"WdfRequestRetrieveOutputBuffer failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
//
// See IrReceive for the reasoning behind capturedByteCount
//
capturedByteCount = (ULONG)receiveParams->ByteCount;
//
// Watch out for a malformed ByteCount...
//
if (capturedByteCount >
(OutputBufferLength - sizeof(IR_PRIORITY_RECEIVE_PARAMS))) {
//
// Tricky user...
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: Buffer size specified in structure is too "\
"large. Buffer Size: 0x%x - Overall buffer size: 0x%Ix",
capturedByteCount, OutputBufferLength));
WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
return;
}
ASSERT(receiveParams);
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -