487 lines
14 KiB
C
487 lines
14 KiB
C
/*++
|
|
|
|
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
|