56acf22cdeb3498fc36f5b2926823e124c7ba448
[reactos.git] / reactos / drivers / bus / acpi / cmbatt / cmbpnp.c
1 /*
2 * PROJECT: ReactOS ACPI-Compliant Control Method Battery
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/bus/acpi/cmbatt/cmbpnp.c
5 * PURPOSE: Plug-and-Play IOCTL/IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "cmbatt.h"
12
13 /* FUNCTIONS ******************************************************************/
14
15 NTSTATUS
16 NTAPI
17 CmBattIoCompletion(PDEVICE_OBJECT DeviceObject,
18 PIRP Irp,
19 PKEVENT Event)
20 {
21 UNIMPLEMENTED;
22 return STATUS_NOT_IMPLEMENTED;
23 }
24
25 NTSTATUS
26 NTAPI
27 CmBattGetAcpiInterfaces(PDEVICE_OBJECT DeviceObject,
28 PACPI_INTERFACE_STANDARD AcpiInterface)
29 {
30 UNIMPLEMENTED;
31 return STATUS_NOT_IMPLEMENTED;
32 }
33
34 VOID
35 NTAPI
36 CmBattDestroyFdo(IN PDEVICE_OBJECT DeviceObject)
37 {
38 PAGED_CODE();
39 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo, Battery.\n");
40
41 /* Delete the device */
42 IoDeleteDevice(DeviceObject);
43 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo: done.\n");
44 }
45
46 NTSTATUS
47 NTAPI
48 CmBattRemoveDevice(IN PDEVICE_OBJECT DeviceObject,
49 IN PIRP Irp)
50 {
51 PCMBATT_DEVICE_EXTENSION DeviceExtension;
52 PVOID Context;
53 DeviceExtension = DeviceObject->DeviceExtension;
54 if (CmBattDebug & 2)
55 DbgPrint("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n",
56 DeviceExtension,
57 DeviceExtension->FdoType,
58 DeviceExtension->DeviceId);
59
60 /* Make sure it's safe to go ahead */
61 IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, 0);
62
63 /* Check for pending power IRP */
64 if (DeviceExtension->PowerIrp)
65 {
66 /* Cancel and clear */
67 IoCancelIrp(DeviceExtension->PowerIrp);
68 DeviceExtension->PowerIrp = NULL;
69 }
70
71 /* Check what type of FDO is being removed */
72 Context = DeviceExtension->AcpiInterface.Context;
73 if (DeviceExtension->FdoType == CmBattBattery)
74 {
75 /* Unregister battery FDO */
76 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context,
77 (PVOID)CmBattNotifyHandler);
78 CmBattWmiDeRegistration(DeviceExtension);
79 if (!NT_SUCCESS(BatteryClassUnload(DeviceExtension->ClassData))) ASSERT(FALSE);
80 }
81 else
82 {
83 /* Unregister AC adapter FDO */
84 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context,
85 (PVOID)CmBattNotifyHandler);
86 CmBattWmiDeRegistration(DeviceExtension);
87 AcAdapterPdo = NULL;
88 }
89
90 /* Detach and delete */
91 IoDetachDevice(DeviceExtension->AttachedDevice);
92 IoDeleteDevice(DeviceExtension->DeviceObject);
93 return STATUS_SUCCESS;
94 }
95
96 NTSTATUS
97 NTAPI
98 CmBattPowerDispatch(PDEVICE_OBJECT DeviceObject,
99 PIRP Irp)
100 {
101 UNIMPLEMENTED;
102 return STATUS_NOT_IMPLEMENTED;
103 }
104
105 NTSTATUS
106 NTAPI
107 CmBattPnpDispatch(PDEVICE_OBJECT DeviceObject,
108 PIRP Irp)
109 {
110 UNIMPLEMENTED;
111 return STATUS_NOT_IMPLEMENTED;
112 }
113
114 NTSTATUS
115 NTAPI
116 CmBattCreateFdo(IN PDRIVER_OBJECT DriverObject,
117 IN PDEVICE_OBJECT DeviceObject,
118 IN ULONG DeviceExtensionSize,
119 IN PDEVICE_OBJECT *NewDeviceObject)
120 {
121 PDEVICE_OBJECT FdoDeviceObject;
122 HANDLE KeyHandle;
123 PCMBATT_DEVICE_EXTENSION FdoExtension;
124 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
125 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
126 NTSTATUS Status;
127 UNICODE_STRING KeyString;
128 ULONG UniqueId;
129 ULONG ResultLength;
130 PAGED_CODE();
131 if (CmBattDebug & 0x220) DbgPrint("CmBattCreateFdo: Entered\n");
132
133 /* Get unique ID */
134 Status = CmBattGetUniqueId(DeviceObject, &UniqueId);
135 if (!NT_SUCCESS(Status))
136 {
137 /* Assume 0 */
138 UniqueId = 0;
139 if (CmBattDebug & 2)
140 DbgPrint("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", Status);
141 }
142
143 /* Create the FDO */
144 Status = IoCreateDevice(DriverObject,
145 DeviceExtensionSize,
146 0,
147 FILE_DEVICE_BATTERY,
148 FILE_DEVICE_SECURE_OPEN,
149 0,
150 &FdoDeviceObject);
151 if (!NT_SUCCESS(Status))
152 {
153 /* Fail */
154 if (CmBattDebug & 0xC)
155 DbgPrint("CmBattCreateFdo: error (0x%x) creating device object\n", Status);
156 return Status;
157 }
158
159 /* Set FDO flags */
160 FdoDeviceObject->Flags |= DO_BUFFERED_IO;
161 FdoDeviceObject->Flags |= DO_MAP_IO_BUFFER;
162 FdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
163
164 /* Initialize the extension */
165 FdoExtension = FdoDeviceObject->DeviceExtension;
166 RtlZeroMemory(FdoExtension, DeviceExtensionSize);
167 FdoExtension->DeviceObject = FdoDeviceObject;
168 FdoExtension->FdoDeviceObject = FdoDeviceObject;
169 FdoExtension->PdoDeviceObject = DeviceObject;
170
171 /* Attach to ACPI */
172 FdoExtension->AttachedDevice = IoAttachDeviceToDeviceStack(FdoDeviceObject,
173 DeviceObject);
174 if (!FdoExtension->AttachedDevice)
175 {
176 /* Destroy and fail */
177 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
178 if (CmBattDebug & 0xC)
179 DbgPrint("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n");
180 return STATUS_UNSUCCESSFUL;
181 }
182
183 /* Get ACPI interface for EVAL */
184 Status = CmBattGetAcpiInterfaces(FdoExtension->AttachedDevice,
185 &FdoExtension->AcpiInterface);
186 if (!FdoExtension->AttachedDevice)
187 {
188 /* Detach, destroy, and fail */
189 IoDetachDevice(FdoExtension->AttachedDevice);
190 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
191 if (CmBattDebug & 0xC)
192 DbgPrint("CmBattCreateFdo: Could not get ACPI interfaces: %x\n", Status);
193 return STATUS_UNSUCCESSFUL;
194 }
195
196 /* Setup the rest of the extension */
197 ExInitializeFastMutex(&FdoExtension->FastMutex);
198 IoInitializeRemoveLock(&FdoExtension->RemoveLock, 0, 0, 0);
199 FdoExtension->HandleCount = 0;
200 FdoExtension->WaitWakeEnable = FALSE;
201 FdoExtension->DeviceId = UniqueId;
202 FdoExtension->DeviceName = NULL;
203 FdoExtension->DelayNotification = FALSE;
204 FdoExtension->ArFlag = 0;
205
206 /* Open the device key */
207 Status = IoOpenDeviceRegistryKey(DeviceObject,
208 PLUGPLAY_REGKEY_DEVICE,
209 KEY_READ,
210 &KeyHandle);
211 if (NT_SUCCESS(Status))
212 {
213 /* Read wait wake value */
214 RtlInitUnicodeString(&KeyString, L"WaitWakeEnabled");
215 Status = ZwQueryValueKey(KeyHandle,
216 &KeyString,
217 KeyValuePartialInformation,
218 PartialInfo,
219 sizeof(Buffer),
220 &ResultLength);
221 if (NT_SUCCESS(Status))
222 {
223 /* Set value */
224 FdoExtension->WaitWakeEnable = *(PULONG)PartialInfo->Data;
225 }
226
227 /* Close the handle */
228 ZwClose(KeyHandle);
229 }
230
231 /* Return success and the new FDO */
232 *NewDeviceObject = FdoDeviceObject;
233 if (CmBattDebug & 0x220)
234 DbgPrint("CmBattCreateFdo: Created FDO %x\n", FdoDeviceObject);
235 return STATUS_SUCCESS;
236 }
237
238 NTSTATUS
239 NTAPI
240 CmBattAddBattery(IN PDRIVER_OBJECT DriverObject,
241 IN PDEVICE_OBJECT DeviceObject)
242 {
243 BATTERY_MINIPORT_INFO MiniportInfo;
244 NTSTATUS Status;
245 PDEVICE_OBJECT FdoDeviceObject;
246 PCMBATT_DEVICE_EXTENSION FdoExtension;
247 PAGED_CODE();
248 if (CmBattDebug & 0x220)
249 DbgPrint("CmBattAddBattery: pdo %x\n", DeviceObject);
250
251 Status = CmBattCreateFdo(DriverObject,
252 DeviceObject,
253 sizeof(CMBATT_DEVICE_EXTENSION),
254 &FdoDeviceObject);
255 if (!NT_SUCCESS(Status))
256 {
257 if (CmBattDebug & 0xC)
258 DbgPrint("CmBattAddBattery: error (0x%x) creating Fdo\n", Status);
259 return Status;
260 }
261
262 /* Build the FDO extensio, check if we support trip points */
263 FdoExtension = FdoDeviceObject->DeviceExtension;
264 FdoExtension->FdoType = CmBattBattery;
265 FdoExtension->Started = 0;
266 FdoExtension->NotifySent = TRUE;
267 InterlockedExchange(&FdoExtension->ArLockValue, 0);
268 FdoExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
269 FdoExtension->Tag = 0;
270 FdoExtension->InterruptTime = KeQueryInterruptTime();
271 FdoExtension->TripPointSet = CmBattSetTripPpoint(FdoExtension, 0) !=
272 STATUS_OBJECT_NAME_NOT_FOUND;
273
274 /* Setup the battery miniport information structure */
275 RtlZeroMemory(&MiniportInfo, sizeof(MiniportInfo));
276 MiniportInfo.Pdo = DeviceObject;
277 MiniportInfo.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
278 MiniportInfo.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
279 MiniportInfo.Context = FdoExtension;
280 MiniportInfo.QueryTag = (PVOID)CmBattQueryTag;
281 MiniportInfo.QueryInformation = (PVOID)CmBattQueryInformation;
282 MiniportInfo.SetInformation = NULL;
283 MiniportInfo.QueryStatus = (PVOID)CmBattQueryStatus;
284 MiniportInfo.SetStatusNotify = (PVOID)CmBattSetStatusNotify;
285 MiniportInfo.DisableStatusNotify = (PVOID)CmBattDisableStatusNotify;
286 MiniportInfo.DeviceName = FdoExtension->DeviceName;
287
288 /* Register with the class driver */
289 Status = BatteryClassInitializeDevice(&MiniportInfo, &FdoExtension->ClassData);
290 if (!NT_SUCCESS(Status))
291 {
292 IoDetachDevice(FdoExtension->AttachedDevice);
293 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
294 if (CmBattDebug & 0xC)
295 DbgPrint("CmBattAddBattery: error (0x%x) registering with class\n", Status);
296 return Status;
297 }
298
299 /* Register WMI */
300 Status = CmBattWmiRegistration(FdoExtension);
301 if (!NT_SUCCESS(Status))
302 {
303 if (CmBattDebug & 0xC)
304 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
305 return Status;
306 }
307
308 /* Register ACPI */
309 Status = FdoExtension->AcpiInterface.RegisterForDeviceNotifications(FdoExtension->AcpiInterface.Context,
310 (PVOID)CmBattNotifyHandler,
311 FdoExtension);
312 if (!NT_SUCCESS(Status))
313 {
314 CmBattWmiDeRegistration(FdoExtension);
315 BatteryClassUnload(FdoExtension->ClassData);
316 IoDetachDevice(FdoExtension->AttachedDevice);
317 CmBattDestroyFdo(FdoExtension->FdoDeviceObject);
318 if (CmBattDebug & 0xC)
319 DbgPrint("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status);
320 }
321
322 /* Return status */
323 return Status;
324 }
325
326 NTSTATUS
327 NTAPI
328 CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject,
329 IN PDEVICE_OBJECT PdoDeviceObject)
330 {
331 PDEVICE_OBJECT FdoDeviceObject;
332 NTSTATUS Status;
333 PCMBATT_DEVICE_EXTENSION DeviceExtension;
334 PAGED_CODE();
335 if (CmBattDebug & 0x220)
336 DbgPrint("CmBattAddAcAdapter: pdo %x\n", PdoDeviceObject);
337
338 /* Check if we already have an AC adapter */
339 if (AcAdapterPdo)
340 {
341 /* Don't do anything */
342 if (CmBattDebug & 0xC)
343 DbgPrint("CmBatt: Second AC adapter found. Current version of driver only supports 1 aadapter.\n");
344 }
345 else
346 {
347 /* Set this as the AC adapter's PDO */
348 AcAdapterPdo = PdoDeviceObject;
349 }
350
351 /* Create the FDO for the adapter */
352 Status = CmBattCreateFdo(DriverObject,
353 PdoDeviceObject,
354 sizeof(CMBATT_DEVICE_EXTENSION),
355 &FdoDeviceObject);
356 if (!NT_SUCCESS(Status))
357 {
358 /* Fail */
359 if (CmBattDebug & 0xC)
360 DbgPrint("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status);
361 return Status;
362 }
363
364 /* Set the type and do WMI registration */
365 DeviceExtension = FdoDeviceObject->DeviceExtension;
366 DeviceExtension->FdoType = CmBattAcAdapter;
367 Status = CmBattWmiRegistration(DeviceExtension);
368 if (!NT_SUCCESS(Status))
369 {
370 /* We can go on without WMI */
371 if (CmBattDebug & 0xC)
372 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status);
373 }
374
375 /* Register with ACPI */
376 Status = DeviceExtension->AcpiInterface.RegisterForDeviceNotifications(DeviceExtension->AcpiInterface.Context,
377 (PVOID)CmBattNotifyHandler,
378 DeviceExtension);
379 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC))
380 DbgPrint("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status);
381
382 /* Send the first manual notification */
383 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
384 return STATUS_SUCCESS;
385 }
386
387 NTSTATUS
388 NTAPI
389 CmBattAddDevice(IN PDRIVER_OBJECT DriverObject,
390 IN PDEVICE_OBJECT PdoDeviceObject)
391 {
392 NTSTATUS Status;
393 HANDLE KeyHandle;
394 ULONG ResultLength;
395 UNICODE_STRING KeyString;
396 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
397 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
398 ULONG PowerSourceType;
399 PAGED_CODE();
400 if (CmBattDebug & 0x220)
401 DbgPrint("CmBattAddDevice: Entered with pdo %x\n", PdoDeviceObject);
402
403 /* Make sure we have a PDO */
404 if (!PdoDeviceObject)
405 {
406 /* Should not be having as one */
407 if (CmBattDebug & 0x24) DbgPrint("CmBattAddDevice: Asked to do detection\n");
408 return STATUS_NO_MORE_ENTRIES;
409 }
410
411 /* Open the driver key */
412 Status = IoOpenDeviceRegistryKey(PdoDeviceObject,
413 PLUGPLAY_REGKEY_DRIVER,
414 KEY_READ,
415 &KeyHandle);
416 if (!NT_SUCCESS(Status))
417 {
418 if (CmBattDebug & 0xC)
419 DbgPrint("CmBattAddDevice: Could not get the software branch: %x\n", Status);
420 return Status;
421 }
422
423 /* Read the power source type */
424 RtlInitUnicodeString(&KeyString, L"PowerSourceType");
425 Status = ZwQueryValueKey(KeyHandle,
426 &KeyString,
427 KeyValuePartialInformation,
428 PartialInfo,
429 sizeof(Buffer),
430 &ResultLength);
431 ZwClose(KeyHandle);
432 if (!NT_SUCCESS(Status))
433 {
434 /* We need the data, fail without it */
435 if (CmBattDebug & 0xC)
436 DbgPrint("CmBattAddDevice: Could not read the power type identifier: %x\n", Status);
437 return Status;
438 }
439
440 /* Check what kind of power source this is */
441 PowerSourceType = *(PULONG)PartialInfo->Data;
442 if (PowerSourceType == 1)
443 {
444 /* Create an AC adapter */
445 Status = CmBattAddAcAdapter(DriverObject, PdoDeviceObject);
446 }
447 else if (PowerSourceType == 0)
448 {
449 /* Create a battery */
450 Status = CmBattAddBattery(DriverObject, PdoDeviceObject);
451 }
452 else
453 {
454 /* Unknown type, fail */
455 if (CmBattDebug & 0xC)
456 DbgPrint("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", PowerSourceType);
457 return STATUS_UNSUCCESSFUL;
458 }
459
460 /* Return whatever the FDO creation routine did */
461 return Status;
462 }
463
464 /* EOF */