Source code of Windows XP (NT5)
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.

577 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. Irp->IoStatus.Status = STATUS_SUCCESS;
  124. PoStartNextPowerIrp (Irp);
  125. IoSkipCurrentIrpStackLocation (Irp);
  126. return PoCallDriver(compBatt->LowerDevice, Irp) ;
  127. }
  128. NTSTATUS
  129. CompBattPnpEventHandler(
  130. IN PVOID NotificationStructure,
  131. IN PVOID Context
  132. )
  133. /*++
  134. Routine Description:
  135. This routine handles Plug and Play event notifications. The only ones that
  136. have been asked for are device interface changes associated with batteries,
  137. so we will only receive notifications when batteries come and go (provided
  138. they register their device interface).
  139. Arguments:
  140. NotificationStructure - This will be type PDEVICE_INTERFACE_CHANGE_NOTIFICATION
  141. Context - The composite battery device extension
  142. Return Value:
  143. STATUS_SUCCESS
  144. --*/
  145. {
  146. PDEVICE_INTERFACE_CHANGE_NOTIFICATION changeNotification;
  147. PCOMPOSITE_BATTERY compBatt;
  148. BattPrint (BATT_TRACE, ("CompBatt: ENTERING PnpEventHandler\n"));
  149. compBatt = (PCOMPOSITE_BATTERY) Context;
  150. changeNotification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
  151. BattPrint(BATT_NOTE, ("CompBatt: Received device interface change notification\n"));
  152. if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
  153. BattPrint(BATT_NOTE, ("CompBatt: Received notification of battery arrival\n"));
  154. CompBattAddNewBattery (changeNotification->SymbolicLinkName, compBatt);
  155. } else if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
  156. BattPrint (BATT_NOTE, ("CompBatt: Received notification of battery removal\n"));
  157. //
  158. // Nothing to do here. MonitorIrpComplete will do cleanup when it's requests fail
  159. // with STATUS_DEVICE_REMOVED.
  160. //
  161. } else {
  162. BattPrint (BATT_NOTE, ("CompBatt: Received unhandled PnP event\n"));
  163. }
  164. BattPrint (BATT_TRACE, ("CompBatt: EXITING PnpEventHandler\n"));
  165. return STATUS_SUCCESS;
  166. }
  167. NTSTATUS
  168. CompBattRemoveBattery(
  169. IN PUNICODE_STRING SymbolicLinkName,
  170. IN PCOMPOSITE_BATTERY CompBatt
  171. )
  172. /*++
  173. Routine Description:
  174. This routine removes an existing battery from the list of batteries kept by the
  175. composite battery.
  176. Arguments:
  177. SymbolicLinkName - Name used to check if battery is on list
  178. and to close the battery if so.
  179. CompBatt - Device extension for the composite battery
  180. Return Value:
  181. NTSTATUS
  182. --*/
  183. {
  184. PCOMPOSITE_ENTRY Battery;
  185. // NonPaged code. This is called by an Irp completion routine.
  186. BattPrint (BATT_TRACE, ("CompBatt: RemoveBattery\n"));
  187. //
  188. // Remove the battery from the list if it is there.
  189. //
  190. Battery = RemoveBatteryFromList (SymbolicLinkName, CompBatt);
  191. if(!Battery) {
  192. //
  193. // removed ok if not on list
  194. //
  195. return STATUS_SUCCESS;
  196. }
  197. //
  198. // Deallocate the Work Item.
  199. //
  200. ObDereferenceObject(Battery->DeviceObject);
  201. ExFreePool (Battery);
  202. // Invalidate cached Battery info and send notification
  203. CompBatt->Info.Valid = 0;
  204. BatteryClassStatusNotify (CompBatt->Class);
  205. return STATUS_SUCCESS;
  206. }
  207. NTSTATUS
  208. CompBattAddNewBattery(
  209. IN PUNICODE_STRING SymbolicLinkName,
  210. IN PCOMPOSITE_BATTERY CompBatt
  211. )
  212. /*++
  213. Routine Description:
  214. This routine adds a new battery to the list of batteries kept by the
  215. composite battery.
  216. Arguments:
  217. SymbolicLinkName - Name used to check if battery is already on list
  218. and to open the battery if not.
  219. CompBatt - Device extension for the composite battery
  220. Return Value:
  221. NTSTATUS
  222. --*/
  223. {
  224. PCOMPOSITE_ENTRY newBattery;
  225. PUNICODE_STRING battName;
  226. PFILE_OBJECT fileObject;
  227. PIO_STACK_LOCATION irpSp;
  228. PIRP newIrp;
  229. BOOLEAN onList;
  230. NTSTATUS status = STATUS_SUCCESS;
  231. PAGED_CODE();
  232. BattPrint (BATT_TRACE, ("CompBatt: ENTERING AddNewBattery \"%w\" \n", SymbolicLinkName->Buffer));
  233. //
  234. // Lock the list and see if this new battery is on it
  235. //
  236. onList = IsBatteryAlreadyOnList (SymbolicLinkName, CompBatt);
  237. if (!onList) {
  238. //
  239. // Create the node for the new battery
  240. //
  241. newBattery = ExAllocatePoolWithTag(
  242. NonPagedPool,
  243. sizeof (COMPOSITE_ENTRY) + SymbolicLinkName->Length,
  244. 'CtaB'
  245. );
  246. if (!newBattery) {
  247. BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery node\n"));
  248. status = STATUS_INSUFFICIENT_RESOURCES;
  249. goto AddNewBatteryClean1;
  250. }
  251. //
  252. // Initialize the new battery
  253. //
  254. RtlZeroMemory (newBattery, sizeof (COMPOSITE_ENTRY));
  255. newBattery->Info.Tag = BATTERY_TAG_INVALID;
  256. newBattery->NewBatt = TRUE;
  257. battName = &newBattery->BattName;
  258. battName->MaximumLength = SymbolicLinkName->Length;
  259. battName->Buffer = (PWCHAR)(battName + 1);
  260. RtlCopyUnicodeString (battName, SymbolicLinkName);
  261. //
  262. // Get the device object.
  263. //
  264. status = CompBattGetDeviceObjectPointer(SymbolicLinkName,
  265. FILE_ALL_ACCESS,
  266. &fileObject,
  267. &newBattery->DeviceObject
  268. );
  269. if (!NT_SUCCESS(status)) {
  270. BattPrint (BATT_ERROR, ("CompBattAddNewBattery: Failed to get device Object. status = %lx\n", status));
  271. goto AddNewBatteryClean2;
  272. }
  273. //
  274. // Increment the reference count to the device object of the battery
  275. //
  276. ObReferenceObject(newBattery->DeviceObject);
  277. //
  278. // Decrement reference count to file handle,
  279. // so batteries will not refuse removal requests.
  280. //
  281. ObDereferenceObject(fileObject);
  282. //
  283. // Allocate a status Irp for the new battery
  284. //
  285. newIrp = IoAllocateIrp ((UCHAR)(newBattery->DeviceObject->StackSize + 1), FALSE);
  286. if (!newIrp) {
  287. BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery Irp\n"));
  288. status = STATUS_INSUFFICIENT_RESOURCES;
  289. goto AddNewBatteryClean3;
  290. }
  291. newBattery->StatusIrp = newIrp;
  292. //
  293. // Setup control data on irp
  294. //
  295. irpSp = IoGetNextIrpStackLocation(newIrp);
  296. irpSp->Parameters.Others.Argument1 = (PVOID) CompBatt;
  297. irpSp->Parameters.Others.Argument2 = (PVOID) newBattery;
  298. //
  299. // Fill in irp so irp handler will re-dispatch it
  300. //
  301. IoSetNextIrpStackLocation (newIrp);
  302. irpSp = IoGetNextIrpStackLocation(newIrp);
  303. newIrp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  304. newBattery->State = CB_ST_GET_TAG;
  305. CompbattInitializeDeleteLock (&newBattery->DeleteLock);
  306. //
  307. // Put Battery onthe battery list before starting the
  308. // MonitorIrpComplete loop.
  309. //
  310. ExAcquireFastMutex (&CompBatt->ListMutex);
  311. InsertTailList (&CompBatt->Batteries, &newBattery->Batteries);
  312. ExReleaseFastMutex (&CompBatt->ListMutex);
  313. //
  314. // Initialize Work Item
  315. //
  316. ExInitializeWorkItem (&newBattery->WorkItem, CompBattMonitorIrpCompleteWorker, newBattery);
  317. //
  318. // Start Monitoring Battery
  319. //
  320. CompBattMonitorIrpComplete (newBattery->DeviceObject, newIrp, NULL);
  321. status = STATUS_SUCCESS;
  322. }
  323. goto AddNewBatteryClean1;
  324. AddNewBatteryClean3:
  325. ObReferenceObject(newBattery->DeviceObject);
  326. AddNewBatteryClean2:
  327. ExFreePool (newBattery);
  328. AddNewBatteryClean1:
  329. BattPrint (BATT_TRACE, ("CompBatt: EXITING AddNewBattery\n"));
  330. return status;
  331. }
  332. NTSTATUS
  333. CompBattGetBatteries(
  334. IN PCOMPOSITE_BATTERY CompBatt
  335. )
  336. /*++
  337. Routine Description:
  338. This routine uses the PnP manager to get all the batteries that have already
  339. registered their interfaces (that we won't get notifications for) and then
  340. adds them to the list of batteries.
  341. Arguments:
  342. CompBatt - Device extension for the composite battery
  343. Return Value:
  344. NTSTATUS
  345. --*/
  346. {
  347. NTSTATUS status;
  348. UNICODE_STRING tmpString;
  349. PWSTR stringPointer;
  350. int i;
  351. BattPrint (BATT_TRACE, ("CompBatt: ENTERING GetBatteries\n"));
  352. //
  353. // Call the PnP manager to get the list of devices already register for the
  354. // battery class.
  355. //
  356. status = IoGetDeviceInterfaces(
  357. &GUID_DEVICE_BATTERY,
  358. NULL,
  359. 0,
  360. &stringPointer
  361. );
  362. if (!NT_SUCCESS(status)) {
  363. BattPrint (BATT_ERROR, ("CompBatt: Couldn't get list of batteries\n"));
  364. } else {
  365. //
  366. // Now parse the list and try to add them to the composite battery list
  367. //
  368. i = 0;
  369. RtlInitUnicodeString (&tmpString, &stringPointer[i]);
  370. while (tmpString.Length) {
  371. status = CompBattAddNewBattery (&tmpString, CompBatt);
  372. i += (tmpString.Length / sizeof(WCHAR)) + 1;
  373. RtlInitUnicodeString (&tmpString, &stringPointer[i]);
  374. }
  375. ExFreePool (stringPointer);
  376. }
  377. BattPrint (BATT_TRACE, ("CompBatt: EXITING GetBatteries\n"));
  378. return status;
  379. }