Skip to content

Commit 849365e

Browse files
committed
Merge: Update drivers/platform/x86/panasonic-laptop.c
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6132 JIRA: https://issues.redhat.com/browse/RHEL-55365 Signed-off-by: David Arcari <darcari@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: Prarit Bhargava <prarit@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Rado Vrbovsky <rvrbovsk@redhat.com>
2 parents 6d489c0 + 2c5cbc9 commit 849365e

File tree

2 files changed

+154
-50
lines changed

2 files changed

+154
-50
lines changed

drivers/platform/x86/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,8 @@ config PANASONIC_LAPTOP
861861
tristate "Panasonic Laptop Extras"
862862
depends on INPUT && ACPI
863863
depends on BACKLIGHT_CLASS_DEVICE
864+
depends on ACPI_VIDEO=n || ACPI_VIDEO
865+
depends on SERIO_I8042 || SERIO_I8042 = n
864866
select INPUT_SPARSEKMAP
865867
help
866868
This driver adds support for access to backlight control and hotkeys

drivers/platform/x86/panasonic-laptop.c

Lines changed: 152 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,23 @@
119119
* - v0.1 start from toshiba_acpi driver written by John Belmonte
120120
*/
121121

122-
#include <linux/kernel.h>
123-
#include <linux/module.h>
124-
#include <linux/init.h>
125-
#include <linux/types.h>
122+
#include <linux/acpi.h>
126123
#include <linux/backlight.h>
124+
#include <linux/bits.h>
127125
#include <linux/ctype.h>
128-
#include <linux/seq_file.h>
129-
#include <linux/uaccess.h>
130-
#include <linux/slab.h>
131-
#include <linux/acpi.h>
126+
#include <linux/i8042.h>
127+
#include <linux/init.h>
132128
#include <linux/input.h>
133129
#include <linux/input/sparse-keymap.h>
130+
#include <linux/kernel.h>
131+
#include <linux/module.h>
134132
#include <linux/platform_device.h>
135-
133+
#include <linux/seq_file.h>
134+
#include <linux/serio.h>
135+
#include <linux/slab.h>
136+
#include <linux/types.h>
137+
#include <linux/uaccess.h>
138+
#include <acpi/video.h>
136139

137140
MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
138141
MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>");
@@ -222,6 +225,17 @@ static const struct key_entry panasonic_keymap[] = {
222225
{ KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
223226
{ KE_KEY, 9, { KEY_BATTERY } },
224227
{ KE_KEY, 10, { KEY_SUSPEND } },
228+
{ KE_KEY, 21, { KEY_MACRO1 } },
229+
{ KE_KEY, 22, { KEY_MACRO2 } },
230+
{ KE_KEY, 24, { KEY_MACRO3 } },
231+
{ KE_KEY, 25, { KEY_MACRO4 } },
232+
{ KE_KEY, 34, { KEY_MACRO5 } },
233+
{ KE_KEY, 35, { KEY_MACRO6 } },
234+
{ KE_KEY, 36, { KEY_MACRO7 } },
235+
{ KE_KEY, 37, { KEY_MACRO8 } },
236+
{ KE_KEY, 41, { KEY_MACRO9 } },
237+
{ KE_KEY, 42, { KEY_MACRO10 } },
238+
{ KE_KEY, 43, { KEY_MACRO11 } },
225239
{ KE_END, 0 }
226240
};
227241

@@ -241,6 +255,42 @@ struct pcc_acpi {
241255
struct platform_device *platform;
242256
};
243257

258+
/*
259+
* On some Panasonic models the volume up / down / mute keys send duplicate
260+
* keypress events over the PS/2 kbd interface, filter these out.
261+
*/
262+
static bool panasonic_i8042_filter(unsigned char data, unsigned char str,
263+
struct serio *port)
264+
{
265+
static bool extended;
266+
267+
if (str & I8042_STR_AUXDATA)
268+
return false;
269+
270+
if (data == 0xe0) {
271+
extended = true;
272+
return true;
273+
} else if (extended) {
274+
extended = false;
275+
276+
switch (data & 0x7f) {
277+
case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
278+
case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
279+
case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
280+
return true;
281+
default:
282+
/*
283+
* Report the previously filtered e0 before continuing
284+
* with the next non-filtered byte.
285+
*/
286+
serio_interrupt(port, 0xe0, 0);
287+
return false;
288+
}
289+
}
290+
291+
return false;
292+
}
293+
244294
/* method access functions */
245295
static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
246296
{
@@ -299,7 +349,8 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
299349
}
300350

301351
if (pcc->num_sifr < hkey->package.count) {
302-
pr_err("SQTY reports bad SINF length\n");
352+
pr_err("SQTY reports bad SINF length SQTY: %lu SINF-pkg-count: %u\n",
353+
pcc->num_sifr, hkey->package.count);
303354
status = AE_ERROR;
304355
goto end;
305356
}
@@ -470,7 +521,7 @@ static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr,
470521
if (!acpi_pcc_retrieve_biosdata(pcc))
471522
return -EIO;
472523

473-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
524+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
474525
}
475526

476527
static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
@@ -482,7 +533,7 @@ static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
482533
if (!acpi_pcc_retrieve_biosdata(pcc))
483534
return -EIO;
484535

485-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
536+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
486537
}
487538

488539
static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
@@ -494,7 +545,7 @@ static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
494545
if (!acpi_pcc_retrieve_biosdata(pcc))
495546
return -EIO;
496547

497-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
548+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]);
498549
}
499550

500551
static ssize_t mute_store(struct device *dev, struct device_attribute *attr,
@@ -524,7 +575,7 @@ static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr
524575
if (!acpi_pcc_retrieve_biosdata(pcc))
525576
return -EIO;
526577

527-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sticky_key);
578+
return sysfs_emit(buf, "%u\n", pcc->sticky_key);
528579
}
529580

530581
static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr,
@@ -566,7 +617,7 @@ static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr,
566617
result = -EIO;
567618
break;
568619
}
569-
return snprintf(buf, PAGE_SIZE, "%u\n", result);
620+
return sysfs_emit(buf, "%u\n", result);
570621
}
571622

572623
static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr,
@@ -625,7 +676,7 @@ static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *a
625676
if (!acpi_pcc_retrieve_biosdata(pcc))
626677
return -EIO;
627678

628-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
679+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
629680
}
630681

631682
static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr,
@@ -655,7 +706,7 @@ static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *a
655706
if (!acpi_pcc_retrieve_biosdata(pcc))
656707
return -EIO;
657708

658-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
709+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
659710
}
660711

661712
static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr,
@@ -685,7 +736,7 @@ static ssize_t current_brightness_show(struct device *dev, struct device_attribu
685736
if (!acpi_pcc_retrieve_biosdata(pcc))
686737
return -EIO;
687738

688-
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
739+
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
689740
}
690741

691742
static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr,
@@ -710,7 +761,7 @@ static ssize_t current_brightness_store(struct device *dev, struct device_attrib
710761
static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr,
711762
char *buf)
712763
{
713-
return snprintf(buf, PAGE_SIZE, "%d\n", get_optd_power_state());
764+
return sysfs_emit(buf, "%d\n", get_optd_power_state());
714765
}
715766

716767
static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr,
@@ -735,6 +786,24 @@ static DEVICE_ATTR_RW(dc_brightness);
735786
static DEVICE_ATTR_RW(current_brightness);
736787
static DEVICE_ATTR_RW(cdpower);
737788

789+
static umode_t pcc_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
790+
{
791+
struct device *dev = kobj_to_dev(kobj);
792+
struct acpi_device *acpi = to_acpi_device(dev);
793+
struct pcc_acpi *pcc = acpi_driver_data(acpi);
794+
795+
if (attr == &dev_attr_mute.attr)
796+
return (pcc->num_sifr > SINF_MUTE) ? attr->mode : 0;
797+
798+
if (attr == &dev_attr_eco_mode.attr)
799+
return (pcc->num_sifr > SINF_ECO_MODE) ? attr->mode : 0;
800+
801+
if (attr == &dev_attr_current_brightness.attr)
802+
return (pcc->num_sifr > SINF_CUR_BRIGHT) ? attr->mode : 0;
803+
804+
return attr->mode;
805+
}
806+
738807
static struct attribute *pcc_sysfs_entries[] = {
739808
&dev_attr_numbatt.attr,
740809
&dev_attr_lcdtype.attr,
@@ -749,8 +818,9 @@ static struct attribute *pcc_sysfs_entries[] = {
749818
};
750819

751820
static const struct attribute_group pcc_attr_group = {
752-
.name = NULL, /* put in device directory */
753-
.attrs = pcc_sysfs_entries,
821+
.name = NULL, /* put in device directory */
822+
.attrs = pcc_sysfs_entries,
823+
.is_visible = pcc_sysfs_is_visible,
754824
};
755825

756826

@@ -762,6 +832,8 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
762832
struct input_dev *hotk_input_dev = pcc->input_dev;
763833
int rc;
764834
unsigned long long result;
835+
unsigned int key;
836+
unsigned int updown;
765837

766838
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
767839
NULL, &result);
@@ -770,20 +842,27 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
770842
return;
771843
}
772844

845+
key = result & GENMASK(6, 0);
846+
updown = result & BIT(7); /* 0x80 == key down; 0x00 = key up */
847+
773848
/* hack: some firmware sends no key down for sleep / hibernate */
774-
if ((result & 0xf) == 0x7 || (result & 0xf) == 0xa) {
775-
if (result & 0x80)
849+
if (key == 7 || key == 10) {
850+
if (updown)
776851
sleep_keydown_seen = 1;
777852
if (!sleep_keydown_seen)
778853
sparse_keymap_report_event(hotk_input_dev,
779-
result & 0xf, 0x80, false);
854+
key, 0x80, false);
780855
}
781856

782-
if ((result & 0xf) == 0x7 || (result & 0xf) == 0x9 || (result & 0xf) == 0xa) {
783-
if (!sparse_keymap_report_event(hotk_input_dev,
784-
result & 0xf, result & 0x80, false))
785-
pr_err("Unknown hotkey event: 0x%04llx\n", result);
786-
}
857+
/*
858+
* Don't report brightness key-presses if they are also reported
859+
* by the ACPI video bus.
860+
*/
861+
if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses())
862+
return;
863+
864+
if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false))
865+
pr_err("Unknown hotkey event: 0x%04llx\n", result);
787866
}
788867

789868
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -894,12 +973,15 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
894973
if (!pcc)
895974
return -EINVAL;
896975

897-
acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
898-
acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
976+
if (pcc->num_sifr > SINF_MUTE)
977+
acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
978+
if (pcc->num_sifr > SINF_ECO_MODE)
979+
acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
899980
acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key);
900981
acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness);
901982
acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness);
902-
acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
983+
if (pcc->num_sifr > SINF_CUR_BRIGHT)
984+
acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
903985

904986
return 0;
905987
}
@@ -916,11 +998,21 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
916998

917999
num_sifr = acpi_pcc_get_sqty(device);
9181000

919-
if (num_sifr < 0 || num_sifr > 255) {
920-
pr_err("num_sifr out of range");
1001+
/*
1002+
* pcc->sinf is expected to at least have the AC+DC brightness entries.
1003+
* Accesses to higher SINF entries are checked against num_sifr.
1004+
*/
1005+
if (num_sifr <= SINF_DC_CUR_BRIGHT || num_sifr > 255) {
1006+
pr_err("num_sifr %d out of range %d - 255\n", num_sifr, SINF_DC_CUR_BRIGHT + 1);
9211007
return -ENODEV;
9221008
}
9231009

1010+
/*
1011+
* Some DSDT-s have an off-by-one bug where the SINF package count is
1012+
* one higher than the SQTY reported value, allocate 1 entry extra.
1013+
*/
1014+
num_sifr++;
1015+
9241016
pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
9251017
if (!pcc) {
9261018
pr_err("Couldn't allocate mem for pcc");
@@ -951,29 +1043,36 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
9511043
pr_err("Couldn't retrieve BIOS data\n");
9521044
goto out_input;
9531045
}
954-
/* initialize backlight */
955-
memset(&props, 0, sizeof(struct backlight_properties));
956-
props.type = BACKLIGHT_PLATFORM;
957-
props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
958-
pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
959-
&pcc_backlight_ops, &props);
960-
if (IS_ERR(pcc->backlight)) {
961-
result = PTR_ERR(pcc->backlight);
962-
goto out_input;
963-
}
9641046

965-
/* read the initial brightness setting from the hardware */
966-
pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1047+
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1048+
/* initialize backlight */
1049+
memset(&props, 0, sizeof(struct backlight_properties));
1050+
props.type = BACKLIGHT_PLATFORM;
1051+
props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
1052+
1053+
pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
1054+
&pcc_backlight_ops, &props);
1055+
if (IS_ERR(pcc->backlight)) {
1056+
result = PTR_ERR(pcc->backlight);
1057+
goto out_input;
1058+
}
1059+
1060+
/* read the initial brightness setting from the hardware */
1061+
pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1062+
}
9671063

9681064
/* Reset initial sticky key mode since the hardware register state is not consistent */
9691065
acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
9701066
pcc->sticky_key = 0;
9711067

972-
pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
973-
pcc->mute = pcc->sinf[SINF_MUTE];
9741068
pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
9751069
pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT];
976-
pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
1070+
if (pcc->num_sifr > SINF_MUTE)
1071+
pcc->mute = pcc->sinf[SINF_MUTE];
1072+
if (pcc->num_sifr > SINF_ECO_MODE)
1073+
pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
1074+
if (pcc->num_sifr > SINF_CUR_BRIGHT)
1075+
pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
9771076

9781077
/* add sysfs attributes */
9791078
result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
@@ -983,7 +1082,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
9831082
/* optical drive initialization */
9841083
if (ACPI_SUCCESS(check_optd_present())) {
9851084
pcc->platform = platform_device_register_simple("panasonic",
986-
-1, NULL, 0);
1085+
PLATFORM_DEVID_NONE, NULL, 0);
9871086
if (IS_ERR(pcc->platform)) {
9881087
result = PTR_ERR(pcc->platform);
9891088
goto out_backlight;
@@ -997,6 +1096,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
9971096
pcc->platform = NULL;
9981097
}
9991098

1099+
i8042_install_filter(panasonic_i8042_filter);
10001100
return 0;
10011101

10021102
out_platform:
@@ -1020,6 +1120,8 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device)
10201120
if (!device || !pcc)
10211121
return;
10221122

1123+
i8042_remove_filter(panasonic_i8042_filter);
1124+
10231125
if (pcc->platform) {
10241126
device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
10251127
platform_device_unregister(pcc->platform);

0 commit comments

Comments
 (0)