540 lines
17 KiB
C
540 lines
17 KiB
C
/*++
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
ioctl.c
|
|
|
|
Abstract: Contains routines to support ioctl queries for the SMB Back Light
|
|
device.
|
|
|
|
Environment:
|
|
Kernel mode
|
|
|
|
Author:
|
|
Michael Tsang (MikeTs) 20-Nov-2000
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SmbLiteIoctl)
|
|
#pragma alloc_text(PAGE, GetBackLightBrightness)
|
|
#pragma alloc_text(PAGE, RegQueryDeviceParam)
|
|
#endif
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func NTSTATUS | SmbLiteIoctl |
|
|
Process the Device Control IRPs sent to this device.
|
|
|
|
@parm IN PDRIVER_OBJECT | DevObj | Points to the driver 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
|
|
SmbLiteIoctl(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("SmbLiteIoctl")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
PSMBLITE_DEVEXT devext;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(1, ("(DevObj=%p,Irp=%p,IrpSp=%p,Ioctl=%s)\n",
|
|
DevObj, Irp, irpsp,
|
|
LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
|
|
IoctlNames)));
|
|
|
|
devext = DevObj->DeviceExtension;
|
|
status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
BOOLEAN fNeedCompletion = TRUE;
|
|
|
|
ASSERT(devext->dwfSmbLite & SMBLITEF_DEVICE_STARTED);
|
|
Irp->IoStatus.Information = 0;
|
|
switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_SMBLITE_GETBRIGHTNESS:
|
|
if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SMBLITE_BRIGHTNESS))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
WARNPRINT(("GetBrightness buffer too small (len=%d,required=%d).\n",
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength,
|
|
sizeof(SMBLITE_BRIGHTNESS)));
|
|
}
|
|
else
|
|
{
|
|
PSMBLITE_BRIGHTNESS Brightness = Irp->UserBuffer;
|
|
|
|
try
|
|
{
|
|
ProbeForWrite(Brightness,
|
|
sizeof(*Brightness),
|
|
sizeof(UCHAR));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
WARNPRINT(("Invalid GetBrightness buffer (status=%x,Buff=%p).\n",
|
|
status, Brightness));
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = GetBackLightBrightness(devext, Brightness);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
Irp->IoStatus.Information = sizeof(*Brightness);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IOCTL_SMBLITE_SETBRIGHTNESS:
|
|
if (irpsp->Parameters.DeviceIoControl.InputBufferLength !=
|
|
sizeof(SMBLITE_SETBRIGHTNESS))
|
|
{
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
WARNPRINT(("SetBrightness buffer length mismatch (len=%d,required=%d).\n",
|
|
irpsp->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof(SMBLITE_SETBRIGHTNESS)));
|
|
}
|
|
else
|
|
{
|
|
PSMBLITE_SETBRIGHTNESS SetBrightness = (PSMBLITE_SETBRIGHTNESS)
|
|
irpsp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
try
|
|
{
|
|
ProbeForRead(SetBrightness,
|
|
sizeof(*SetBrightness),
|
|
sizeof(UCHAR));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
WARNPRINT(("Invalid SetBrightness buffer (status=%x,Buff=%p).\n",
|
|
status, SetBrightness));
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = SetBackLightBrightness(
|
|
devext,
|
|
&SetBrightness->Brightness,
|
|
SetBrightness->fSaveSettings);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#ifdef SYSACC
|
|
case IOCTL_SYSACC_MEM_REQUEST:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case IOCTL_SYSACC_IO_REQUEST:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case IOCTL_SYSACC_PCICFG_REQUEST:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case IOCTL_SYSACC_SMBUS_REQUEST:
|
|
if ((irpsp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SMB_REQUEST)) ||
|
|
(irpsp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SMB_REQUEST)))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
WARNPRINT(("SMBusRequest buffer too small (len=%d,required=%d).\n",
|
|
irpsp->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof(SMB_REQUEST)));
|
|
}
|
|
else
|
|
{
|
|
PSMB_REQUEST SmbReqIn = (PSMB_REQUEST)
|
|
Irp->AssociatedIrp.SystemBuffer;
|
|
PSMB_REQUEST SmbReqOut = (PSMB_REQUEST)
|
|
Irp->UserBuffer;
|
|
|
|
try
|
|
{
|
|
ProbeForWrite(SmbReqOut,
|
|
sizeof(*SmbReqOut),
|
|
sizeof(UCHAR));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
WARNPRINT(("Invalid SMBRequest buffer (status=%x,Buff=%p).\n",
|
|
status, SmbReqOut));
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = SMBRequest(devext, SmbReqIn);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
RtlCopyMemory(SmbReqOut,
|
|
SmbReqIn,
|
|
sizeof(*SmbReqOut));
|
|
Irp->IoStatus.Information = sizeof(*SmbReqOut);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
WARNPRINT(("unsupported ioctl code (ioctl=%s)\n",
|
|
LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
|
|
IoctlNames)));
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
IoReleaseRemoveLock(&devext->RemoveLock, Irp);
|
|
}
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
EXIT(1, ("=%x\n", status));
|
|
return status;
|
|
} //SmbLiteIoctl
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func NTSTATUS | GetBackLightBrightness |
|
|
Query the Backlight brightness via the SMBus driver.
|
|
|
|
@parm IN PSMBLITE_DEVEXT | devext | Points to the device extension.
|
|
@parm OUT PSMBLITE_BRIGHTNESS | Brightness | To hold the brightness value.
|
|
|
|
@rvalue Always returns STATUS_SUCCESS
|
|
--*/
|
|
|
|
NTSTATUS INTERNAL
|
|
GetBackLightBrightness(
|
|
IN PSMBLITE_DEVEXT devext,
|
|
OUT PSMBLITE_BRIGHTNESS Brightness
|
|
)
|
|
{
|
|
PROCNAME("GetBackLightBrightness")
|
|
|
|
PAGED_CODE();
|
|
ENTER(2, ("(devext=%p,Brightness=%p)\n", devext, Brightness));
|
|
|
|
*Brightness = devext->BackLightBrightness;
|
|
|
|
EXIT(2, ("=%x (ACValue=%d,DCValue=%d)\n",
|
|
STATUS_SUCCESS, Brightness->bACValue, Brightness->bDCValue));
|
|
return STATUS_SUCCESS;
|
|
} //GetBackLightBrightness
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func NTSTATUS | SetBackLightBrightness |
|
|
Set the Backlight brightness via the SMBus driver.
|
|
|
|
@parm IN PSMBLITE_DEVEXT | devext | Points to the device extension.
|
|
@parm IN PSMBLITE_BRIGHTNESS | Brightness | The backlight brightness
|
|
values.
|
|
@parm IN BOOL | fSaveSettings | TRUE if need to save setting in the
|
|
registry.
|
|
|
|
@rvalue SUCCESS | returns STATUS_SUCCESS
|
|
@rvalue FAILURE | returns NT status code
|
|
--*/
|
|
|
|
NTSTATUS INTERNAL
|
|
SetBackLightBrightness(
|
|
IN PSMBLITE_DEVEXT devext,
|
|
IN PSMBLITE_BRIGHTNESS Brightness,
|
|
IN BOOLEAN fSaveSettings
|
|
)
|
|
{
|
|
PROCNAME("SetBackLightBrightness")
|
|
NTSTATUS status;
|
|
SMB_REQUEST SmbReq;
|
|
UCHAR bBrightness;
|
|
|
|
ENTER(2, ("(devext=%p,Brightness=%p,fSave=%x,ACValue=%d,DCValue=%d)\n",
|
|
devext, Brightness, fSaveSettings, Brightness->bACValue,
|
|
Brightness->bDCValue));
|
|
|
|
//
|
|
// Note: this routine must not be pageable because it could be called
|
|
// by PowerStateCallbackProc which could be called at DPC.
|
|
//
|
|
bBrightness = (devext->dwfSmbLite & SMBLITEF_SYSTEM_ON_AC)?
|
|
Brightness->bACValue: Brightness->bDCValue;
|
|
DBGPRINT(1, ("Set Brightness level=%d (%s).\n",
|
|
bBrightness,
|
|
(devext->dwfSmbLite & SMBLITEF_SYSTEM_ON_AC)? "AC": "DC"));
|
|
SmbReq.Protocol = SMB_WRITE_BYTE;
|
|
SmbReq.Address = SMBADDR_BACKLIGHT;
|
|
SmbReq.Command = SMBCMD_BACKLIGHT_NORMAL;
|
|
SmbReq.Data[0] = (UCHAR)(bBrightness << 2);
|
|
status = SMBRequest(devext, &SmbReq);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
devext->BackLightBrightness = *Brightness;
|
|
if (fSaveSettings)
|
|
{
|
|
RegSetDeviceParam(devext->PDO,
|
|
gcwstrACBrightness,
|
|
&Brightness->bACValue,
|
|
sizeof(Brightness->bACValue));
|
|
RegSetDeviceParam(devext->PDO,
|
|
gcwstrDCBrightness,
|
|
&Brightness->bDCValue,
|
|
sizeof(Brightness->bDCValue));
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //SetBackLightBrightness
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func NTSTATUS | SMBRequest |
|
|
Make a request to the SMBus driver.
|
|
|
|
@parm IN PSMBLITE_DEVEXT | devext | Points to the device extension.
|
|
@parm IN OUT PSMB_REQUEST | SmbReq | Points to the SMB request.
|
|
|
|
@rvalue SUCCESS | returns STATUS_SUCCESS
|
|
@rvalue FAILURE | returns NT status code
|
|
--*/
|
|
|
|
NTSTATUS INTERNAL
|
|
SMBRequest(
|
|
IN PSMBLITE_DEVEXT devext,
|
|
IN OUT PSMB_REQUEST SmbReq
|
|
)
|
|
{
|
|
PROCNAME("SMBRequest")
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
ENTER(2, ("(devext=%p,Req=%p,Protocol=%s,Addr=%x,Cmd=%x,Data0=%x,Data1=%x)\n",
|
|
devext, SmbReq, LookupName(SmbReq->Protocol, ProtocolNames),
|
|
SmbReq->Address, SmbReq->Command, SmbReq->Data[0],
|
|
SmbReq->Data[1]));
|
|
|
|
//
|
|
// Note: this routine must not be pageable because it could be called
|
|
// by SetBackLightBrightness and then PowerStateCallbackProc which could
|
|
// be called at DPC.
|
|
//
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
irp = IoBuildDeviceIoControlRequest(SMB_BUS_REQUEST,
|
|
devext->LowerDevice,
|
|
SmbReq,
|
|
sizeof(SMB_REQUEST),
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&iosb);
|
|
if (irp != NULL)
|
|
{
|
|
status = IoCallDriver(devext->LowerDevice, irp);
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
status = iosb.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
ERRPRINT(("failed SMB request ioctl (status=%x).\n", status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed to build smb request ioctl request.\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //SMBRequest
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func NTSTATUS | RegQueryDeviceParam | Query the registry for a device
|
|
parameter.
|
|
|
|
@parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
|
|
@parm IN PCWSTR | pwstrParamName | Points to the param name string.
|
|
@parm OUT PVOID | pbBuff | Points to the buffer to hold the result.
|
|
@parm IN ULONG | dwcbLen | Specifies the length of the buffer.
|
|
|
|
@rvalue SUCCESS | Returns STATUS_SUCCESS
|
|
@rvalue FAILURE | Returns NT status code
|
|
--*/
|
|
|
|
NTSTATUS INTERNAL
|
|
RegQueryDeviceParam(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PCWSTR pwstrParamName,
|
|
OUT PVOID pbBuff,
|
|
IN ULONG dwcbLen
|
|
)
|
|
{
|
|
PROCNAME("RegQueryDeviceParam")
|
|
NTSTATUS status;
|
|
ULONG dwSize;
|
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
|
|
|
PAGED_CODE();
|
|
ENTER(2, ("(DevObj=%p,ParamName=%S,pbBuff=%p,Len=%d)\n",
|
|
DevObj, pwstrParamName, pbBuff, dwcbLen));
|
|
|
|
dwSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwcbLen;
|
|
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
dwSize,
|
|
SMBLITE_POOLTAG);
|
|
if (ValueInfo != NULL)
|
|
{
|
|
HANDLE hkey;
|
|
|
|
status = IoOpenDeviceRegistryKey(DevObj,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ,
|
|
&hkey);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
UNICODE_STRING ucKeyName;
|
|
|
|
RtlInitUnicodeString(&ucKeyName, pwstrParamName);
|
|
status = ZwQueryValueKey(hkey,
|
|
&ucKeyName,
|
|
KeyValuePartialInformation,
|
|
ValueInfo,
|
|
dwSize,
|
|
&dwSize);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
ASSERT(ValueInfo->DataLength == dwcbLen);
|
|
RtlCopyMemory(pbBuff, ValueInfo->Data, dwcbLen);
|
|
}
|
|
else
|
|
{
|
|
WARNPRINT(("failed to read parameter %S (status=%x)\n",
|
|
pwstrParamName, status));
|
|
}
|
|
|
|
ZwClose(hkey);
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed to open device registry key (status=%x)\n",
|
|
status));
|
|
}
|
|
|
|
ExFreePool(ValueInfo);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ERRPRINT(("failed to allocate registry value buffer (size=%d)\n",
|
|
dwSize));
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //RegQueryDeviceParam
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func NTSTATUS | RegSetDeviceParam | Set a device parameter into the
|
|
registry.
|
|
|
|
@parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
|
|
@parm IN PCWSTR | pwstrParamName | Points to the param name string.
|
|
@parm IN PVOID | pbBuff | Points to the buffer containing data.
|
|
@parm IN ULONG | dwcbLen | Specifies the length of the buffer.
|
|
|
|
@rvalue SUCCESS | Returns STATUS_SUCCESS
|
|
@rvalue FAILURE | Returns NT status code
|
|
--*/
|
|
|
|
NTSTATUS INTERNAL
|
|
RegSetDeviceParam(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PCWSTR pwstrParamName,
|
|
IN PVOID pbBuff,
|
|
IN ULONG dwcbLen
|
|
)
|
|
{
|
|
PROCNAME("RegSetDeviceParam")
|
|
NTSTATUS status;
|
|
HANDLE hkey;
|
|
|
|
ENTER(2, ("(DevObj=%p,ParamName=%S,pbBuff=%p,Len=%d)\n",
|
|
DevObj, pwstrParamName, pbBuff, dwcbLen));
|
|
|
|
//
|
|
// Note: this routine must not be pageable because it could be called
|
|
// by SetBackLightBrightness and then PowerStateCallbackProc which could
|
|
// be called at DPC.
|
|
//
|
|
status = IoOpenDeviceRegistryKey(DevObj,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_WRITE,
|
|
&hkey);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
UNICODE_STRING ucKeyName;
|
|
|
|
RtlInitUnicodeString(&ucKeyName, pwstrParamName);
|
|
status = ZwSetValueKey(hkey,
|
|
&ucKeyName,
|
|
0,
|
|
REG_BINARY,
|
|
pbBuff,
|
|
dwcbLen);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
WARNPRINT(("failed to write device parameter %S (status=%x)\n",
|
|
pwstrParamName, status));
|
|
}
|
|
|
|
ZwClose(hkey);
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed to open device registry key (status=%x)\n",
|
|
status));
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //RegSetDeviceParam
|