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