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