Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

452 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. selSusp.c
  5. Abstract:
  6. This module contains code for a generic client driver that can be loaded
  7. for all USB devices/child interfaces.
  8. Author:
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Copyright (c) 2000 Microsoft Corporation.
  13. All Rights Reserved.
  14. --*/
  15. #include "selSusp.h"
  16. #include "sSPnP.h"
  17. #include "sSPwr.h"
  18. #include "sSUsr.h"
  19. #include "sSDevCtr.h"
  20. #include "sSWmi.h"
  21. //
  22. // Globals
  23. //
  24. GLOBALS Globals;
  25. ULONG DebugLevel = 1;
  26. NTSTATUS
  27. DriverEntry(
  28. IN PDRIVER_OBJECT DriverObject,
  29. IN PUNICODE_STRING UniRegistryPath
  30. );
  31. VOID
  32. SS_DriverUnload(
  33. IN PDRIVER_OBJECT DriverObject
  34. );
  35. NTSTATUS
  36. SS_AddDevice(
  37. IN PDRIVER_OBJECT DriverObject,
  38. IN PDEVICE_OBJECT PhysicalDeviceObject
  39. );
  40. #ifdef PAGE_CODE
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(INIT, DriverEntry)
  43. #pragma alloc_text(PAGE, SS_DriverUnload)
  44. #pragma alloc_text(PAGE, SS_DispatchCreate)
  45. #pragma alloc_text(PAGE, SS_DispatchClose)
  46. #endif
  47. #endif
  48. NTSTATUS
  49. DriverEntry(
  50. IN PDRIVER_OBJECT DriverObject,
  51. IN PUNICODE_STRING UniRegistryPath
  52. )
  53. /*++
  54. Routine Description:
  55. Installable driver initialization entry point.
  56. This entry point is called directly by the I/O system.
  57. Arguments:
  58. DriverObject - pointer to driver object
  59. RegistryPath - pointer to a unicode string representing the path to driver
  60. specific key in the registry.
  61. Return Values:
  62. NT status code
  63. --*/
  64. {
  65. NTSTATUS ntStatus;
  66. PUNICODE_STRING registryPath;
  67. //
  68. // initialization of variables
  69. //
  70. registryPath = &Globals.SSRegistryPath;
  71. //
  72. // Allocate pool to hold a null-terminated copy of the path.
  73. // Safe in paged pool since all registry routines execute at
  74. // PASSIVE_LEVEL.
  75. //
  76. registryPath->MaximumLength = UniRegistryPath->Length + sizeof(UNICODE_NULL);
  77. registryPath->Length = UniRegistryPath->Length;
  78. registryPath->Buffer = ExAllocatePool(PagedPool,
  79. registryPath->MaximumLength);
  80. if (!registryPath->Buffer) {
  81. SSDbgPrint(1, ("Failed to allocate memory for registryPath\n"));
  82. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  83. goto DriverEntry_Exit;
  84. }
  85. RtlZeroMemory (registryPath->Buffer,
  86. registryPath->MaximumLength);
  87. RtlMoveMemory (registryPath->Buffer,
  88. UniRegistryPath->Buffer,
  89. UniRegistryPath->Length);
  90. ntStatus = STATUS_SUCCESS;
  91. //
  92. // Initialize the driver object with this driver's entry points.
  93. //
  94. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SS_DispatchDevCtrl;
  95. DriverObject->MajorFunction[IRP_MJ_POWER] = SS_DispatchPower;
  96. DriverObject->MajorFunction[IRP_MJ_PNP] = SS_DispatchPnP;
  97. DriverObject->MajorFunction[IRP_MJ_CREATE] = SS_DispatchCreate;
  98. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SS_DispatchClose;
  99. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SS_DispatchClean;
  100. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SS_DispatchSysCtrl;
  101. DriverObject->DriverUnload = SS_DriverUnload;
  102. DriverObject->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)
  103. SS_AddDevice;
  104. DriverEntry_Exit:
  105. return ntStatus;
  106. }
  107. VOID
  108. SS_DriverUnload(
  109. IN PDRIVER_OBJECT DriverObject
  110. )
  111. /*++
  112. Description:
  113. This function will free the memory allocations in DriverEntry.
  114. Arguments:
  115. DriverObject - pointer to driver object
  116. Return:
  117. None
  118. --*/
  119. {
  120. PUNICODE_STRING registryPath;
  121. SSDbgPrint(3, ("SS_DriverUnload - begins\n"));
  122. registryPath = &Globals.SSRegistryPath;
  123. if(registryPath->Buffer) {
  124. ExFreePool(registryPath->Buffer);
  125. registryPath->Buffer = NULL;
  126. }
  127. SSDbgPrint(3, ("SS_DriverUnload - ends\n"));
  128. return;
  129. }
  130. NTSTATUS
  131. SS_AddDevice(
  132. IN PDRIVER_OBJECT DriverObject,
  133. IN PDEVICE_OBJECT PhysicalDeviceObject
  134. )
  135. /*++
  136. Description:
  137. Arguments:
  138. DriverObject - Store the pointer to the object representing us.
  139. PhysicalDeviceObject - Pointer to the device object created by the
  140. undelying bus driver.
  141. Return:
  142. STATUS_SUCCESS - if successful
  143. STATUS_UNSUCCESSFUL - otherwise
  144. --*/
  145. {
  146. NTSTATUS ntStatus;
  147. PDEVICE_OBJECT deviceObject;
  148. PDEVICE_EXTENSION deviceExtension;
  149. POWER_STATE state;
  150. KIRQL oldIrql;
  151. SSDbgPrint(3, ("SS_AddDevice - begins\n"));
  152. deviceObject = NULL;
  153. ntStatus = IoCreateDevice(
  154. DriverObject, // our driver object
  155. sizeof(DEVICE_EXTENSION), // extension size for us
  156. NULL, // name for this device
  157. FILE_DEVICE_UNKNOWN,
  158. FILE_AUTOGENERATED_DEVICE_NAME, // device characteristics
  159. FALSE, // Not exclusive
  160. &deviceObject); // Our device object
  161. if(!NT_SUCCESS(ntStatus)) {
  162. //
  163. // returning failure here prevents the entire stack from functioning,
  164. // but most likely the rest of the stack will not be able to create
  165. // device objects either, so it is still OK.
  166. //
  167. SSDbgPrint(1, ("Failed to create device object\n"));
  168. return ntStatus;
  169. }
  170. //
  171. // Initialize the device extension
  172. //
  173. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  174. deviceExtension->FunctionalDeviceObject = deviceObject;
  175. deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
  176. deviceObject->Flags |= DO_BUFFERED_IO;
  177. //
  178. // initialize the device state lock and set the device state
  179. //
  180. KeInitializeSpinLock(&deviceExtension->DevStateLock);
  181. INITIALIZE_PNP_STATE(deviceExtension);
  182. //
  183. //initialize OpenHandleCount
  184. //
  185. deviceExtension->OpenHandleCount = 0;
  186. //
  187. // Initialize the selective suspend variables
  188. //
  189. KeInitializeSpinLock(&deviceExtension->IdleReqStateLock);
  190. deviceExtension->IdleReqPend = 0;
  191. deviceExtension->PendingIdleIrp = NULL;
  192. //
  193. // Hold requests until the device is started
  194. //
  195. deviceExtension->QueueState = HoldRequests;
  196. //
  197. // Initialize the queue and the queue spin lock
  198. //
  199. InitializeListHead(&deviceExtension->NewRequestsQueue);
  200. KeInitializeSpinLock(&deviceExtension->QueueLock);
  201. //
  202. // Initialize the remove event to not-signaled.
  203. //
  204. KeInitializeEvent(&deviceExtension->RemoveEvent,
  205. SynchronizationEvent,
  206. FALSE);
  207. //
  208. // Initialize the stop event to signaled.
  209. // This event is signaled when the OutstandingIO becomes 1
  210. //
  211. KeInitializeEvent(&deviceExtension->StopEvent,
  212. SynchronizationEvent,
  213. TRUE);
  214. //
  215. // OutstandingIo count biased to 1.
  216. // Transition to 0 during remove device means IO is finished.
  217. // Transition to 1 means the device can be stopped
  218. //
  219. deviceExtension->OutStandingIO = 1;
  220. KeInitializeSpinLock(&deviceExtension->IOCountLock);
  221. //
  222. // Delegating to WMILIB
  223. //
  224. ntStatus = SSWmiRegistration(deviceExtension);
  225. if(!NT_SUCCESS(ntStatus)) {
  226. SSDbgPrint(1, ("SSWmiRegistration failed with %X\n", ntStatus));
  227. IoDeleteDevice(deviceObject);
  228. return ntStatus;
  229. }
  230. //
  231. // set the flags as underlying PDO
  232. //
  233. if(PhysicalDeviceObject->Flags & DO_POWER_PAGABLE) {
  234. deviceObject->Flags |= DO_POWER_PAGABLE;
  235. }
  236. //
  237. // Typically, the function driver for a device is its
  238. // power policy owner, although for some devices another
  239. // driver or system component may assume this role.
  240. // Set the initial power state of the device, if known, by calling
  241. // PoSetPowerState.
  242. //
  243. deviceExtension->DevPower = PowerDeviceD0;
  244. deviceExtension->SysPower = PowerSystemWorking;
  245. state.DeviceState = PowerDeviceD0;
  246. PoSetPowerState(deviceObject, DevicePowerState, state);
  247. //
  248. // attach our driver to device stack
  249. // The return value of IoAttachDeviceToDeviceStack is the top of the
  250. // attachment chain. This is where all the IRPs should be routed.
  251. //
  252. deviceExtension->TopOfStackDeviceObject =
  253. IoAttachDeviceToDeviceStack(deviceObject,
  254. PhysicalDeviceObject);
  255. if(NULL == deviceExtension->TopOfStackDeviceObject) {
  256. SSWmiDeRegistration(deviceExtension);
  257. IoDeleteDevice(deviceObject);
  258. return STATUS_NO_SUCH_DEVICE;
  259. }
  260. //
  261. // Register device interfaces
  262. //
  263. ntStatus = IoRegisterDeviceInterface(deviceExtension->PhysicalDeviceObject,
  264. &GUID_GENERIC_SELECTIVE_SUSPEND,
  265. NULL,
  266. &deviceExtension->InterfaceName);
  267. if(!NT_SUCCESS(ntStatus)) {
  268. SSWmiDeRegistration(deviceExtension);
  269. IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
  270. IoDeleteDevice(deviceObject);
  271. return ntStatus;
  272. }
  273. if(IoIsWdmVersionAvailable(1, 0x20)) {
  274. deviceExtension->WdmVersion = WinXpOrBetter;
  275. }
  276. else if(IoIsWdmVersionAvailable(1, 0x10)) {
  277. deviceExtension->WdmVersion = Win2kOrBetter;
  278. }
  279. else if(IoIsWdmVersionAvailable(1, 0x5)) {
  280. deviceExtension->WdmVersion = WinMeOrBetter;
  281. }
  282. else if(IoIsWdmVersionAvailable(1, 0x0)) {
  283. deviceExtension->WdmVersion = Win98OrBetter;
  284. }
  285. deviceExtension->SSRegistryEnable = 0;
  286. deviceExtension->SSEnable = 0;
  287. //
  288. // Win XP only
  289. // check the registry flag -
  290. // whether the device should selectively
  291. // suspend when idle
  292. //
  293. if(WinXpOrBetter == deviceExtension->WdmVersion) {
  294. SS_GetRegistryDword(SELSUSP_REGISTRY_PARAMETERS_PATH,
  295. L"SelectSuspendEnable",
  296. &deviceExtension->SSRegistryEnable);
  297. if(deviceExtension->SSRegistryEnable) {
  298. //
  299. // initialize the DPC
  300. //
  301. KeInitializeDpc(&deviceExtension->DeferredProcCall,
  302. DpcRoutine,
  303. deviceObject);
  304. //
  305. // initialize the timer.
  306. // the DPC and the timer in conjunction,
  307. // monitor the state of the device to
  308. // selectively suspend the device.
  309. //
  310. KeInitializeTimerEx(&deviceExtension->Timer,
  311. NotificationTimer);
  312. //
  313. // Initialize the NoDpcWorkItemPendingEvent to signaled state.
  314. // This event is cleared when a Dpc is fired and signaled
  315. // on completion of the work-item.
  316. //
  317. KeInitializeEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
  318. NotificationEvent,
  319. TRUE);
  320. //
  321. // Initialize the NoIdleReqPendEvent to ensure that the idle request
  322. // is indeed complete before we unload the drivers.
  323. //
  324. KeInitializeEvent(&deviceExtension->NoIdleReqPendEvent,
  325. NotificationEvent,
  326. TRUE);
  327. }
  328. }
  329. //
  330. // Clear the DO_DEVICE_INITIALIZING flag.
  331. // Note: Do not clear this flag until the driver has set the
  332. // device power state and the power DO flags.
  333. //
  334. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  335. SSDbgPrint(3, ("SS_AddDevice - ends\n"));
  336. return ntStatus;
  337. }