xref: /reactos/drivers/bluetooth/fbtusb/fbtusb.c (revision 60eea2d7)
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 
342