/*++ Copyright (c) 2000 Microsoft Corporation Module Name: smblite.c Abstract: SMBus LCD Back Light Driver Environment: Kernel mode Author: Michael Tsang (MikeTs) 20-Nov-2000 Revision History: --*/ #include "pch.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, SmbLiteAddDevice) #pragma alloc_text(PAGE, RemoveDevice) #pragma alloc_text(PAGE, SmbLiteUnload) #pragma alloc_text(PAGE, SmbLiteCreateClose) #pragma alloc_text(PAGE, HookPowerStateCallback) #endif //ifdef ALLOC_PRAGMA const WCHAR gcwstrACBrightness[] = L"ACBrightness"; const WCHAR gcwstrDCBrightness[] = L"DCBrightness"; const WCHAR gcwstrDeviceName[] = L"\\Device\\SMBusBackLight"; const WCHAR gcwstrDosDeviceName[] = L"\\DosDevices\\SMBusBackLight"; NTSYSAPI NTSTATUS NTAPI ZwPowerInformation( IN POWER_INFORMATION_LEVEL InformationLevel, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength ); /*++ @doc EXTERNAL @func NTSTATUS | DriverEntry | Installable driver initialization entry point. This entry point is called directly by the I/O system. @parm IN PDRIVER_OBJECT | DrvObj | Points to the driver object. @parm IN PUNICODE_STRINT | RegPath | Points to the registry path. @rvalue SUCCESS | returns STATUS_SUCCESS @rvalue FAILURE | returns NT status code --*/ NTSTATUS EXTERNAL DriverEntry( IN PDRIVER_OBJECT DrvObj, IN PUNICODE_STRING RegPath ) { PROCNAME("DriverEntry") NTSTATUS status = STATUS_SUCCESS; ENTER(1, ("(DrvObj=%p,RegPath=%p)\n", DrvObj, RegPath)); DrvObj->DriverExtension->AddDevice = SmbLiteAddDevice; DrvObj->DriverUnload = SmbLiteUnload; DrvObj->MajorFunction[IRP_MJ_CREATE] = DrvObj->MajorFunction[IRP_MJ_CLOSE] = SmbLiteCreateClose; DrvObj->MajorFunction[IRP_MJ_PNP] = SmbLitePnp; DrvObj->MajorFunction[IRP_MJ_POWER] = SmbLitePower; DrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SmbLiteIoctl; EXIT(1, ("=%x\n", status)); return status; } //DriverEntry /*++ @doc EXTERNAL @func NTSTATUS | SmbLiteAddDevice | Add the new backlite device. @parm IN PDRIVER_OBJECT | DrvObj | Points to the driver object. @parm IN PDEVICE_OBJECT | DevObj | Points to a functional device object created by hidclass. @rvalue SUCCESS | Returns STATUS_SUCCESS. @rvalue FAILURE | Returns NT status code. --*/ NTSTATUS EXTERNAL SmbLiteAddDevice( IN PDRIVER_OBJECT DrvObj, IN PDEVICE_OBJECT DevObj ) { PROCNAME("SmbLiteAddDevice") NTSTATUS status; PDEVICE_OBJECT fdo = NULL; UNICODE_STRING UnicodeString; PSMBLITE_DEVEXT devext = NULL; PAGED_CODE (); ENTER(1, ("(DrvObj=%p,DevObj=%p)\n", DrvObj, DevObj)); ASSERT(DevObj != NULL); RtlInitUnicodeString(&UnicodeString, gcwstrDeviceName); status = IoCreateDevice(DrvObj, sizeof(SMBLITE_DEVEXT), &UnicodeString, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); if (NT_SUCCESS(status)) { devext = (PSMBLITE_DEVEXT)fdo->DeviceExtension; RtlZeroMemory(devext, sizeof(*devext)); fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; fdo->Flags &= ~DO_DEVICE_INITIALIZING; IoInitializeRemoveLock(&devext->RemoveLock, SMBLITE_POOLTAG, 1, 64); devext->FDO = fdo; devext->PDO = DevObj; devext->LowerDevice = IoAttachDeviceToDeviceStack(fdo, DevObj); if (devext->LowerDevice == NULL) { ERRPRINT(("failed to attach to lower device\n")); status = STATUS_UNSUCCESSFUL; } else { RtlInitUnicodeString(&devext->SymbolicName, gcwstrDosDeviceName); status = IoCreateSymbolicLink(&devext->SymbolicName, &UnicodeString); if (!NT_SUCCESS(status)) { ERRPRINT(("failed to create device symbolic name (status=%x).\n", status)); } else { devext->dwfSmbLite |= SMBLITEF_SYM_LINK_CREATED; status = HookPowerStateCallback(devext); if (!NT_SUCCESS(status)) { ERRPRINT(("failed to hook power state callback (status=%x).\n", status)); } else { SYSTEM_BATTERY_STATE BatteryState; status = ZwPowerInformation(SystemBatteryState, NULL, 0, &BatteryState, sizeof(BatteryState)); if (!NT_SUCCESS(status)) { ERRPRINT(("failed to query power information (status=%x).\n", status)); } else { if (BatteryState.AcOnLine) { devext->dwfSmbLite |= SMBLITEF_SYSTEM_ON_AC; DBGPRINT(1, ("System is on AC.\n")); } else { devext->dwfSmbLite &= ~SMBLITEF_SYSTEM_ON_AC; DBGPRINT(1, ("System is on DC.\n")); } if (RegQueryDeviceParam( DevObj, gcwstrACBrightness, &devext->BackLightBrightness.bACValue, sizeof(devext->BackLightBrightness.bACValue)) != STATUS_SUCCESS) { devext->BackLightBrightness.bACValue = DEF_ACBRIGHTNESS; } if (RegQueryDeviceParam( DevObj, gcwstrDCBrightness, &devext->BackLightBrightness.bDCValue, sizeof(devext->BackLightBrightness.bDCValue)) != STATUS_SUCCESS) { devext->BackLightBrightness.bDCValue = DEF_DCBRIGHTNESS; } status = SetBackLightBrightness(devext, &devext->BackLightBrightness, FALSE); if (!NT_SUCCESS(status)) { ERRPRINT(("failed to set backlight to initial brightness (status=%x).\n", status)); } } } } } } else { ERRPRINT(("failed to create FDO (status=%x)\n", status)); } if (!NT_SUCCESS(status) && (fdo != NULL) && (devext != NULL)) { RemoveDevice(devext); } EXIT(1, ("=%x\n", status)); return status; } //SmbLiteAddDevice /*++ @doc INTERNAL @func VOID | RemoveDevice | Clean up. @parm IN PSMBLITE_DEVEXT | devext | Points to device extension. @rvalue None. --*/ VOID INTERNAL RemoveDevice( IN PSMBLITE_DEVEXT devext ) { PROCNAME("RemoveDevice") NTSTATUS status; PAGED_CODE (); ENTER(2, ("(devext=%p)\n", devext)); ASSERT(devext != NULL); if (devext->dwfSmbLite & SMBLITEF_SYM_LINK_CREATED) { status = IoDeleteSymbolicLink(&devext->SymbolicName); if (!NT_SUCCESS(status)) { WARNPRINT(("failed to delete device symbolic name (status=%x).\n", status)); } } if (devext->hPowerStateCallback) { ExUnregisterCallback(devext->hPowerStateCallback); } if (devext->LowerDevice != NULL) { IoDetachDevice(devext->LowerDevice); } if (devext->FDO != NULL) { IoDeleteDevice(devext->FDO); } EXIT(2, ("!\n")); return; } //RemoveDevice /*++ @doc EXTERNAL @func void | SmbLiteUnload | Free all the allocated resources, etc. @parm IN PDRIVER_OBJECT | DrvObj | Points to the driver object. @rvalue None. --*/ VOID EXTERNAL SmbLiteUnload( IN PDRIVER_OBJECT DrvObj ) { PROCNAME("SmbLiteUnload") PAGED_CODE(); ENTER(1, ("(DrvObj=%p)\n", DrvObj)); ASSERT(DrvObj->DeviceObject == NULL); UNREFERENCED_PARAMETER(DrvObj); EXIT(1, ("!\n")); return; } //SmbLiteUnload /*++ @doc EXTERNAL @func NTSTATUS | SmbLiteCreateClose | Process the create and close IRPs sent to this device. @parm IN PDEVICE_OBJECT | DevObj | Points to the device object. @parm IN PIRP | Irp | Points to an I/O Request Packet. @rvalue SUCCESS | Returns STATUS_SUCCESS @rvalue FAILURE | Returns NT status code --*/ NTSTATUS EXTERNAL SmbLiteCreateClose( IN PDEVICE_OBJECT DevObj, IN PIRP Irp ) { PROCNAME("SmbLiteCreateClose") NTSTATUS status; PSMBLITE_DEVEXT devext; PIO_STACK_LOCATION irpsp; PAGED_CODE (); devext = DevObj->DeviceExtension; irpsp = IoGetCurrentIrpStackLocation(Irp); ENTER(1, ("(DevObj=%p,Irp=%p,IrpStack=%p,Major=%s)\n", DevObj, Irp, irpsp, LookupName(irpsp->MajorFunction, MajorFnNames))); if (irpsp->MajorFunction == IRP_MJ_CREATE) { status = IoAcquireRemoveLock(&devext->RemoveLock, irpsp->FileObject); } else { ASSERT(irpsp->MajorFunction == IRP_MJ_CLOSE); IoReleaseRemoveLock(&devext->RemoveLock, irpsp->FileObject); } Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); EXIT(1, ("=%x\n", status)); return status; } //SmbLiteCreateClose /*++ @doc INTERNAL @func NTSTATUS | HookPowerStateCallback | Hook system power state callback to monitor if AC power is plugged in or not. @parm IN PSMBLITE_DEVEXT | devext | Points to the device extension. @rvalue SUCCESS | Returns STATUS_SUCCESS @rvalue FAILURE | Returns NT status code --*/ NTSTATUS INTERNAL HookPowerStateCallback( IN PSMBLITE_DEVEXT devext ) { PROCNAME("HookPowerStateCallback") NTSTATUS status; UNICODE_STRING CallbackName; OBJECT_ATTRIBUTES ObjAttrib; PCALLBACK_OBJECT PowerStateCallbackObj; PAGED_CODE(); ENTER(2, ("(devext=%p)\n", devext)); RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); InitializeObjectAttributes(&ObjAttrib, &CallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); status = ExCreateCallback(&PowerStateCallbackObj, &ObjAttrib, FALSE, TRUE); if (NT_SUCCESS(status)) { devext->hPowerStateCallback = ExRegisterCallback( PowerStateCallbackObj, PowerStateCallbackProc, devext); if (devext->hPowerStateCallback == NULL) { ERRPRINT(("failed to register battery power callback function.\n")); status = STATUS_UNSUCCESSFUL; } ObDereferenceObject(PowerStateCallbackObj); } else { ERRPRINT(("failed to create battery power callback object (status=%x).\n", status)); } EXIT(2, ("=%x\n", status)); return status; } //HookPowerStateCallback /*++ @doc INTERNAL @func VOID | PowerStateCallbackProc | Power state callback. @parm IN PVOID | CallbackContext | Callback context. @parm IN PVOID | Arg1 | Action. @parm IN PVOID | Arg2 | Value. @rvalue None. --*/ VOID PowerStateCallbackProc( IN PVOID CallbackContext, IN PVOID Arg1, IN PVOID Arg2 ) { PROCNAME("PowerStateCallback") ENTER(2, ("(Context=%p,Arg1=%p,Arg2=%p)\n", CallbackContext, Arg1, Arg2)); // // This callback must be non-pageable because it could be called at // DISPATCH level. // if ((ULONG)Arg1 == PO_CB_AC_STATUS) { PSMBLITE_DEVEXT devext = (PSMBLITE_DEVEXT)CallbackContext; ULONG dwfOnAC = (Arg2 == 0)? 0: SMBLITEF_SYSTEM_ON_AC; DBGPRINT(1, ("System is on %s, previous state is %s.\n", dwfOnAC? "AC": "DC", (devext->dwfSmbLite & SMBLITEF_SYSTEM_ON_AC)? "AC": "DC")); if ((devext->dwfSmbLite & SMBLITEF_SYSTEM_ON_AC)^dwfOnAC) { NTSTATUS status; // // AC/DC status has changed. // devext->dwfSmbLite &= ~SMBLITEF_SYSTEM_ON_AC; devext->dwfSmbLite |= dwfOnAC; status = SetBackLightBrightness(devext, &devext->BackLightBrightness, FALSE); if (!NT_SUCCESS(status)) { WARNPRINT(("failed to set %s backlight brightness (status=%x).\n", dwfOnAC? "AC": "DC", status)); } } } EXIT(2, ("!\n")); return; } //PowerStateCallbackProc