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