📄 io.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright 2005 OSR, Open Systems Resources, Inc. All rights Reserved.
//
// Module Name:
//
// io.c
//
// Abstract:
//
// Contains routines to handle opens, closes, and all necessary IOCTLs
//
// Author:
//
// Revision History:
//
#include "smscir.h"
#ifdef WPP_TRACING
#include "io.tmh"
#endif
NTSTATUS
IrTransmitBuildFifoData(
PIR_TRANSMIT_CHUNK TransmitChunk,
ULONG CapturedByteCount,
PSMSCIR_TX_FIFO_DATA *TxFifoData
);
PCCHAR
IoctlToString(
ULONG IoControlCode
);
VOID
SmscIrEvtDeviceFileCreate(
IN WDFDEVICE Device,
IN WDFREQUEST Request,
IN WDFFILEOBJECT FileObject
) {
/*++
Routine Description:
This routine is called when IRCLASS is opening a handle to our
device.
Arguments:
Device - Handle to a framework device object.
FileObject - Pointer to fileobject that represents the open handle.
CreateParams - Parameters of IO_STACK_LOCATION for create
--*/
PSMSCIR_DATA deviceData;
KIRQL oldIrql;
BOOLEAN createOK;
UNREFERENCED_PARAMETER(FileObject);
deviceData = (PSMSCIR_DATA)GetIrData(Device);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_CREATE_CLOSE_INFO,
("SmscIrEvtDeviceFileCreate: Entered"));
//
// The initial open indicates an open of the normal receiver.
// We switch to the priority receiver in response to
// an ENTER_PRIORITY_RECEIVE IOCTL
//
KeAcquireSpinLock(&deviceData->Receiver.ListSpinLock, &oldIrql);
if (deviceData->Receiver.OpenCount == 0) {
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_CREATE_CLOSE_INFO,
("SmscIrEvtDeviceFileCreate: Allowing open of FDO"));
createOK = TRUE;
deviceData->Receiver.OpenCount = 1;
} else {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_CREATE_CLOSE_INFO,
("SmscIrEvtDeviceFileCreate: Failing request to open "\
"FDO, device already open"));
createOK = FALSE;
}
KeReleaseSpinLock(&deviceData->Receiver.ListSpinLock, oldIrql);
if (createOK) {
WdfRequestComplete(Request, STATUS_SUCCESS);
} else {
WdfRequestComplete(Request, STATUS_DEVICE_BUSY);
}
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_CREATE_CLOSE_INFO,
("SmscIrEvtDeviceFileCreate: Exit"));
return;
}
VOID
SmscIrEvtFileClose(
IN WDFFILEOBJECT FileObject
) {
/*++
Routine Description:
EvtFileClose is called when all the handles represented by the FileObject
is closed and all the references to FileObject is removed.
Arguments:
FileObject - Pointer to fileobject that represents the open handle.
Return Value:
VOID
--*/
PSMSCIR_DATA deviceData;
KIRQL oldIrql;
deviceData = (PSMSCIR_DATA)GetIrData(WdfFileObjectGetDevice(FileObject));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_CREATE_CLOSE_INFO,
("SmscIrEvtFileClose: Closing FDO"));
KeAcquireSpinLock(&deviceData->Receiver.ListSpinLock, &oldIrql);
deviceData->Receiver.OpenCount = 0;
KeReleaseSpinLock(&deviceData->Receiver.ListSpinLock, oldIrql);
return;
}
VOID
SmscIrEvtIoDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
) {
/*++
Routine Description.
This routine handles IOCTL requests to the FDO.
Note that this is the callback for the DEFAULT
PARALLEL QUEUE. This routine can be called
concurrently by multiple threads submitting IOCTL
requests
For the receive paths, we're OK with this. We're
usually swarmed with requests for receive I/O and
we serialize that ourselves with a spinlock. This
provides greater concurrency and usually guarantees
that once I/O is done we have a new I/O waiting to
pick up the slack.
However, for several of the other IOCTLs we really only
want to support them one at a time. WDF provides the
concept of a sequential queue, which will present the
I/Os within it to our driver one at a time. We've created
one of those queues and we will forward all requests
that we want to serialize against each other to it. So,
we get requests here and decide if we want to handle
the request in parallel with other requests. If we do,
we handle it and provide synchronization. If not, we
forward it to our serial queue and let WDF hand the
requests off to us one by one.
Arguments:
Queue - Our FDO's default WDF queue
Request - The IOCTL request
OutputBufferLength - Size of the output buffer
InputBufferLength - Size of the input buffer
IoControlCode = The IOCTL to process
--*/
PSMSCIR_DATA deviceData;
NTSTATUS status;
UNREFERENCED_PARAMETER(InputBufferLength);
deviceData = (PSMSCIR_DATA)GetIrData(WdfIoQueueGetDevice(Queue));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("SmscIrEvtIoDeviceControl: Processing IOCTL 0x%x (%s)",
IoControlCode,
IoctlToString(IoControlCode)));
switch (IoControlCode) {
case IOCTL_IR_RECEIVE: {
IrReceive(deviceData,
Request,
OutputBufferLength);
return;
}
case IOCTL_IR_PRIORITY_RECEIVE: {
IrPriorityReceive(deviceData,
Request,
OutputBufferLength);
return;
}
default: {
break;
}
}
//
// If we didn't handle it here, forward it to
// the SerialQueue for serial processing...This
// will serialize this IOCTL with all other IOCTLs
// that are forwarded to this queue.
//
status = WdfRequestForwardToIoQueue(Request,
deviceData->SerialQueue);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("WdfRequestForwardToIoQueue failed with Status code 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
return;
}
VOID
SmscIrEvtIoDeviceControlSerial(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
) {
/*++
Routine Description.
This routine handles all IOCTL requests that have
been forwarded to the SerialQueue, Note that only
once instance of this routine will ever be running,
so we have implicit synchronization within all of the
IOCTL processing routines.
Arguments:
Queue - Our FDO's default WDF queue
Request - The IOCTL request
OutputBufferLength - Size of the output buffer
InputBufferLength - Size of the input buffer
IoControlCode = The IOCTL to process
--*/
PSMSCIR_DATA deviceData
= (PSMSCIR_DATA)GetIrData(WdfIoQueueGetDevice(Queue));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("SmscIrEvtIoDeviceControlSerial: Processing serial IOCTL: %s",
IoctlToString(IoControlCode)));
//
// Remember - we're called here SERIALLY, so all of these
// routines are synchronized against each other. This is
// fine, because none of these are performance sensitive
//
switch (IoControlCode) {
case IOCTL_IR_HANDSHAKE: {
IrHandshake(deviceData,
Request);
return;
}
case IOCTL_IR_ENTER_PRIORITY_RECEIVE: {
IrEnterPriorityMode(deviceData,
Request,
InputBufferLength);
return;
}
case IOCTL_IR_EXIT_PRIORITY_RECEIVE: {
IrExitPriorityMode(deviceData,
Request);
return;
}
case IOCTL_IR_USER_OPEN: {
IrUserOpen(deviceData,
Request);
return;
}
case IOCTL_IR_USER_CLOSE: {
IrUserClose(deviceData,
Request);
return;
}
case IOCTL_IR_TRANSMIT: {
IrTransmit(deviceData,
Request,
OutputBufferLength,
InputBufferLength);
return;
}
case IOCTL_IR_GET_DEV_CAPS: {
IrGetDevCaps(deviceData,
Request,
OutputBufferLength);
return;
}
case IOCTL_IR_GET_EMITTERS: {
IrGetEmitters(deviceData,
Request,
OutputBufferLength);
return;
}
case IOCTL_IR_FLASH_RECEIVER: {
IrFlashReceiver(deviceData,
Request,
InputBufferLength);
return;
}
case IOCTL_IR_RESET_DEVICE: {
IrResetDevice(deviceData,
Request);
return;
}
default: {
break;
}
}
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("SmscIrEvtIoDeviceControlSerial: Failing unknown IOCTL"));
WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
}
VOID
IrHandshake(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request
) {
/*++
Routine Description.
Called here by IRCLASS before the creation of the
HID PDO. A rejection of this message prevents the
HID stack from being created.
Request is to completed synchronously.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_HANDSHAKE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -