Rapidly Turn Off and On Monitor by Driver

Hi NTDEV Community

Just for your information, the following question/issue is mainly just for fun or sparetime.
I simply want to turn off and on the backlight of my monitor since I was planning to (mis)use the large glowing area as a small software controlled LED strobe light.
As the built in backlight isn’t made of a fluorescent light tube but rather a LED array (if referring to my notebook stickers), judged on the hardware my notebook should theoretically able to support quite fast turn off and turn on cycles.
Remember that LEDs can be pulsed up to MHz…

Obviously, for this little project I would’t need to run my display at MHz frequencies, however, I would appreciate to control the display on a say, 20ms granularity, which would be just little above the thread switching time.

I ended up trying it by leveraging a device driver since I couldn’t find any suitable high level API that lets me just turn off and turn on the backlight:
I tried to scrutinize the working principle of the Windows power settings and learned that I can alter the screen brightness within a short timespan but I couldn’t make the screen go off, entirely.
After further research, I found a small program called “nircmd” which finally let me turn off my screen. I tracked then down the used API command “SendMessageA(INVALID_HANDLE_VALUE, 0x112, 0xF170, 2)” until this command vanished in the deep, undocumented darkness of win32k.sys.
There were two major issues with this command:

1.) The transition of turning off the screen was incredibly long. (100ms?)
2.) I did’t find a complementary API letting me turn on the screen again.

Next, I developed a small driver which hooks the whole IRP_MJ_XXX array of a arbitrary driver. I hooked the dispatch table of several driver objects including \acpi, \nvlddmkm, \BasicRender, \monitor, \dxgkrnl and so on, all the time looking after a particular IRP being sent clearly corresponding with the turn off command issued.
I even wrote an additional API which let me send a keyboard turn-on-capslock-LED IOCTL to i8042prt.sys while at DISPATCH_LEVEL which enabled me to take up to 10ms exact time measurements. I used my smart phone to measure the time the “turn off!”-command was received by my patch driver until the screen actually went black.
Interestingly, as long as I didn’t hook nvlddmkm.sys, the screen went black way before the keyboard LED turned on! (1s NEGATIVE! delay)
When I hooked nvlddmkm.sys the delay between the screen beginning to darken and my capslock LED turning on was about 60ms.

By provoking a precisely timed BSOD I was able to seemingly get the missing piece of the puzzle:

ffffd00107708578 fffff8020e20cab8 : 0000000000000050 fffffffffffffffe 0000000000000001 ffffd001077087d0 : nt!KeBugCheckEx
ffffd00107708580 fffff8020e0e8e78 : 0000000000000001 ffffe0007afe8900 ffffd001077087d0 ffffe0007932e000 : nt! ?? ::FNODOBFM::string'+0x29408 ffffd00107708620 fffff8020e1dd42f : 00000000c0000002 ffffffffff676980 ffffe00079370000 ffffd001077087d0 : nt!MmAccessFault+0x758 ffffd001077087d0 fffff8005e4014b5 : fffff8005e402070 0000000000000004 0000000000000065 0000000000000001 : nt!KiPageFault+0x12f ffffd00107708960 fffff960001edb9d : ffffe0007afb6910 ffffe0007dc8acc0 0000000000000000 ffffe00079247470 : IRP_HookTst+0x14b5 ffffd001077089d0 fffff96000265d6a : fffff901400b1be0 0000000000000000 fffff901400fb2a0 00000000c0000001 : win32k!GreDeviceIoControlEx+0xd9 ffffd00107708a70 fffff960001d6689 : fffff90144ee3010 0000000000000004 0000000000000001 0000000000000000 : win32k!DrvSetMonitorPowerState+0xfe ffffd00107708ad0 fffff960001d6b25 : 0000000000000000 0000000000000001 ffffe0000000003c fffff90144ee3010 : win32k!PowerOffMonitor+0xe1 ffffd00107708b10 fffff960001d7879 : ffffe0007fce56b0 0000000300000100 000000000000001f fffff9600023b8fc : win32k!xxxUserPowerEventCalloutWorker+0x211 ffffd00107708bb0 fffff96000172f74 : ffffe000770ac080 0000000000000000 0000000000000000 0000000000000000 : win32k!xxxUserPowerCalloutWorker+0x89 ffffd00107708c10 fffff8020e1de9b3 : ffffe000770ac080 0000000000000002 0000000000000020 ffffd00107708c40 : win32k!NtUserCallNoParam+0x44 ffffd00107708c40 00007ffaa92a161a : 00007ffaa92a17f3 0000000000000004 0000000000000000 0000000000000000 : nt!KiSystemServiceCopyEnd+0x13 000000bbf26bfc38 00007ffaa92a17f3 : 0000000000000004 0000000000000000 0000000000000000 0000000000000004 : winsrv!NtUserCallNoParam+0xa \<--here, my SendMessageA command vanished! 000000bbf26bfc40 00007ffaabf54411 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : winsrv!NotificationThread+0x1bc 000000bbf26bff40 0000000000000000 : 0000000000000000 0000000000000000 0000000000000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x25

Since I exactly knew the IOCTL requirements nvlddmkm had at this point, I sent the IOCTL “0x23200F” to the first device object obtained from nvlddmkm->DeviceObject using the following code:

PUCHAR pPuffer = ExAllocatePool(NonPagedPool, 8);
pPuffer[0] = 0x4;
PIRP pIrp = IoBuildDeviceIoControlRequest(0x23200F, pPhysicalDrive, pPuffer, 4, NULL, 0, TRUE, NULL, &ioStatusBlock);
if (!pIrp){
DbgPrint(“could not allocate irp”);
return STATUS_NO_MEMORY;
}
DbgPrint(“0x%lX”, IofCallDriver(pPhysicalDrive, pIrp));

After calling IofCallDriver the screen went black as expected. Writing 0x1 to pPuffer turned the screen back on.
Unfortunately, I saw in no time that the screen control was extremely slow.
The same was true if I issued the request to monitor.sys. It also worked but it was still insanely slow so no chance to construct a strobe light from screen.

Since I also intercepted IRP_MJ_POWER IRPs during my research I leveraged PoRequestPowerIrp to send a power IRP to monitor.sys which led to a WDF_VIOLATION BSOD. An issue to nvlddmkm using the same technique returned me a 0xC0000010, INVALID_DEVICE_REQUEST.

Finally, I build a IRP_MJ_INTERNAL_DEVICE_CONTROL IRP, overwrote the major and minor function codes with IRP_MJ_POWER as well as IRP_MN_SET_POWER and crafted the returned IRP so it looked to the monitor.sys driver like a power IRP. I planned to circumvent the power manager as well as the KMDF by doing so.
Unfortunately, my IRP seemed to look a little too much like a real power request, so it kept being processed by the power manager.
That again bluescreened my computer with a WDF_VIOLATION message.

So you can see, I tried my best and researched a lot; however, I didn’t succeed in rapidly controlling my notebook display’s backlight.

Now onto my questions:

  • What other possiblities do you know of (rapidly) controlling the screen backlight?

  • Should I reverse monitor.sys and try to call internal APIs of monitor.sys, thus directly controlling the backlight?

  • Should I try to use WRITE_PORT_UCHAR() to directly control the internal display port?

  • Are there drivers other than monitor.sys or the proprietary nvidia driver I should issue IOCTLs to?

  • Why does it take so long to switch the monitor of if directly called with a IOCTL as mentioned above??

  • Do you know a component responsible (lowest level, Bus driver or port driver or whatever) which directly controls my hardware?

  • Am I even suggested to completely ignore the backlight and just to leverage documented Win32 graphic functions to black and white paint a window area as large as my desktop?

Some more information: As always with me, I do neither bother how undocumented your recommendations are, nor if a particular dirty solution only will work with my current OS with the exactly defined build number.
Preferred OS would be Windows 8.1, x64, Build 9600
Hardware is a ASUS G60J notebook with 4GB RAM, a LED backlight and a NVIDIA GTX260M graphics solution.

I do not bother either if your solution generates large lags, high CPU loads, or hangs as long as the screen is flashing, because everything like these problems can be solved at a later time. :wink:

If you don’t see a particular rapid solution just tell everything, including slow solutions. This helps me to better understand the internals and maybe com up with a rapid solution on my own.
And if nothing helps I will go for writing real mode boot code turning the screen off and on, since after all, there MUST be some command(s) controlling the backlight…on Windows 8.1 it’s just too good hidden from me…

Any help really appreciated, thanks in advance!

Best Regards

Microwave

P.S. I have also analyzed what happens if I alter the screen brightness.
There are IOCTLs to monitor.sys/nvlddmkm.sys sent ranging from 0x0 to 0x64 according to 0…100% brightness setting. So no need to send 0x0, as 0x0 already is being sent but doens’t mean “screen off”.

Just redraw the whole screen black and white, and sync it with the vertical scan.

xxxxx@gmail.com wrote:

Just for your information, the following question/issue is mainly just for fun or sparetime.
I simply want to turn off and on the backlight of my monitor since I was planning to (mis)use the large glowing area as a small software controlled LED strobe light.
As the built in backlight isn’t made of a fluorescent light tube but rather a LED array (if referring to my notebook stickers), judged on the hardware my notebook should theoretically able to support quite fast turn off and turn on cycles.
Remember that LEDs can be pulsed up to MHz…

Yes, but the hardware design for your laptop did not require millisecond
on/off response times, but did require human factors engineering. It is
entirely possible that the backlight circuit includes conditioning
circuitry with extra capacitors that provide buffering and ramping to
make the transitions a little less jarring to the eye.

Plus, this function is often managed by the BIOS, so there may be ACPI
calls in there, which add even more time.

I ended up trying it by leveraging a device driver since I couldn’t find any suitable high level API that lets me just turn off and turn on the backlight:

Well, except for the one you found, which IS documented.

After further research, I found a small program called “nircmd” which finally let me turn off my screen. I tracked then down the used API command “SendMessageA(INVALID_HANDLE_VALUE, 0x112, 0xF170, 2)” until this command vanished in the deep, undocumented darkness of win32k.sys.

Did you look any of this up? 0x112 is WM_SYSCOMMAND. 0xF170 is
SC_MONITORPOWER. The window handle is probably the desktop window.
This combination is documented in MSDN.

There were two major issues with this command:

1.) The transition of turning off the screen was incredibly long. (100ms?)
2.) I did’t find a complementary API letting me turn on the screen again.

You didn’t really do much investigating, then. The documentation will
tell you this.

Since I exactly knew the IOCTL requirements nvlddmkm had at this point, I sent the IOCTL “0x23200F” to the first device object obtained from nvlddmkm->DeviceObject using the following code:

That’s a custom video ioctl. 0x230000 is the range for IOCTL_VIDEO, but
the function code is 0x803, which is in the custom range. nvlddmkm is
Nvidia’s custom WDDM driver.

After calling IofCallDriver the screen went black as expected. Writing 0x1 to pPuffer turned the screen back on.
Unfortunately, I saw in no time that the screen control was extremely slow.
The same was true if I issued the request to monitor.sys. It also worked but it was still insanely slow so no chance to construct a strobe light from screen.

Right. You’re going to find that’s a hardware limitation, not a
software limitation.

So you can see, I tried my best and researched a lot; however, I didn’t succeed in rapidly controlling my notebook display’s backlight.

Right, and you won’t be able to.

Now onto my questions:

  • What other possiblities do you know of (rapidly) controlling the screen backlight?

There are none. Your hardware does not have this ability.

  • Should I reverse monitor.sys and try to call internal APIs of monitor.sys, thus directly controlling the backlight?

It’s not in monitor.sys. There is no standard hardware mechanism for
controlling the backlight. Every piece of hardware does it in a
different way, so the function has to be handled by the graphics driver.

  • Should I try to use WRITE_PORT_UCHAR() to directly control the internal display port?

No. It’s almost certainly not an I/O port anyway.

  • Why does it take so long to switch the monitor of if directly called with a IOCTL as mentioned above??

Because it doesn’t HAVE to be fast. That wasn’t a design requirement.

  • Do you know a component responsible (lowest level, Bus driver or port driver or whatever) which directly controls my hardware?

Yes, it’s your Nvidia GPU.

And if nothing helps I will go for writing real mode boot code turning the screen off and on, since after all, there MUST be some command(s) controlling the backlight…on Windows 8.1 it’s just too good hidden from me…

You ARE controlling the backlight. Nothing you could do from real mode
will control it any faster. The hardware simpy will not switch that
fast, because it doesn’t have to. The design requirement was to make
the switching smooth.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Have you considered just synthesizing some compressed video file with the
pattern of white/black that you want. The black would not be quite as dark
as with display illumination off, but video is a lot more portable across
systems.

Jan

xxxxx@gmail.com wrote:
>Just for your information, the following question/issue is mainly just
>for fun or sparetime.
> I simply want to turn off and on the backlight of my monitor since I
>was planning to (mis)use the large glowing area as a small software
>controlled LED strobe light.
> As the built in backlight isn’t made of a fluorescent light tube but
>rather a LED array (if referring to my notebook stickers), judged on the
>hardware my notebook should theoretically able to support quite fast
>turn off and turn on cycles.
> Remember that LEDs can be pulsed up to MHz…

Thank you for all your helpful replies!

I also think that I cannot go much further here since my hardware as Tim states just isn’t as fast because it don’t need to. There might be some delay added…

On another forum I was suggested to use a DOS and to easily try this in real mode.
I will do so and otherways I will try to leverage a special video for this.
Unfortunately, my black isn’t that proper. However, it would be more than nothing (and hopefully enough performant…

Best Regards

Microwave89

P.S. Actually, when I began of thinking of backlight control I dreamed of 1ms on time and like 50ms off time… :wink:

xxxxx@gmail.com wrote:

Thank you for all your helpful replies!

I also think that I cannot go much further here since my hardware as Tim states just isn’t as fast because it don’t need to. There might be some delay added…

On another forum I was suggested to use a DOS and to easily try this in real mode.

I hope you understand that, if our assumption is correct and the
hardware contains buffering for this, it wouldn’t matter if you used
magic pixie dust. Unless you grab your soldering iron and redesign the
hardware, this will never be possible. NEVER.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.