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