1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/battery/battc/battc.c 5 * PURPOSE: Battery Class Driver 6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 7 */ 8 9 #include <battc.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 NTSTATUS 15 NTAPI 16 DriverEntry(PDRIVER_OBJECT DriverObject, 17 PUNICODE_STRING RegistryPath) 18 { 19 DPRINT("Battery class driver initialized\n"); 20 21 return STATUS_SUCCESS; 22 } 23 24 BCLASSAPI 25 NTSTATUS 26 NTAPI 27 BatteryClassUnload(PVOID ClassData) 28 { 29 PBATTERY_CLASS_DATA BattClass; 30 31 DPRINT("Battery %p is being unloaded\n", ClassData); 32 33 BattClass = ClassData; 34 if (BattClass->InterfaceName.Length != 0) 35 { 36 IoSetDeviceInterfaceState(&BattClass->InterfaceName, FALSE); 37 RtlFreeUnicodeString(&BattClass->InterfaceName); 38 } 39 40 ExFreePoolWithTag(BattClass, 41 BATTERY_CLASS_DATA_TAG); 42 43 return STATUS_SUCCESS; 44 } 45 46 BCLASSAPI 47 NTSTATUS 48 NTAPI 49 BatteryClassSystemControl(PVOID ClassData, 50 PVOID WmiLibContext, 51 PDEVICE_OBJECT DeviceObject, 52 PIRP Irp, 53 PVOID Disposition) 54 { 55 UNIMPLEMENTED; 56 57 return STATUS_WMI_GUID_NOT_FOUND; 58 } 59 60 BCLASSAPI 61 NTSTATUS 62 NTAPI 63 BatteryClassQueryWmiDataBlock(PVOID ClassData, 64 PDEVICE_OBJECT DeviceObject, 65 PIRP Irp, 66 ULONG GuidIndex, 67 PULONG InstanceLengthArray, 68 ULONG OutBufferSize, 69 PUCHAR Buffer) 70 { 71 UNIMPLEMENTED; 72 73 return STATUS_WMI_GUID_NOT_FOUND; 74 } 75 76 BCLASSAPI 77 NTSTATUS 78 NTAPI 79 BatteryClassStatusNotify( 80 _In_ PVOID ClassData) 81 { 82 PBATTERY_CLASS_DATA BattClass; 83 PBATTERY_WAIT_STATUS BattWait; 84 BATTERY_STATUS BattStatus; 85 ULONG Tag; 86 NTSTATUS Status; 87 88 DPRINT("Received battery status notification from %p\n", ClassData); 89 90 BattClass = ClassData; 91 BattWait = BattClass->EventTriggerContext; 92 93 ExAcquireFastMutex(&BattClass->Mutex); 94 if (!BattClass->Waiting) 95 { 96 ExReleaseFastMutex(&BattClass->Mutex); 97 return STATUS_SUCCESS; 98 } 99 100 switch (BattClass->EventTrigger) 101 { 102 case EVENT_BATTERY_TAG: 103 ExReleaseFastMutex(&BattClass->Mutex); 104 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, 105 &Tag); 106 if (!NT_SUCCESS(Status)) 107 return Status; 108 109 ExAcquireFastMutex(&BattClass->Mutex); 110 KeSetEvent(&BattClass->WaitEvent, IO_NO_INCREMENT, FALSE); 111 ExReleaseFastMutex(&BattClass->Mutex); 112 break; 113 114 case EVENT_BATTERY_STATUS: 115 ExReleaseFastMutex(&BattClass->Mutex); 116 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, 117 BattWait->BatteryTag, 118 &BattStatus); 119 if (!NT_SUCCESS(Status)) 120 return Status; 121 122 ExAcquireFastMutex(&BattClass->Mutex); 123 124 if (BattWait->PowerState != BattStatus.PowerState || 125 BattWait->HighCapacity < BattStatus.Capacity || 126 BattWait->LowCapacity > BattStatus.Capacity) 127 { 128 KeSetEvent(&BattClass->WaitEvent, IO_NO_INCREMENT, FALSE); 129 } 130 131 ExReleaseFastMutex(&BattClass->Mutex); 132 break; 133 134 default: 135 ExReleaseFastMutex(&BattClass->Mutex); 136 ASSERT(FALSE); 137 break; 138 } 139 140 return STATUS_SUCCESS; 141 } 142 143 BCLASSAPI 144 NTSTATUS 145 NTAPI 146 BatteryClassInitializeDevice(PBATTERY_MINIPORT_INFO MiniportInfo, 147 PVOID *ClassData) 148 { 149 NTSTATUS Status; 150 PBATTERY_CLASS_DATA BattClass; 151 152 BattClass = ExAllocatePoolWithTag(NonPagedPool, 153 sizeof(BATTERY_CLASS_DATA), 154 BATTERY_CLASS_DATA_TAG); 155 if (BattClass == NULL) 156 return STATUS_INSUFFICIENT_RESOURCES; 157 158 RtlZeroMemory(BattClass, sizeof(BATTERY_CLASS_DATA)); 159 160 RtlCopyMemory(&BattClass->MiniportInfo, 161 MiniportInfo, 162 sizeof(BattClass->MiniportInfo)); 163 164 KeInitializeEvent(&BattClass->WaitEvent, SynchronizationEvent, FALSE); 165 166 ExInitializeFastMutex(&BattClass->Mutex); 167 168 if (MiniportInfo->Pdo != NULL) 169 { 170 Status = IoRegisterDeviceInterface(MiniportInfo->Pdo, 171 &GUID_DEVICE_BATTERY, 172 NULL, 173 &BattClass->InterfaceName); 174 if (NT_SUCCESS(Status)) 175 { 176 DPRINT("Initialized battery interface: %wZ\n", &BattClass->InterfaceName); 177 Status = IoSetDeviceInterfaceState(&BattClass->InterfaceName, TRUE); 178 if (Status == STATUS_OBJECT_NAME_EXISTS) 179 { 180 DPRINT1("Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n"); 181 Status = STATUS_SUCCESS; 182 } 183 } 184 else 185 { 186 DPRINT1("IoRegisterDeviceInterface failed (0x%x)\n", Status); 187 } 188 } 189 190 *ClassData = BattClass; 191 192 return STATUS_SUCCESS; 193 } 194 195 BCLASSAPI 196 NTSTATUS 197 NTAPI 198 BatteryClassIoctl(PVOID ClassData, 199 PIRP Irp) 200 { 201 PBATTERY_CLASS_DATA BattClass; 202 PIO_STACK_LOCATION IrpSp; 203 NTSTATUS Status; 204 ULONG WaitTime; 205 BATTERY_WAIT_STATUS BattWait; 206 PBATTERY_QUERY_INFORMATION BattQueryInfo; 207 PBATTERY_SET_INFORMATION BattSetInfo; 208 LARGE_INTEGER Timeout; 209 PBATTERY_STATUS BattStatus; 210 BATTERY_NOTIFY BattNotify; 211 ULONG ReturnedLength; 212 213 DPRINT("BatteryClassIoctl(%p %p)\n", ClassData, Irp); 214 215 BattClass = ClassData; 216 217 IrpSp = IoGetCurrentIrpStackLocation(Irp); 218 Irp->IoStatus.Information = 0; 219 220 DPRINT("Received IOCTL %x for %p\n", IrpSp->Parameters.DeviceIoControl.IoControlCode, 221 ClassData); 222 223 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 224 { 225 case IOCTL_BATTERY_QUERY_TAG: 226 if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG) && IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) || 227 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) 228 { 229 Status = STATUS_BUFFER_TOO_SMALL; 230 break; 231 } 232 233 WaitTime = IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(ULONG) ? *(PULONG)Irp->AssociatedIrp.SystemBuffer : 0; 234 235 Timeout.QuadPart = Int32x32To64(WaitTime, -10000); 236 237 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, 238 (PULONG)Irp->AssociatedIrp.SystemBuffer); 239 if (!NT_SUCCESS(Status)) 240 { 241 ExAcquireFastMutex(&BattClass->Mutex); 242 BattClass->EventTrigger = EVENT_BATTERY_TAG; 243 BattClass->Waiting = TRUE; 244 ExReleaseFastMutex(&BattClass->Mutex); 245 246 Status = KeWaitForSingleObject(&BattClass->WaitEvent, 247 Executive, 248 KernelMode, 249 FALSE, 250 WaitTime != -1 ? &Timeout : NULL); 251 252 ExAcquireFastMutex(&BattClass->Mutex); 253 BattClass->Waiting = FALSE; 254 ExReleaseFastMutex(&BattClass->Mutex); 255 256 if (Status == STATUS_SUCCESS) 257 { 258 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, 259 (PULONG)Irp->AssociatedIrp.SystemBuffer); 260 if (NT_SUCCESS(Status)) 261 Irp->IoStatus.Information = sizeof(ULONG); 262 } 263 else 264 { 265 Status = STATUS_NO_SUCH_DEVICE; 266 } 267 } 268 else 269 { 270 Irp->IoStatus.Information = sizeof(ULONG); 271 } 272 break; 273 274 case IOCTL_BATTERY_QUERY_STATUS: 275 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BattWait) || 276 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS)) 277 { 278 Status = STATUS_BUFFER_TOO_SMALL; 279 break; 280 } 281 282 BattWait = *(PBATTERY_WAIT_STATUS)Irp->AssociatedIrp.SystemBuffer; 283 284 Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -10000); 285 286 BattStatus = Irp->AssociatedIrp.SystemBuffer; 287 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, 288 BattWait.BatteryTag, 289 BattStatus); 290 291 if (!NT_SUCCESS(Status) || 292 (BattWait.PowerState == BattStatus->PowerState && 293 BattWait.HighCapacity >= BattStatus->Capacity && 294 BattWait.LowCapacity <= BattStatus->Capacity)) 295 { 296 BattNotify.PowerState = BattWait.PowerState; 297 BattNotify.HighCapacity = BattWait.HighCapacity; 298 BattNotify.LowCapacity = BattWait.LowCapacity; 299 300 BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, 301 BattWait.BatteryTag, 302 &BattNotify); 303 304 ExAcquireFastMutex(&BattClass->Mutex); 305 BattClass->EventTrigger = EVENT_BATTERY_STATUS; 306 BattClass->EventTriggerContext = &BattWait; 307 BattClass->Waiting = TRUE; 308 ExReleaseFastMutex(&BattClass->Mutex); 309 310 Status = KeWaitForSingleObject(&BattClass->WaitEvent, 311 Executive, 312 KernelMode, 313 FALSE, 314 BattWait.Timeout != -1 ? &Timeout : NULL); 315 if (Status == STATUS_TIMEOUT) 316 Status = STATUS_SUCCESS; 317 318 ExAcquireFastMutex(&BattClass->Mutex); 319 BattClass->Waiting = FALSE; 320 ExReleaseFastMutex(&BattClass->Mutex); 321 322 BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context); 323 } 324 else 325 { 326 Irp->IoStatus.Information = sizeof(BATTERY_STATUS); 327 } 328 break; 329 330 case IOCTL_BATTERY_QUERY_INFORMATION: 331 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo)) 332 { 333 Status = STATUS_BUFFER_TOO_SMALL; 334 break; 335 } 336 337 BattQueryInfo = Irp->AssociatedIrp.SystemBuffer; 338 339 Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context, 340 BattQueryInfo->BatteryTag, 341 BattQueryInfo->InformationLevel, 342 BattQueryInfo->AtRate, 343 Irp->AssociatedIrp.SystemBuffer, 344 IrpSp->Parameters.DeviceIoControl.OutputBufferLength, 345 &ReturnedLength); 346 Irp->IoStatus.Information = ReturnedLength; 347 if (!NT_SUCCESS(Status)) 348 { 349 DPRINT1("QueryInformation failed (0x%x)\n", Status); 350 } 351 break; 352 353 case IOCTL_BATTERY_SET_INFORMATION: 354 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo)) 355 { 356 Status = STATUS_BUFFER_TOO_SMALL; 357 break; 358 } 359 360 BattSetInfo = Irp->AssociatedIrp.SystemBuffer; 361 362 Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context, 363 BattSetInfo->BatteryTag, 364 BattSetInfo->InformationLevel, 365 BattSetInfo->Buffer); 366 if (!NT_SUCCESS(Status)) 367 { 368 DPRINT1("SetInformation failed (0x%x)\n", Status); 369 } 370 break; 371 372 default: 373 DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); 374 /* Do NOT complete the irp */ 375 return STATUS_NOT_SUPPORTED; 376 } 377 378 Irp->IoStatus.Status = Status; 379 IoCompleteRequest(Irp, IO_NO_INCREMENT); 380 381 return Status; 382 } 383