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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// Copyright (c) 2004, Antony C. Roberts

// Use of this file is subject to the terms
// described in the LICENSE.TXT file that
// accompanies this file.
//
// Your use of this file indicates your
// acceptance of the terms described in
// LICENSE.TXT.
//
// http://www.freebt.net

#include "stdio.h"
#include "fbtusb.h"
#include "fbtpnp.h"
#include "fbtpwr.h"
#include "fbtdev.h"
#include "fbtwmi.h"
#include "fbtrwr.h"

#include "fbtusr.h"


// Globals
GLOBALS Globals;
ULONG DebugLevel=255;

// Forward declaration
NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT  DriverObject, IN PUNICODE_STRING UniRegistryPath );
VOID NTAPI FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS NTAPI FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);

#ifdef PAGE_CODE
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, FreeBT_DriverUnload)
#endif
#endif

NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING UniRegistryPath)
{
    NTSTATUS        ntStatus;
    PUNICODE_STRING registryPath;

    registryPath = &Globals.FreeBT_RegistryPath;

    registryPath->MaximumLength = UniRegistryPath->Length + sizeof(UNICODE_NULL);
    registryPath->Length        = UniRegistryPath->Length;
    registryPath->Buffer        = (PWSTR) ExAllocatePool(PagedPool, registryPath->MaximumLength);

    if (!registryPath->Buffer)
    {
        FreeBT_DbgPrint(1, ("FBTUSB: Failed to allocate memory for registryPath\n"));
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        goto DriverEntry_Exit;

    }


    RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
    RtlMoveMemory (registryPath->Buffer, UniRegistryPath->Buffer, UniRegistryPath->Length);

    ntStatus = STATUS_SUCCESS;

    // Initialize the driver object with this driver's entry points.
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FreeBT_DispatchDevCtrl;
    DriverObject->MajorFunction[IRP_MJ_POWER]          = FreeBT_DispatchPower;
    DriverObject->MajorFunction[IRP_MJ_PNP]            = FreeBT_DispatchPnP;
    DriverObject->MajorFunction[IRP_MJ_CREATE]         = FreeBT_DispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = FreeBT_DispatchClose;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = FreeBT_DispatchClean;
    DriverObject->MajorFunction[IRP_MJ_READ]           = FreeBT_DispatchRead;
    DriverObject->MajorFunction[IRP_MJ_WRITE]          = FreeBT_DispatchWrite;
#ifdef ENABLE_WMI
    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = FreeBT_DispatchSysCtrl;
#endif
    DriverObject->DriverUnload                         = FreeBT_DriverUnload;
    DriverObject->DriverExtension->AddDevice           = (PDRIVER_ADD_DEVICE) FreeBT_AddDevice;

DriverEntry_Exit:
    return ntStatus;

}

VOID NTAPI FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    PUNICODE_STRING registryPath;

    FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Entered\n"));

    registryPath = &Globals.FreeBT_RegistryPath;
    if(registryPath->Buffer)
    {
        ExFreePool(registryPath->Buffer);
        registryPath->Buffer = NULL;

    }

    FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Leaving\n"));

    return;

}

// AddDevice, called when an instance of our supported hardware is found
// Returning anything other than NT_SUCCESS here causes the device to fail
// to initialise
NTSTATUS NTAPI FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
{
    NTSTATUS            ntStatus;
    PDEVICE_OBJECT      deviceObject;
    PDEVICE_EXTENSION   deviceExtension;
    POWER_STATE         state;
    //KIRQL               oldIrql;
    UNICODE_STRING      uniDeviceName;
    WCHAR               wszDeviceName[255]={0};
    UNICODE_STRING      uniDosDeviceName;
    LONG                instanceNumber=0;

    FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Entered\n"));

    deviceObject = NULL;

    swprintf(wszDeviceName, L"\\Device\\FbtUsb%02d", instanceNumber);<--- Null pointer dereference
    RtlInitUnicodeString(&uniDeviceName, wszDeviceName);
    ntStatus=STATUS_OBJECT_NAME_COLLISION;
    while (instanceNumber<99 && !NT_SUCCESS(ntStatus))
    {
        swprintf(wszDeviceName, L"\\Device\\FbtUsb%02d", instanceNumber);
        uniDeviceName.Length = wcslen(wszDeviceName) * sizeof(WCHAR);
        FreeBT_DbgPrint(1, ("FBTUSB: Attempting to create device %ws\n", wszDeviceName));
        ntStatus = IoCreateDevice(
                        DriverObject,                   // our driver object
                        sizeof(DEVICE_EXTENSION),       // extension size for us
                        &uniDeviceName,                 // name for this device
                        FILE_DEVICE_UNKNOWN,
                        0,                              // device characteristics
                        FALSE,                          // Not exclusive
                        &deviceObject);                 // Our device object

        if (!NT_SUCCESS(ntStatus))
            instanceNumber++;

    }

    if (!NT_SUCCESS(ntStatus))
    {
        FreeBT_DbgPrint(1, ("FBTUSB: Failed to create device object\n"));
        return ntStatus;

    }

    FreeBT_DbgPrint(1, ("FBTUSB: Created device %ws\n", wszDeviceName));

    deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
    deviceExtension->FunctionalDeviceObject = deviceObject;
    deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
    deviceObject->Flags |= DO_DIRECT_IO;

    swprintf(deviceExtension->wszDosDeviceName, L"\\DosDevices\\FbtUsb%02d", instanceNumber);
    RtlInitUnicodeString(&uniDosDeviceName, deviceExtension->wszDosDeviceName);
    ntStatus=IoCreateSymbolicLink(&uniDosDeviceName, &uniDeviceName);
    if (!NT_SUCCESS(ntStatus))
    {
        FreeBT_DbgPrint(1, ("FBTUSB: Failed to create symbolic link %ws to %ws, status=0x%08x\n", deviceExtension->wszDosDeviceName, wszDeviceName, ntStatus));
        IoDeleteDevice(deviceObject);
        return ntStatus;

    }

    FreeBT_DbgPrint(1, ("FBTUSB: Created symbolic link %ws\n", deviceExtension->wszDosDeviceName));

    KeInitializeSpinLock(&deviceExtension->DevStateLock);

    INITIALIZE_PNP_STATE(deviceExtension);

    deviceExtension->OpenHandleCount = 0;

    // Initialize the selective suspend variables
    KeInitializeSpinLock(&deviceExtension->IdleReqStateLock);
    deviceExtension->IdleReqPend = 0;
    deviceExtension->PendingIdleIrp = NULL;

    // Hold requests until the device is started
    deviceExtension->QueueState = HoldRequests;

    // Initialize the queue and the queue spin lock
    InitializeListHead(&deviceExtension->NewRequestsQueue);
    KeInitializeSpinLock(&deviceExtension->QueueLock);

    // Initialize the remove event to not-signaled.
    KeInitializeEvent(&deviceExtension->RemoveEvent, SynchronizationEvent, FALSE);

    // Initialize the stop event to signaled.
    // This event is signaled when the OutstandingIO becomes 1
    KeInitializeEvent(&deviceExtension->StopEvent, SynchronizationEvent, TRUE);

    // OutstandingIo count biased to 1.
    // Transition to 0 during remove device means IO is finished.
    // Transition to 1 means the device can be stopped
    deviceExtension->OutStandingIO = 1;
    KeInitializeSpinLock(&deviceExtension->IOCountLock);

#ifdef ENABLE_WMI 
    // Delegating to WMILIB
    ntStatus = FreeBT_WmiRegistration(deviceExtension);
    if (!NT_SUCCESS(ntStatus))
    {
        FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WmiRegistration failed with %X\n", ntStatus));
        IoDeleteDevice(deviceObject);
        IoDeleteSymbolicLink(&uniDosDeviceName);
        return ntStatus;

    }
#endif

    // Set the flags as underlying PDO
    if (PhysicalDeviceObject->Flags & DO_POWER_PAGABLE)
    {
        deviceObject->Flags |= DO_POWER_PAGABLE;

    }

    // Typically, the function driver for a device is its
    // power policy owner, although for some devices another
    // driver or system component may assume this role.
    // Set the initial power state of the device, if known, by calling
    // PoSetPowerState.
    deviceExtension->DevPower = PowerDeviceD0;
    deviceExtension->SysPower = PowerSystemWorking;

    state.DeviceState = PowerDeviceD0;
    PoSetPowerState(deviceObject, DevicePowerState, state);

    // attach our driver to device stack
    // The return value of IoAttachDeviceToDeviceStack is the top of the
    // attachment chain.  This is where all the IRPs should be routed.
    deviceExtension->TopOfStackDeviceObject = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
    if (NULL == deviceExtension->TopOfStackDeviceObject)
    {
#ifdef ENABLE_WMI
        FreeBT_WmiDeRegistration(deviceExtension);
#endif
        IoDeleteDevice(deviceObject);
        IoDeleteSymbolicLink(&uniDosDeviceName);
        return STATUS_NO_SUCH_DEVICE;

    }

    // Register device interfaces
    ntStatus = IoRegisterDeviceInterface(deviceExtension->PhysicalDeviceObject,
                                         &GUID_CLASS_FREEBT_USB,
                                         NULL,
                                         &deviceExtension->InterfaceName);
    if (!NT_SUCCESS(ntStatus))
    {
#ifdef ENABLE_WMI
        FreeBT_WmiDeRegistration(deviceExtension);
#endif
        IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
        IoDeleteDevice(deviceObject);
        IoDeleteSymbolicLink(&uniDosDeviceName);
        return ntStatus;

    }

    if (IoIsWdmVersionAvailable(1, 0x20))
    {
        deviceExtension->WdmVersion = WinXpOrBetter;

    }

    else if (IoIsWdmVersionAvailable(1, 0x10))
    {
        deviceExtension->WdmVersion = Win2kOrBetter;

    }

    else if (IoIsWdmVersionAvailable(1, 0x5))
    {
        deviceExtension->WdmVersion = WinMeOrBetter;

    }

    else if (IoIsWdmVersionAvailable(1, 0x0))
    {
        deviceExtension->WdmVersion = Win98OrBetter;

    }

    deviceExtension->SSRegistryEnable = 0;
    deviceExtension->SSEnable = 0;

    // WinXP only: check the registry flag indicating whether
    // the device should selectively suspend when idle
    if (WinXpOrBetter == deviceExtension->WdmVersion)
    {
        FreeBT_GetRegistryDword(FREEBT_REGISTRY_PARAMETERS_PATH,
                                 L"BulkUsbEnable",
                                 (PULONG)(&deviceExtension->SSRegistryEnable));
        if (deviceExtension->SSRegistryEnable)
        {
            // initialize DPC
            KeInitializeDpc(&deviceExtension->DeferredProcCall, DpcRoutine, deviceObject);

            // initialize the timer.
            // the DPC and the timer in conjunction,
            // monitor the state of the device to
            // selectively suspend the device.
            KeInitializeTimerEx(&deviceExtension->Timer, NotificationTimer);

            // Initialize the NoDpcWorkItemPendingEvent to signaled state.
            // This event is cleared when a Dpc is fired and signaled
            // on completion of the work-item.
            KeInitializeEvent(&deviceExtension->NoDpcWorkItemPendingEvent, NotificationEvent, TRUE);

            // Initialize the NoIdleReqPendEvent to ensure that the idle request
            // is indeed complete before we unload the drivers.
            KeInitializeEvent(&deviceExtension->NoIdleReqPendEvent, NotificationEvent, TRUE);

        }

    }

    // Initialize the NoIdleReqPendEvent to ensure that the idle request
    // is indeed complete before we unload the drivers.
    KeInitializeEvent(&deviceExtension->DelayEvent, NotificationEvent, FALSE);

    // Clear the DO_DEVICE_INITIALIZING flag.
    // Note: Do not clear this flag until the driver has set the
    // device power state and the power DO flags.
    deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
    InterlockedIncrement(&instanceNumber);

    FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Leaving\n"));

    return ntStatus;

}