/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/battery/battc/battc.c * PURPOSE: Battery Class Driver * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) */ #include #define NDEBUG #include NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DPRINT("Battery class driver initialized\n"); return STATUS_SUCCESS; } BCLASSAPI NTSTATUS NTAPI BatteryClassUnload(PVOID ClassData) { PBATTERY_CLASS_DATA BattClass; DPRINT("Battery %p is being unloaded\n", ClassData); BattClass = ClassData; if (BattClass->InterfaceName.Length != 0) { IoSetDeviceInterfaceState(&BattClass->InterfaceName, FALSE); RtlFreeUnicodeString(&BattClass->InterfaceName); } ExFreePoolWithTag(BattClass, BATTERY_CLASS_DATA_TAG); return STATUS_SUCCESS; } BCLASSAPI NTSTATUS NTAPI BatteryClassSystemControl(PVOID ClassData, PVOID WmiLibContext, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Disposition) { UNIMPLEMENTED; return STATUS_WMI_GUID_NOT_FOUND; } BCLASSAPI NTSTATUS NTAPI BatteryClassQueryWmiDataBlock(PVOID ClassData, PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG GuidIndex, PULONG InstanceLengthArray, ULONG OutBufferSize, PUCHAR Buffer) { UNIMPLEMENTED; return STATUS_WMI_GUID_NOT_FOUND; } BCLASSAPI NTSTATUS NTAPI BatteryClassStatusNotify(PVOID ClassData) { PBATTERY_CLASS_DATA BattClass; PBATTERY_WAIT_STATUS BattWait; BATTERY_STATUS BattStatus; NTSTATUS Status; DPRINT("Received battery status notification from %p\n", ClassData); BattClass = ClassData; BattWait = BattClass->EventTriggerContext; ExAcquireFastMutex(&BattClass->Mutex); if (!BattClass->Waiting) { ExReleaseFastMutex(&BattClass->Mutex); return STATUS_SUCCESS; } switch (BattClass->EventTrigger) { case EVENT_BATTERY_TAG: ExReleaseFastMutex(&BattClass->Mutex); DPRINT1("Waiting for battery is UNIMPLEMENTED!\n"); break; case EVENT_BATTERY_STATUS: ExReleaseFastMutex(&BattClass->Mutex); Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, BattWait->BatteryTag, &BattStatus); if (!NT_SUCCESS(Status)) return Status; ExAcquireFastMutex(&BattClass->Mutex); if (!(BattWait->PowerState & BattStatus.PowerState) || (BattWait->HighCapacity > BattStatus.Capacity) || (BattWait->LowCapacity < BattStatus.Capacity)) { KeSetEvent(&BattClass->WaitEvent, IO_NO_INCREMENT, FALSE); } ExReleaseFastMutex(&BattClass->Mutex); break; default: ExReleaseFastMutex(&BattClass->Mutex); ASSERT(FALSE); break; } return STATUS_SUCCESS; } BCLASSAPI NTSTATUS NTAPI BatteryClassInitializeDevice(PBATTERY_MINIPORT_INFO MiniportInfo, PVOID *ClassData) { NTSTATUS Status; PBATTERY_CLASS_DATA BattClass; BattClass = ExAllocatePoolWithTag(NonPagedPool, sizeof(BATTERY_CLASS_DATA), BATTERY_CLASS_DATA_TAG); if (BattClass == NULL) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(BattClass, sizeof(BATTERY_CLASS_DATA)); RtlCopyMemory(&BattClass->MiniportInfo, MiniportInfo, sizeof(BattClass->MiniportInfo)); KeInitializeEvent(&BattClass->WaitEvent, SynchronizationEvent, FALSE); ExInitializeFastMutex(&BattClass->Mutex); if (MiniportInfo->Pdo != NULL) { Status = IoRegisterDeviceInterface(MiniportInfo->Pdo, &GUID_DEVICE_BATTERY, NULL, &BattClass->InterfaceName); if (NT_SUCCESS(Status)) { DPRINT("Initialized battery interface: %wZ\n", &BattClass->InterfaceName); Status = IoSetDeviceInterfaceState(&BattClass->InterfaceName, TRUE); if (Status == STATUS_OBJECT_NAME_EXISTS) { DPRINT1("Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n"); Status = STATUS_SUCCESS; } } else { DPRINT1("IoRegisterDeviceInterface failed (0x%x)\n", Status); } } *ClassData = BattClass; return STATUS_SUCCESS; } BCLASSAPI NTSTATUS NTAPI BatteryClassIoctl(PVOID ClassData, PIRP Irp) { PBATTERY_CLASS_DATA BattClass; PIO_STACK_LOCATION IrpSp; NTSTATUS Status; ULONG WaitTime; BATTERY_WAIT_STATUS BattWait; PBATTERY_QUERY_INFORMATION BattQueryInfo; PBATTERY_SET_INFORMATION BattSetInfo; LARGE_INTEGER Timeout; PBATTERY_STATUS BattStatus; BATTERY_NOTIFY BattNotify; ULONG ReturnedLength; DPRINT("BatteryClassIoctl(%p %p)\n", ClassData, Irp); BattClass = ClassData; IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0; DPRINT("Received IOCTL %x for %p\n", IrpSp->Parameters.DeviceIoControl.IoControlCode, ClassData); switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_BATTERY_QUERY_TAG: if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG) && IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } WaitTime = IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(ULONG) ? *(PULONG)Irp->AssociatedIrp.SystemBuffer : 0; Timeout.QuadPart = Int32x32To64(WaitTime, -1000); Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, (PULONG)Irp->AssociatedIrp.SystemBuffer); if (!NT_SUCCESS(Status)) { ExAcquireFastMutex(&BattClass->Mutex); BattClass->EventTrigger = EVENT_BATTERY_TAG; BattClass->Waiting = TRUE; ExReleaseFastMutex(&BattClass->Mutex); Status = KeWaitForSingleObject(&BattClass->WaitEvent, Executive, KernelMode, FALSE, WaitTime != -1 ? &Timeout : NULL); ExAcquireFastMutex(&BattClass->Mutex); BattClass->Waiting = FALSE; ExReleaseFastMutex(&BattClass->Mutex); if (Status == STATUS_SUCCESS) { Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context, (PULONG)Irp->AssociatedIrp.SystemBuffer); if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); } else { Status = STATUS_NO_SUCH_DEVICE; } } else { Irp->IoStatus.Information = sizeof(ULONG); } break; case IOCTL_BATTERY_QUERY_STATUS: if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BattWait) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } BattWait = *(PBATTERY_WAIT_STATUS)Irp->AssociatedIrp.SystemBuffer; Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -1000); Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, BattWait.BatteryTag, (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer); BattStatus = Irp->AssociatedIrp.SystemBuffer; if (!NT_SUCCESS(Status) || ((BattWait.PowerState & BattStatus->PowerState) && (BattWait.HighCapacity <= BattStatus->Capacity) && (BattWait.LowCapacity >= BattStatus->Capacity))) { BattNotify.PowerState = BattWait.PowerState; BattNotify.HighCapacity = BattWait.HighCapacity; BattNotify.LowCapacity = BattWait.LowCapacity; BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, BattWait.BatteryTag, &BattNotify); ExAcquireFastMutex(&BattClass->Mutex); BattClass->EventTrigger = EVENT_BATTERY_STATUS; BattClass->EventTriggerContext = &BattWait; BattClass->Waiting = TRUE; ExReleaseFastMutex(&BattClass->Mutex); Status = KeWaitForSingleObject(&BattClass->WaitEvent, Executive, KernelMode, FALSE, BattWait.Timeout != -1 ? &Timeout : NULL); ExAcquireFastMutex(&BattClass->Mutex); BattClass->Waiting = FALSE; ExReleaseFastMutex(&BattClass->Mutex); BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context); if (Status == STATUS_SUCCESS) { Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, BattWait.BatteryTag, (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer); if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); } else { Status = STATUS_NO_SUCH_DEVICE; } } else { Irp->IoStatus.Information = sizeof(BATTERY_STATUS); } break; case IOCTL_BATTERY_QUERY_INFORMATION: if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo)) { Status = STATUS_BUFFER_TOO_SMALL; break; } BattQueryInfo = Irp->AssociatedIrp.SystemBuffer; Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context, BattQueryInfo->BatteryTag, BattQueryInfo->InformationLevel, BattQueryInfo->AtRate, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, &ReturnedLength); Irp->IoStatus.Information = ReturnedLength; if (!NT_SUCCESS(Status)) { DPRINT1("QueryInformation failed (0x%x)\n", Status); } break; case IOCTL_BATTERY_SET_INFORMATION: if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo)) { Status = STATUS_BUFFER_TOO_SMALL; break; } BattSetInfo = Irp->AssociatedIrp.SystemBuffer; Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context, BattSetInfo->BatteryTag, BattSetInfo->InformationLevel, BattSetInfo->Buffer); if (!NT_SUCCESS(Status)) { DPRINT1("SetInformation failed (0x%x)\n", Status); } break; default: DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); /* Do NOT complete the irp */ return STATUS_NOT_SUPPORTED; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }