Bug 204077

Summary: EasyNoteMZ35, video module wrongly sends brightens up/down key to userspace
Product: Drivers Reporter: Kacper (cosiekvfj)
Component: Platform_x86Assignee: drivers_platform_x86 (drivers_platform_x86)
Status: RESOLVED CODE_FIX    
Severity: normal CC: jwrdegoede
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 5.1.16 Subsystem:
Regression: No Bisected commit-id:
Attachments: dmesg
evemu-record
lsmod
[PATCH] ACPI / video: Add new hw_brightness_change quirk, set it on PB Easynote MZ35

Description Kacper 2019-07-06 04:50:50 UTC
Reference: https://github.com/systemd/systemd/issues/12915

/sys/class/dmi/id/bios_date:07/11/2007
/sys/class/dmi/id/bios_vendor:Packard Bell                    
/sys/class/dmi/id/bios_version:V0.22                           
/sys/class/dmi/id/board_name:EasyNote MZ35
/sys/class/dmi/id/board_vendor:Packard Bell BV                 
/sys/class/dmi/id/board_version:D3B
/sys/class/dmi/id/chassis_type:10
/sys/class/dmi/id/chassis_vendor:Packard Bell BV                 
/sys/class/dmi/id/chassis_version:N/A                             
/sys/class/dmi/id/modalias:dmi:bvnPackardBell:bvrV0.22:bd07/11/2007:svnPackardBellBV:pnEasyNoteMZ35:pvr:rvnPackardBellBV:rnEasyNoteMZ35:rvrD3B:cvnPackardBellBV:ct10:cvrN/A:
/sys/class/dmi/id/product_name:EasyNote MZ35
/sys/class/dmi/id/sys_vendor:Packard Bell BV                 
/sys/class/dmi/id/uevent:MODALIAS=dmi:bvnPackardBell:bvrV0.22:bd07/11/2007:svnPackardBellBV:pnEasyNoteMZ35:pvr:rvnPackardBellBV:rnEasyNoteMZ35:rvrD3B:cvnPackardBellBV:ct10:cvrN/A:


lrwxrwxrwx 1 root root 0 2005-12-22  acpi_video0 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:05.0/backlight/acpi_video0

My laptop control brightness in hardware. So when I press brightness up key:
Brightness up key -> laptop raises brightness -> video module raises brightness up and sends brightness up key to userspace
Comment 1 Kacper 2019-07-06 04:52:32 UTC
Created attachment 283563 [details]
dmesg
Comment 2 Kacper 2019-07-06 04:54:07 UTC
Created attachment 283565 [details]
evemu-record

Only /dev/input/event3:	Video Bus seems to generate events. Keyboard don't send any event on brightness up/down key
Comment 3 Kacper 2019-07-06 04:57:35 UTC
Created attachment 283567 [details]
lsmod
Comment 4 Kacper 2019-07-06 05:22:27 UTC
After adding both "video.brightness_switch_enabled=0" and "video.report_key_events=1" to the kernel commandline brightness is changed only once but no event is send on video bus.

With just "video.brightness_switch_enabled=0" brightness is changed only one and brightness up/down events are send on video bus.
Comment 5 Kacper 2019-07-06 05:36:46 UTC
For both acpi_backlight=vendor and acpi_backlight=native there is nothing under /sys/class/backlight, brightness change only once and video bus sends brightness up/down key.
Comment 6 Hans de Goede 2019-07-11 11:11:23 UTC
Thank you for the bug-report.

I've tested that just calling backlight_force_update() and not sending any keypresses to userspace still triggers the brightness change OSD popup. At least with GNOME3 this works as expected.

The way I've tested this is by setting video.report_key_events=1 on a machine which uses the acpi_video0 backlight interface. This means no key-events are reported to userspace. Since userspace does not react and since video.brightness_switch_enabled is its default value of 1, this causes the kernel to change the brightness itself and then call backlight_force_update(), which does properly trigger the OSD. So it seems that the fix for your machine would be to make acpi_video_device_notify() call backlight_force_update() and not do anything else (on your machine).

I've prepared a patch for this, which I will attach here.

Please build a kernel with this patch (see your distros documentation) and let me know if this fixes things.

After booting the new kernel, please do:

cat /sys/module/video/parameters/hw_brightness_change

And verify it is "1", if it is not then the DMI match in the patch is somehow wrong.

If the DMI match is wrong (should not happen) please try to test the rest of the patch by passing video.hw_brightness_change=1 on the kernel commandline. Note you only need to do this if the DMI match does not work, please try without this first.

If "cat /sys/module/video/parameters/hw_brightness_change" returns "1" then you should be able to use the hotkeys to change the brightness, get a change of only 1 level/step and get the ODS (at least with GNOME3).
Comment 7 Hans de Goede 2019-07-11 11:23:40 UTC
Created attachment 283623 [details]
[PATCH] ACPI / video: Add new hw_brightness_change quirk, set it on PB Easynote MZ35
Comment 8 Hans de Goede 2019-07-11 11:27:18 UTC
When you can confirm this patch fixes things I will submit it upstream, is it ok if I add the unredacted version of:

Reported-and-tested-by: Kacper <cosiekvfj@redacted>

to the commit message when submitting it upstream?
Comment 9 Kacper 2019-07-12 08:01:06 UTC
> Please build a kernel with this patch (see your distros documentation)

It was actually easier than I thought. I just downloaded repo for 5.1 kernel from my distro, edited PKGBUILD to add patch command after all the other patches, installed some deps and voilà. Tomorrow morning I had nice .pkg.tar.gz file waiting for me.


> cat /sys/module/video/parameters/hw_brightness_change

I will assume that you meant hw_changes_brightness. It is indeed 1.

> by passing video.hw_brightness_change=1 on the kernel commandline

It's easier to just "sudo tee /sys/module/video/parameters/hw_brightness_change"
You can change any parameter in "/sys/module/video/parameters/" that way while system is on. No reboot required. :)

> If "cat /sys/module/video/parameters/hw_brightness_change" returns "1" then
> you should be able to use the hotkeys to change the brightness, get a change
> of only 1 level/step and get the ODS (at least with GNOME3).

I can confirm that this patch allow me to change brightness by only 1 level/step. evemu-record don't show any events from "video bus" while changing brightness. backlight_force_update() is working differently than just sending events thru "video bus"?

I didn't test ODS.
(I just didn't install any userspace brightness changer because I already had 2, laptop itself and kernel module. Is there a easy way to check if backlight_force_update() is called?)

Also when I set hw_changes_brightness to 0 everything seems to work like before.  2 brightness steps per one brightness key and key events on "video bus"


> When you can confirm this patch fixes things I will submit it upstream, is it
> ok if I add the unredacted version of:

> Reported-and-tested-by: Kacper <cosiekvfj@redacted>

> to the commit message when submitting it upstream?

Yes. Please include my full name "Kacper Piwiński"
Comment 10 Kacper 2019-07-12 08:09:18 UTC
Do this kind of hardware workaround fixes really need to be that deep i kernel modules? I thought it would be just some quirk database higher up. :)

> Some machines change the brightness themselves when a brightness hotkey
gets pressed, despite us telling them not to.

Do you also want to test different acpi_osi= kernel parameters?


> Subject: [PATCH] ACPI / video: Add new hw_brightness_change quirk, set it on…
> This commit adds a new hw_brightness_change quirk which makes…

But you actually named it hw_changes_brightness :)
Comment 11 Hans de Goede 2019-07-12 09:55:46 UTC
(In reply to Kacper from comment #9)
> > cat /sys/module/video/parameters/hw_brightness_change
> 
> I will assume that you meant hw_changes_brightness. It is indeed 1.

Yeah my bad somehow between writing the code and writing the commit message (and the bugzilla comment) I ended up changing the quirk name in my head.

> > Subject: [PATCH] ACPI / video: Add new hw_brightness_change quirk, set it
> on…
> > This commit adds a new hw_brightness_change quirk which makes…
> 
> But you actually named it hw_changes_brightness :)

Thank you for catching that, I've fixed this before submitting it upstream.

> It's easier to just "sudo tee
> /sys/module/video/parameters/hw_brightness_change"
> You can change any parameter in "/sys/module/video/parameters/" that way
> while system is on. No reboot required. :)

Right this parameter can also be changed runtime, that is not always the case, so I always tell people to put it on the kernel commandline.

> I can confirm that this patch allow me to change brightness by only 1
> level/step. evemu-record don't show any events from "video bus" while
> changing brightness. backlight_force_update() is working differently than
> just sending events thru "video bus"?

The "video bus" device behaves as a human input device (kbd/mouse) so it sends keypresses through a /dev/input/event# node. The backlight_force_update() call sends a udev change event from /sys/class/backlight/acpi_video0/uevent. 

Under GNOME3 /usr/libexec/gsd-power, which controls the display brightness listens to this (through libudev and udevd), and then activates the OSD on the change event.

> I didn't test ODS.
> (I just didn't install any userspace brightness changer because I already
> had 2, laptop itself and kernel module. Is there a easy way to check if
> backlight_force_update() is called?)

No not really, but since you're no longer seeing the keypresses I'm pretty sure that everything is working as it should, so that is fine.

> Also when I set hw_changes_brightness to 0 everything seems to work like
> before.  2 brightness steps per one brightness key and key events on "video
> bus"

Right, that is as expected, the default value is -1 which means auto / use DMI quirks, if you force it to 0 you get what you ask for :)

Note on the MZ35 you do not see the -1 since the dmi quirk overrides it to 1:

+static int video_hw_changes_brightness(
+       const struct dmi_system_id *d)
+{
+       if (hw_changes_brightness == -1)
+               hw_changes_brightness = 1;
+       return 0;
+}
+

If however you set it to 0 on the kernel commandline then the DMI quirk will not touch it and the same goes for runtime changes since the DMI quirk code runs only once during boot.

> > When you can confirm this patch fixes things I will submit it upstream, is
> it
> > ok if I add the unredacted version of:
> 
> > Reported-and-tested-by: Kacper <cosiekvfj@redacted>
> 
> > to the commit message when submitting it upstream?
> 
> Yes. Please include my full name "Kacper Piwiński"

Ok will do.

(In reply to Kacper from comment #10)
> Do this kind of hardware workaround fixes really need to be that deep i
> kernel modules? I thought it would be just some quirk database higher up. :)

Sometimes we can fix things with e.g. keymapping changes in systemd's hwdb, but in this case we need to change how the acpi_video_device_notify() function works, which we can only do at the kernel level.

> > Some machines change the brightness themselves when a brightness hotkey
> gets pressed, despite us telling them not to.
> 
> Do you also want to test different acpi_osi= kernel parameters?

No that is not necessary.
Comment 12 Kacper 2019-07-22 08:51:10 UTC
I have two more questions.

> * Some machines change the brightness themselves when a brightness
	 * hotkey gets pressed, despite us telling them not to.

Where do we tell them to not do that? :)


I wonder if It was possible to get the same behaviour by setting "brightness_switch_enabled" and "report_key_events" instead of creating another module parameter? :)


I will report if everything is correct when I will test 5.3 kernel :)
Comment 13 Hans de Goede 2019-07-25 15:56:11 UTC
(In reply to Kacper from comment #12)
> I have two more questions.
> 
> > * Some machines change the brightness themselves when a brightness
>        * hotkey gets pressed, despite us telling them not to.
> 
> Where do we tell them to not do that? :)

See acpi_video_bus_DOS and its callers in drivers/acpi/acpi_video.c 

> I wonder if It was possible to get the same behaviour by setting
> "brightness_switch_enabled" and "report_key_events" instead of creating
> another module parameter? :)

No that is not possible.
Comment 14 Kacper 2019-09-15 09:06:00 UTC
Everything seems to work ok. Now I can set any of my 8 levels of brightness.

As I understand, setting
"brightness_switch_enabled" to 0 and "report_key_events" to 1
won't produce the same behavior because it wouldn't call "backlight_force_update()" ?
Comment 15 Hans de Goede 2019-09-15 12:35:41 UTC
(In reply to Kacper from comment #14)
> Everything seems to work ok. Now I can set any of my 8 levels of brightness.

Good, I believe that this bug can be closed then.

> As I understand, setting
> "brightness_switch_enabled" to 0 and "report_key_events" to 1
> won't produce the same behavior because it wouldn't call
> "backlight_force_update()" ?

Right, so that would work, but you would not get the OSD (on screen display) notification about the brightness changing.
Comment 16 Kacper 2019-09-15 17:28:56 UTC
> > > * Some machines change the brightness themselves when a brightness
> > > * hotkey gets pressed, despite us telling them not to.
> >
> > Where do we tell them to not do that? :)
>
> See acpi_video_bus_DOS and its callers in drivers/acpi/acpi_video.c



static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0,
				  acpi_osi_is_win8() ? 1 : 0);
}`
Comment 17 Kacper 2019-09-15 17:31:01 UTC
But on my machine acpi_osi_is_win8() return false (I build simple module to test that) so actually we never tell the BIOS to not change brightness by itself.

Sorry for double comment. Missclick
Comment 18 Hans de Goede 2019-09-15 18:23:48 UTC
(In reply to Kacper from comment #17)
> But on my machine acpi_osi_is_win8() return false (I build simple module to
> test that) so actually we never tell the BIOS to not change brightness by
> itself.

Older BIOS-es are simply expected to not change the brightness by themselves without needing the lcd_flag to be 1. I guess it could be that your BIOS is
somehow somewhat in between the behavior expected from older BIOS-es vs that expected from newer BIOS-es.

If you want you can try dropping the acpi_osi_is_win8() check and always pass 1 for the lcd_flag value passed to acpi_video_bus_DOS() combined with adding
video.hw_changes_brightness=0 on the kernel commandline to disable my patch. I guess this might do the trick too.

But then we would need to have a DMI based quirk to override the lcd_flag value... So I do not think that would be any better.
Comment 19 Kacper 2019-09-16 18:37:47 UTC
(In reply to Hans de Goede)

First, thank you for your help.

I have build kernel with:

static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0, 1);
}

static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0, 0);
}

But there was no change in brightness key behavior. BIOS was still controlling the brightness keys.



Couple more points:


1.

 *	lcd_flag	:
 *		0.	The system BIOS should automatically control the brightness level
 *			of the LCD when the power changes from AC to DC
 *		1.	The system BIOS should NOT automatically control the brightness
 *			level of the LCD when the power changes from AC to DC.

This description of lcd_flag talk only about BIOS changing brighness when you plug your charger. But we where talking about it like it was controlling if BIOS should handle brightness keys.

2.

static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0,
				  acpi_osi_is_win8() ? 0 : 1);
}

As I understand this get called when the driver no longer use that hardware. Why we set lcd_flag to 1 then? If we don't control brightness keys then we should tell hardware to control it?

3.
So maybe it should look like 

static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0,
				  acpi_osi_is_win8() ? 1 : 0);
}

static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0, 0);
}

if we are worrying that setting it to 1 on non win8 hardware will expose some bugs. But that seems to me unlikely considering that we already was setting it to 1 on device stopping.

4.
So maybe it should always set it like this?

static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0, 1);
}

static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
{
	return acpi_video_bus_DOS(video, 0, 0);
}

regardless if machine is win8+. As I understand we always wants to control brightness keys ourselves. So we always should set lcd_flag to 1 and only with buggy hardware(like mine) we should let hardware to control those keys.

5.
Why are we not using bios_flag 3?

 *		3.	The system BIOS should not automatically switch (toggle) the
 *			active display output, but instead generate the display switch
 *			event notify code.

instead we set it to 0.

6.
typo:

		/*
		 * if the function of acpi_video_register is already called,
		 * don't register the acpi_vide_bus again and return no error.
		 */

acpi_vide_bus instead of acpi_video_bus

;)



Cheers, let me know if any of this makes any sense and if I could write some patches for it.
Comment 20 Hans de Goede 2019-10-10 13:07:37 UTC
(In reply to Kacper from comment #19)
> (In reply to Hans de Goede)
> 
> First, thank you for your help.
> 
> I have build kernel with:
> 
> static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0, 1);
> }
> 
> static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0, 0);
> }
> 
> But there was no change in brightness key behavior. BIOS was still
> controlling the brightness keys.

Right, so this shows that the quirk which my patch (which has been merged in the mean time) for this adds is really necessary.

> Couple more points:
> 
> 
> 1.
> 
>  *    lcd_flag        :
>  *            0.      The system BIOS should automatically control the
>  brightness level
>  *                    of the LCD when the power changes from AC to DC
>  *            1.      The system BIOS should NOT automatically control the
>  brightness
>  *                    level of the LCD when the power changes from AC to DC.
> 
> This description of lcd_flag talk only about BIOS changing brighness when
> you plug your charger. But we where talking about it like it was controlling
> if BIOS should handle brightness keys.

As the comment above acpi_video_bus_start_devices() explains this has changed with windows 8 and later, firmwares targetting win 8 and later will automatically adjust the brightness on hotkey presses unless the lcd_flag is set to 1.

> 2.
> 
> static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0,
>                                 acpi_osi_is_win8() ? 0 : 1);
> }
> 
> As I understand this get called when the driver no longer use that hardware.
> Why we set lcd_flag to 1 then? If we don't control brightness keys then we
> should tell hardware to control it?

Notice that we do set it to 0 for win8+ systems, we only set it to 1 for
older systems. We already did that before the changes were made to behave differently on win8+ systems:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=efaa14c7e981b

As for wht we pass 1 on older systems, that pre-dates git history it seems.

Also note that this code only runs though if someone does a "rmmod i915" and/or "rmmod video". Which normally never happens.

> 3.
> So maybe it should look like 
> 
> static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0,
>                                 acpi_osi_is_win8() ? 1 : 0);
> }
> 
> static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0, 0);
> }
> 
> if we are worrying that setting it to 1 on non win8 hardware will expose
> some bugs. But that seems to me unlikely considering that we already was
> setting it to 1 on device stopping.

Maybe, as said I do not know why the 1 on older systems is there and I see no reason to change this at this moment.

> 4.
> So maybe it should always set it like this?
> 
> static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0, 1);
> }
> 
> static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
> {
>       return acpi_video_bus_DOS(video, 0, 0);
> }
> 
> regardless if machine is win8+. As I understand we always wants to control
> brightness keys ourselves. So we always should set lcd_flag to 1 and only
> with buggy hardware(like mine) we should let hardware to control those keys.

A lot of this is magic which we have collected over the years as we learn how to make things work with each generation of hw. I'm pretty sure the changes you suggest will likely break some XP area hw. I believe this is a case of if it is not broken do not fix it. We simply do not have access to all hardware, esp. not to older hw which still has users out there. So unless there is a good reason to do so this is best left unchanged IMHO.

> 5.
> Why are we not using bios_flag 3?
> 
>  *            3.      The system BIOS should not automatically switch
>  (toggle) the
>  *                    active display output, but instead generate the display
>  switch
>  *                    event notify code.
> 
> instead we set it to 0.

I guess Windows has always set this to 0, so we do to and as I'm not aware of any issues with the BIOS changing the output underneath us I think out current behavior is fine,

> 
> 6.
> typo:
> 
>               /*
>                * if the function of acpi_video_register is already called,
>                * don't register the acpi_vide_bus again and return no error.
>                */
> 
> acpi_vide_bus instead of acpi_video_bus

Feel free to submit a patch upstream to fix this :)