[CMBATT]: Implement PnP handling. Only the ACPI-facing interface needs to be written...
[reactos.git] / reactos / drivers / bus / acpi / cmbatt / cmbpnp.c
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
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
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
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->MinorFunction = IRP_MN_QUERY_INTERFACE;
91 IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_ACPI_INTERFACE_STANDARD;
92 IoStackLocation->Parameters.QueryInterface.Size = sizeof(ACPI_INTERFACE_STANDARD);
93 IoStackLocation->Parameters.QueryInterface.Version = 1;
94 IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)AcpiInterface;
95 IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL;
96
97 /* Set default ACPI interface data */
98 AcpiInterface->Size = sizeof(ACPI_INTERFACE_STANDARD);
99 AcpiInterface->Version = 1;
100
101 /* Initialize our wait event */
102 KeInitializeEvent(&Event, SynchronizationEvent, 0);
103
104 /* Set the completion routine */
105 IoCopyCurrentIrpStackLocationToNext(Irp);
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
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
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
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 IofCompleteRequest(Irp, IO_NO_INCREMENT);
254 }
255
256 /* Return status */
257 return Status;
258 }
259
260 NTSTATUS
261 NTAPI
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, 0);
280 if (!NT_SUCCESS(Status))
281 {
282 /* Complete the request */
283 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
284 IofCompleteRequest(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(DeviceObject, 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: Recieved 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(DeviceObject, 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 IofCompleteRequest(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 IofCompleteRequest(Irp, IO_NO_INCREMENT);
518 }
519
520 /* Release the remove lock and return status */
521 return Status;
522 }
523
524 NTSTATUS
525 NTAPI
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_BUFFERED_IO;
571 FdoDeviceObject->Flags |= DO_MAP_IO_BUFFER;
572 FdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
573
574 /* Initialize the extension */
575 FdoExtension = FdoDeviceObject->DeviceExtension;
576 RtlZeroMemory(FdoExtension, DeviceExtensionSize);
577 FdoExtension->DeviceObject = FdoDeviceObject;
578 FdoExtension->FdoDeviceObject = FdoDeviceObject;
579 FdoExtension->PdoDeviceObject = DeviceObject;
580
581 /* Attach to ACPI */
582 FdoExtension->AttachedDevice = IoAttachDeviceToDeviceStack(FdoDeviceObject,
583 DeviceObject);
584 if (!FdoExtension->AttachedDevice)
585 {
586 /* Destroy and fail */
587 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
588 if (CmBattDebug & 0xC)
589 DbgPrint("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n");
590 return STATUS_UNSUCCESSFUL;
591 }
592
593 /* Get ACPI interface for EVAL */
594 Status = CmBattGetAcpiInterfaces(FdoExtension->AttachedDevice,
595 &FdoExtension->AcpiInterface);
596 if (!FdoExtension->AttachedDevice)
597 {
598 /* Detach, destroy, and fail */
599 IoDetachDevice(FdoExtension->AttachedDevice);
600 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
601 if (CmBattDebug & 0xC)
602 DbgPrint("CmBattCreateFdo: Could not get ACPI interfaces: %x\n", Status);
603 return STATUS_UNSUCCESSFUL;
604 }
605
606 /* Setup the rest of the extension */
607 ExInitializeFastMutex(&FdoExtension->FastMutex);
608 IoInitializeRemoveLock(&FdoExtension->RemoveLock, 0, 0, 0);
609 FdoExtension->HandleCount = 0;
610 FdoExtension->WaitWakeEnable = FALSE;
611 FdoExtension->DeviceId = UniqueId;
612 FdoExtension->DeviceName = NULL;
613 FdoExtension->DelayNotification = FALSE;
614 FdoExtension->ArFlag = 0;
615
616 /* Open the device key */
617 Status = IoOpenDeviceRegistryKey(DeviceObject,
618 PLUGPLAY_REGKEY_DEVICE,
619 KEY_READ,
620 &KeyHandle);
621 if (NT_SUCCESS(Status))
622 {
623 /* Read wait wake value */
624 RtlInitUnicodeString(&KeyString, L"WaitWakeEnabled");
625 Status = ZwQueryValueKey(KeyHandle,
626 &KeyString,
627 KeyValuePartialInformation,
628 PartialInfo,
629 sizeof(Buffer),
630 &ResultLength);
631 if (NT_SUCCESS(Status))
632 {
633 /* Set value */
634 FdoExtension->WaitWakeEnable = *(PULONG)PartialInfo->Data;
635 }
636
637 /* Close the handle */
638 ZwClose(KeyHandle);
639 }
640
641 /* Return success and the new FDO */
642 *NewDeviceObject = FdoDeviceObject;
643 if (CmBattDebug & 0x220)
644 DbgPrint("CmBattCreateFdo: Created FDO %x\n", FdoDeviceObject);
645 return STATUS_SUCCESS;
646 }
647
648 NTSTATUS
649 NTAPI
650 CmBattAddBattery(IN PDRIVER_OBJECT DriverObject,
651 IN PDEVICE_OBJECT DeviceObject)
652 {
653 BATTERY_MINIPORT_INFO MiniportInfo;
654 NTSTATUS Status;
655 PDEVICE_OBJECT FdoDeviceObject;
656 PCMBATT_DEVICE_EXTENSION FdoExtension;
657 PAGED_CODE();
658 if (CmBattDebug & 0x220)
659 DbgPrint("CmBattAddBattery: pdo %x\n", DeviceObject);
660
661 /* Create the FDO */
662 Status = CmBattCreateFdo(DriverObject,
663 DeviceObject,
664 sizeof(CMBATT_DEVICE_EXTENSION),
665 &FdoDeviceObject);
666 if (!NT_SUCCESS(Status))
667 {
668 if (CmBattDebug & 0xC)
669 DbgPrint("CmBattAddBattery: error (0x%x) creating Fdo\n", Status);
670 return Status;
671 }
672
673 /* Build the FDO extensio, check if we support trip points */
674 FdoExtension = FdoDeviceObject->DeviceExtension;
675 FdoExtension->FdoType = CmBattBattery;
676 FdoExtension->Started = 0;
677 FdoExtension->NotifySent = TRUE;
678 InterlockedExchange(&FdoExtension->ArLockValue, 0);
679 FdoExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
680 FdoExtension->Tag = 0;
681 FdoExtension->InterruptTime = KeQueryInterruptTime();
682 FdoExtension->TripPointSet = CmBattSetTripPpoint(FdoExtension, 0) !=
683 STATUS_OBJECT_NAME_NOT_FOUND;
684
685 /* Setup the battery miniport information structure */
686 RtlZeroMemory(&MiniportInfo, sizeof(MiniportInfo));
687 MiniportInfo.Pdo = DeviceObject;
688 MiniportInfo.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
689 MiniportInfo.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
690 MiniportInfo.Context = FdoExtension;
691 MiniportInfo.QueryTag = (PVOID)CmBattQueryTag;
692 MiniportInfo.QueryInformation = (PVOID)CmBattQueryInformation;
693 MiniportInfo.SetInformation = NULL;
694 MiniportInfo.QueryStatus = (PVOID)CmBattQueryStatus;
695 MiniportInfo.SetStatusNotify = (PVOID)CmBattSetStatusNotify;
696 MiniportInfo.DisableStatusNotify = (PVOID)CmBattDisableStatusNotify;
697 MiniportInfo.DeviceName = FdoExtension->DeviceName;
698
699 /* Register with the class driver */
700 Status = BatteryClassInitializeDevice(&MiniportInfo, &FdoExtension->ClassData);
701 if (!NT_SUCCESS(Status))
702 {
703 IoDetachDevice(FdoExtension->AttachedDevice);
704 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
705 if (CmBattDebug & 0xC)
706 DbgPrint("CmBattAddBattery: error (0x%x) registering with class\n", Status);
707 return Status;
708 }
709
710 /* Register WMI */
711 Status = CmBattWmiRegistration(FdoExtension);
712 if (!NT_SUCCESS(Status))
713 {
714 if (CmBattDebug & 0xC)
715 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
716 return Status;
717 }
718
719 /* Register ACPI */
720 Status = FdoExtension->AcpiInterface.RegisterForDeviceNotifications(FdoExtension->AcpiInterface.Context,
721 (PVOID)CmBattNotifyHandler,
722 FdoExtension);
723 if (!NT_SUCCESS(Status))
724 {
725 CmBattWmiDeRegistration(FdoExtension);
726 BatteryClassUnload(FdoExtension->ClassData);
727 IoDetachDevice(FdoExtension->AttachedDevice);
728 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
729 if (CmBattDebug & 0xC)
730 DbgPrint("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status);
731 }
732
733 /* Return status */
734 return Status;
735 }
736
737 NTSTATUS
738 NTAPI
739 CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject,
740 IN PDEVICE_OBJECT PdoDeviceObject)
741 {
742 PDEVICE_OBJECT FdoDeviceObject;
743 NTSTATUS Status;
744 PCMBATT_DEVICE_EXTENSION DeviceExtension;
745 PAGED_CODE();
746 if (CmBattDebug & 0x220)
747 DbgPrint("CmBattAddAcAdapter: pdo %x\n", PdoDeviceObject);
748
749 /* Check if we already have an AC adapter */
750 if (AcAdapterPdo)
751 {
752 /* Don't do anything */
753 if (CmBattDebug & 0xC)
754 DbgPrint("CmBatt: Second AC adapter found. Current version of driver only supports 1 aadapter.\n");
755 }
756 else
757 {
758 /* Set this as the AC adapter's PDO */
759 AcAdapterPdo = PdoDeviceObject;
760 }
761
762 /* Create the FDO for the adapter */
763 Status = CmBattCreateFdo(DriverObject,
764 PdoDeviceObject,
765 sizeof(CMBATT_DEVICE_EXTENSION),
766 &FdoDeviceObject);
767 if (!NT_SUCCESS(Status))
768 {
769 /* Fail */
770 if (CmBattDebug & 0xC)
771 DbgPrint("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status);
772 return Status;
773 }
774
775 /* Set the type and do WMI registration */
776 DeviceExtension = FdoDeviceObject->DeviceExtension;
777 DeviceExtension->FdoType = CmBattAcAdapter;
778 Status = CmBattWmiRegistration(DeviceExtension);
779 if (!NT_SUCCESS(Status))
780 {
781 /* We can go on without WMI */
782 if (CmBattDebug & 0xC)
783 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
784 }
785
786 /* Register with ACPI */
787 Status = DeviceExtension->AcpiInterface.RegisterForDeviceNotifications(DeviceExtension->AcpiInterface.Context,
788 (PVOID)CmBattNotifyHandler,
789 DeviceExtension);
790 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC))
791 DbgPrint("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status);
792
793 /* Send the first manual notification */
794 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
795 return STATUS_SUCCESS;
796 }
797
798 NTSTATUS
799 NTAPI
800 CmBattAddDevice(IN PDRIVER_OBJECT DriverObject,
801 IN PDEVICE_OBJECT PdoDeviceObject)
802 {
803 NTSTATUS Status;
804 HANDLE KeyHandle;
805 ULONG ResultLength;
806 UNICODE_STRING KeyString;
807 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
808 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
809 ULONG PowerSourceType;
810 PAGED_CODE();
811 if (CmBattDebug & 0x220)
812 DbgPrint("CmBattAddDevice: Entered with pdo %x\n", PdoDeviceObject);
813
814 /* Make sure we have a PDO */
815 if (!PdoDeviceObject)
816 {
817 /* Should not be having as one */
818 if (CmBattDebug & 0x24) DbgPrint("CmBattAddDevice: Asked to do detection\n");
819 return STATUS_NO_MORE_ENTRIES;
820 }
821
822 /* Open the driver key */
823 Status = IoOpenDeviceRegistryKey(PdoDeviceObject,
824 PLUGPLAY_REGKEY_DRIVER,
825 KEY_READ,
826 &KeyHandle);
827 if (!NT_SUCCESS(Status))
828 {
829 if (CmBattDebug & 0xC)
830 DbgPrint("CmBattAddDevice: Could not get the software branch: %x\n", Status);
831 return Status;
832 }
833
834 /* Read the power source type */
835 RtlInitUnicodeString(&KeyString, L"PowerSourceType");
836 Status = ZwQueryValueKey(KeyHandle,
837 &KeyString,
838 KeyValuePartialInformation,
839 PartialInfo,
840 sizeof(Buffer),
841 &ResultLength);
842 ZwClose(KeyHandle);
843 if (!NT_SUCCESS(Status))
844 {
845 /* We need the data, fail without it */
846 if (CmBattDebug & 0xC)
847 DbgPrint("CmBattAddDevice: Could not read the power type identifier: %x\n", Status);
848 return Status;
849 }
850
851 /* Check what kind of power source this is */
852 PowerSourceType = *(PULONG)PartialInfo->Data;
853 if (PowerSourceType == 1)
854 {
855 /* Create an AC adapter */
856 Status = CmBattAddAcAdapter(DriverObject, PdoDeviceObject);
857 }
858 else if (PowerSourceType == 0)
859 {
860 /* Create a battery */
861 Status = CmBattAddBattery(DriverObject, PdoDeviceObject);
862 }
863 else
864 {
865 /* Unknown type, fail */
866 if (CmBattDebug & 0xC)
867 DbgPrint("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", PowerSourceType);
868 return STATUS_UNSUCCESSFUL;
869 }
870
871 /* Return whatever the FDO creation routine did */
872 return Status;
873 }
874
875 /* EOF */