1 // Copyright (c) 2004, Antony C. Roberts
3 // Use of this file is subject to the terms
4 // described in the LICENSE.TXT file that
5 // accompanies this file.
7 // Your use of this file indicates your
8 // acceptance of the terms described in
11 // http://www.freebt.net
28 // Forward declaration
29 NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject
, IN PUNICODE_STRING UniRegistryPath
);
30 VOID NTAPI
FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject
);
31 NTSTATUS NTAPI
FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject
, IN PDEVICE_OBJECT PhysicalDeviceObject
);
35 #pragma alloc_text(INIT, DriverEntry)
36 #pragma alloc_text(PAGE, FreeBT_DriverUnload)
40 NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject
, IN PUNICODE_STRING UniRegistryPath
)
43 PUNICODE_STRING registryPath
;
45 registryPath
= &Globals
.FreeBT_RegistryPath
;
47 registryPath
->MaximumLength
= UniRegistryPath
->Length
+ sizeof(UNICODE_NULL
);
48 registryPath
->Length
= UniRegistryPath
->Length
;
49 registryPath
->Buffer
= (PWSTR
) ExAllocatePool(PagedPool
, registryPath
->MaximumLength
);
51 if (!registryPath
->Buffer
)
53 FreeBT_DbgPrint(1, ("FBTUSB: Failed to allocate memory for registryPath\n"));
54 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
55 goto DriverEntry_Exit
;
60 RtlZeroMemory (registryPath
->Buffer
, registryPath
->MaximumLength
);
61 RtlMoveMemory (registryPath
->Buffer
, UniRegistryPath
->Buffer
, UniRegistryPath
->Length
);
63 ntStatus
= STATUS_SUCCESS
;
65 // Initialize the driver object with this driver's entry points.
66 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = FreeBT_DispatchDevCtrl
;
67 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = FreeBT_DispatchPower
;
68 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = FreeBT_DispatchPnP
;
69 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FreeBT_DispatchCreate
;
70 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FreeBT_DispatchClose
;
71 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = FreeBT_DispatchClean
;
72 DriverObject
->MajorFunction
[IRP_MJ_READ
] = FreeBT_DispatchRead
;
73 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FreeBT_DispatchWrite
;
75 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = FreeBT_DispatchSysCtrl
;
77 DriverObject
->DriverUnload
= FreeBT_DriverUnload
;
78 DriverObject
->DriverExtension
->AddDevice
= (PDRIVER_ADD_DEVICE
) FreeBT_AddDevice
;
85 VOID NTAPI
FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject
)
87 PUNICODE_STRING registryPath
;
89 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Entered\n"));
91 registryPath
= &Globals
.FreeBT_RegistryPath
;
92 if(registryPath
->Buffer
)
94 ExFreePool(registryPath
->Buffer
);
95 registryPath
->Buffer
= NULL
;
99 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Leaving\n"));
105 // AddDevice, called when an instance of our supported hardware is found
106 // Returning anything other than NT_SUCCESS here causes the device to fail
108 NTSTATUS NTAPI
FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject
, IN PDEVICE_OBJECT PhysicalDeviceObject
)
111 PDEVICE_OBJECT deviceObject
;
112 PDEVICE_EXTENSION deviceExtension
;
115 UNICODE_STRING uniDeviceName
;
116 WCHAR wszDeviceName
[255]={0};
117 UNICODE_STRING uniDosDeviceName
;
118 LONG instanceNumber
=0;
120 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Entered\n"));
124 swprintf(wszDeviceName
, L
"\\Device\\FbtUsb%02d", instanceNumber
);
125 RtlInitUnicodeString(&uniDeviceName
, wszDeviceName
);
126 ntStatus
=STATUS_OBJECT_NAME_COLLISION
;
127 while (instanceNumber
<99 && !NT_SUCCESS(ntStatus
))
129 swprintf(wszDeviceName
, L
"\\Device\\FbtUsb%02d", instanceNumber
);
130 uniDeviceName
.Length
= wcslen(wszDeviceName
) * sizeof(WCHAR
);
131 FreeBT_DbgPrint(1, ("FBTUSB: Attempting to create device %ws\n", wszDeviceName
));
132 ntStatus
= IoCreateDevice(
133 DriverObject
, // our driver object
134 sizeof(DEVICE_EXTENSION
), // extension size for us
135 &uniDeviceName
, // name for this device
137 0, // device characteristics
138 FALSE
, // Not exclusive
139 &deviceObject
); // Our device object
141 if (!NT_SUCCESS(ntStatus
))
146 if (!NT_SUCCESS(ntStatus
))
148 FreeBT_DbgPrint(1, ("FBTUSB: Failed to create device object\n"));
153 FreeBT_DbgPrint(1, ("FBTUSB: Created device %ws\n", wszDeviceName
));
155 deviceExtension
= (PDEVICE_EXTENSION
) deviceObject
->DeviceExtension
;
156 deviceExtension
->FunctionalDeviceObject
= deviceObject
;
157 deviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
158 deviceObject
->Flags
|= DO_DIRECT_IO
;
160 swprintf(deviceExtension
->wszDosDeviceName
, L
"\\DosDevices\\FbtUsb%02d", instanceNumber
);
161 RtlInitUnicodeString(&uniDosDeviceName
, deviceExtension
->wszDosDeviceName
);
162 ntStatus
=IoCreateSymbolicLink(&uniDosDeviceName
, &uniDeviceName
);
163 if (!NT_SUCCESS(ntStatus
))
165 FreeBT_DbgPrint(1, ("FBTUSB: Failed to create symbolic link %ws to %ws, status=0x%08x\n", deviceExtension
->wszDosDeviceName
, wszDeviceName
, ntStatus
));
166 IoDeleteDevice(deviceObject
);
171 FreeBT_DbgPrint(1, ("FBTUSB: Created symbolic link %ws\n", deviceExtension
->wszDosDeviceName
));
173 KeInitializeSpinLock(&deviceExtension
->DevStateLock
);
175 INITIALIZE_PNP_STATE(deviceExtension
);
177 deviceExtension
->OpenHandleCount
= 0;
179 // Initialize the selective suspend variables
180 KeInitializeSpinLock(&deviceExtension
->IdleReqStateLock
);
181 deviceExtension
->IdleReqPend
= 0;
182 deviceExtension
->PendingIdleIrp
= NULL
;
184 // Hold requests until the device is started
185 deviceExtension
->QueueState
= HoldRequests
;
187 // Initialize the queue and the queue spin lock
188 InitializeListHead(&deviceExtension
->NewRequestsQueue
);
189 KeInitializeSpinLock(&deviceExtension
->QueueLock
);
191 // Initialize the remove event to not-signaled.
192 KeInitializeEvent(&deviceExtension
->RemoveEvent
, SynchronizationEvent
, FALSE
);
194 // Initialize the stop event to signaled.
195 // This event is signaled when the OutstandingIO becomes 1
196 KeInitializeEvent(&deviceExtension
->StopEvent
, SynchronizationEvent
, TRUE
);
198 // OutstandingIo count biased to 1.
199 // Transition to 0 during remove device means IO is finished.
200 // Transition to 1 means the device can be stopped
201 deviceExtension
->OutStandingIO
= 1;
202 KeInitializeSpinLock(&deviceExtension
->IOCountLock
);
205 // Delegating to WMILIB
206 ntStatus
= FreeBT_WmiRegistration(deviceExtension
);
207 if (!NT_SUCCESS(ntStatus
))
209 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WmiRegistration failed with %X\n", ntStatus
));
210 IoDeleteDevice(deviceObject
);
211 IoDeleteSymbolicLink(&uniDosDeviceName
);
217 // Set the flags as underlying PDO
218 if (PhysicalDeviceObject
->Flags
& DO_POWER_PAGABLE
)
220 deviceObject
->Flags
|= DO_POWER_PAGABLE
;
224 // Typically, the function driver for a device is its
225 // power policy owner, although for some devices another
226 // driver or system component may assume this role.
227 // Set the initial power state of the device, if known, by calling
229 deviceExtension
->DevPower
= PowerDeviceD0
;
230 deviceExtension
->SysPower
= PowerSystemWorking
;
232 state
.DeviceState
= PowerDeviceD0
;
233 PoSetPowerState(deviceObject
, DevicePowerState
, state
);
235 // attach our driver to device stack
236 // The return value of IoAttachDeviceToDeviceStack is the top of the
237 // attachment chain. This is where all the IRPs should be routed.
238 deviceExtension
->TopOfStackDeviceObject
= IoAttachDeviceToDeviceStack(deviceObject
, PhysicalDeviceObject
);
239 if (NULL
== deviceExtension
->TopOfStackDeviceObject
)
242 FreeBT_WmiDeRegistration(deviceExtension
);
244 IoDeleteDevice(deviceObject
);
245 IoDeleteSymbolicLink(&uniDosDeviceName
);
246 return STATUS_NO_SUCH_DEVICE
;
250 // Register device interfaces
251 ntStatus
= IoRegisterDeviceInterface(deviceExtension
->PhysicalDeviceObject
,
252 &GUID_CLASS_FREEBT_USB
,
254 &deviceExtension
->InterfaceName
);
255 if (!NT_SUCCESS(ntStatus
))
258 FreeBT_WmiDeRegistration(deviceExtension
);
260 IoDetachDevice(deviceExtension
->TopOfStackDeviceObject
);
261 IoDeleteDevice(deviceObject
);
262 IoDeleteSymbolicLink(&uniDosDeviceName
);
267 if (IoIsWdmVersionAvailable(1, 0x20))
269 deviceExtension
->WdmVersion
= WinXpOrBetter
;
273 else if (IoIsWdmVersionAvailable(1, 0x10))
275 deviceExtension
->WdmVersion
= Win2kOrBetter
;
279 else if (IoIsWdmVersionAvailable(1, 0x5))
281 deviceExtension
->WdmVersion
= WinMeOrBetter
;
285 else if (IoIsWdmVersionAvailable(1, 0x0))
287 deviceExtension
->WdmVersion
= Win98OrBetter
;
291 deviceExtension
->SSRegistryEnable
= 0;
292 deviceExtension
->SSEnable
= 0;
294 // WinXP only: check the registry flag indicating whether
295 // the device should selectively suspend when idle
296 if (WinXpOrBetter
== deviceExtension
->WdmVersion
)
298 FreeBT_GetRegistryDword(FREEBT_REGISTRY_PARAMETERS_PATH
,
300 (PULONG
)(&deviceExtension
->SSRegistryEnable
));
301 if (deviceExtension
->SSRegistryEnable
)
304 KeInitializeDpc(&deviceExtension
->DeferredProcCall
, DpcRoutine
, deviceObject
);
306 // initialize the timer.
307 // the DPC and the timer in conjunction,
308 // monitor the state of the device to
309 // selectively suspend the device.
310 KeInitializeTimerEx(&deviceExtension
->Timer
, NotificationTimer
);
312 // Initialize the NoDpcWorkItemPendingEvent to signaled state.
313 // This event is cleared when a Dpc is fired and signaled
314 // on completion of the work-item.
315 KeInitializeEvent(&deviceExtension
->NoDpcWorkItemPendingEvent
, NotificationEvent
, TRUE
);
317 // Initialize the NoIdleReqPendEvent to ensure that the idle request
318 // is indeed complete before we unload the drivers.
319 KeInitializeEvent(&deviceExtension
->NoIdleReqPendEvent
, NotificationEvent
, TRUE
);
325 // Initialize the NoIdleReqPendEvent to ensure that the idle request
326 // is indeed complete before we unload the drivers.
327 KeInitializeEvent(&deviceExtension
->DelayEvent
, NotificationEvent
, FALSE
);
329 // Clear the DO_DEVICE_INITIALIZING flag.
330 // Note: Do not clear this flag until the driver has set the
331 // device power state and the power DO flags.
332 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
333 InterlockedIncrement(&instanceNumber
);
335 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Leaving\n"));