📄 pnp.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright 2005 OSR, Open Systems Resources, Inc. All rights Reserved.
//
// Module Name:
//
// pnp.c
//
// Abstract:
//
// Contains routines to handle PnP and power transitions
//
// Author:
//
// Revision History:
//
#include "smscir.h"
#ifdef WPP_TRACING
#include "pnp.tmh"
#endif
VOID
SmscIrEvtIoQueueStop(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN ULONG ActionFlags
);
NTSTATUS
SmscIrEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
) {
/*++
Routine Description.
This routine is called when the FDO for the SMSC
IR device needs to be created
Arguments:
Driver - Our WDF Driver object (not used)
DeviceInit - The WDFDEVICE_INIT structure that we will use to
indicate the characteristics of our device
--*/
NTSTATUS status;
PSMSCIR_DATA deviceData;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES fdoAttributes;
WDFDEVICE device;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
WDF_FILEOBJECT_CONFIG fileConfig;
WDF_INTERRUPT_CONFIG interruptConfig;
WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks;
WDF_TIMER_CONFIG timerConfig;
WDF_OBJECT_ATTRIBUTES timerAttributes;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Entered"));
//
// Initialize all the properties specific to the device.
// Framework has default values for the one that are not
// set explicitly here.
//
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SMSCIR);
//
// We want MDLs...
//
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
//
// Initialize the pnpPowerCallbacks structure. Callback events for PNP
// and Power are specified here. If you don't supply any callbacks,
// the Framework will take appropriate default actions for an FDO
//
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
//
// We'll need to get our port resource in the prepare
// callback and return it in the release.
//
pnpPowerCallbacks.EvtDevicePrepareHardware
= SmscIrEvtDevicePrepareHardware;
pnpPowerCallbacks.EvtDeviceReleaseHardware
= SmscIrEvtDeviceReleaseHardware;
//
// These two callbacks are called as we go in and out of the D0-working
// state.
//
pnpPowerCallbacks.EvtDeviceD0Entry = SmscIrEvtDeviceD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = SmscIrEvtDeviceD0Exit;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks);
//
// We might need to arm the device for wake, so provide
// an "arming for wake" callback
//
powerPolicyCallbacks.EvtDeviceArmWakeFromSx = SmscIrEvtDeviceWakeArm;
//
// Register the power policy callbacks.
//
WdfDeviceInitSetPowerPolicyEventCallbacks(DeviceInit, &powerPolicyCallbacks);
WDF_OBJECT_ATTRIBUTES_INIT(&fdoAttributes);
//
// We deal with our synchronization
//
fdoAttributes.SynchronizationScope = WdfSynchronizationScopeNone;
//
// Specify size and accessor function for storing device context.
//
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdoAttributes, SMSCIR_DATA);
//
// We want to specify an open and close routine so we know
// when IRCLASS is trying to open our device...
//
WDF_FILEOBJECT_CONFIG_INIT(&fileConfig,
SmscIrEvtDeviceFileCreate,
SmscIrEvtFileClose,
NULL);
WdfDeviceInitSetFileObjectConfig(DeviceInit,
&fileConfig,
NULL);
//
// Create a framework device object. In response to this call, framework
// creates a WDM deviceobject and attaches it to the PDO.
//
status = WdfDeviceCreate(&DeviceInit,
&fdoAttributes,
&device);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: WdfDeviceCreate failed - 0x%x", status));
return status;
}
//
// Initialize our context area....
//
deviceData = (PSMSCIR_DATA)GetIrData(device);
//
// Keep a pointer to the driver
//
deviceData->WdfDriverObject = Driver;
//
// Set the default number of FFs we need to see to signal
// a data end
//
deviceData->NumFFsForDataEnd = SMSCIR_NUM_FFS_FOR_DATA_END;
//
// Initialize the basic portions of our receivers
//
SMSCIR_INITIALIZE_RECEIVER(&deviceData->Receiver,
deviceData,
FALSE);
SMSCIR_INITIALIZE_RECEIVER(&deviceData->PriorityReceiver,
deviceData,
TRUE);
KeInitializeSpinLock(&deviceData->TxFifoDataLock);
InitializeListHead(&deviceData->TxFifoDataList);
//
// Create our deadman timer
//
WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig,
SmscIrEvtDeadManTimerForTransmit,
SMSCIR_DEADMAN_TIMER_PERIOD);
WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
//
// Set the device as the parent of the timer so
// that the timer will go away when the
// device does
//
timerAttributes.ParentObject = device;
status = WdfTimerCreate(&timerConfig,
&timerAttributes,
&deviceData->DeadManTimer);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Error creating timer - 0x%x", status));
return status;
}
//
// Create our interrupt object.
//
WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
SmscIrEvtInterruptIsr,
SmscIrEvtInterruptDpc);
interruptConfig.EvtInterruptEnable = SmscIrEvtInterruptEnable;
interruptConfig.EvtInterruptDisable = SmscIrEvtInterruptDisable;
status = WdfInterruptCreate(device,
&interruptConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&deviceData->Interrupt);
if( !NT_SUCCESS(status) ) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Error creating interrupt - 0x%x", status));
return status;
}
//
// Create a parallel default queue
//
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchParallel);
ioQueueConfig.EvtIoDeviceControl = SmscIrEvtIoDeviceControl;
//
// And we need a stop callback so that we can kill the current
// IR receive request
//
ioQueueConfig.EvtIoStop = SmscIrEvtIoQueueStop;
status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: WdfIoQueueCreate failed - 0x%x", status));
return status;
}
//
// Serial queue for things that we want to process
// exclusive to each other.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig,
WdfIoQueueDispatchSequential);
ioQueueConfig.EvtIoDeviceControl = SmscIrEvtIoDeviceControlSerial;
ioQueueConfig.EvtIoStop = SmscIrEvtIoQueueStop;
status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&deviceData->SerialQueue);
if(!NT_SUCCESS (status)){
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Creating IOCTL queue - 0x%x", status));
return status;
}
//
// Manual internal queue for regular receives reqeusts.
// This will be used to queue the recieve requests presented
// to us from the parallel default queue
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig,
WdfIoQueueDispatchManual);
ioQueueConfig.EvtIoStop = SmscIrEvtIoQueueStop;
status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&deviceData->Receiver.PendingReceiveQueue);
if(!NT_SUCCESS (status)){
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Error creating read queue - 0x%x", status));
return status;
}
//
// One more queue...We need a place to put the priority receive
// requests that we get from the parallel queue.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig,
WdfIoQueueDispatchManual);
ioQueueConfig.EvtIoStop = SmscIrEvtIoQueueStop;
status = WdfIoQueueCreate(
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&deviceData->PriorityReceiver.PendingReceiveQueue);
if(!NT_SUCCESS (status)){
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Error creating priority queue - 0x%x",
status));
return status;
}
//
// Register a device interface. IRCLASS will be notified of our
// presence when WDF enables the interface and will then create
// a HID PDO for our device.
//
status = WdfDeviceCreateDeviceInterface(device,
(LPGUID)&GUID_DEVINTERFACE_IRPORT,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: WdfDeviceCreateDeviceInterface "\
"failed - 0x%x", status));
return status;
}
//
// Setup the wake key
//
SmscIrSetWakeKeyInfo(deviceData);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_PNP_INFO,
("SmscIrEvtDeviceAdd: Exit"));
return STATUS_SUCCESS;
}
VOID
SmscIrEvtIoQueueStop(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN ULONG ActionFlags
) {
/*++
Routine Description.
This routine is called when a queue of ours needs to
pause, notably due to power down.
Arguments:
Queue - The WDFQUEUE that is stopping
Request - We're called here multiple times, once
for each request on the queue. This is one
such request
ActionFlags - More detailed info about the stop.
--*/
PSMSCIR_DATA deviceData;
KIRQL oldIrql;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_PNP_INFO,
("SmscIrEvtIoQueueStop: Stopping request 0x%p - 0x%x",
Request, ActionFlags));
deviceData = (PSMSCIR_DATA)GetIrData(WdfIoQueueGetDevice(Queue));
KeAcquireSpinLock(&deviceData->Receiver.ListSpinLock, &oldIrql);
if (deviceData->Receiver.CurrentIrReceiveRequest == Request) {
//
// Do not requeue the request, just ACK and leave it where it is
//
WdfRequestStopAcknowledge(Request, FALSE);
}
KeReleaseSpinLock(&deviceData->Receiver.ListSpinLock, oldIrql);
KeAcquireSpinLock(&deviceData->PriorityReceiver.ListSpinLock, &oldIrql);
if (deviceData->PriorityReceiver.CurrentIrReceiveRequest == Request) {
//
// Do not requeue the request, just ACK and leave it where it is
//
WdfRequestStopAcknowledge(Request, FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -