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.

575 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Comppnp.c
  5. Abstract:
  6. Composite Battery PnP and power functions
  7. Author:
  8. Scott Brenden
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "compbatt.h"
  14. #include <initguid.h>
  15. #include <wdmguid.h>
  16. #include <batclass.h>
  17. NTSTATUS
  18. CompBattPnpDispatch(
  19. IN PDEVICE_OBJECT DeviceObject,
  20. IN PIRP Irp
  21. )
  22. /*++
  23. Routine Description:
  24. IOCTL handler for the plug and play irps.
  25. Arguments:
  26. DeviceObject - Battery for request
  27. Irp - IO request
  28. Return Value:
  29. Status of request
  30. --*/
  31. {
  32. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  33. NTSTATUS status = STATUS_NOT_SUPPORTED;
  34. PCOMPOSITE_BATTERY compBatt = (PCOMPOSITE_BATTERY)DeviceObject->DeviceExtension;
  35. BattPrint (BATT_TRACE, ("CompBatt: ENTERING PnpDispatch\n"));
  36. switch (irpStack->MinorFunction) {
  37. case IRP_MN_START_DEVICE: {
  38. //
  39. // Register for Pnp notification of batteries coming and going
  40. //
  41. status = IoRegisterPlugPlayNotification(
  42. EventCategoryDeviceInterfaceChange,
  43. 0,
  44. (LPGUID)&GUID_DEVICE_BATTERY,
  45. DeviceObject->DriverObject,
  46. CompBattPnpEventHandler,
  47. compBatt,
  48. &compBatt->NotificationEntry
  49. );
  50. if (!NT_SUCCESS(status)) {
  51. BattPrint (BATT_ERROR, ("CompBatt: Couldn't register for PnP notification - %x\n", status));
  52. } else {
  53. BattPrint (BATT_NOTE, ("CompBatt: Successfully registered for PnP notification\n"));
  54. //
  55. // Get the batteries that are already present in the system
  56. //
  57. status = CompBattGetBatteries (compBatt);
  58. }
  59. break;
  60. }
  61. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  62. //
  63. // Prevent device from being manually uninstalled.
  64. //
  65. Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
  66. status = STATUS_SUCCESS;
  67. break;
  68. }
  69. case IRP_MN_REMOVE_DEVICE:
  70. case IRP_MN_QUERY_REMOVE_DEVICE:
  71. case IRP_MN_STOP_DEVICE:
  72. case IRP_MN_QUERY_STOP_DEVICE: {
  73. status = STATUS_INVALID_DEVICE_REQUEST;
  74. break;
  75. }
  76. case IRP_MN_CANCEL_REMOVE_DEVICE:
  77. case IRP_MN_CANCEL_STOP_DEVICE:
  78. case IRP_MN_SURPRISE_REMOVAL: {
  79. status = STATUS_SUCCESS;
  80. break;
  81. }
  82. }
  83. //
  84. // Rules for handling PnP IRPs:
  85. // 1) Don't change the status of any IRP we don't handle. We identify
  86. // IRPs we don't handle via the code STATUS_NOT_SUPPORTED. This is
  87. // the same code all PNP irps start out with, and as we are not allowed
  88. // to fail IRPs with that code, it is the perfect choice to use this
  89. // way.
  90. // 2) Pass down all IRPs that we succeed or do not touch. Immediately
  91. // complete any failures (excepting STATUS_NOT_SUPPORTED of course).
  92. //
  93. if (status != STATUS_NOT_SUPPORTED) {
  94. Irp->IoStatus.Status = status;
  95. }
  96. if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
  97. IoSkipCurrentIrpStackLocation (Irp);
  98. status = IoCallDriver(compBatt->LowerDevice, Irp) ;
  99. } else {
  100. status = Irp->IoStatus.Status ;
  101. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  102. }
  103. BattPrint (BATT_TRACE, ("CompBatt: EXITING PnpDispatch\n"));
  104. return status;
  105. }
  106. NTSTATUS
  107. CompBattPowerDispatch(
  108. IN PDEVICE_OBJECT DeviceObject,
  109. IN PIRP Irp
  110. )
  111. /*++
  112. Routine Description:
  113. IOCTL handler for the power irps.
  114. Arguments:
  115. DeviceObject - Battery for request
  116. Irp - IO request
  117. Return Value:
  118. Status of request
  119. --*/
  120. {
  121. PCOMPOSITE_BATTERY compBatt = (PCOMPOSITE_BATTERY)DeviceObject->DeviceExtension;
  122. BattPrint (BATT_TRACE, ("CompBatt: PowerDispatch recieved power IRP.\n"));
  123. PoStartNextPowerIrp (Irp);
  124. IoSkipCurrentIrpStackLocation (Irp);
  125. return PoCallDriver(compBatt->LowerDevice, Irp) ;
  126. }
  127. NTSTATUS
  128. CompBattPnpEventHandler(
  129. IN PVOID NotificationStructure,
  130. IN PVOID Context
  131. )
  132. /*++
  133. Routine Description:
  134. This routine handles Plug and Play event notifications. The only ones that
  135. have been asked for are device interface changes associated with batteries,
  136. so we will only receive notifications when batteries come and go (provided
  137. they register their device interface).
  138. Arguments:
  139. NotificationStructure - This will be type PDEVICE_INTERFACE_CHANGE_NOTIFICATION
  140. Context - The composite battery device extension
  141. Return Value:
  142. STATUS_SUCCESS
  143. --*/
  144. {
  145. PDEVICE_INTERFACE_CHANGE_NOTIFICATION changeNotification;
  146. PCOMPOSITE_BATTERY compBatt;
  147. BattPrint (BATT_TRACE, ("CompBatt: ENTERING PnpEventHandler\n"));
  148. compBatt = (PCOMPOSITE_BATTERY) Context;
  149. changeNotification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
  150. BattPrint(BATT_NOTE, ("CompBatt: Received device interface change notification\n"));
  151. if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
  152. BattPrint(BATT_NOTE, ("CompBatt: Received notification of battery arrival\n"));
  153. CompBattAddNewBattery (changeNotification->SymbolicLinkName, compBatt);
  154. } else if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
  155. BattPrint (BATT_NOTE, ("CompBatt: Received notification of battery removal\n"));
  156. //
  157. // Nothing to do here. MonitorIrpComplete will do cleanup when it's requests fail
  158. // with STATUS_DEVICE_REMOVED.
  159. //
  160. } else {
  161. BattPrint (BATT_NOTE, ("CompBatt: Received unhandled PnP event\n"));
  162. }
  163. BattPrint (BATT_TRACE, ("CompBatt: EXITING PnpEventHandler\n"));
  164. return STATUS_SUCCESS;
  165. }
  166. NTSTATUS
  167. CompBattRemoveBattery(
  168. IN PUNICODE_STRING SymbolicLinkName,
  169. IN PCOMPOSITE_BATTERY CompBatt
  170. )
  171. /*++
  172. Routine Description:
  173. This routine removes an existing battery from the list of batteries kept by the
  174. composite battery.
  175. Arguments:
  176. SymbolicLinkName - Name used to check if battery is on list
  177. and to close the battery if so.
  178. CompBatt - Device extension for the composite battery
  179. Return Value:
  180. NTSTATUS
  181. --*/
  182. {
  183. PCOMPOSITE_ENTRY Battery;
  184. // NonPaged code. This is called by an Irp completion routine.
  185. BattPrint (BATT_TRACE, ("CompBatt: RemoveBattery\n"));
  186. //
  187. // Remove the battery from the list if it is there.
  188. //
  189. Battery = RemoveBatteryFromList (SymbolicLinkName, CompBatt);
  190. if(!Battery) {
  191. //
  192. // removed ok if not on list
  193. //
  194. return STATUS_SUCCESS;
  195. }
  196. //
  197. // Deallocate the Work Item.
  198. //
  199. ObDereferenceObject(Battery->DeviceObject);
  200. ExFreePool (Battery);
  201. // Invalidate cached Battery info and send notification
  202. CompBatt->Info.Valid = 0;
  203. BatteryClassStatusNotify (CompBatt->Class);
  204. return STATUS_SUCCESS;
  205. }
  206. NTSTATUS
  207. CompBattAddNewBattery(
  208. IN PUNICODE_STRING SymbolicLinkName,
  209. IN PCOMPOSITE_BATTERY CompBatt
  210. )
  211. /*++
  212. Routine Description:
  213. This routine adds a new battery to the list of batteries kept by the
  214. composite battery.
  215. Arguments:
  216. SymbolicLinkName - Name used to check if battery is already on list
  217. and to open the battery if not.
  218. CompBatt - Device extension for the composite battery
  219. Return Value:
  220. NTSTATUS
  221. --*/
  222. {
  223. PCOMPOSITE_ENTRY newBattery;
  224. PUNICODE_STRING battName;
  225. PFILE_OBJECT fileObject;
  226. PIO_STACK_LOCATION irpSp;
  227. PIRP newIrp;
  228. BOOLEAN onList;
  229. NTSTATUS status = STATUS_SUCCESS;
  230. PAGED_CODE();
  231. BattPrint (BATT_TRACE, ("CompBatt: ENTERING AddNewBattery \"%w\" \n", SymbolicLinkName->Buffer));
  232. //
  233. // Lock the list and see if this new battery is on it
  234. //
  235. onList = IsBatteryAlreadyOnList (SymbolicLinkName, CompBatt);
  236. if (!onList) {
  237. //
  238. // Create the node for the new battery
  239. //
  240. newBattery = ExAllocatePoolWithTag(
  241. NonPagedPool,
  242. sizeof (COMPOSITE_ENTRY) + SymbolicLinkName->Length,
  243. 'CtaB'
  244. );
  245. if (!newBattery) {
  246. BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery node\n"));
  247. status = STATUS_INSUFFICIENT_RESOURCES;
  248. goto AddNewBatteryClean1;
  249. }
  250. //
  251. // Initialize the new battery
  252. //
  253. RtlZeroMemory (newBattery, sizeof (COMPOSITE_ENTRY));
  254. newBattery->Info.Tag = BATTERY_TAG_INVALID;
  255. newBattery->NewBatt = TRUE;
  256. battName = &newBattery->BattName;
  257. battName->MaximumLength = SymbolicLinkName->Length;
  258. battName->Buffer = (PWCHAR)(battName + 1);
  259. RtlCopyUnicodeString (battName, SymbolicLinkName);
  260. //
  261. // Get the device object.
  262. //
  263. status = CompBattGetDeviceObjectPointer(SymbolicLinkName,
  264. FILE_ALL_ACCESS,
  265. &fileObject,
  266. &newBattery->DeviceObject
  267. );
  268. if (!NT_SUCCESS(status)) {
  269. BattPrint (BATT_ERROR, ("CompBattAddNewBattery: Failed to get device Object. status = %lx\n", status));
  270. goto AddNewBatteryClean2;
  271. }
  272. //
  273. // Increment the reference count to the device object of the battery
  274. //
  275. ObReferenceObject(newBattery->DeviceObject);
  276. //
  277. // Decrement reference count to file handle,
  278. // so batteries will not refuse removal requests.
  279. //
  280. ObDereferenceObject(fileObject);
  281. //
  282. // Allocate a status Irp for the new battery
  283. //
  284. newIrp = IoAllocateIrp ((UCHAR)(newBattery->DeviceObject->StackSize + 1), FALSE);
  285. if (!newIrp) {
  286. BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery Irp\n"));
  287. status = STATUS_INSUFFICIENT_RESOURCES;
  288. goto AddNewBatteryClean3;
  289. }
  290. newBattery->StatusIrp = newIrp;
  291. //
  292. // Setup control data on irp
  293. //
  294. irpSp = IoGetNextIrpStackLocation(newIrp);
  295. irpSp->Parameters.Others.Argument1 = (PVOID) CompBatt;
  296. irpSp->Parameters.Others.Argument2 = (PVOID) newBattery;
  297. //
  298. // Fill in irp so irp handler will re-dispatch it
  299. //
  300. IoSetNextIrpStackLocation (newIrp);
  301. irpSp = IoGetNextIrpStackLocation(newIrp);
  302. newIrp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  303. newBattery->State = CB_ST_GET_TAG;
  304. CompbattInitializeDeleteLock (&newBattery->DeleteLock);
  305. //
  306. // Put Battery onthe battery list before starting the
  307. // MonitorIrpComplete loop.
  308. //
  309. ExAcquireFastMutex (&CompBatt->ListMutex);
  310. InsertTailList (&CompBatt->Batteries, &newBattery->Batteries);
  311. ExReleaseFastMutex (&CompBatt->ListMutex);
  312. //
  313. // Initialize Work Item
  314. //
  315. ExInitializeWorkItem (&newBattery->WorkItem, CompBattMonitorIrpCompleteWorker, newBattery);
  316. //
  317. // Start Monitoring Battery
  318. //
  319. CompBattMonitorIrpComplete (newBattery->DeviceObject, newIrp, NULL);
  320. status = STATUS_SUCCESS;
  321. }
  322. goto AddNewBatteryClean1;
  323. AddNewBatteryClean3:
  324. ObDereferenceObject(newBattery->DeviceObject);
  325. AddNewBatteryClean2:
  326. ExFreePool (newBattery);
  327. AddNewBatteryClean1:
  328. BattPrint (BATT_TRACE, ("CompBatt: EXITING AddNewBattery\n"));
  329. return status;
  330. }
  331. NTSTATUS
  332. CompBattGetBatteries(
  333. IN PCOMPOSITE_BATTERY CompBatt
  334. )
  335. /*++
  336. Routine Description:
  337. This routine uses the PnP manager to get all the batteries that have already
  338. registered their interfaces (that we won't get notifications for) and then
  339. adds them to the list of batteries.
  340. Arguments:
  341. CompBatt - Device extension for the composite battery
  342. Return Value:
  343. NTSTATUS
  344. --*/
  345. {
  346. NTSTATUS status;
  347. UNICODE_STRING tmpString;
  348. PWSTR stringPointer;
  349. int i;
  350. BattPrint (BATT_TRACE, ("CompBatt: ENTERING GetBatteries\n"));
  351. //
  352. // Call the PnP manager to get the list of devices already register for the
  353. // battery class.
  354. //
  355. status = IoGetDeviceInterfaces(
  356. &GUID_DEVICE_BATTERY,
  357. NULL,
  358. 0,
  359. &stringPointer
  360. );
  361. if (!NT_SUCCESS(status)) {
  362. BattPrint (BATT_ERROR, ("CompBatt: Couldn't get list of batteries\n"));
  363. } else {
  364. //
  365. // Now parse the list and try to add them to the composite battery list
  366. //
  367. i = 0;
  368. RtlInitUnicodeString (&tmpString, &stringPointer[i]);
  369. while (tmpString.Length) {
  370. status = CompBattAddNewBattery (&tmpString, CompBatt);
  371. i += (tmpString.Length / sizeof(WCHAR)) + 1;
  372. RtlInitUnicodeString (&tmpString, &stringPointer[i]);
  373. }
  374. ExFreePool (stringPointer);
  375. }
  376. BattPrint (BATT_TRACE, ("CompBatt: EXITING GetBatteries\n"));
  377. return status;
  378. }