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