^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Dell laptop extras
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) Red Hat <mjg@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2014 Pali Rohár <pali@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based on documentation in the libsmbios package:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2005-2014 Dell Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/rfkill.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/i8042.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <acpi/video.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "dell-rbtn.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "dell-smbios.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct quirk_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) bool touchpad_led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) bool kbd_led_not_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) bool kbd_led_levels_off_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bool kbd_missing_ac_tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bool needs_kbd_timeouts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Ordered list of timeouts expressed in seconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * The list must end with -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int kbd_timeouts[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static struct quirk_entry *quirks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static struct quirk_entry quirk_dell_vostro_v130 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .touchpad_led = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static int __init dmi_matched(const struct dmi_system_id *dmi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) quirks = dmi->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * These values come from Windows utility provided by Dell. If any other value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * is used then BIOS silently set timeout to 0 without any error message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static struct quirk_entry quirk_dell_xps13_9333 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .needs_kbd_timeouts = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static struct quirk_entry quirk_dell_xps13_9370 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .kbd_missing_ac_tag = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static struct quirk_entry quirk_dell_latitude_e6410 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .kbd_led_levels_off_1 = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static struct quirk_entry quirk_dell_inspiron_1012 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .kbd_led_not_present = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static struct platform_driver platform_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .name = "dell-laptop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static struct platform_device *platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static struct backlight_device *dell_backlight_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static struct rfkill *wifi_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static struct rfkill *bluetooth_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static struct rfkill *wwan_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static bool force_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) module_param(force_rfkill, bool, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static const struct dmi_system_id dell_device_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .ident = "Dell laptop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .ident = "Dell Computer Corporation",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) MODULE_DEVICE_TABLE(dmi, dell_device_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static const struct dmi_system_id dell_quirks[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .ident = "Dell Vostro V130",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .ident = "Dell Vostro V131",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .ident = "Dell Vostro 3350",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .ident = "Dell Vostro 3555",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .ident = "Dell Inspiron N311z",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .ident = "Dell Inspiron M5110",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .ident = "Dell Vostro 3360",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .ident = "Dell Vostro 3460",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3460"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .ident = "Dell Vostro 3560",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3560"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .ident = "Dell Vostro 3450",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) DMI_MATCH(DMI_PRODUCT_NAME, "Dell System Vostro 3450"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .ident = "Dell Inspiron 5420",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5420"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .ident = "Dell Inspiron 5520",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5520"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .ident = "Dell Inspiron 5720",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5720"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .ident = "Dell Inspiron 7420",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7420"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .ident = "Dell Inspiron 7520",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .ident = "Dell Inspiron 7720",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .driver_data = &quirk_dell_vostro_v130,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .ident = "Dell XPS13 9333",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .driver_data = &quirk_dell_xps13_9333,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .ident = "Dell XPS 13 9370",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9370"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .driver_data = &quirk_dell_xps13_9370,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .ident = "Dell Latitude E6410",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6410"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .driver_data = &quirk_dell_latitude_e6410,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .ident = "Dell Inspiron 1012",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .driver_data = &quirk_dell_inspiron_1012,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .ident = "Dell Inspiron 1018",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1018"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .driver_data = &quirk_dell_inspiron_1012,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static void dell_fill_request(struct calling_interface_buffer *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) u32 arg0, u32 arg1, u32 arg2, u32 arg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) memset(buffer, 0, sizeof(struct calling_interface_buffer));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) buffer->input[0] = arg0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) buffer->input[1] = arg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) buffer->input[2] = arg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) buffer->input[3] = arg3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static int dell_send_request(struct calling_interface_buffer *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) u16 class, u16 select)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) buffer->cmd_class = class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) buffer->cmd_select = select;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) ret = dell_smbios_call(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return dell_smbios_error(buffer->output[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * Derived from information in smbios-wireless-ctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * cbSelect 17, Value 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * Return Wireless Info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * cbArg1, byte0 = 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * cbRes2 Info bit flags:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * 0 Hardware switch supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * 1 WiFi locator supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * 2 WLAN supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * 3 Bluetooth (BT) supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * 4 WWAN supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * 5 Wireless KBD supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * 6 Uw b supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * 7 WiGig supported (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * 8 WLAN installed (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * 9 BT installed (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * 10 WWAN installed (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * 11 Uw b installed (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * 12 WiGig installed (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * 13-15 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * 16 Hardware (HW) switch is On (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * 17 WLAN disabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * 18 BT disabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * 19 WWAN disabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * 20 Uw b disabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * 21 WiGig disabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * 20-31 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * cbRes3 NVRAM size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * cbRes4, byte 0 NVRAM format version number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * Set QuickSet Radio Disable Flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * cbArg1, byte0 = 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * cbArg1, byte1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * Radio ID value:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * 0 Radio Status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * 1 WLAN ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * 2 BT ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * 3 WWAN ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * 4 UWB ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * 5 WIGIG ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * cbArg1, byte2 Flag bits:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * 0 QuickSet disables radio (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * 1-7 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * cbRes2 QuickSet (QS) radio disable bit map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * 0 QS disables WLAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * 1 QS disables BT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * 2 QS disables WWAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * 3 QS disables UWB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * 4 QS disables WIGIG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * 5-31 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * Wireless Switch Configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * cbArg1, byte0 = 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) * cbArg1, byte1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * Subcommand:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * 0 Get config
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * 1 Set config
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * 2 Set WiFi locator enable/disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * cbArg1,byte2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * Switch settings (if byte 1==1):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * 0 WLAN sw itch control (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * 1 BT sw itch control (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * 2 WWAN sw itch control (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * 3 UWB sw itch control (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * 4 WiGig sw itch control (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * 5-7 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * cbArg1, byte2 Enable bits (if byte 1==2):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * 0 Enable WiFi locator (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * cbRes2 QuickSet radio disable bit map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * 0 WLAN controlled by sw itch (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * 1 BT controlled by sw itch (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * 2 WWAN controlled by sw itch (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * 3 UWB controlled by sw itch (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * 4 WiGig controlled by sw itch (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) * 5-6 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * 7 Wireless sw itch config locked (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * 8 WiFi locator enabled (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * 9-14 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * 15 WiFi locator setting locked (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * 16-31 Reserved (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * Read Local Config Data (LCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * cbArg1, byte0 = 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * cbArg1, byte1 NVRAM index low byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * cbArg1, byte2 NVRAM index high byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) * cbRes2 4 bytes read from LCD[index]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * cbRes3 4 bytes read from LCD[index+4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * cbRes4 4 bytes read from LCD[index+8]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) * Write Local Config Data (LCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) * cbArg1, byte0 = 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * cbArg1, byte1 NVRAM index low byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * cbArg1, byte2 NVRAM index high byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * cbArg2 4 bytes to w rite at LCD[index]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * cbArg3 4 bytes to w rite at LCD[index+4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * cbArg4 4 bytes to w rite at LCD[index+8]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * Populate Local Config Data from NVRAM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * cbArg1, byte0 = 0x12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * Commit Local Config Data to NVRAM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * cbArg1, byte0 = 0x13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static int dell_rfkill_set(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) int disable = blocked ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) unsigned long radio = (unsigned long)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) int hwswitch_bit = (unsigned long)data - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int hwswitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) status = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) dell_fill_request(&buffer, 0x2, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) hwswitch = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /* If the hardware switch controls this radio, and the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) switch is disabled, always disable the radio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (ret == 0 && (hwswitch & BIT(hwswitch_bit)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) (status & BIT(0)) && !(status & BIT(16)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) disable = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (status & BIT(0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) /* Has hw-switch, sync sw_state to BIOS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) int block = rfkill_blocked(rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) dell_fill_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 1 | (radio << 8) | (block << 16), 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) /* No hw-switch, sync BIOS state to sw_state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) int status, int hwswitch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (hwswitch & (BIT(radio - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) rfkill_set_hw_state(rfkill, !(status & BIT(16)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) static void dell_rfkill_query(struct rfkill *rfkill, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) int radio = ((unsigned long)data & 0xF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) int hwswitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) status = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (ret != 0 || !(status & BIT(0))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) dell_fill_request(&buffer, 0x2, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) hwswitch = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) dell_rfkill_update_hw_state(rfkill, radio, status, hwswitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) static const struct rfkill_ops dell_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) .set_block = dell_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) .query = dell_rfkill_query,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) static struct dentry *dell_laptop_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) static int dell_debugfs_show(struct seq_file *s, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) int hwswitch_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) int hwswitch_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) status = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) dell_fill_request(&buffer, 0x2, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (hwswitch_ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return hwswitch_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) hwswitch_state = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) seq_printf(s, "return:\t%d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) seq_printf(s, "status:\t0x%X\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) seq_printf(s, "Bit 0 : Hardware switch supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) status & BIT(0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) seq_printf(s, "Bit 1 : Wifi locator supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) (status & BIT(1)) >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) seq_printf(s, "Bit 2 : Wifi is supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) (status & BIT(2)) >> 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) seq_printf(s, "Bit 3 : Bluetooth is supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) (status & BIT(3)) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) seq_printf(s, "Bit 4 : WWAN is supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) (status & BIT(4)) >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) (status & BIT(5)) >> 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) seq_printf(s, "Bit 6 : UWB supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) (status & BIT(6)) >> 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) seq_printf(s, "Bit 7 : WiGig supported: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) (status & BIT(7)) >> 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) seq_printf(s, "Bit 8 : Wifi is installed: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) (status & BIT(8)) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) (status & BIT(9)) >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) seq_printf(s, "Bit 10: WWAN is installed: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) (status & BIT(10)) >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) seq_printf(s, "Bit 11: UWB installed: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) (status & BIT(11)) >> 11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) seq_printf(s, "Bit 12: WiGig installed: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) (status & BIT(12)) >> 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) seq_printf(s, "Bit 16: Hardware switch is on: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) (status & BIT(16)) >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) seq_printf(s, "Bit 17: Wifi is blocked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) (status & BIT(17)) >> 17);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) seq_printf(s, "Bit 18: Bluetooth is blocked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) (status & BIT(18)) >> 18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) seq_printf(s, "Bit 19: WWAN is blocked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) (status & BIT(19)) >> 19);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) seq_printf(s, "Bit 20: UWB is blocked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) (status & BIT(20)) >> 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) seq_printf(s, "Bit 21: WiGig is blocked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) (status & BIT(21)) >> 21);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) seq_printf(s, "\nhwswitch_return:\t%d\n", hwswitch_ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) seq_printf(s, "hwswitch_state:\t0x%X\n", hwswitch_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) hwswitch_state & BIT(0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) (hwswitch_state & BIT(1)) >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) (hwswitch_state & BIT(2)) >> 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) seq_printf(s, "Bit 3 : UWB controlled by switch: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) (hwswitch_state & BIT(3)) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) seq_printf(s, "Bit 4 : WiGig controlled by switch: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) (hwswitch_state & BIT(4)) >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) (hwswitch_state & BIT(7)) >> 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) (hwswitch_state & BIT(8)) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) seq_printf(s, "Bit 15: Wifi locator setting locked: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) (hwswitch_state & BIT(15)) >> 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) DEFINE_SHOW_ATTRIBUTE(dell_debugfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) static void dell_update_rfkill(struct work_struct *ignored)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) int hwswitch = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) status = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) dell_fill_request(&buffer, 0x2, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (ret == 0 && (status & BIT(0)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) hwswitch = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (wifi_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (bluetooth_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) hwswitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if (wwan_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) struct serio *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static bool extended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (str & I8042_STR_AUXDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (unlikely(data == 0xe0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) extended = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) } else if (unlikely(extended)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) switch (data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) case 0x8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) schedule_delayed_work(&dell_rfkill_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) round_jiffies_relative(HZ / 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) extended = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int (*dell_rbtn_notifier_register_func)(struct notifier_block *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) static int (*dell_rbtn_notifier_unregister_func)(struct notifier_block *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static int dell_laptop_rbtn_notifier_call(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) unsigned long action, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) schedule_delayed_work(&dell_rfkill_work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) static struct notifier_block dell_laptop_rbtn_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) .notifier_call = dell_laptop_rbtn_notifier_call,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) static int __init dell_setup_rfkill(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) int status, ret, whitelisted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) const char *product;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) * rfkill support causes trouble on various models, mostly Inspirons.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) * So we whitelist certain series, and don't support rfkill on others.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) whitelisted = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) product = dmi_get_system_info(DMI_PRODUCT_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (product && (strncmp(product, "Latitude", 8) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) strncmp(product, "Precision", 9) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) whitelisted = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (!force_rfkill && !whitelisted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) status = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) /* dell wireless info smbios call is not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* rfkill is only tested on laptops with a hwswitch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (!(status & BIT(0)) && !force_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) RFKILL_TYPE_WLAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) &dell_rfkill_ops, (void *) 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (!wifi_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) goto err_wifi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) ret = rfkill_register(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) goto err_wifi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) bluetooth_rfkill = rfkill_alloc("dell-bluetooth",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) &platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) RFKILL_TYPE_BLUETOOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) &dell_rfkill_ops, (void *) 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (!bluetooth_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) goto err_bluetooth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) ret = rfkill_register(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) goto err_bluetooth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) wwan_rfkill = rfkill_alloc("dell-wwan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) &platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) RFKILL_TYPE_WWAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) &dell_rfkill_ops, (void *) 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (!wwan_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) goto err_wwan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) ret = rfkill_register(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) goto err_wwan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) * Dell Airplane Mode Switch driver (dell-rbtn) supports ACPI devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) * which can receive events from HW slider switch.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * Dell SMBIOS on whitelisted models supports controlling radio devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * but does not support receiving HW button switch events. We can use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * i8042 filter hook function to receive keyboard data and handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * keycode for HW button.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) * So if it is possible we will use Dell Airplane Mode Switch ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * driver for receiving HW events and Dell SMBIOS for setting rfkill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) * states. If ACPI driver or device is not available we will fallback to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) * i8042 filter hook function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) * To prevent duplicate rfkill devices which control and do same thing,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) * dell-rbtn driver will automatically remove its own rfkill devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * once function dell_rbtn_notifier_register() is called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) dell_rbtn_notifier_register_func =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) symbol_request(dell_rbtn_notifier_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (dell_rbtn_notifier_register_func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) dell_rbtn_notifier_unregister_func =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) symbol_request(dell_rbtn_notifier_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (!dell_rbtn_notifier_unregister_func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) symbol_put(dell_rbtn_notifier_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) dell_rbtn_notifier_register_func = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (dell_rbtn_notifier_register_func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) ret = dell_rbtn_notifier_register_func(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) &dell_laptop_rbtn_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) symbol_put(dell_rbtn_notifier_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) dell_rbtn_notifier_register_func = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) symbol_put(dell_rbtn_notifier_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) dell_rbtn_notifier_unregister_func = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) pr_info("Symbols from dell-rbtn acpi driver are not available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) pr_info("Using dell-rbtn acpi driver for receiving events\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) } else if (ret != -ENODEV) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) pr_warn("Unable to register dell rbtn notifier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) goto err_filter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) ret = i8042_install_filter(dell_laptop_i8042_filter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) pr_warn("Unable to install key filter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) goto err_filter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) pr_info("Using i8042 filter function for receiving events\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) err_filter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) if (wwan_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) rfkill_unregister(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) err_wwan:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) rfkill_destroy(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if (bluetooth_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) rfkill_unregister(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) err_bluetooth:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) rfkill_destroy(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (wifi_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) rfkill_unregister(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) err_wifi:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) rfkill_destroy(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) static void dell_cleanup_rfkill(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (dell_rbtn_notifier_unregister_func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) dell_rbtn_notifier_unregister_func(&dell_laptop_rbtn_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) symbol_put(dell_rbtn_notifier_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) dell_rbtn_notifier_unregister_func = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) i8042_remove_filter(dell_laptop_i8042_filter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) cancel_delayed_work_sync(&dell_rfkill_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (wifi_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) rfkill_unregister(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) rfkill_destroy(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (bluetooth_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) rfkill_unregister(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) rfkill_destroy(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) if (wwan_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) rfkill_unregister(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) rfkill_destroy(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) static int dell_send_intensity(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (!token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) dell_fill_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) token->location, bd->props.brightness, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (power_supply_is_system_supplied() > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) static int dell_get_intensity(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) if (!token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) dell_fill_request(&buffer, token->location, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (power_supply_is_system_supplied() > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) CLASS_TOKEN_READ, SELECT_TOKEN_AC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) ret = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static const struct backlight_ops dell_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .get_brightness = dell_get_intensity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .update_status = dell_send_intensity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) static void touchpad_led_on(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) int command = 0x97;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) char data = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) i8042_command(&data, command | 1 << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) static void touchpad_led_off(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) int command = 0x97;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) char data = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) i8042_command(&data, command | 1 << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static void touchpad_led_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (value > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) touchpad_led_on();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) touchpad_led_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) static struct led_classdev touchpad_led = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) .name = "dell-laptop::touchpad",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .brightness_set = touchpad_led_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) .flags = LED_CORE_SUSPENDRESUME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) static int __init touchpad_led_init(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) return led_classdev_register(dev, &touchpad_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) static void touchpad_led_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) led_classdev_unregister(&touchpad_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) * Derived from information in smbios-keyboard-ctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) * cbClass 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) * cbSelect 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) * Keyboard illumination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) * cbArg1 determines the function to be performed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * cbArg1 0x0 = Get Feature Information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * cbRES1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * cbRES2, word0 Bitmap of user-selectable modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * bit 0 Always off (All systems)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * bit 1 Always on (Travis ATG, Siberia)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) * bit 4 Auto: Input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * bits 9-15 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) * cbRES2, byte2 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) * cbRES2, byte3 Keyboard illumination type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * 0 Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) * 1 Tasklight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * 2 Backlight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) * 3-255 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) * cbRES3, byte0 Supported auto keyboard illumination trigger bitmap.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) * bit 0 Any keystroke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) * bit 1 Touchpad activity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) * bit 2 Pointing stick
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) * bit 3 Any mouse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) * bits 4-7 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) * cbRES3, byte1 Supported timeout unit bitmap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) * bit 0 Seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * bit 1 Minutes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) * bit 2 Hours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) * bit 3 Days
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * bits 4-7 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) * cbRES3, byte2 Number of keyboard light brightness levels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) * cbRES4, byte0 Maximum acceptable seconds value (0 if seconds not supported).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) * cbRES4, byte1 Maximum acceptable minutes value (0 if minutes not supported).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) * cbRES4, byte2 Maximum acceptable hours value (0 if hours not supported).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * cbRES4, byte3 Maximum acceptable days value (0 if days not supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) * cbArg1 0x1 = Get Current State
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) * cbRES1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) * cbRES2, word0 Bitmap of current mode state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) * bit 0 Always off (All systems)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) * bit 1 Always on (Travis ATG, Siberia)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) * bit 4 Auto: Input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) * bits 9-15 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) * Note: Only One bit can be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) * cbRES2, byte2 Currently active auto keyboard illumination triggers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) * bit 0 Any keystroke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) * bit 1 Touchpad activity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) * bit 2 Pointing stick
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) * bit 3 Any mouse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) * bits 4-7 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) * cbRES2, byte3 Current Timeout on battery
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) * bits 7:6 Timeout units indicator:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) * 00b Seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) * 01b Minutes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) * 10b Hours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) * 11b Days
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) * bits 5:0 Timeout value (0-63) in sec/min/hr/day
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) * are set upon return from the [Get feature information] call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) * cbRES3, byte0 Current setting of ALS value that turns the light on or off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) * cbRES3, byte1 Current ALS reading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) * cbRES3, byte2 Current keyboard light level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) * cbRES3, byte3 Current timeout on AC Power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) * bits 7:6 Timeout units indicator:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) * 00b Seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) * 01b Minutes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) * 10b Hours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) * 11b Days
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) * Bits 5:0 Timeout value (0-63) in sec/min/hr/day
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) * are set upon return from the upon return from the [Get Feature information] call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) * cbArg1 0x2 = Set New State
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) * cbRES1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) * cbArg2, word0 Bitmap of current mode state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) * bit 0 Always off (All systems)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) * bit 1 Always on (Travis ATG, Siberia)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) * bit 4 Auto: Input-activity-based On; input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) * bits 9-15 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) * Note: Only One bit can be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) * cbArg2, byte2 Desired auto keyboard illumination triggers. Must remain inactive to allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) * keyboard to turn off automatically.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) * bit 0 Any keystroke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) * bit 1 Touchpad activity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * bit 2 Pointing stick
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * bit 3 Any mouse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) * bits 4-7 Reserved for future use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) * cbArg2, byte3 Desired Timeout on battery
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) * bits 7:6 Timeout units indicator:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) * 00b Seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) * 01b Minutes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) * 10b Hours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * 11b Days
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * bits 5:0 Timeout value (0-63) in sec/min/hr/day
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * cbArg3, byte0 Desired setting of ALS value that turns the light on or off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) * cbArg3, byte2 Desired keyboard light level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * cbArg3, byte3 Desired Timeout on AC power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) * bits 7:6 Timeout units indicator:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) * 00b Seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * 01b Minutes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * 10b Hours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * 11b Days
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * bits 5:0 Timeout value (0-63) in sec/min/hr/day
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) enum kbd_timeout_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) KBD_TIMEOUT_SECONDS = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) KBD_TIMEOUT_MINUTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) KBD_TIMEOUT_HOURS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) KBD_TIMEOUT_DAYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) enum kbd_mode_bit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) KBD_MODE_BIT_OFF = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) KBD_MODE_BIT_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) KBD_MODE_BIT_ALS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) KBD_MODE_BIT_TRIGGER_ALS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) KBD_MODE_BIT_TRIGGER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) KBD_MODE_BIT_TRIGGER_25,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) KBD_MODE_BIT_TRIGGER_50,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) KBD_MODE_BIT_TRIGGER_75,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) KBD_MODE_BIT_TRIGGER_100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) #define kbd_is_als_mode_bit(bit) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) #define kbd_is_trigger_mode_bit(bit) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) #define kbd_is_level_mode_bit(bit) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) struct kbd_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) u16 modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) u8 triggers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) u8 levels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) u8 seconds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) u8 minutes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) u8 hours;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) u8 days;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) struct kbd_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) u8 mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) u8 triggers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) u8 timeout_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) u8 timeout_unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) u8 timeout_value_ac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) u8 timeout_unit_ac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) u8 als_setting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) u8 als_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) u8 level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) static const int kbd_tokens[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) KBD_LED_OFF_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) KBD_LED_AUTO_25_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) KBD_LED_AUTO_50_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) KBD_LED_AUTO_75_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) KBD_LED_AUTO_100_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) KBD_LED_ON_TOKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) static u16 kbd_token_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) static struct kbd_info kbd_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) static bool kbd_als_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) static bool kbd_triggers_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) static bool kbd_timeout_ac_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) static u8 kbd_mode_levels[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) static int kbd_mode_levels_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) static u8 kbd_previous_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) static u8 kbd_previous_mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) static bool kbd_led_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) static DEFINE_MUTEX(kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) static enum led_brightness kbd_led_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) * NOTE: there are three ways to set the keyboard backlight level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) * There are laptops which support only one of these methods. If we want to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) * support as many machines as possible we need to implement all three methods.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) * The first two methods use the kbd_state structure. The third uses SMBIOS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) * tokens. If kbd_info.levels == 0, the machine does not support setting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) * keyboard backlight level via kbd_state.level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) static int kbd_get_info(struct kbd_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) u8 units;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) dell_fill_request(&buffer, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) info->modes = buffer.output[1] & 0xFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) info->type = (buffer.output[1] >> 24) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) info->triggers = buffer.output[2] & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) units = (buffer.output[2] >> 8) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) info->levels = (buffer.output[2] >> 16) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) if (quirks && quirks->kbd_led_levels_off_1 && info->levels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) info->levels--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) if (units & BIT(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) info->seconds = (buffer.output[3] >> 0) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) if (units & BIT(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) info->minutes = (buffer.output[3] >> 8) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) if (units & BIT(2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) info->hours = (buffer.output[3] >> 16) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) if (units & BIT(3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) info->days = (buffer.output[3] >> 24) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) static unsigned int kbd_get_max_level(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) if (kbd_info.levels != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) return kbd_info.levels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) if (kbd_mode_levels_count > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) return kbd_mode_levels_count - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) static int kbd_get_level(struct kbd_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) if (kbd_info.levels != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) return state->level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) if (kbd_mode_levels_count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) for (i = 0; i < kbd_mode_levels_count; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) if (kbd_mode_levels[i] == state->mode_bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) static int kbd_set_level(struct kbd_state *state, u8 level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) if (kbd_info.levels != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) if (level != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) kbd_previous_level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) if (state->level == level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) state->level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) state->mode_bit = kbd_previous_mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) kbd_previous_mode_bit = state->mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) state->mode_bit = KBD_MODE_BIT_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) if (level != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) kbd_previous_level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) state->mode_bit = kbd_mode_levels[level];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) static int kbd_get_state(struct kbd_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) dell_fill_request(&buffer, 0x1, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) state->mode_bit = ffs(buffer.output[1] & 0xFFFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) if (state->mode_bit != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) state->mode_bit--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) state->triggers = (buffer.output[1] >> 16) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) state->timeout_value = (buffer.output[1] >> 24) & 0x3F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) state->timeout_unit = (buffer.output[1] >> 30) & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) state->als_setting = buffer.output[2] & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) state->als_value = (buffer.output[2] >> 8) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) state->level = (buffer.output[2] >> 16) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) static int kbd_set_state(struct kbd_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) u32 input1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) u32 input2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) input1 = BIT(state->mode_bit) & 0xFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) input1 |= (state->triggers & 0xFF) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) input1 |= (state->timeout_value & 0x3F) << 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) input1 |= (state->timeout_unit & 0x3) << 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) input2 = state->als_setting & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) input2 |= (state->level & 0xFF) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) input2 |= (state->timeout_value_ac & 0x3F) << 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) input2 |= (state->timeout_unit_ac & 0x3) << 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) dell_fill_request(&buffer, 0x2, input1, input2, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) ret = kbd_set_state(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) * When setting the new state fails,try to restore the previous one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) * This is needed on some machines where BIOS sets a default state when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) * setting a new state fails. This default state could be all off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) if (kbd_set_state(old))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) pr_err("Setting old previous keyboard state failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) static int kbd_set_token_bit(u8 bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) if (bit >= ARRAY_SIZE(kbd_tokens))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) token = dell_smbios_find_token(kbd_tokens[bit]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) if (!token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) dell_fill_request(&buffer, token->location, token->value, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) static int kbd_get_token_bit(u8 bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) if (bit >= ARRAY_SIZE(kbd_tokens))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) token = dell_smbios_find_token(kbd_tokens[bit]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) if (!token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) dell_fill_request(&buffer, token->location, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) val = buffer.output[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) return (val == token->value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) static int kbd_get_first_active_token_bit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) ret = kbd_get_token_bit(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) if (ret == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) static int kbd_get_valid_token_counts(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) return hweight16(kbd_token_bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) static inline int kbd_init_info(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) ret = kbd_get_info(&kbd_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) /* NOTE: Old models without KBD_LED_AC_TOKEN token supports only one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) * timeout value which is shared for both battery and AC power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) * settings. So do not try to set AC values on old models.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if ((quirks && quirks->kbd_missing_ac_tag) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) dell_smbios_find_token(KBD_LED_AC_TOKEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) kbd_timeout_ac_supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) /* NOTE: timeout value is stored in 6 bits so max value is 63 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) if (kbd_info.seconds > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) kbd_info.seconds = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) if (kbd_info.minutes > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) kbd_info.minutes = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) if (kbd_info.hours > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) kbd_info.hours = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) if (kbd_info.days > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) kbd_info.days = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) /* NOTE: On tested machines ON mode did not work and caused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) * problems (turned backlight off) so do not use it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) kbd_info.modes &= ~BIT(KBD_MODE_BIT_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) kbd_previous_level = kbd_get_level(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) kbd_previous_mode_bit = state.mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) if (kbd_previous_level == 0 && kbd_get_max_level() != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) kbd_previous_level = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) if (kbd_previous_mode_bit == KBD_MODE_BIT_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) kbd_previous_mode_bit =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) ffs(kbd_info.modes & ~BIT(KBD_MODE_BIT_OFF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) if (kbd_previous_mode_bit != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) kbd_previous_mode_bit--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) if (kbd_info.modes & (BIT(KBD_MODE_BIT_ALS) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) BIT(KBD_MODE_BIT_TRIGGER_ALS)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) kbd_als_supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) if (kbd_info.modes & (
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) BIT(KBD_MODE_BIT_TRIGGER_ALS) | BIT(KBD_MODE_BIT_TRIGGER) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) BIT(KBD_MODE_BIT_TRIGGER_25) | BIT(KBD_MODE_BIT_TRIGGER_50) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) BIT(KBD_MODE_BIT_TRIGGER_75) | BIT(KBD_MODE_BIT_TRIGGER_100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) kbd_triggers_supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) /* kbd_mode_levels[0] is reserved, see below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) for (i = 0; i < 16; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) if (kbd_is_level_mode_bit(i) && (BIT(i) & kbd_info.modes))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) kbd_mode_levels[1 + kbd_mode_levels_count++] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) * Find the first supported mode and assign to kbd_mode_levels[0].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) * This should be 0 (off), but we cannot depend on the BIOS to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) * support 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) if (kbd_mode_levels_count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) for (i = 0; i < 16; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) if (BIT(i) & kbd_info.modes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) kbd_mode_levels[0] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) kbd_mode_levels_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) static inline void kbd_init_tokens(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) if (dell_smbios_find_token(kbd_tokens[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) kbd_token_bits |= BIT(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) static void kbd_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) if (quirks && quirks->kbd_led_not_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) ret = kbd_init_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) kbd_init_tokens();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) * Only supports keyboard backlight when it has at least two modes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) if ((ret == 0 && (kbd_info.levels != 0 || kbd_mode_levels_count >= 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) || kbd_get_valid_token_counts() >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) kbd_led_present = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) static ssize_t kbd_led_timeout_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) struct kbd_state new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) bool convert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) char ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) u8 unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) ret = sscanf(buf, "%d %c", &value, &ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) if (ret < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) else if (ret == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) ch = 's';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) convert = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) switch (ch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) case 's':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) if (value > kbd_info.seconds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) convert = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) unit = KBD_TIMEOUT_SECONDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) case 'm':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) if (value > kbd_info.minutes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) convert = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) unit = KBD_TIMEOUT_MINUTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) if (value > kbd_info.hours)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) convert = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) unit = KBD_TIMEOUT_HOURS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) case 'd':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) if (value > kbd_info.days)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) convert = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) unit = KBD_TIMEOUT_DAYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) if (quirks && quirks->needs_kbd_timeouts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) convert = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) if (convert) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) /* Convert value from current units to seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) switch (unit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) case KBD_TIMEOUT_DAYS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) value *= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) case KBD_TIMEOUT_HOURS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) value *= 60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) case KBD_TIMEOUT_MINUTES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) value *= 60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) unit = KBD_TIMEOUT_SECONDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) if (quirks && quirks->needs_kbd_timeouts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) for (i = 0; quirks->kbd_timeouts[i] != -1; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) if (value <= quirks->kbd_timeouts[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) value = quirks->kbd_timeouts[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) if (value <= kbd_info.seconds && kbd_info.seconds) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) unit = KBD_TIMEOUT_SECONDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) } else if (value / 60 <= kbd_info.minutes && kbd_info.minutes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) value /= 60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) unit = KBD_TIMEOUT_MINUTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) } else if (value / (60 * 60) <= kbd_info.hours && kbd_info.hours) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) value /= (60 * 60);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) unit = KBD_TIMEOUT_HOURS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) } else if (value / (60 * 60 * 24) <= kbd_info.days && kbd_info.days) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) value /= (60 * 60 * 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) unit = KBD_TIMEOUT_DAYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) new_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) new_state.timeout_value_ac = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) new_state.timeout_unit_ac = unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) new_state.timeout_value = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) new_state.timeout_unit = unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) ret = kbd_set_state_safe(&new_state, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) static ssize_t kbd_led_timeout_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) u8 unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) value = state.timeout_value_ac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) unit = state.timeout_unit_ac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) value = state.timeout_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) unit = state.timeout_unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) len = sprintf(buf, "%d", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) switch (unit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) case KBD_TIMEOUT_SECONDS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) return len + sprintf(buf+len, "s\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) case KBD_TIMEOUT_MINUTES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) return len + sprintf(buf+len, "m\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) case KBD_TIMEOUT_HOURS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) return len + sprintf(buf+len, "h\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) case KBD_TIMEOUT_DAYS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) return len + sprintf(buf+len, "d\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) kbd_led_timeout_show, kbd_led_timeout_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) static const char * const kbd_led_triggers[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) "keyboard",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) "touchpad",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) /*"trackstick"*/ NULL, /* NOTE: trackstick is just alias for touchpad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) "mouse",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) static ssize_t kbd_led_triggers_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) struct kbd_state new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) bool triggers_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) int trigger_bit = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) char trigger[21];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) ret = sscanf(buf, "%20s", trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) if (ret != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) if (trigger[0] != '+' && trigger[0] != '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) if (kbd_triggers_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) if (kbd_triggers_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) if (!(kbd_info.triggers & BIT(i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) if (!kbd_led_triggers[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) if (strcmp(trigger+1, kbd_led_triggers[i]) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) if (trigger[0] == '+' &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) triggers_enabled && (state.triggers & BIT(i))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) if (trigger[0] == '-' &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) (!triggers_enabled || !(state.triggers & BIT(i)))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) trigger_bit = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) if (trigger_bit == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) new_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) if (trigger[0] == '+')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) new_state.triggers |= BIT(trigger_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) new_state.triggers &= ~BIT(trigger_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) * NOTE: trackstick bit (2) must be disabled when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) * disabling touchpad bit (1), otherwise touchpad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) * bit (1) will not be disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) if (trigger_bit == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) new_state.triggers &= ~BIT(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) if ((kbd_info.triggers & new_state.triggers) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) new_state.triggers) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) if (new_state.triggers && !triggers_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) kbd_set_level(&new_state, kbd_previous_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) } else if (new_state.triggers == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) kbd_set_level(&new_state, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) if (!(kbd_info.modes & BIT(new_state.mode_bit))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) ret = kbd_set_state_safe(&new_state, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) if (new_state.mode_bit != KBD_MODE_BIT_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) kbd_previous_mode_bit = new_state.mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) static ssize_t kbd_led_triggers_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) bool triggers_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) int level, i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) int len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) if (kbd_triggers_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) level = kbd_get_level(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) if (!(kbd_info.triggers & BIT(i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) if (!kbd_led_triggers[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) if ((triggers_enabled || level <= 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) (state.triggers & BIT(i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) buf[len++] = '+';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) buf[len++] = '-';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) len += sprintf(buf+len, "%s ", kbd_led_triggers[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) if (len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) buf[len - 1] = '\n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) kbd_led_triggers_show, kbd_led_triggers_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) static ssize_t kbd_led_als_enabled_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) struct kbd_state new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) bool triggers_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) int enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) ret = kstrtoint(buf, 0, &enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) if (enable == kbd_is_als_mode_bit(state.mode_bit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) new_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) if (kbd_triggers_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) if (triggers_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) new_state.mode_bit = KBD_MODE_BIT_ALS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) if (triggers_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) kbd_set_level(&new_state, kbd_previous_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) new_state.mode_bit = KBD_MODE_BIT_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) if (!(kbd_info.modes & BIT(new_state.mode_bit))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) ret = kbd_set_state_safe(&new_state, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) kbd_previous_mode_bit = new_state.mode_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) static ssize_t kbd_led_als_enabled_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) bool enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) enabled = kbd_is_als_mode_bit(state.mode_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) return sprintf(buf, "%d\n", enabled ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) static DEVICE_ATTR(als_enabled, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) kbd_led_als_enabled_show, kbd_led_als_enabled_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) static ssize_t kbd_led_als_setting_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) struct kbd_state new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) u8 setting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) ret = kstrtou8(buf, 10, &setting);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) new_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) new_state.als_setting = setting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) ret = kbd_set_state_safe(&new_state, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) static ssize_t kbd_led_als_setting_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) return sprintf(buf, "%d\n", state.als_setting);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) kbd_led_als_setting_show, kbd_led_als_setting_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) static struct attribute *kbd_led_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) &dev_attr_stop_timeout.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) &dev_attr_start_triggers.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) static const struct attribute_group kbd_led_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) .attrs = kbd_led_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) static struct attribute *kbd_led_als_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) &dev_attr_als_enabled.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) &dev_attr_als_setting.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) static const struct attribute_group kbd_led_als_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) .attrs = kbd_led_als_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) static const struct attribute_group *kbd_led_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) &kbd_led_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) &kbd_led_als_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) u16 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) if (kbd_get_max_level()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) ret = kbd_get_level(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) if (kbd_get_valid_token_counts()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) ret = kbd_get_first_active_token_bit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) for (num = kbd_token_bits; num != 0 && ret > 0; --ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) num &= num - 1; /* clear the first bit set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) if (num == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) return ffs(num) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) pr_warn("Keyboard brightness level control not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) static int kbd_led_level_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) enum led_brightness new_value = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) struct kbd_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) struct kbd_state new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) u16 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) if (kbd_get_max_level()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) ret = kbd_get_state(&state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) new_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) ret = kbd_set_level(&new_state, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) ret = kbd_set_state_safe(&new_state, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) } else if (kbd_get_valid_token_counts()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) for (num = kbd_token_bits; num != 0 && value > 0; --value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) num &= num - 1; /* clear the first bit set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) if (num == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) ret = kbd_set_token_bit(ffs(num) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) pr_warn("Keyboard brightness level control not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) kbd_led_level = new_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) static struct led_classdev kbd_led = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) .name = "dell::kbd_backlight",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) .flags = LED_BRIGHT_HW_CHANGED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) .brightness_set_blocking = kbd_led_level_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) .brightness_get = kbd_led_level_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) .groups = kbd_led_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) static int __init kbd_led_init(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) kbd_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) if (!kbd_led_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) if (!kbd_als_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) kbd_led_groups[1] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) kbd_led.max_brightness = kbd_get_max_level();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) if (!kbd_led.max_brightness) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) kbd_led.max_brightness = kbd_get_valid_token_counts();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) if (kbd_led.max_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) kbd_led.max_brightness--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) kbd_led_level = kbd_led_level_get(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) ret = led_classdev_register(dev, &kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) kbd_led_present = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) static void brightness_set_exit(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) /* Don't change backlight level on exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) static void kbd_led_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) if (!kbd_led_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) kbd_led.brightness_set = brightness_set_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) led_classdev_unregister(&kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) static int dell_laptop_notifier_call(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) unsigned long action, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) bool changed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) enum led_brightness new_kbd_led_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) switch (action) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) if (!kbd_led_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) mutex_lock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) new_kbd_led_level = kbd_led_level_get(&kbd_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) if (kbd_led_level != new_kbd_led_level) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) kbd_led_level = new_kbd_led_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) changed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) mutex_unlock(&kbd_led_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) if (changed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) led_classdev_notify_brightness_hw_changed(&kbd_led,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) kbd_led_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) static struct notifier_block dell_laptop_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) .notifier_call = dell_laptop_notifier_call,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) static int micmute_led_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) int state = brightness != LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) if (state == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) if (!token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) dell_fill_request(&buffer, token->location, token->value, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) static struct led_classdev micmute_led_cdev = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) .name = "platform::micmute",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) .max_brightness = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) .brightness_set_blocking = micmute_led_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) .default_trigger = "audio-micmute",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) static int __init dell_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) struct calling_interface_token *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) int max_intensity = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) if (!dmi_check_system(dell_device_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) quirks = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) /* find if this machine support other functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) dmi_check_system(dell_quirks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) ret = platform_driver_register(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) goto fail_platform_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) platform_device = platform_device_alloc("dell-laptop", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) if (!platform_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) goto fail_platform_device1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) ret = platform_device_add(platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) goto fail_platform_device2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189) ret = dell_setup_rfkill();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) pr_warn("Unable to setup rfkill\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) goto fail_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) if (quirks && quirks->touchpad_led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) touchpad_led_init(&platform_device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) kbd_led_init(&platform_device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201) dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) &dell_debugfs_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) dell_laptop_register_notifier(&dell_laptop_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) if (dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) goto fail_led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) if (token) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) struct calling_interface_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222) dell_fill_request(&buffer, token->location, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) ret = dell_send_request(&buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) CLASS_TOKEN_READ, SELECT_TOKEN_AC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) max_intensity = buffer.output[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) if (max_intensity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232) props.type = BACKLIGHT_PLATFORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) props.max_brightness = max_intensity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234) dell_backlight_device = backlight_device_register("dell_backlight",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) &platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) &dell_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238) &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240) if (IS_ERR(dell_backlight_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) ret = PTR_ERR(dell_backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242) dell_backlight_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) goto fail_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) dell_backlight_device->props.brightness =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) dell_get_intensity(dell_backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) if (dell_backlight_device->props.brightness < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) ret = dell_backlight_device->props.brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) goto fail_get_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252) backlight_update_status(dell_backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257) fail_get_brightness:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) backlight_device_unregister(dell_backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) fail_backlight:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) led_classdev_unregister(&micmute_led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) fail_led:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) dell_cleanup_rfkill();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) fail_rfkill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264) platform_device_del(platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) fail_platform_device2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) platform_device_put(platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) fail_platform_device1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) platform_driver_unregister(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) fail_platform_driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) static void __exit dell_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) dell_laptop_unregister_notifier(&dell_laptop_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276) debugfs_remove_recursive(dell_laptop_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) if (quirks && quirks->touchpad_led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) touchpad_led_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279) kbd_led_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) backlight_device_unregister(dell_backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) led_classdev_unregister(&micmute_led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282) dell_cleanup_rfkill();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283) if (platform_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284) platform_device_unregister(platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) platform_driver_unregister(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) /* dell-rbtn.c driver export functions which will not work correctly (and could
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) * cause kernel crash) if they are called before dell-rbtn.c init code. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291) * not problem when dell-rbtn.c is compiled as external module. When both files
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) * (dell-rbtn.c and dell-laptop.c) are compiled statically into kernel, then we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) * need to ensure that dell_init() will be called after initializing dell-rbtn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) * This can be achieved by late_initcall() instead module_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) late_initcall(dell_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297) module_exit(dell_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301) MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) MODULE_DESCRIPTION("Dell laptop driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) MODULE_LICENSE("GPL");