windows-nt/Source/XPSP1/NT/drivers/wdm/input/tabletpc/smblite/smblite.c
2020-09-26 16:20:57 +08:00

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