Sunc with trunk revision 58971.
[reactos.git] / drivers / bluetooth / fbtusb / fbtusb.c
1 // Copyright (c) 2004, Antony C. Roberts
2
3 // Use of this file is subject to the terms
4 // described in the LICENSE.TXT file that
5 // accompanies this file.
6 //
7 // Your use of this file indicates your
8 // acceptance of the terms described in
9 // LICENSE.TXT.
10 //
11 // http://www.freebt.net
12
13 #include "stdio.h"
14 #include "fbtusb.h"
15 #include "fbtpnp.h"
16 #include "fbtpwr.h"
17 #include "fbtdev.h"
18 #include "fbtwmi.h"
19 #include "fbtrwr.h"
20
21 #include "fbtusr.h"
22
23
24 // Globals
25 GLOBALS Globals;
26 ULONG DebugLevel=255;
27
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);
32
33 #ifdef PAGE_CODE
34 #ifdef ALLOC_PRAGMA
35 #pragma alloc_text(INIT, DriverEntry)
36 #pragma alloc_text(PAGE, FreeBT_DriverUnload)
37 #endif
38 #endif
39
40 NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING UniRegistryPath)
41 {
42 NTSTATUS ntStatus;
43 PUNICODE_STRING registryPath;
44
45 registryPath = &Globals.FreeBT_RegistryPath;
46
47 registryPath->MaximumLength = UniRegistryPath->Length + sizeof(UNICODE_NULL);
48 registryPath->Length = UniRegistryPath->Length;
49 registryPath->Buffer = (PWSTR) ExAllocatePool(PagedPool, registryPath->MaximumLength);
50
51 if (!registryPath->Buffer)
52 {
53 FreeBT_DbgPrint(1, ("FBTUSB: Failed to allocate memory for registryPath\n"));
54 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
55 goto DriverEntry_Exit;
56
57 }
58
59
60 RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
61 RtlMoveMemory (registryPath->Buffer, UniRegistryPath->Buffer, UniRegistryPath->Length);
62
63 ntStatus = STATUS_SUCCESS;
64
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;
74 #ifdef ENABLE_WMI
75 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = FreeBT_DispatchSysCtrl;
76 #endif
77 DriverObject->DriverUnload = FreeBT_DriverUnload;
78 DriverObject->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE) FreeBT_AddDevice;
79
80 DriverEntry_Exit:
81 return ntStatus;
82
83 }
84
85 VOID NTAPI FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject)
86 {
87 PUNICODE_STRING registryPath;
88
89 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Entered\n"));
90
91 registryPath = &Globals.FreeBT_RegistryPath;
92 if(registryPath->Buffer)
93 {
94 ExFreePool(registryPath->Buffer);
95 registryPath->Buffer = NULL;
96
97 }
98
99 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Leaving\n"));
100
101 return;
102
103 }
104
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
107 // to initialise
108 NTSTATUS NTAPI FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
109 {
110 NTSTATUS ntStatus;
111 PDEVICE_OBJECT deviceObject;
112 PDEVICE_EXTENSION deviceExtension;
113 POWER_STATE state;
114 //KIRQL oldIrql;
115 UNICODE_STRING uniDeviceName;
116 WCHAR wszDeviceName[255]={0};
117 UNICODE_STRING uniDosDeviceName;
118 LONG instanceNumber=0;
119
120 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Entered\n"));
121
122 deviceObject = NULL;
123
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))
128 {
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
136 FILE_DEVICE_UNKNOWN,
137 0, // device characteristics
138 FALSE, // Not exclusive
139 &deviceObject); // Our device object
140
141 if (!NT_SUCCESS(ntStatus))
142 instanceNumber++;
143
144 }
145
146 if (!NT_SUCCESS(ntStatus))
147 {
148 FreeBT_DbgPrint(1, ("FBTUSB: Failed to create device object\n"));
149 return ntStatus;
150
151 }
152
153 FreeBT_DbgPrint(1, ("FBTUSB: Created device %ws\n", wszDeviceName));
154
155 deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
156 deviceExtension->FunctionalDeviceObject = deviceObject;
157 deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
158 deviceObject->Flags |= DO_DIRECT_IO;
159
160 swprintf(deviceExtension->wszDosDeviceName, L"\\DosDevices\\FbtUsb%02d", instanceNumber);
161 RtlInitUnicodeString(&uniDosDeviceName, deviceExtension->wszDosDeviceName);
162 ntStatus=IoCreateSymbolicLink(&uniDosDeviceName, &uniDeviceName);
163 if (!NT_SUCCESS(ntStatus))
164 {
165 FreeBT_DbgPrint(1, ("FBTUSB: Failed to create symbolic link %ws to %ws, status=0x%08x\n", deviceExtension->wszDosDeviceName, wszDeviceName, ntStatus));
166 IoDeleteDevice(deviceObject);
167 return ntStatus;
168
169 }
170
171 FreeBT_DbgPrint(1, ("FBTUSB: Created symbolic link %ws\n", deviceExtension->wszDosDeviceName));
172
173 KeInitializeSpinLock(&deviceExtension->DevStateLock);
174
175 INITIALIZE_PNP_STATE(deviceExtension);
176
177 deviceExtension->OpenHandleCount = 0;
178
179 // Initialize the selective suspend variables
180 KeInitializeSpinLock(&deviceExtension->IdleReqStateLock);
181 deviceExtension->IdleReqPend = 0;
182 deviceExtension->PendingIdleIrp = NULL;
183
184 // Hold requests until the device is started
185 deviceExtension->QueueState = HoldRequests;
186
187 // Initialize the queue and the queue spin lock
188 InitializeListHead(&deviceExtension->NewRequestsQueue);
189 KeInitializeSpinLock(&deviceExtension->QueueLock);
190
191 // Initialize the remove event to not-signaled.
192 KeInitializeEvent(&deviceExtension->RemoveEvent, SynchronizationEvent, FALSE);
193
194 // Initialize the stop event to signaled.
195 // This event is signaled when the OutstandingIO becomes 1
196 KeInitializeEvent(&deviceExtension->StopEvent, SynchronizationEvent, TRUE);
197
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);
203
204 #ifdef ENABLE_WMI
205 // Delegating to WMILIB
206 ntStatus = FreeBT_WmiRegistration(deviceExtension);
207 if (!NT_SUCCESS(ntStatus))
208 {
209 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WmiRegistration failed with %X\n", ntStatus));
210 IoDeleteDevice(deviceObject);
211 IoDeleteSymbolicLink(&uniDosDeviceName);
212 return ntStatus;
213
214 }
215 #endif
216
217 // Set the flags as underlying PDO
218 if (PhysicalDeviceObject->Flags & DO_POWER_PAGABLE)
219 {
220 deviceObject->Flags |= DO_POWER_PAGABLE;
221
222 }
223
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
228 // PoSetPowerState.
229 deviceExtension->DevPower = PowerDeviceD0;
230 deviceExtension->SysPower = PowerSystemWorking;
231
232 state.DeviceState = PowerDeviceD0;
233 PoSetPowerState(deviceObject, DevicePowerState, state);
234
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)
240 {
241 #ifdef ENABLE_WMI
242 FreeBT_WmiDeRegistration(deviceExtension);
243 #endif
244 IoDeleteDevice(deviceObject);
245 IoDeleteSymbolicLink(&uniDosDeviceName);
246 return STATUS_NO_SUCH_DEVICE;
247
248 }
249
250 // Register device interfaces
251 ntStatus = IoRegisterDeviceInterface(deviceExtension->PhysicalDeviceObject,
252 &GUID_CLASS_FREEBT_USB,
253 NULL,
254 &deviceExtension->InterfaceName);
255 if (!NT_SUCCESS(ntStatus))
256 {
257 #ifdef ENABLE_WMI
258 FreeBT_WmiDeRegistration(deviceExtension);
259 #endif
260 IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
261 IoDeleteDevice(deviceObject);
262 IoDeleteSymbolicLink(&uniDosDeviceName);
263 return ntStatus;
264
265 }
266
267 if (IoIsWdmVersionAvailable(1, 0x20))
268 {
269 deviceExtension->WdmVersion = WinXpOrBetter;
270
271 }
272
273 else if (IoIsWdmVersionAvailable(1, 0x10))
274 {
275 deviceExtension->WdmVersion = Win2kOrBetter;
276
277 }
278
279 else if (IoIsWdmVersionAvailable(1, 0x5))
280 {
281 deviceExtension->WdmVersion = WinMeOrBetter;
282
283 }
284
285 else if (IoIsWdmVersionAvailable(1, 0x0))
286 {
287 deviceExtension->WdmVersion = Win98OrBetter;
288
289 }
290
291 deviceExtension->SSRegistryEnable = 0;
292 deviceExtension->SSEnable = 0;
293
294 // WinXP only: check the registry flag indicating whether
295 // the device should selectively suspend when idle
296 if (WinXpOrBetter == deviceExtension->WdmVersion)
297 {
298 FreeBT_GetRegistryDword(FREEBT_REGISTRY_PARAMETERS_PATH,
299 L"BulkUsbEnable",
300 (PULONG)(&deviceExtension->SSRegistryEnable));
301 if (deviceExtension->SSRegistryEnable)
302 {
303 // initialize DPC
304 KeInitializeDpc(&deviceExtension->DeferredProcCall, DpcRoutine, deviceObject);
305
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);
311
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);
316
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);
320
321 }
322
323 }
324
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);
328
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);
334
335 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Leaving\n"));
336
337 return ntStatus;
338
339 }
340
341