1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
#include "RadioSwitchHidUsbFx2.h"
#pragma warning(disable:28252)
#pragma warning(disable:28253)
#include "driver.tmh"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, HidFx2EvtDriverContextCleanup)
#pragma alloc_text(PAGE, HidFx2EvtDeviceAdd)
#endif
//Installable driver initialization entry point. This entry point is called directly by the I/O system.
//
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING pszRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_DRIVER_CONFIG config;
WDF_OBJECT_ATTRIBUTES attributes;
// Initialize WPP Tracing
WPP_INIT_TRACING(pDriverObject, pszRegistryPath);
TraceInfo(DBG_INIT, "(%!FUNC!) Enter -DriverEntry\n");
WDF_DRIVER_CONFIG_INIT(&config, HidFx2EvtDeviceAdd);
// Register a cleanup callback so that we can call WPP_CLEANUP when the framework driver object is deleted during driver unload.
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.EvtCleanupCallback = HidFx2EvtDriverContextCleanup;
// Create a framework driver object to represent our driver.
status = WdfDriverCreate(pDriverObject,
pszRegistryPath,
&attributes, // Driver Attributes
&config, // Driver Config Info
WDF_NO_HANDLE
);
if (!NT_SUCCESS(status))
{
TraceErr(DBG_INIT, "(%!FUNC!)WdfDriverCreate failed with status %!STATUS!\n", status);
WPP_CLEANUP(pDriverObject);
}
TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n");
return status;
}
//Free resources allocated in DriverEntry that are not automatically cleaned up framework.
//
void HidFx2EvtDriverContextCleanup(_In_ WDFOBJECT hDriver)
{
PAGED_CODE ();
TraceVerbose(DBG_INIT, "(%!FUNC!) Enter/Exit\n");
WPP_CLEANUP(WdfDriverWdmGetDriverObject(hDriver));
}
//HidFx2EvtDeviceAdd is called by the framework in response to AddDevicecall from the PnP manager.
//We create and initialize a WDF device object to represent a new instance of device.
//
NTSTATUS HidFx2EvtDeviceAdd(_In_ WDFDRIVER hDriver, _Inout_ PWDFDEVICE_INIT pDeviceInit)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_IO_QUEUE_CONFIG queueConfig;
WDF_OBJECT_ATTRIBUTES attributes;
WDFDEVICE hDevice;
PDEVICE_EXTENSION pDevContext = NULL;
WDFQUEUE hQueue;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_TIMER_CONFIG timerConfig;
WDFTIMER hTimer;
UNREFERENCED_PARAMETER(hDriver);
PAGED_CODE();
TraceVerbose(DBG_PNP, "(%!FUNC!) Enter\n");
// Tell framework this is a filter driver.
WdfFdoInitSetFilter(pDeviceInit);
// Initialize pnp-power callbacks, attributes and a context area for the device object.
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
// For usb devices, PrepareHardware callback is the to place select the interface and configure the device.
pnpPowerCallbacks.EvtDevicePrepareHardware = HidFx2EvtDevicePrepareHardware;
// These two callbacks start and stop the wdfusb pipe continuous reader as we go in and out of the D0-working state.
pnpPowerCallbacks.EvtDeviceD0Entry = HidFx2EvtDeviceD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = HidFx2EvtDeviceD0Exit;
WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &pnpPowerCallbacks);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION);
// Create a framework device object.This call will in turn create a WDM device object, attach to the lower stack.
status = WdfDeviceCreate(&pDeviceInit, &attributes, &hDevice);
if (!NT_SUCCESS(status))
{
TraceErr(DBG_PNP, "(%!FUNC!) WdfDeviceCreate failed with status code %!STATUS!\n", status);
return status;
}
pDevContext = GetDeviceContext(hDevice);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel);
queueConfig.EvtIoInternalDeviceControl = HidFx2EvtInternalDeviceControl;
status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &hQueue);
if (!NT_SUCCESS (status))
{
TraceErr(DBG_PNP, "(%!FUNC!) WdfIoQueueCreate failed 0x%x\n", status);
return status;
}
// Register a manual I/O queue for handling Interrupt Message Read Requests.
WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual);
// This queue is used for requests that dont directly access the device.
// The requests in this queue are serviced only when the device is in a fully powered state and sends an interrupt.
queueConfig.PowerManaged = WdfFalse;
status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->hInterruptMsgQueue);
if (!NT_SUCCESS(status))
{
TraceErr(DBG_PNP, "(%!FUNC!) WdfIoQueueCreate failed %!STATUS!\n", status);
return status;
}
// Create a timer to handle debouncing of switchpack
WDF_TIMER_CONFIG_INIT(&timerConfig, HidFx2EvtTimerFunction);
timerConfig.AutomaticSerialization = FALSE;
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = hDevice;
status = WdfTimerCreate(&timerConfig, &attributes, &hTimer);
if (!NT_SUCCESS(status))
{
TraceErr(DBG_PNP, "(%!FUNC!) WdfTimerCreate failed status:%!STATUS!\n", status);
return status;
}
pDevContext->hDebounceTimer = hTimer;
TraceVerbose(DBG_PNP, "(%!FUNC!) Exit\n");
return status;
}
|