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.

599 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. apmbpnp.c
  5. Abstract:
  6. Control Method Battery Plug and Play support
  7. Author:
  8. Ron Mosgrove
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "ApmBattp.h"
  14. #include <initguid.h>
  15. #include <wdmguid.h>
  16. #include <ntapm.h>
  17. //
  18. // Device Names
  19. //
  20. PCWSTR ApmBattDeviceName = L"\\Device\\ApmBattery";
  21. //PCWSTR AcAdapterName = L"\\Device\\AcAdapter";
  22. //
  23. // This is a special Hack as part of this general APM special hack
  24. //
  25. PVOID ApmGlobalClass = NULL;
  26. //
  27. // Prototypes
  28. //
  29. NTSTATUS
  30. ApmBattAddDevice(
  31. IN PDRIVER_OBJECT DriverObject,
  32. IN PDEVICE_OBJECT Pdo
  33. );
  34. NTSTATUS
  35. ApmBattAddBattery(
  36. IN PDRIVER_OBJECT DriverObject,
  37. IN PDEVICE_OBJECT Pdo
  38. );
  39. #if 0
  40. NTSTATUS
  41. ApmBattAddAcAdapter(
  42. IN PDRIVER_OBJECT DriverObject,
  43. IN PDEVICE_OBJECT Pdo
  44. );
  45. #endif
  46. NTSTATUS
  47. ApmBattCreateFdo(
  48. IN PDRIVER_OBJECT DriverObject,
  49. IN ULONG DeviceId,
  50. OUT PDEVICE_OBJECT *NewDeviceObject
  51. );
  52. NTSTATUS
  53. ApmBattCompleteRequest(
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PIRP Irp,
  56. IN PVOID Context
  57. );
  58. NTSTATUS
  59. ApmBattAddDevice(
  60. IN PDRIVER_OBJECT DriverObject,
  61. IN PDEVICE_OBJECT Pdo
  62. )
  63. /*++
  64. Routine Description:
  65. This routine creates functional device objects for each ApmBatt controller in the
  66. system and attaches them to the physical device objects for the controllers
  67. Arguments:
  68. DriverObject - a pointer to the object for this driver
  69. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  70. Return Value:
  71. Status from device creation and initialization
  72. --*/
  73. {
  74. PAGED_CODE();
  75. ApmBattPrint (APMBATT_TRACE, ("ApmBattAddDevice\n"));
  76. ASSERT(DeviceCount == 0);
  77. if (DeviceCount != 0) {
  78. return STATUS_UNSUCCESSFUL;
  79. }
  80. DeviceCount = 1;
  81. ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattAddDevice: Entered with pdo %x\n", Pdo));
  82. if (Pdo == NULL) {
  83. //
  84. // Have we been asked to do detection on our own?
  85. // if so just return no more devices
  86. //
  87. ApmBattPrint((APMBATT_WARN | APMBATT_PNP), ("ApmBattAddDevice: Asked to do detection\n"));
  88. return STATUS_NO_MORE_ENTRIES;
  89. } else {
  90. //
  91. // This device is a control-method battery
  92. //
  93. return (ApmBattAddBattery (DriverObject, Pdo));
  94. }
  95. return STATUS_UNSUCCESSFUL;
  96. }
  97. NTSTATUS
  98. ApmBattAddBattery(
  99. IN PDRIVER_OBJECT DriverObject,
  100. IN PDEVICE_OBJECT Pdo
  101. )
  102. /*++
  103. Routine Description:
  104. This routine creates a functional device object for a CM battery, and attache it
  105. to the physical device object for the battery.
  106. Arguments:
  107. DriverObject - a pointer to the object for this driver
  108. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  109. Return Value:
  110. Status from device creation and initialization
  111. --*/
  112. {
  113. PDEVICE_OBJECT Fdo = NULL;
  114. PDEVICE_OBJECT lowerDevice = NULL;
  115. PCM_BATT ApmBatt;
  116. NTSTATUS Status;
  117. BATTERY_MINIPORT_INFO BattInit;
  118. ULONG uniqueId;
  119. PNTAPM_LINK pparms;
  120. PIRP Irp;
  121. PIO_STACK_LOCATION IrpSp;
  122. PAGED_CODE();
  123. ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattAddBattery: pdo %x\n", Pdo));
  124. //DbgBreakPoint();
  125. uniqueId = 0;
  126. //
  127. // Create and initialize the new functional device object
  128. //
  129. Status = ApmBattCreateFdo(DriverObject, uniqueId, &Fdo);
  130. if (!NT_SUCCESS(Status)) {
  131. ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: error (0x%x) creating Fdo\n", Status));
  132. return Status;
  133. }
  134. //
  135. // Initialize Fdo device extension data
  136. //
  137. ApmBatt = (PCM_BATT) Fdo->DeviceExtension;
  138. ApmBatt->Fdo = Fdo;
  139. ApmBatt->Pdo = Pdo;
  140. //
  141. // Layer our FDO on top of the PDO
  142. //
  143. lowerDevice = IoAttachDeviceToDeviceStack(Fdo,Pdo);
  144. //
  145. // No status. Do the best we can.
  146. //
  147. if (!lowerDevice) {
  148. ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: Could not attach to lower device\n"));
  149. return STATUS_UNSUCCESSFUL;
  150. }
  151. ApmBatt->LowerDeviceObject = lowerDevice;
  152. //
  153. // Attach to the Class Driver
  154. //
  155. RtlZeroMemory (&BattInit, sizeof(BattInit));
  156. BattInit.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
  157. BattInit.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
  158. BattInit.Context = ApmBatt;
  159. BattInit.QueryTag = ApmBattQueryTag;
  160. BattInit.QueryInformation = ApmBattQueryInformation;
  161. BattInit.SetInformation = NULL; // tbd
  162. BattInit.QueryStatus = ApmBattQueryStatus;
  163. BattInit.SetStatusNotify = ApmBattSetStatusNotify;
  164. BattInit.DisableStatusNotify = ApmBattDisableStatusNotify;
  165. BattInit.Pdo = Pdo;
  166. BattInit.DeviceName = ApmBatt->DeviceName;
  167. Status = BatteryClassInitializeDevice (&BattInit, &ApmBatt->Class);
  168. ApmGlobalClass = ApmBatt->Class;
  169. if (!NT_SUCCESS(Status)) {
  170. //
  171. // if we can't attach to class driver we're toast
  172. //
  173. ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: error (0x%x) registering with class\n", Status));
  174. return Status;
  175. }
  176. //
  177. // link up with APM driver (if we can't we're toast)
  178. //
  179. // Should be able to just call into Pdo.
  180. //
  181. // DO WORK HERE
  182. //
  183. Irp = IoAllocateIrp((CCHAR) (Pdo->StackSize+2), FALSE);
  184. if (!Irp) {
  185. return STATUS_UNSUCCESSFUL;
  186. }
  187. IrpSp = IoGetNextIrpStackLocation(Irp);
  188. IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  189. IrpSp->MinorFunction = 0;
  190. IrpSp->DeviceObject = Pdo;
  191. pparms = (PNTAPM_LINK) &(IrpSp->Parameters.Others);
  192. pparms->Signature = NTAPM_LINK_SIGNATURE;
  193. pparms->Version = NTAPM_LINK_VERSION;
  194. pparms->BattLevelPtr = (ULONG)(&(NtApmGetBatteryLevel));
  195. pparms->ChangeNotify = (ULONG)(&(ApmBattPowerNotifyHandler));
  196. IoSetCompletionRoutine(Irp, ApmBattCompleteRequest, NULL, TRUE, TRUE, TRUE);
  197. if (IoCallDriver(Pdo, Irp) != STATUS_SUCCESS) {
  198. return STATUS_UNSUCCESSFUL;
  199. }
  200. //DbgPrint("apmbatt: NtApmGetBatteryLevel: %08lx\n", NtApmGetBatteryLevel);
  201. return STATUS_SUCCESS;
  202. }
  203. NTSTATUS
  204. ApmBattCompleteRequest(
  205. IN PDEVICE_OBJECT DeviceObject,
  206. IN PIRP Irp,
  207. IN PVOID Context
  208. )
  209. /*++
  210. Routine Description:
  211. Completion routine for ioctl call to apm.
  212. Arguments:
  213. DeviceObject - The target device which the request was sent
  214. Irp - The irp completing
  215. Context - The requestors completion routine
  216. Return Value:
  217. --*/
  218. {
  219. IoFreeIrp(Irp);
  220. return STATUS_MORE_PROCESSING_REQUIRED;
  221. }
  222. NTSTATUS
  223. ApmBattCreateFdo(
  224. IN PDRIVER_OBJECT DriverObject,
  225. IN ULONG DeviceId,
  226. OUT PDEVICE_OBJECT *NewFdo
  227. )
  228. /*++
  229. Routine Description:
  230. This routine will create and initialize a functional device object to
  231. be attached to a Control Method Battery PDO.
  232. Arguments:
  233. DriverObject - a pointer to the driver object this is created under
  234. NewFdo - a location to store the pointer to the new device object
  235. Return Value:
  236. STATUS_SUCCESS if everything was successful
  237. reason for failure otherwise
  238. --*/
  239. {
  240. PUNICODE_STRING unicodeString;
  241. PDEVICE_OBJECT Fdo;
  242. NTSTATUS Status;
  243. PCM_BATT ApmBatt;
  244. UNICODE_STRING numberString;
  245. WCHAR numberBuffer[10];
  246. PAGED_CODE();
  247. ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattCreateFdo, Battery Id=%x\n", DeviceId));
  248. //
  249. // Allocate the UNICODE_STRING for the device name
  250. //
  251. unicodeString = ExAllocatePoolWithTag (
  252. PagedPool,
  253. sizeof (UNICODE_STRING) + MAX_DEVICE_NAME_LENGTH,
  254. 'taBC'
  255. );
  256. if (!unicodeString) {
  257. ApmBattPrint(APMBATT_ERROR, ("ApmBattCreateFdo: could not allocate unicode string\n"));
  258. return STATUS_INSUFFICIENT_RESOURCES;
  259. }
  260. unicodeString->MaximumLength = MAX_DEVICE_NAME_LENGTH;
  261. unicodeString->Length = 0;
  262. unicodeString->Buffer = (PWCHAR) (unicodeString + 1);
  263. //
  264. // Create the PDO device name based on the battery instance
  265. //
  266. numberString.MaximumLength = 10;
  267. numberString.Buffer = &numberBuffer[0];
  268. RtlIntegerToUnicodeString (DeviceId, 10, &numberString);
  269. RtlAppendUnicodeToString (unicodeString, (PWSTR) ApmBattDeviceName);
  270. RtlAppendUnicodeToString (unicodeString, &numberString.Buffer[0]);
  271. Status = IoCreateDevice(
  272. DriverObject,
  273. sizeof (CM_BATT),
  274. unicodeString,
  275. FILE_DEVICE_BATTERY,
  276. 0,
  277. FALSE,
  278. &Fdo
  279. );
  280. if (Status != STATUS_SUCCESS) {
  281. ApmBattPrint(APMBATT_ERROR, ("ApmBattCreateFdo: error (0x%x) creating device object\n", Status));
  282. ExFreePool (unicodeString);
  283. return(Status);
  284. }
  285. Fdo->Flags |= DO_BUFFERED_IO;
  286. Fdo->Flags |= DO_POWER_PAGABLE; // Don't want power Irps at irql 2
  287. Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  288. Fdo->StackSize = 2;
  289. //
  290. // Initialize Fdo device extension data
  291. //
  292. ApmBatt = (PCM_BATT) Fdo->DeviceExtension;
  293. RtlZeroMemory(ApmBatt, sizeof(CM_BATT));
  294. ApmBatt->DeviceName = unicodeString;
  295. ApmBatt->DeviceNumber = (USHORT) DeviceId;
  296. ApmBatt->DeviceObject = Fdo;
  297. *NewFdo = Fdo;
  298. ApmBattPrint((APMBATT_TRACE | APMBATT_PNP), ("ApmBattCreateFdo: Created FDO %x\n", Fdo));
  299. return STATUS_SUCCESS;
  300. }
  301. NTSTATUS
  302. ApmBattPnpDispatch(
  303. IN PDEVICE_OBJECT DeviceObject,
  304. IN PIRP Irp
  305. )
  306. /*++
  307. Routine Description:
  308. This routine is the dispatch routine for plug and play requests.
  309. Arguments:
  310. DeviceObject - Pointer to class device object.
  311. Irp - Pointer to the request packet.
  312. Return Value:
  313. Status is returned.
  314. --*/
  315. {
  316. PIO_STACK_LOCATION irpStack;
  317. PCM_BATT ApmBatt;
  318. NTSTATUS Status;
  319. PAGED_CODE();
  320. ApmBattPrint (APMBATT_TRACE, ("ApmBattPnpDispatch\n"));
  321. Status = STATUS_NOT_IMPLEMENTED;
  322. Irp->IoStatus.Information = 0;
  323. //
  324. // Get a pointer to the current parameters for this request. The
  325. // information is contained in the current stack location.
  326. //
  327. irpStack = IoGetCurrentIrpStackLocation(Irp);
  328. ApmBatt = DeviceObject->DeviceExtension;
  329. //
  330. // Dispatch minor function
  331. //
  332. switch (irpStack->MinorFunction) {
  333. case IRP_MN_START_DEVICE:
  334. //
  335. // if the Add succeeded, we are actually started...
  336. //
  337. ApmBattPrint (APMBATT_PNP, ("ApmBattPnpDispatch: IRP_MN_START_DEVICE\n"));
  338. Status = STATUS_SUCCESS;
  339. Irp->IoStatus.Status = Status;
  340. ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
  341. break;
  342. case IRP_MN_QUERY_DEVICE_RELATIONS:
  343. ApmBattPrint (APMBATT_PNP, ("ApmBattPnpDispatch: IRP_MN_QUERY_DEVICE_RELATIONS - type (%d)\n",
  344. irpStack->Parameters.QueryDeviceRelations.Type));
  345. //
  346. // Just pass it down
  347. //
  348. ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
  349. break;
  350. case IRP_MN_QUERY_STOP_DEVICE:
  351. case IRP_MN_CANCEL_STOP_DEVICE:
  352. case IRP_MN_QUERY_REMOVE_DEVICE:
  353. case IRP_MN_CANCEL_REMOVE_DEVICE:
  354. Status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  355. IoCompleteRequest(Irp, 0);
  356. break;
  357. default:
  358. ApmBattPrint (APMBATT_PNP,
  359. ("ApmBattPnpDispatch: Unimplemented minor %0x\n",
  360. irpStack->MinorFunction));
  361. //
  362. // Unimplemented minor, Pass this down to ACPI
  363. //
  364. ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
  365. break;
  366. }
  367. return Status;
  368. }
  369. NTSTATUS
  370. ApmBattPowerDispatch(
  371. IN PDEVICE_OBJECT DeviceObject,
  372. IN PIRP Irp
  373. )
  374. /*++
  375. Routine Description:
  376. This routine is the dispatch routine for power requests.
  377. Arguments:
  378. DeviceObject - Pointer to class device object.
  379. Irp - Pointer to the request packet.
  380. Return Value:
  381. Status is returned.
  382. --*/
  383. {
  384. PIO_STACK_LOCATION irpStack;
  385. PCM_BATT ApmBatt;
  386. NTSTATUS Status;
  387. PAGED_CODE();
  388. ApmBattPrint ((APMBATT_TRACE | APMBATT_POWER), ("ApmBattPowerDispatch\n"));
  389. //
  390. // Get a pointer to the current parameters for this request. The
  391. // information is contained in the current stack location.
  392. //
  393. irpStack = IoGetCurrentIrpStackLocation(Irp);
  394. ApmBatt = DeviceObject->DeviceExtension;
  395. //
  396. // Dispatch minor function
  397. //
  398. switch (irpStack->MinorFunction) {
  399. case IRP_MN_WAIT_WAKE:
  400. ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"));
  401. break;
  402. case IRP_MN_POWER_SEQUENCE:
  403. ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"));
  404. break;
  405. case IRP_MN_SET_POWER:
  406. ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_SET_POWER\n"));
  407. TagValue++;
  408. break;
  409. case IRP_MN_QUERY_POWER:
  410. ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_QUERY_POWER\n"));
  411. break;
  412. default:
  413. ApmBattPrint(APMBATT_LOW, ("ApmBattPowerDispatch: minor %d\n",
  414. irpStack->MinorFunction));
  415. break;
  416. }
  417. //
  418. // What do we do with the irp?
  419. //
  420. PoStartNextPowerIrp( Irp );
  421. if (ApmBatt->LowerDeviceObject != NULL) {
  422. //
  423. // Forward the request along
  424. //
  425. IoSkipCurrentIrpStackLocation( Irp );
  426. Status = PoCallDriver( ApmBatt->LowerDeviceObject, Irp );
  427. } else {
  428. //
  429. // Complete the request with the current status
  430. //
  431. Status = Irp->IoStatus.Status;
  432. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  433. }
  434. return Status;
  435. }