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(PVOID ClassData) 80 { 81 PBATTERY_CLASS_DATA BattClass; 82 PBATTERY_WAIT_STATUS BattWait; 83 BATTERY_STATUS BattStatus; 84 NTSTATUS Status; 85 86 DPRINT("Received battery status notification from %p\n", ClassData); 87 88 BattClass = ClassData; 89 BattWait = BattClass->EventTriggerContext; 90 91 ExAcquireFastMutex(&BattClass->Mutex); 92 if (!BattClass->Waiting) 93 { 94 ExReleaseFastMutex(&BattClass->Mutex); 95 return STATUS_SUCCESS; 96 } 97 98 switch (BattClass->EventTrigger) 99 { 100 case EVENT_BATTERY_TAG: 101 ExReleaseFastMutex(&BattClass->Mutex); 102 DPRINT1("Waiting for battery is UNIMPLEMENTED!\n"); 103 break; 104 105 case EVENT_BATTERY_STATUS: 106 ExReleaseFastMutex(&BattClass->Mutex); 107 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, 108 BattWait->BatteryTag, 109 &BattStatus); 110 if (!NT_SUCCESS(Status)) 111 return Status; 112 113 ExAcquireFastMutex(&BattClass->Mutex); 114 115 if (!(BattWait->PowerState & BattStatus.PowerState) || 116 (BattWait->HighCapacity > BattStatus.Capacity) || 117 (BattWait->LowCapacity < BattStatus.Capacity)) 118 { 119 KeSetEvent(&BattClass->WaitEvent, IO_NO_INCREMENT, FALSE); 120 } 121 122 ExReleaseFastMutex(&BattClass->Mutex); 123 break; 124 125 default: 126 ExReleaseFastMutex(&BattClass->Mutex); 127 ASSERT(FALSE); 128 break; 129 } 130 131 return STATUS_SUCCESS; 132 } 133 134 BCLASSAPI 135 NTSTATUS 136 NTAPI 137 BatteryClassInitializeDevice(PBATTERY_MINIPORT_INFO MiniportInfo, 138 PVOID *ClassData) 139 { 140 NTSTATUS Status; 141 PBATTERY_CLASS_DATA BattClass; 142 143 BattClass = ExAllocatePoolWithTag(NonPagedPool, 144 sizeof(BATTERY_CLASS_DATA), 145 BATTERY_CLASS_DATA_TAG); 146 if (BattClass == NULL) 147 return STATUS_INSUFFICIENT_RESOURCES; 148 149 RtlZeroMemory(BattClass, sizeof(BATTERY_CLASS_DATA)); 150 151 RtlCopyMemory(&BattClass->MiniportInfo, 152 MiniportInfo, 153 sizeof(BattClass->MiniportInfo)); 154 155 KeInitializeEvent(&BattClass->WaitEvent, SynchronizationEvent, FALSE); 156 157 ExInitializeFastMutex(&BattClass->Mutex); 158 159 if (MiniportInfo->Pdo != NULL) 160 { 161 Status = IoRegisterDeviceInterface(MiniportInfo->Pdo, 162 &GUID_DEVICE_BATTERY, 163 NULL, 164 &BattClass->InterfaceName); 165 if (NT_SUCCESS(Status)) 166 { 167 DPRINT("Initialized battery interface: %wZ\n", &BattClass->InterfaceName); 168 Status = IoSetDeviceInterfaceState(&BattClass->InterfaceName, TRUE); 169 if (Status == STATUS_OBJECT_NAME_EXISTS) 170 { 171 DPRINT1("Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n"); 172 Status = STATUS_SUCCESS; 173 } 174 } 175 else 176 { 177 DPRINT1("IoRegisterDeviceInterface failed (0x%x)\n", Status); 178 } 179 } 180 181 *ClassData = BattClass; 182 183 return STATUS_SUCCESS; 184 } 185 186 BCLASSAPI 187 NTSTATUS 188 NTAPI 189 BatteryClassIoctl(PVOID ClassData, 190 PIRP Irp) 191 { 192 PBATTERY_CLASS_DATA BattClass; 193 PIO_STACK_LOCATION IrpSp; 194 NTSTATUS Status; 195 ULONG WaitTime; 196 PBATTERY_WAIT_STATUS BattWait; 197 PBATTERY_QUERY_INFORMATION BattQueryInfo; 198 PBATTERY_SET_INFORMATION BattSetInfo; 199 LARGE_INTEGER Timeout; 200 PBATTERY_STATUS BattStatus; 201 BATTERY_NOTIFY BattNotify; 202 ULONG ReturnedLength; 203 204 DPRINT("BatteryClassIoctl(%p %p)\n", ClassData, Irp); 205 206 BattClass = ClassData; 207 208 IrpSp = IoGetCurrentIrpStackLocation(Irp); 209 Irp->IoStatus.Information = 0; 210 211 DPRINT("Received IOCTL %x for %p\n", IrpSp->Parameters.DeviceIoControl.IoControlCode, 212 ClassData); 213 214 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 215 { 216 case IOCTL_BATTERY_QUERY_TAG: 217 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) || 218 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) 219 { 220 Status = STATUS_BUFFER_TOO_SMALL; 221 break; 222 } 223 224 WaitTime = *(PULONG)Irp->AssociatedIrp.SystemBuffer; 225 226 Timeout.QuadPart = Int32x32To64(WaitTime, -1000); 227 228 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, 229 (PULONG)Irp->AssociatedIrp.SystemBuffer); 230 if (!NT_SUCCESS(Status)) 231 { 232 ExAcquireFastMutex(&BattClass->Mutex); 233 BattClass->EventTrigger = EVENT_BATTERY_TAG; 234 BattClass->Waiting = TRUE; 235 ExReleaseFastMutex(&BattClass->Mutex); 236 237 Status = KeWaitForSingleObject(&BattClass->WaitEvent, 238 Executive, 239 KernelMode, 240 FALSE, 241 WaitTime != -1 ? &Timeout : NULL); 242 243 ExAcquireFastMutex(&BattClass->Mutex); 244 BattClass->Waiting = FALSE; 245 ExReleaseFastMutex(&BattClass->Mutex); 246 247 if (Status == STATUS_SUCCESS) 248 { 249 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, 250 (PULONG)Irp->AssociatedIrp.SystemBuffer); 251 if (NT_SUCCESS(Status)) 252 Irp->IoStatus.Information = sizeof(ULONG); 253 } 254 else 255 { 256 Status = STATUS_NO_SUCH_DEVICE; 257 } 258 } 259 else 260 { 261 Irp->IoStatus.Information = sizeof(ULONG); 262 } 263 break; 264 265 case IOCTL_BATTERY_QUERY_STATUS: 266 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattWait) || 267 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS)) 268 { 269 Status = STATUS_BUFFER_TOO_SMALL; 270 break; 271 } 272 273 BattWait = Irp->AssociatedIrp.SystemBuffer; 274 275 Timeout.QuadPart = Int32x32To64(BattWait->Timeout, -1000); 276 277 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, 278 BattWait->BatteryTag, 279 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer); 280 281 BattStatus = Irp->AssociatedIrp.SystemBuffer; 282 283 if (!NT_SUCCESS(Status) || 284 ((BattWait->PowerState & BattStatus->PowerState) && 285 (BattWait->HighCapacity <= BattStatus->Capacity) && 286 (BattWait->LowCapacity >= BattStatus->Capacity))) 287 { 288 BattNotify.PowerState = BattWait->PowerState; 289 BattNotify.HighCapacity = BattWait->HighCapacity; 290 BattNotify.LowCapacity = BattWait->LowCapacity; 291 292 BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, 293 BattWait->BatteryTag, 294 &BattNotify); 295 296 ExAcquireFastMutex(&BattClass->Mutex); 297 BattClass->EventTrigger = EVENT_BATTERY_STATUS; 298 BattClass->EventTriggerContext = BattWait; 299 BattClass->Waiting = TRUE; 300 ExReleaseFastMutex(&BattClass->Mutex); 301 302 Status = KeWaitForSingleObject(&BattClass->WaitEvent, 303 Executive, 304 KernelMode, 305 FALSE, 306 BattWait->Timeout != -1 ? &Timeout : NULL); 307 308 ExAcquireFastMutex(&BattClass->Mutex); 309 BattClass->Waiting = FALSE; 310 ExReleaseFastMutex(&BattClass->Mutex); 311 312 BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context); 313 314 if (Status == STATUS_SUCCESS) 315 { 316 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, 317 BattWait->BatteryTag, 318 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer); 319 if (NT_SUCCESS(Status)) 320 Irp->IoStatus.Information = sizeof(ULONG); 321 } 322 else 323 { 324 Status = STATUS_NO_SUCH_DEVICE; 325 } 326 } 327 else 328 { 329 Irp->IoStatus.Information = sizeof(BATTERY_STATUS); 330 } 331 break; 332 333 case IOCTL_BATTERY_QUERY_INFORMATION: 334 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo)) 335 { 336 Status = STATUS_BUFFER_TOO_SMALL; 337 break; 338 } 339 340 BattQueryInfo = Irp->AssociatedIrp.SystemBuffer; 341 342 Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context, 343 BattQueryInfo->BatteryTag, 344 BattQueryInfo->InformationLevel, 345 BattQueryInfo->AtRate, 346 Irp->AssociatedIrp.SystemBuffer, 347 IrpSp->Parameters.DeviceIoControl.OutputBufferLength, 348 &ReturnedLength); 349 Irp->IoStatus.Information = ReturnedLength; 350 if (!NT_SUCCESS(Status)) 351 { 352 DPRINT1("QueryInformation failed (0x%x)\n", Status); 353 } 354 break; 355 356 case IOCTL_BATTERY_SET_INFORMATION: 357 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo)) 358 { 359 Status = STATUS_BUFFER_TOO_SMALL; 360 break; 361 } 362 363 BattSetInfo = Irp->AssociatedIrp.SystemBuffer; 364 365 Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context, 366 BattSetInfo->BatteryTag, 367 BattSetInfo->InformationLevel, 368 BattSetInfo->Buffer); 369 if (!NT_SUCCESS(Status)) 370 { 371 DPRINT1("SetInformation failed (0x%x)\n", Status); 372 } 373 break; 374 375 default: 376 DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); 377 /* Do NOT complete the irp */ 378 return STATUS_NOT_SUPPORTED; 379 } 380 381 Irp->IoStatus.Status = Status; 382 IoCompleteRequest(Irp, IO_NO_INCREMENT); 383 384 return Status; 385 } 386