1 /*
2 * PROJECT: ReactOS ACPI-Compliant Control Method Battery
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/bus/acpi/cmbatt/cmbpnp.c
5 * PURPOSE: Plug-and-Play IOCTL/IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "cmbatt.h"
12
13 /* FUNCTIONS ******************************************************************/
14
15 VOID
16 NTAPI
CmBattWaitWakeLoop(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatusBlock)17 CmBattWaitWakeLoop(IN PDEVICE_OBJECT DeviceObject,
18 IN UCHAR MinorFunction,
19 IN POWER_STATE PowerState,
20 IN PVOID Context,
21 IN PIO_STATUS_BLOCK IoStatusBlock)
22 {
23 NTSTATUS Status;
24 PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
25 if (CmBattDebug & 0x20) DbgPrint("CmBattWaitWakeLoop: Entered.\n");
26
27 /* Check for success */
28 if ((NT_SUCCESS(IoStatusBlock->Status)) && (DeviceExtension->WaitWakeEnable))
29 {
30 /* Request a new power IRP */
31 if (CmBattDebug & 2) DbgPrint("CmBattWaitWakeLoop: completed successfully\n");
32 Status = PoRequestPowerIrp(DeviceObject,
33 MinorFunction,
34 PowerState,
35 CmBattWaitWakeLoop,
36 Context,
37 &DeviceExtension->PowerIrp);
38 if (CmBattDebug & 2)
39 DbgPrint("CmBattWaitWakeLoop: PoRequestPowerIrp: status = 0x%08x.\n",
40 Status);
41 }
42 else
43 {
44 /* Clear the power IRP, we failed */
45 if (CmBattDebug & 0xC)
46 DbgPrint("CmBattWaitWakeLoop: failed: status = 0x%08x.\n",
47 IoStatusBlock->Status);
48 DeviceExtension->PowerIrp = NULL;
49 }
50 }
51
52 NTSTATUS
53 NTAPI
CmBattIoCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PKEVENT Event)54 CmBattIoCompletion(IN PDEVICE_OBJECT DeviceObject,
55 IN PIRP Irp,
56 IN PKEVENT Event)
57 {
58 if (CmBattDebug & 2) DbgPrint("CmBattIoCompletion: Event (%x)\n", Event);
59
60 /* Set the completion event */
61 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
62 return STATUS_MORE_PROCESSING_REQUIRED;
63 }
64
65 NTSTATUS
66 NTAPI
CmBattGetAcpiInterfaces(IN PDEVICE_OBJECT DeviceObject,IN OUT PACPI_INTERFACE_STANDARD AcpiInterface)67 CmBattGetAcpiInterfaces(IN PDEVICE_OBJECT DeviceObject,
68 IN OUT PACPI_INTERFACE_STANDARD AcpiInterface)
69 {
70 PIRP Irp;
71 NTSTATUS Status;
72 PIO_STACK_LOCATION IoStackLocation;
73 KEVENT Event;
74
75 /* Allocate the IRP */
76 Irp = IoAllocateIrp(DeviceObject->StackSize, 0);
77 if (!Irp)
78 {
79 /* Fail */
80 if (CmBattDebug & 0xC)
81 DbgPrint("CmBattGetAcpiInterfaces: Failed to allocate Irp\n");
82 return STATUS_INSUFFICIENT_RESOURCES;
83 }
84
85 /* Set default error code */
86 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
87
88 /* Build the query */
89 IoStackLocation = IoGetNextIrpStackLocation(Irp);
90 IoStackLocation->MajorFunction = IRP_MJ_PNP;
91 IoStackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
92 IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_ACPI_INTERFACE_STANDARD;
93 IoStackLocation->Parameters.QueryInterface.Size = sizeof(ACPI_INTERFACE_STANDARD);
94 IoStackLocation->Parameters.QueryInterface.Version = 1;
95 IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)AcpiInterface;
96 IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL;
97
98 /* Set default ACPI interface data */
99 AcpiInterface->Size = sizeof(ACPI_INTERFACE_STANDARD);
100 AcpiInterface->Version = 1;
101
102 /* Initialize our wait event */
103 KeInitializeEvent(&Event, SynchronizationEvent, 0);
104
105 /* Set the completion routine */
106 IoSetCompletionRoutine(Irp,
107 (PVOID)CmBattIoCompletion,
108 &Event,
109 TRUE,
110 TRUE,
111 TRUE);
112
113 /* Now call ACPI */
114 Status = IoCallDriver(DeviceObject, Irp);
115 if (Status == STATUS_PENDING)
116 {
117 /* Wait for completion */
118 KeWaitForSingleObject(&Event,
119 Executive,
120 KernelMode,
121 FALSE,
122 NULL);
123 Status = Irp->IoStatus.Status;
124 }
125
126 /* Free the IRP */
127 IoFreeIrp(Irp);
128
129 /* Return status */
130 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC))
131 DbgPrint("CmBattGetAcpiInterfaces: Could not get ACPI driver interfaces, status = %x\n", Status);
132 return Status;
133 }
134
135 VOID
136 NTAPI
CmBattDestroyFdo(IN PDEVICE_OBJECT DeviceObject)137 CmBattDestroyFdo(IN PDEVICE_OBJECT DeviceObject)
138 {
139 PAGED_CODE();
140 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo, Battery.\n");
141
142 /* Delete the device */
143 IoDeleteDevice(DeviceObject);
144 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo: done.\n");
145 }
146
147 NTSTATUS
148 NTAPI
CmBattRemoveDevice(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)149 CmBattRemoveDevice(IN PDEVICE_OBJECT DeviceObject,
150 IN PIRP Irp)
151 {
152 PCMBATT_DEVICE_EXTENSION DeviceExtension;
153 PVOID Context;
154 DeviceExtension = DeviceObject->DeviceExtension;
155 if (CmBattDebug & 2)
156 DbgPrint("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n",
157 DeviceExtension,
158 DeviceExtension->FdoType,
159 DeviceExtension->DeviceId);
160
161 /* Make sure it's safe to go ahead */
162 IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, 0);
163
164 /* Check for pending power IRP */
165 if (DeviceExtension->PowerIrp)
166 {
167 /* Cancel and clear */
168 IoCancelIrp(DeviceExtension->PowerIrp);
169 DeviceExtension->PowerIrp = NULL;
170 }
171
172 /* Check what type of FDO is being removed */
173 Context = DeviceExtension->AcpiInterface.Context;
174 if (DeviceExtension->FdoType == CmBattBattery)
175 {
176 /* Unregister battery FDO */
177 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context,
178 (PVOID)CmBattNotifyHandler);
179 CmBattWmiDeRegistration(DeviceExtension);
180 if (!NT_SUCCESS(BatteryClassUnload(DeviceExtension->ClassData))) ASSERT(FALSE);
181 }
182 else
183 {
184 /* Unregister AC adapter FDO */
185 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context,
186 (PVOID)CmBattNotifyHandler);
187 CmBattWmiDeRegistration(DeviceExtension);
188 AcAdapterPdo = NULL;
189 }
190
191 /* Detach and delete */
192 IoDetachDevice(DeviceExtension->AttachedDevice);
193 IoDeleteDevice(DeviceExtension->DeviceObject);
194 return STATUS_SUCCESS;
195 }
196
197 NTSTATUS
198 NTAPI
CmBattPowerDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)199 CmBattPowerDispatch(IN PDEVICE_OBJECT DeviceObject,
200 IN PIRP Irp)
201 {
202 PIO_STACK_LOCATION IoStackLocation;
203 PCMBATT_DEVICE_EXTENSION DeviceExtension;
204 NTSTATUS Status;
205 if (CmBattDebug & 0x210) DbgPrint("CmBattPowerDispatch\n");
206
207 /* Get stack location and device extension */
208 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
209 DeviceExtension = DeviceObject->DeviceExtension;
210 switch (IoStackLocation->MinorFunction)
211 {
212 case IRP_MN_WAIT_WAKE:
213 if (CmBattDebug & 0x10)
214 DbgPrint("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n");
215 break;
216
217 case IRP_MN_POWER_SEQUENCE:
218 if (CmBattDebug & 0x10)
219 DbgPrint("CmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n");
220 break;
221
222 case IRP_MN_QUERY_POWER:
223 if (CmBattDebug & 0x10)
224 DbgPrint("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n");
225 break;
226
227 case IRP_MN_SET_POWER:
228 if (CmBattDebug & 0x10)
229 DbgPrint("CmBattPowerDispatch: IRP_MN_SET_POWER type: %d, State: %d \n",
230 IoStackLocation->Parameters.Power.Type,
231 IoStackLocation->Parameters.Power.State);
232 break;
233
234 default:
235
236 if (CmBattDebug & 1)
237 DbgPrint("CmBattPowerDispatch: minor %d\n", IoStackLocation->MinorFunction);
238 break;
239 }
240
241 /* Start the next IRP and see if we're attached */
242 PoStartNextPowerIrp(Irp);
243 if (DeviceExtension->AttachedDevice)
244 {
245 /* Call ACPI */
246 IoSkipCurrentIrpStackLocation(Irp);
247 Status = PoCallDriver(DeviceExtension->AttachedDevice, Irp);
248 }
249 else
250 {
251 /* Complete the request here */
252 Status = Irp->IoStatus.Status;
253 IoCompleteRequest(Irp, IO_NO_INCREMENT);
254 }
255
256 /* Return status */
257 return Status;
258 }
259
260 NTSTATUS
261 NTAPI
CmBattPnpDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)262 CmBattPnpDispatch(IN PDEVICE_OBJECT DeviceObject,
263 IN PIRP Irp)
264 {
265 PIO_STACK_LOCATION IoStackLocation;
266 PCMBATT_DEVICE_EXTENSION DeviceExtension;
267 NTSTATUS Status;
268 KEVENT Event;
269 PAGED_CODE();
270
271 /* Get stack location and device extension */
272 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
273 DeviceExtension = DeviceObject->DeviceExtension;
274
275 /* Set default error */
276 Status = STATUS_NOT_SUPPORTED;
277
278 /* Try to acquire the lock before doing anything */
279 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
280 if (!NT_SUCCESS(Status))
281 {
282 /* Complete the request */
283 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
284 IoCompleteRequest(Irp, IO_NO_INCREMENT);
285 return STATUS_DEVICE_REMOVED;
286 }
287
288 /* What's the operation? */
289 switch (IoStackLocation->MinorFunction)
290 {
291 case IRP_MN_QUERY_PNP_DEVICE_STATE:
292
293 /* Initialize our wait event */
294 KeInitializeEvent(&Event, SynchronizationEvent, 0);
295
296 /* Set the completion routine */
297 IoCopyCurrentIrpStackLocationToNext(Irp);
298 IoSetCompletionRoutine(Irp,
299 (PVOID)CmBattIoCompletion,
300 &Event,
301 TRUE,
302 TRUE,
303 TRUE);
304
305 /* Now call ACPI to inherit its PnP Device State */
306 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
307 if (Status == STATUS_PENDING)
308 {
309 /* Wait for completion */
310 KeWaitForSingleObject(&Event,
311 Executive,
312 KernelMode,
313 FALSE,
314 NULL);
315 Status = Irp->IoStatus.Status;
316 }
317
318 /* However, a battery CAN be disabled */
319 Irp->IoStatus.Information &= ~PNP_DEVICE_NOT_DISABLEABLE;
320
321 /* Release the remove lock and complete the request */
322 IoCompleteRequest(Irp, IO_NO_INCREMENT);
323 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
324 return Status;
325
326 case IRP_MN_SURPRISE_REMOVAL:
327 if (CmBattDebug & 0x20)
328 DbgPrint("CmBattPnpDispatch: IRP_MN_SURPRISE_REMOVAL\n");
329
330 /* Lock the device extension and set the handle count to invalid */
331 ExAcquireFastMutex(&DeviceExtension->FastMutex);
332 DeviceExtension->HandleCount = -1;
333 ExReleaseFastMutex(&DeviceExtension->FastMutex);
334 Status = STATUS_SUCCESS;
335 break;
336
337 case IRP_MN_START_DEVICE:
338 if (CmBattDebug & 0x20)
339 DbgPrint("CmBattPnpDispatch: IRP_MN_START_DEVICE\n");
340
341 /* Mark the extension as started */
342 if (DeviceExtension->FdoType == CmBattBattery) DeviceExtension->Started = TRUE;
343 Status = STATUS_SUCCESS;
344 break;
345
346 case IRP_MN_STOP_DEVICE:
347 if (CmBattDebug & 0x20)
348 DbgPrint("CmBattPnpDispatch: IRP_MN_STOP_DEVICE\n");
349
350 /* Mark the extension as stopped */
351 if (DeviceExtension->FdoType == CmBattBattery) DeviceExtension->Started = FALSE;
352 Status = STATUS_SUCCESS;
353 break;
354
355 case IRP_MN_QUERY_REMOVE_DEVICE:
356 if (CmBattDebug & 0x20)
357 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n");
358
359 /* Lock the extension and get the current handle count */
360 ExAcquireFastMutex(&DeviceExtension->FastMutex);
361 if (DeviceExtension->HandleCount == 0)
362 {
363 /* No handles. Mark it as invalid since it'll be removed */
364 DeviceExtension->HandleCount = -1;
365 Status = STATUS_SUCCESS;
366 }
367 else if (DeviceExtension->HandleCount == -1)
368 {
369 /* Don't do anything, but this is strange since it's already removed */
370 Status = STATUS_SUCCESS;
371 if (CmBattDebug & 4)
372 DbgPrint("CmBattPnpDispatch: Received two consecutive QUERY_REMOVE requests.\n");
373 }
374 else
375 {
376 /* Fail because there's still open handles */
377 Status = STATUS_UNSUCCESSFUL;
378 }
379
380 /* Release the lock and return */
381 ExReleaseFastMutex(&DeviceExtension->FastMutex);
382 break;
383
384 case IRP_MN_REMOVE_DEVICE:
385 if (CmBattDebug & 0x20)
386 DbgPrint("CmBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n");
387
388 /* Call the remove code */
389 Status = CmBattRemoveDevice(DeviceObject, Irp);
390 break;
391
392 case IRP_MN_CANCEL_REMOVE_DEVICE:
393 if (CmBattDebug & 0x20)
394 DbgPrint("CmBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n");
395
396 /* Lock the extension and get the handle count */
397 ExAcquireFastMutex(&DeviceExtension->FastMutex);
398 if (DeviceExtension->HandleCount == -1)
399 {
400 /* A remove was in progress, set the handle count back to 0 */
401 DeviceExtension->HandleCount = 0;
402 }
403 else if (CmBattDebug & 2)
404 {
405 /* Nop, but warn about it */
406 DbgPrint("CmBattPnpDispatch: Received CANCEL_REMOVE when OpenCount == %x\n",
407 DeviceExtension->HandleCount);
408 }
409
410 /* Return success in all cases, and release the lock */
411 Status = STATUS_SUCCESS;
412 ExReleaseFastMutex(&DeviceExtension->FastMutex);
413 break;
414
415 case IRP_MN_QUERY_STOP_DEVICE:
416 if (CmBattDebug & 0x20)
417 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n");
418
419 /* There's no real support for this */
420 Status = STATUS_NOT_IMPLEMENTED;
421 break;
422
423 case IRP_MN_CANCEL_STOP_DEVICE:
424 if (CmBattDebug & 0x20)
425 DbgPrint("CmBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n");
426
427 /* There's no real support for this */
428 Status = STATUS_NOT_IMPLEMENTED;
429 break;
430
431 case IRP_MN_QUERY_CAPABILITIES:
432
433 /* Initialize our wait event */
434 KeInitializeEvent(&Event, SynchronizationEvent, 0);
435
436 /* Set the completion routine */
437 IoCopyCurrentIrpStackLocationToNext(Irp);
438 IoSetCompletionRoutine(Irp,
439 (PVOID)CmBattIoCompletion,
440 &Event,
441 TRUE,
442 TRUE,
443 TRUE);
444
445 /* Now call ACPI */
446 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
447 if (Status == STATUS_PENDING)
448 {
449 /* Wait for completion */
450 KeWaitForSingleObject(&Event,
451 Executive,
452 KernelMode,
453 FALSE,
454 NULL);
455 Status = Irp->IoStatus.Status;
456 }
457
458 /* Get the wake power state */
459 DeviceExtension->PowerState.SystemState = IoStackLocation->Parameters.DeviceCapabilities.Capabilities->SystemWake;
460 if (CmBattDebug & 0x20)
461 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES %d Capabilities->SystemWake = %x\n",
462 DeviceExtension->FdoType,
463 DeviceExtension->PowerState);
464
465 /* Check if it's invalid */
466 if (DeviceExtension->PowerState.SystemState == PowerSystemUnspecified)
467 {
468 /* Wait wake is not supported in this scenario */
469 DeviceExtension->WaitWakeEnable = FALSE;
470 if (CmBattDebug & 0x20)
471 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES Wake not supported.\n");
472 }
473 else if (!(DeviceExtension->PowerIrp) &&
474 (DeviceExtension->WaitWakeEnable))
475 {
476 /* If it was requested in the registry, request the power IRP for it */
477 PoRequestPowerIrp(DeviceExtension->DeviceObject,
478 0,
479 DeviceExtension->PowerState,
480 CmBattWaitWakeLoop,
481 0,
482 &DeviceExtension->PowerIrp);
483 if (CmBattDebug & 0x20)
484 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES wait/Wake irp sent.\n");
485 }
486
487 /* Release the remove lock and complete the request */
488 IoCompleteRequest(Irp, IO_NO_INCREMENT);
489 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
490 return Status;
491
492 default:
493 /* Unsupported */
494 if (CmBattDebug & 0x20)
495 DbgPrint("CmBattPnpDispatch: Unimplemented minor %0x\n",
496 IoStackLocation->MinorFunction);
497 break;
498 }
499
500 /* Release the remove lock */
501 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
502
503 /* Set IRP status if we have one */
504 if (Status != STATUS_NOT_SUPPORTED) Irp->IoStatus.Status = Status;
505
506 /* Did someone pick it up? */
507 if ((NT_SUCCESS(Status)) || (Status == STATUS_NOT_SUPPORTED))
508 {
509 /* Still unsupported, try ACPI */
510 IoSkipCurrentIrpStackLocation(Irp);
511 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
512 }
513 else
514 {
515 /* Complete the request */
516 Status = Irp->IoStatus.Status;
517 IoCompleteRequest(Irp, IO_NO_INCREMENT);
518 }
519
520 /* Release the remove lock and return status */
521 return Status;
522 }
523
524 NTSTATUS
525 NTAPI
CmBattCreateFdo(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject,IN ULONG DeviceExtensionSize,IN PDEVICE_OBJECT * NewDeviceObject)526 CmBattCreateFdo(IN PDRIVER_OBJECT DriverObject,
527 IN PDEVICE_OBJECT DeviceObject,
528 IN ULONG DeviceExtensionSize,
529 IN PDEVICE_OBJECT *NewDeviceObject)
530 {
531 PDEVICE_OBJECT FdoDeviceObject;
532 HANDLE KeyHandle;
533 PCMBATT_DEVICE_EXTENSION FdoExtension;
534 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
535 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
536 NTSTATUS Status;
537 UNICODE_STRING KeyString;
538 ULONG UniqueId;
539 ULONG ResultLength;
540 PAGED_CODE();
541 if (CmBattDebug & 0x220) DbgPrint("CmBattCreateFdo: Entered\n");
542
543 /* Get unique ID */
544 Status = CmBattGetUniqueId(DeviceObject, &UniqueId);
545 if (!NT_SUCCESS(Status))
546 {
547 /* Assume 0 */
548 UniqueId = 0;
549 if (CmBattDebug & 2)
550 DbgPrint("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", Status);
551 }
552
553 /* Create the FDO */
554 Status = IoCreateDevice(DriverObject,
555 DeviceExtensionSize,
556 0,
557 FILE_DEVICE_BATTERY,
558 FILE_DEVICE_SECURE_OPEN,
559 0,
560 &FdoDeviceObject);
561 if (!NT_SUCCESS(Status))
562 {
563 /* Fail */
564 if (CmBattDebug & 0xC)
565 DbgPrint("CmBattCreateFdo: error (0x%x) creating device object\n", Status);
566 return Status;
567 }
568
569 /* Set FDO flags */
570 FdoDeviceObject->Flags |= (DO_POWER_PAGABLE | DO_BUFFERED_IO);
571 FdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
572
573 /* Initialize the extension */
574 FdoExtension = FdoDeviceObject->DeviceExtension;
575 RtlZeroMemory(FdoExtension, DeviceExtensionSize);
576 FdoExtension->DeviceObject = FdoDeviceObject;
577 FdoExtension->FdoDeviceObject = FdoDeviceObject;
578 FdoExtension->PdoDeviceObject = DeviceObject;
579
580 /* Attach to ACPI */
581 FdoExtension->AttachedDevice = IoAttachDeviceToDeviceStack(FdoDeviceObject,
582 DeviceObject);
583 if (!FdoExtension->AttachedDevice)
584 {
585 /* Destroy and fail */
586 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
587 if (CmBattDebug & 0xC)
588 DbgPrint("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n");
589 return STATUS_UNSUCCESSFUL;
590 }
591
592 /* Get ACPI interface for EVAL */
593 Status = CmBattGetAcpiInterfaces(FdoExtension->AttachedDevice,
594 &FdoExtension->AcpiInterface);
595 if (!FdoExtension->AttachedDevice)
596 {
597 /* Detach, destroy, and fail */
598 IoDetachDevice(FdoExtension->AttachedDevice);
599 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
600 if (CmBattDebug & 0xC)
601 DbgPrint("CmBattCreateFdo: Could not get ACPI interfaces: %x\n", Status);
602 return STATUS_UNSUCCESSFUL;
603 }
604
605 /* Setup the rest of the extension */
606 ExInitializeFastMutex(&FdoExtension->FastMutex);
607 IoInitializeRemoveLock(&FdoExtension->RemoveLock, 'RbmC', 0, 0);
608 FdoExtension->HandleCount = 0;
609 FdoExtension->WaitWakeEnable = FALSE;
610 FdoExtension->DeviceId = UniqueId;
611 FdoExtension->DeviceName = NULL;
612 FdoExtension->DelayNotification = FALSE;
613 FdoExtension->ArFlag = 0;
614
615 /* Open the device key */
616 Status = IoOpenDeviceRegistryKey(DeviceObject,
617 PLUGPLAY_REGKEY_DEVICE,
618 KEY_READ,
619 &KeyHandle);
620 if (NT_SUCCESS(Status))
621 {
622 /* Read wait wake value */
623 RtlInitUnicodeString(&KeyString, L"WaitWakeEnabled");
624 Status = ZwQueryValueKey(KeyHandle,
625 &KeyString,
626 KeyValuePartialInformation,
627 PartialInfo,
628 sizeof(Buffer),
629 &ResultLength);
630 if (NT_SUCCESS(Status))
631 {
632 /* Set value */
633 FdoExtension->WaitWakeEnable = ((*(PULONG)PartialInfo->Data) != 0);
634 }
635
636 /* Close the handle */
637 ZwClose(KeyHandle);
638 }
639
640 /* Return success and the new FDO */
641 *NewDeviceObject = FdoDeviceObject;
642 if (CmBattDebug & 0x220)
643 DbgPrint("CmBattCreateFdo: Created FDO %x\n", FdoDeviceObject);
644 return STATUS_SUCCESS;
645 }
646
647 NTSTATUS
648 NTAPI
CmBattAddBattery(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject)649 CmBattAddBattery(IN PDRIVER_OBJECT DriverObject,
650 IN PDEVICE_OBJECT DeviceObject)
651 {
652 BATTERY_MINIPORT_INFO MiniportInfo;
653 NTSTATUS Status;
654 PDEVICE_OBJECT FdoDeviceObject;
655 PCMBATT_DEVICE_EXTENSION FdoExtension;
656 PAGED_CODE();
657 if (CmBattDebug & 0x220)
658 DbgPrint("CmBattAddBattery: pdo %x\n", DeviceObject);
659
660 /* Create the FDO */
661 Status = CmBattCreateFdo(DriverObject,
662 DeviceObject,
663 sizeof(CMBATT_DEVICE_EXTENSION),
664 &FdoDeviceObject);
665 if (!NT_SUCCESS(Status))
666 {
667 if (CmBattDebug & 0xC)
668 DbgPrint("CmBattAddBattery: error (0x%x) creating Fdo\n", Status);
669 return Status;
670 }
671
672 /* Build the FDO extension, check if we support trip points */
673 FdoExtension = FdoDeviceObject->DeviceExtension;
674 FdoExtension->FdoType = CmBattBattery;
675 FdoExtension->Started = 0;
676 FdoExtension->NotifySent = TRUE;
677 InterlockedExchange(&FdoExtension->ArLockValue, 0);
678 FdoExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
679 FdoExtension->Tag = 0;
680 FdoExtension->InterruptTime = KeQueryInterruptTime();
681 FdoExtension->TripPointSet = CmBattSetTripPpoint(FdoExtension, 0) !=
682 STATUS_OBJECT_NAME_NOT_FOUND;
683
684 /* Setup the battery miniport information structure */
685 RtlZeroMemory(&MiniportInfo, sizeof(MiniportInfo));
686 MiniportInfo.Pdo = DeviceObject;
687 MiniportInfo.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
688 MiniportInfo.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
689 MiniportInfo.Context = FdoExtension;
690 MiniportInfo.QueryTag = (PVOID)CmBattQueryTag;
691 MiniportInfo.QueryInformation = (PVOID)CmBattQueryInformation;
692 MiniportInfo.SetInformation = NULL;
693 MiniportInfo.QueryStatus = (PVOID)CmBattQueryStatus;
694 MiniportInfo.SetStatusNotify = (PVOID)CmBattSetStatusNotify;
695 MiniportInfo.DisableStatusNotify = (PVOID)CmBattDisableStatusNotify;
696 MiniportInfo.DeviceName = FdoExtension->DeviceName;
697
698 /* Register with the class driver */
699 Status = BatteryClassInitializeDevice(&MiniportInfo, &FdoExtension->ClassData);
700 if (!NT_SUCCESS(Status))
701 {
702 IoDetachDevice(FdoExtension->AttachedDevice);
703 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
704 if (CmBattDebug & 0xC)
705 DbgPrint("CmBattAddBattery: error (0x%x) registering with class\n", Status);
706 return Status;
707 }
708
709 /* Register WMI */
710 Status = CmBattWmiRegistration(FdoExtension);
711 if (!NT_SUCCESS(Status))
712 {
713 if (CmBattDebug & 0xC)
714 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
715 return Status;
716 }
717
718 /* Register ACPI */
719 Status = FdoExtension->AcpiInterface.RegisterForDeviceNotifications(FdoExtension->AcpiInterface.Context,
720 (PVOID)CmBattNotifyHandler,
721 FdoExtension);
722 if (!NT_SUCCESS(Status))
723 {
724 CmBattWmiDeRegistration(FdoExtension);
725 BatteryClassUnload(FdoExtension->ClassData);
726 IoDetachDevice(FdoExtension->AttachedDevice);
727 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
728 if (CmBattDebug & 0xC)
729 DbgPrint("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status);
730 }
731
732 /* Return status */
733 return Status;
734 }
735
736 NTSTATUS
737 NTAPI
CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PdoDeviceObject)738 CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject,
739 IN PDEVICE_OBJECT PdoDeviceObject)
740 {
741 PDEVICE_OBJECT FdoDeviceObject;
742 NTSTATUS Status;
743 PCMBATT_DEVICE_EXTENSION DeviceExtension;
744 PAGED_CODE();
745 if (CmBattDebug & 0x220)
746 DbgPrint("CmBattAddAcAdapter: pdo %x\n", PdoDeviceObject);
747
748 /* Check if we already have an AC adapter */
749 if (AcAdapterPdo)
750 {
751 /* Don't do anything */
752 if (CmBattDebug & 0xC)
753 DbgPrint("CmBatt: Second AC adapter found. Current version of driver only supports 1 adapter.\n");
754 }
755 else
756 {
757 /* Set this as the AC adapter's PDO */
758 AcAdapterPdo = PdoDeviceObject;
759 }
760
761 /* Create the FDO for the adapter */
762 Status = CmBattCreateFdo(DriverObject,
763 PdoDeviceObject,
764 sizeof(CMBATT_DEVICE_EXTENSION),
765 &FdoDeviceObject);
766 if (!NT_SUCCESS(Status))
767 {
768 /* Fail */
769 if (CmBattDebug & 0xC)
770 DbgPrint("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status);
771 return Status;
772 }
773
774 /* Set the type and do WMI registration */
775 DeviceExtension = FdoDeviceObject->DeviceExtension;
776 DeviceExtension->FdoType = CmBattAcAdapter;
777 Status = CmBattWmiRegistration(DeviceExtension);
778 if (!NT_SUCCESS(Status))
779 {
780 /* We can go on without WMI */
781 if (CmBattDebug & 0xC)
782 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
783 }
784
785 /* Register with ACPI */
786 Status = DeviceExtension->AcpiInterface.RegisterForDeviceNotifications(DeviceExtension->AcpiInterface.Context,
787 (PVOID)CmBattNotifyHandler,
788 DeviceExtension);
789 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC))
790 DbgPrint("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status);
791
792 /* Send the first manual notification */
793 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
794 return STATUS_SUCCESS;
795 }
796
797 NTSTATUS
798 NTAPI
CmBattAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PdoDeviceObject)799 CmBattAddDevice(IN PDRIVER_OBJECT DriverObject,
800 IN PDEVICE_OBJECT PdoDeviceObject)
801 {
802 NTSTATUS Status;
803 HANDLE KeyHandle;
804 ULONG ResultLength;
805 UNICODE_STRING KeyString;
806 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
807 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
808 ULONG PowerSourceType;
809 PAGED_CODE();
810 if (CmBattDebug & 0x220)
811 DbgPrint("CmBattAddDevice: Entered with pdo %x\n", PdoDeviceObject);
812
813 /* Make sure we have a PDO */
814 if (!PdoDeviceObject)
815 {
816 /* Should not be having as one */
817 if (CmBattDebug & 0x24) DbgPrint("CmBattAddDevice: Asked to do detection\n");
818 return STATUS_NO_MORE_ENTRIES;
819 }
820
821 /* Open the driver key */
822 Status = IoOpenDeviceRegistryKey(PdoDeviceObject,
823 PLUGPLAY_REGKEY_DRIVER,
824 KEY_READ,
825 &KeyHandle);
826 if (!NT_SUCCESS(Status))
827 {
828 if (CmBattDebug & 0xC)
829 DbgPrint("CmBattAddDevice: Could not get the software branch: %x\n", Status);
830 return Status;
831 }
832
833 /* Read the power source type */
834 RtlInitUnicodeString(&KeyString, L"PowerSourceType");
835 Status = ZwQueryValueKey(KeyHandle,
836 &KeyString,
837 KeyValuePartialInformation,
838 PartialInfo,
839 sizeof(Buffer),
840 &ResultLength);
841 ZwClose(KeyHandle);
842 if (!NT_SUCCESS(Status))
843 {
844 /* We need the data, fail without it */
845 if (CmBattDebug & 0xC)
846 DbgPrint("CmBattAddDevice: Could not read the power type identifier: %x\n", Status);
847 return Status;
848 }
849
850 /* Check what kind of power source this is */
851 PowerSourceType = *(PULONG)PartialInfo->Data;
852 if (PowerSourceType == 1)
853 {
854 /* Create an AC adapter */
855 Status = CmBattAddAcAdapter(DriverObject, PdoDeviceObject);
856 }
857 else if (PowerSourceType == 0)
858 {
859 /* Create a battery */
860 Status = CmBattAddBattery(DriverObject, PdoDeviceObject);
861 }
862 else
863 {
864 /* Unknown type, fail */
865 if (CmBattDebug & 0xC)
866 DbgPrint("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", PowerSourceType);
867 return STATUS_UNSUCCESSFUL;
868 }
869
870 /* Return whatever the FDO creation routine did */
871 return Status;
872 }
873
874 /* EOF */
875