summaryrefslogtreecommitdiff
path: root/network/radio/HidSwitchDriverSample/driver.c
blob: 61cc97fcf0489329c35fc1a491a9fa19cc58955a (plain)
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;
}