diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-26 13:44:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-26 13:44:46 -0700 |
commit | 78d425677217b655ed36c492a070b5002832fc73 (patch) | |
tree | a178a3bf773027f3a70ecec1ad6f9d35074e4263 | |
parent | 36a8032d77649430f5ef11fbf0df2bb026be0b04 (diff) | |
parent | 358d6a2c3ecae2b22c7d7e61f9d5672557446dfb (diff) |
Merge tag 'platform-drivers-x86-v4.1-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart:
"This series includes significant updates to the toshiba_acpi driver
and the reintroduction of the dell-laptop keyboard backlight additions
I had to revert previously. Also included are various fixes for
typos, warnings, correctness, and minor bugs.
Specifics:
dell-laptop:
- add support for keyboard backlight.
toshiba_acpi:
- adaptive keyboard, hotkey, USB sleep and charge, and backlight
updates. Update sysfs documentation.
toshiba_bluetooth:
- fix enabling/disabling loop on recent devices
apple-gmux:
- lock iGP IO to protect from vgaarb changes
other:
- Fix typos, clear gcc warnings, clarify pr_* messages, correct
return types, update MAINTAINERS"
* tag 'platform-drivers-x86-v4.1-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (25 commits)
toshiba_acpi: Do not register vendor backlight when acpi_video bl is available
MAINTAINERS: Add me on list of Dell laptop drivers
platform: x86: dell-laptop: Add support for keyboard backlight
Documentation/ABI: Update sysfs-driver-toshiba_acpi entry
toshiba_acpi: Fix pr_* messages from USB Sleep Functions
toshiba_acpi: Update and fix USB Sleep and Charge modes
wmi: Use bool function return values of true/false not 1/0
toshiba_bluetooth: Fix enabling/disabling loop on recent devices
toshiba_bluetooth: Clean up *_add function and disable BT device at removal
toshiba_bluetooth: Add three new functions to the driver
toshiba_acpi: Fix the enabling of the Special Functions
toshiba_acpi: Use the Hotkey Event Type function for keymap choosing
toshiba_acpi: Add Hotkey Event Type function and definitions
x86/wmi: delete unused wmi_data_lock mutex causing gcc warning
apple-gmux: lock iGP IO to protect from vgaarb changes
MAINTAINERS: Add missing Toshiba devices and add myself as maintainer
toshiba_acpi: Update events in toshiba_acpi_notify
intel-oaktrail: Fix trivial typo in comment
thinkpad_acpi: off by one in adaptive_keyboard_hotkey_notify_hotkey()
thinkpad_acpi: signedness bugs getting current_mode
...
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-toshiba_acpi | 93 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-dell-laptop | 69 | ||||
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 18 | ||||
-rw-r--r-- | MAINTAINERS | 22 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/apple-gmux.c | 48 | ||||
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 1089 | ||||
-rw-r--r-- | drivers/platform/x86/intel_oaktrail.c | 2 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 320 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 256 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_bluetooth.c | 133 | ||||
-rw-r--r-- | drivers/platform/x86/wmi.c | 5 |
12 files changed, 1838 insertions, 218 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi index ca9c71a531c5..eed922ef42e5 100644 --- a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi +++ b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi @@ -8,9 +8,11 @@ Description: This file controls the keyboard backlight operation mode, valid * 0x2 -> AUTO (also called TIMER) * 0x8 -> ON * 0x10 -> OFF - Note that the kernel 3.16 onwards this file accepts all listed + Note that from kernel 3.16 onwards this file accepts all listed parameters, kernel 3.15 only accepts the first two (FN-Z and AUTO). + Also note that toggling this value on type 1 devices, requires + a reboot for changes to take effect. Users: KToshiba What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_timeout @@ -67,15 +69,72 @@ Description: This file shows the current keyboard backlight type, * 2 -> Type 2, supporting modes TIMER, ON and OFF Users: KToshiba +What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_charge +Date: January 23, 2015 +KernelVersion: 4.0 +Contact: Azael Avalos <coproscefalo@gmail.com> +Description: This file controls the USB Sleep & Charge charging mode, which + can be: + * 0 -> Disabled (0x00) + * 1 -> Alternate (0x09) + * 2 -> Auto (0x21) + * 3 -> Typical (0x11) + Note that from kernel 4.1 onwards this file accepts all listed + values, kernel 4.0 only supports the first three. + Note that this feature only works when connected to power, if + you want to use it under battery, see the entry named + "sleep_functions_on_battery" +Users: KToshiba + +What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/sleep_functions_on_battery +Date: January 23, 2015 +KernelVersion: 4.0 +Contact: Azael Avalos <coproscefalo@gmail.com> +Description: This file controls the USB Sleep Functions under battery, and + set the level at which point they will be disabled, accepted + values can be: + * 0 -> Disabled + * 1-100 -> Battery level to disable sleep functions + Currently it prints two values, the first one indicates if the + feature is enabled or disabled, while the second one shows the + current battery level set. + Note that when the value is set to disabled, the sleep function + will only work when connected to power. +Users: KToshiba + +What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_rapid_charge +Date: January 23, 2015 +KernelVersion: 4.0 +Contact: Azael Avalos <coproscefalo@gmail.com> +Description: This file controls the USB Rapid Charge state, which can be: + * 0 -> Disabled + * 1 -> Enabled + Note that toggling this value requires a reboot for changes to + take effect. +Users: KToshiba + +What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_music +Date: January 23, 2015 +KernelVersion: 4.0 +Contact: Azael Avalos <coproscefalo@gmail.com> +Description: This file controls the Sleep & Music state, which values can be: + * 0 -> Disabled + * 1 -> Enabled + Note that this feature only works when connected to power, if + you want to use it under battery, see the entry named + "sleep_functions_on_battery" +Users: KToshiba + What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version -Date: February, 2015 -KernelVersion: 3.20 +Date: February 12, 2015 +KernelVersion: 4.0 Contact: Azael Avalos <coproscefalo@gmail.com> Description: This file shows the current version of the driver +Users: KToshiba What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan -Date: February, 2015 -KernelVersion: 3.20 +Date: February 12, 2015 +KernelVersion: 4.0 Contact: Azael Avalos <coproscefalo@gmail.com> Description: This file controls the state of the internal fan, valid values are: @@ -83,8 +142,8 @@ Description: This file controls the state of the internal fan, valid * 1 -> ON What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys -Date: February, 2015 -KernelVersion: 3.20 +Date: February 12, 2015 +KernelVersion: 4.0 Contact: Azael Avalos <coproscefalo@gmail.com> Description: This file controls the Special Functions (hotkeys) operation mode, valid values are: @@ -94,21 +153,29 @@ Description: This file controls the Special Functions (hotkeys) operation and the hotkeys are accessed via FN-F{1-12}. In the "Special Functions" mode, the F{1-12} keys trigger the hotkey and the F{1-12} keys are accessed via FN-F{1-12}. + Note that toggling this value requires a reboot for changes to + take effect. +Users: KToshiba What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on -Date: February, 2015 -KernelVersion: 3.20 +Date: February 12, 2015 +KernelVersion: 4.0 Contact: Azael Avalos <coproscefalo@gmail.com> Description: This file controls whether the laptop should turn ON whenever the LID is opened, valid values are: * 0 -> Disabled * 1 -> Enabled + Note that toggling this value requires a reboot for changes to + take effect. +Users: KToshiba What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three -Date: February, 2015 -KernelVersion: 3.20 +Date: February 12, 2015 +KernelVersion: 4.0 Contact: Azael Avalos <coproscefalo@gmail.com> -Description: This file controls whether the USB 3 functionality, valid - values are: +Description: This file controls the USB 3 functionality, valid values are: * 0 -> Disabled (Acts as a regular USB 2) * 1 -> Enabled (Full USB 3 functionality) + Note that toggling this value requires a reboot for changes to + take effect. +Users: KToshiba diff --git a/Documentation/ABI/testing/sysfs-platform-dell-laptop b/Documentation/ABI/testing/sysfs-platform-dell-laptop new file mode 100644 index 000000000000..8c6a0b8e1131 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-dell-laptop @@ -0,0 +1,69 @@ +What: /sys/class/leds/dell::kbd_backlight/als_enabled +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, + Pali Rohár <pali.rohar@gmail.com> +Description: + This file allows to control the automatic keyboard + illumination mode on some systems that have an ambient + light sensor. Write 1 to this file to enable the auto + mode, 0 to disable it. + +What: /sys/class/leds/dell::kbd_backlight/als_setting +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, + Pali Rohár <pali.rohar@gmail.com> +Description: + This file allows to specifiy the on/off threshold value, + as reported by the ambient light sensor. + +What: /sys/class/leds/dell::kbd_backlight/start_triggers +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, + Pali Rohár <pali.rohar@gmail.com> +Description: + This file allows to control the input triggers that + turn on the keyboard backlight illumination that is + disabled because of inactivity. + Read the file to see the triggers available. The ones + enabled are preceded by '+', those disabled by '-'. + + To enable a trigger, write its name preceded by '+' to + this file. To disable a trigger, write its name preceded + by '-' instead. + + For example, to enable the keyboard as trigger run: + echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers + To disable it: + echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers + + Note that not all the available triggers can be configured. + +What: /sys/class/leds/dell::kbd_backlight/stop_timeout +Date: December 2014 +KernelVersion: 3.19 +Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, + Pali Rohár <pali.rohar@gmail.com> +Description: + This file allows to specify the interval after which the + keyboard illumination is disabled because of inactivity. + The timeouts are expressed in seconds, minutes, hours and + days, for which the symbols are 's', 'm', 'h' and 'd' + respectively. + + To configure the timeout, write to this file a value along + with any the above units. If no unit is specified, the value + is assumed to be expressed in seconds. + + For example, to set the timeout to 10 minutes run: + echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout + + Note that when this file is read, the returned value might be + expressed in a different unit than the one used when the timeout + was set. + + Also note that only some timeouts are supported and that + some systems might fall back to a specific timeout in case + an invalid timeout is written to this file. diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index fc04c14de4bb..72a150d8f3df 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -1355,6 +1355,24 @@ Sysfs notes: rfkill controller switch "tpacpi_uwb_sw": refer to Documentation/rfkill.txt for details. +Adaptive keyboard +----------------- + +sysfs device attribute: adaptive_kbd_mode + +This sysfs attribute controls the keyboard "face" that will be shown on the +Lenovo X1 Carbon 2nd gen (2014)'s adaptive keyboard. The value can be read +and set. + +1 = Home mode +2 = Web-browser mode +3 = Web-conference mode +4 = Function mode +5 = Layflat mode + +For more details about which buttons will appear depending on the mode, please +review the laptop's user guide: +http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf Multiple Commands, Module Parameters ------------------------------------ diff --git a/MAINTAINERS b/MAINTAINERS index 62cd43e7f56f..2b38266d592a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3066,10 +3066,16 @@ F: drivers/net/fddi/defxx.* DELL LAPTOP DRIVER M: Matthew Garrett <mjg59@srcf.ucam.org> +M: Pali Rohár <pali.rohar@gmail.com> L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/dell-laptop.c +DELL LAPTOP FREEFALL DRIVER +M: Pali Rohár <pali.rohar@gmail.com> +S: Maintained +F: drivers/platform/x86/dell-smo8800.c + DELL LAPTOP SMM DRIVER M: Guenter Roeck <linux@roeck-us.net> S: Maintained @@ -3084,6 +3090,7 @@ F: drivers/firmware/dcdbas.* DELL WMI EXTRAS DRIVER M: Matthew Garrett <mjg59@srcf.ucam.org> +M: Pali Rohár <pali.rohar@gmail.com> S: Maintained F: drivers/platform/x86/dell-wmi.c @@ -9949,10 +9956,23 @@ S: Maintained F: drivers/platform/x86/topstar-laptop.c TOSHIBA ACPI EXTRAS DRIVER +M: Azael Avalos <coproscefalo@gmail.com> L: platform-driver-x86@vger.kernel.org -S: Orphan +S: Maintained F: drivers/platform/x86/toshiba_acpi.c +TOSHIBA BLUETOOTH DRIVER +M: Azael Avalos <coproscefalo@gmail.com> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/toshiba_bluetooth.c + +TOSHIBA HDD ACTIVE PROTECTION SENSOR DRIVER +M: Azael Avalos <coproscefalo@gmail.com> +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/toshiba_haps.c + TOSHIBA SMM DRIVER M: Jonathan Buzzard <jonathan@buzzard.org.uk> L: tlinux-users@tce.toshiba-dme.co.jp diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 97527614141b..f9f205cb1f11 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -614,6 +614,7 @@ config ACPI_TOSHIBA depends on INPUT depends on RFKILL || RFKILL = n depends on SERIO_I8042 || SERIO_I8042 = n + depends on ACPI_VIDEO || ACPI_VIDEO = n select INPUT_POLLDEV select INPUT_SPARSEKMAP ---help--- diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 66d6d22c239c..6808715003f6 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/vga_switcheroo.h> +#include <linux/vgaarb.h> #include <acpi/video.h> #include <asm/io.h> @@ -31,6 +32,7 @@ struct apple_gmux_data { bool indexed; struct mutex index_lock; + struct pci_dev *pdev; struct backlight_device *bdev; /* switcheroo data */ @@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev) return 0; } +static struct pci_dev *gmux_get_io_pdev(void) +{ + struct pci_dev *pdev = NULL; + + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { + u16 cmd; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_IO)) + continue; + + return pdev; + } + + return NULL; +} + static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { struct apple_gmux_data *gmux_data; @@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) int ret = -ENXIO; acpi_status status; unsigned long long gpe; + struct pci_dev *pdev = NULL; if (apple_gmux_data) return -EBUSY; @@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ver_minor = (version >> 16) & 0xff; ver_release = (version >> 8) & 0xff; } else { - pr_info("gmux device not present\n"); + pr_info("gmux device not present or IO disabled\n"); ret = -ENODEV; goto err_release; } @@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, ver_release, (gmux_data->indexed ? "indexed" : "classic")); + /* + * Apple systems with gmux are EFI based and normally don't use + * VGA. In addition changing IO+MEM ownership between IGP and dGPU + * disables IO/MEM used for backlight control on some systems. + * Lock IO+MEM to GPU with active IO to prevent switch. + */ + pdev = gmux_get_io_pdev(); + if (pdev && vga_tryget(pdev, + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) { + pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n", + pci_name(pdev)); + ret = -EBUSY; + goto err_release; + } else if (pdev) + pr_info("locked IO for PCI:%s\n", pci_name(pdev)); + gmux_data->pdev = pdev; + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); @@ -574,6 +611,10 @@ err_enable_gpe: err_notify: backlight_device_unregister(bdev); err_release: + if (gmux_data->pdev) + vga_put(gmux_data->pdev, + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); + pci_dev_put(pdev); release_region(gmux_data->iostart, gmux_data->iolen); err_free: kfree(gmux_data); @@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp) &gmux_notify_handler); } + if (gmux_data->pdev) { + vga_put(gmux_data->pdev, + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); + pci_dev_put(gmux_data->pdev); + } backlight_device_unregister(gmux_data->bdev); release_region(gmux_data->iostart, gmux_data->iolen); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 3d21efe11d7b..d688d806a8a5 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -2,9 +2,11 @@ * Driver for Dell laptop extras * * Copyright (c) Red Hat <mjg@redhat.com> + * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> + * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> * - * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell - * Inc. + * Based on documentation in the libsmbios package: + * Copyright (C) 2005-2014 Dell Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,6 +34,13 @@ #include "../../firmware/dcdbas.h" #define BRIGHTNESS_TOKEN 0x7d +#define KBD_LED_OFF_TOKEN 0x01E1 +#define KBD_LED_ON_TOKEN 0x01E2 +#define KBD_LED_AUTO_TOKEN 0x01E3 +#define KBD_LED_AUTO_25_TOKEN 0x02EA +#define KBD_LED_AUTO_50_TOKEN 0x02EB +#define KBD_LED_AUTO_75_TOKEN 0x02EC +#define KBD_LED_AUTO_100_TOKEN 0x02F6 /* This structure will be modified by the firmware when we enter * system management mode, hence the volatiles */ @@ -62,6 +71,13 @@ struct calling_interface_structure { struct quirk_entry { u8 touchpad_led; + + int needs_kbd_timeouts; + /* + * Ordered list of timeouts expressed in seconds. + * The list must end with -1 + */ + int kbd_timeouts[]; }; static struct quirk_entry *quirks; @@ -76,6 +92,15 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) return 1; } +/* + * These values come from Windows utility provided by Dell. If any other value + * is used then BIOS silently set timeout to 0 without any error message. + */ +static struct quirk_entry quirk_dell_xps13_9333 = { + .needs_kbd_timeouts = 1, + .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, +}; + static int da_command_address; static int da_command_code; static int da_num_tokens; @@ -267,6 +292,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = { }, .driver_data = &quirk_dell_vostro_v130, }, + { + .callback = dmi_matched, + .ident = "Dell XPS13 9333", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"), + }, + .driver_data = &quirk_dell_xps13_9333, + }, { } }; @@ -331,17 +365,29 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy) } } -static int find_token_location(int tokenid) +static int find_token_id(int tokenid) { int i; + for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].tokenID == tokenid) - return da_tokens[i].location; + return i; } return -1; } +static int find_token_location(int tokenid) +{ + int id; + + id = find_token_id(tokenid); + if (id == -1) + return -1; + + return da_tokens[id].location; +} + static struct calling_interface_buffer * dell_send_request(struct calling_interface_buffer *buffer, int class, int select) @@ -362,6 +408,20 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, return buffer; } +static inline int dell_smi_error(int value) +{ + switch (value) { + case 0: /* Completed successfully */ + return 0; + case -1: /* Completed with error */ + return -EIO; + case -2: /* Function not supported */ + return -ENXIO; + default: /* Unknown error */ + return -EINVAL; + } +} + /* Derived from information in DellWirelessCtl.cpp: Class 17, select 11 is radio control. It returns an array of 32-bit values. @@ -716,7 +776,7 @@ static int dell_send_intensity(struct backlight_device *bd) else dell_send_request(buffer, 1, 1); -out: + out: release_buffer(); return ret; } @@ -740,7 +800,7 @@ static int dell_get_intensity(struct backlight_device *bd) ret = buffer->output[1]; -out: + out: release_buffer(); return ret; } @@ -789,6 +849,1018 @@ static void touchpad_led_exit(void) led_classdev_unregister(&touchpad_led); } +/* + * Derived from information in smbios-keyboard-ctl: + * + * cbClass 4 + * cbSelect 11 + * Keyboard illumination + * cbArg1 determines the function to be performed + * + * cbArg1 0x0 = Get Feature Information + * cbRES1 Standard return codes (0, -1, -2) + * cbRES2, word0 Bitmap of user-selectable modes + * bit 0 Always off (All systems) + * bit 1 Always on (Travis ATG, Siberia) + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off + * bit 4 Auto: Input-activity-based On; input-activity based Off + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off + * bits 9-15 Reserved for future use + * cbRES2, byte2 Reserved for future use + * cbRES2, byte3 Keyboard illumination type + * 0 Reserved + * 1 Tasklight + * 2 Backlight + * 3-255 Reserved for future use + * cbRES3, byte0 Supported auto keyboard illumination trigger bitmap. + * bit 0 Any keystroke + * bit 1 Touchpad activity + * bit 2 Pointing stick + * bit 3 Any mouse + * bits 4-7 Reserved for future use + * cbRES3, byte1 Supported timeout unit bitmap + * bit 0 Seconds + * bit 1 Minutes + * bit 2 Hours + * bit 3 Days + * bits 4-7 Reserved for future use + * cbRES3, byte2 Number of keyboard light brightness levels + * cbRES4, byte0 Maximum acceptable seconds value (0 if seconds not supported). + * cbRES4, byte1 Maximum acceptable minutes value (0 if minutes not supported). + * cbRES4, byte2 Maximum acceptable hours value (0 if hours not supported). + * cbRES4, byte3 Maximum acceptable days value (0 if days not supported) + * + * cbArg1 0x1 = Get Current State + * cbRES1 Standard return codes (0, -1, -2) + * cbRES2, word0 Bitmap of current mode state + * bit 0 Always off (All systems) + * bit 1 Always on (Travis ATG, Siberia) + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off + * bit 4 Auto: Input-activity-based On; input-activity based Off + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off + * bits 9-15 Reserved for future use + * Note: Only One bit can be set + * cbRES2, byte2 Currently active auto keyboard illumination triggers. + * bit 0 Any keystroke + * bit 1 Touchpad activity + * bit 2 Pointing stick + * bit 3 Any mouse + * bits 4-7 Reserved for future use + * cbRES2, byte3 Current Timeout + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * bits 5:0 Timeout value (0-63) in sec/min/hr/day + * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte + * are set upon return from the [Get feature information] call. + * cbRES3, byte0 Current setting of ALS value that turns the light on or off. + * cbRES3, byte1 Current ALS reading + * cbRES3, byte2 Current keyboard light level. + * + * cbArg1 0x2 = Set New State + * cbRES1 Standard return codes (0, -1, -2) + * cbArg2, word0 Bitmap of current mode state + * bit 0 Always off (All systems) + * bit 1 Always on (Travis ATG, Siberia) + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off + * bit 4 Auto: Input-activity-based On; input-activity based Off + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off + * bits 9-15 Reserved for future use + * Note: Only One bit can be set + * cbArg2, byte2 Desired auto keyboard illumination triggers. Must remain inactive to allow + * keyboard to turn off automatically. + * bit 0 Any keystroke + * bit 1 Touchpad activity + * bit 2 Pointing stick + * bit 3 Any mouse + * bits 4-7 Reserved for future use + * cbArg2, byte3 Desired Timeout + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * bits 5:0 Timeout value (0-63) in sec/min/hr/day + * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. + * cbArg3, byte2 Desired keyboard light level. + */ + + +enum kbd_timeout_unit { + KBD_TIMEOUT_SECONDS = 0, + KBD_TIMEOUT_MINUTES, + KBD_TIMEOUT_HOURS, + KBD_TIMEOUT_DAYS, +}; + +enum kbd_mode_bit { + KBD_MODE_BIT_OFF = 0, + KBD_MODE_BIT_ON, + KBD_MODE_BIT_ALS, + KBD_MODE_BIT_TRIGGER_ALS, + KBD_MODE_BIT_TRIGGER, + KBD_MODE_BIT_TRIGGER_25, + KBD_MODE_BIT_TRIGGER_50, + KBD_MODE_BIT_TRIGGER_75, + KBD_MODE_BIT_TRIGGER_100, +}; + +#define kbd_is_als_mode_bit(bit) \ + ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS) +#define kbd_is_trigger_mode_bit(bit) \ + ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100) +#define kbd_is_level_mode_bit(bit) \ + ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100) + +struct kbd_info { + u16 modes; + u8 type; + u8 triggers; + u8 levels; + u8 seconds; + u8 minutes; + u8 hours; + u8 days; +}; + +struct kbd_state { + u8 mode_bit; + u8 triggers; + u8 timeout_value; + u8 timeout_unit; + u8 als_setting; + u8 als_value; + u8 level; +}; + +static const int kbd_tokens[] = { + KBD_LED_OFF_TOKEN, + KBD_LED_AUTO_25_TOKEN, + KBD_LED_AUTO_50_TOKEN, + KBD_LED_AUTO_75_TOKEN, + KBD_LED_AUTO_100_TOKEN, + KBD_LED_ON_TOKEN, +}; + +static u16 kbd_token_bits; + +static struct kbd_info kbd_info; +static bool kbd_als_supported; +static bool kbd_triggers_supported; + +static u8 kbd_mode_levels[16]; +static int kbd_mode_levels_count; + +static u8 kbd_previous_level; +static u8 kbd_previous_mode_bit; + +static bool kbd_led_present; + +/* + * NOTE: there are three ways to set the keyboard backlight level. + * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value). + * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels). + * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens) + * + * There are laptops which support only one of these methods. If we want to + * support as many machines as possible we need to implement all three methods. + * The first two methods use the kbd_state structure. The third uses SMBIOS + * tokens. If kbd_info.levels == 0, the machine does not support setting the + * keyboard backlight level via kbd_state.level. + */ + +static int kbd_get_info(struct kbd_info *info) +{ + u8 units; + int ret; + + get_buffer(); + + buffer->input[0] = 0x0; + dell_send_request(buffer, 4, 11); + ret = buffer->output[0]; + + if (ret) { + ret = dell_smi_error(ret); + goto out; + } + + info->modes = buffer->output[1] & 0xFFFF; + info->type = (buffer->output[1] >> 24) & 0xFF; + info->triggers = buffer->output[2] & 0xFF; + units = (buffer->output[2] >> 8) & 0xFF; + info->levels = (buffer->output[2] >> 16) & 0xFF; + + if (units & BIT(0)) + info->seconds = (buffer->output[3] >> 0) & 0xFF; + if (units & BIT(1)) + info->minutes = (buffer->output[3] >> 8) & 0xFF; + if (units & BIT(2)) + info->hours = (buffer->output[3] >> 16) & 0xFF; + if (units & BIT(3)) + info->days = (buffer->output[3] >> 24) & 0xFF; + + out: + release_buffer(); + return ret; +} + +static unsigned int kbd_get_max_level(void) +{ + if (kbd_info.levels != 0) + return kbd_info.levels; + if (kbd_mode_levels_count > 0) + return kbd_mode_levels_count - 1; + return 0; +} + +static int kbd_get_level(struct kbd_state *state) +{ + int i; + + if (kbd_info.levels != 0) + return state->level; + + if (kbd_mode_levels_count > 0) { + for (i = 0; i < kbd_mode_levels_count; ++i) + if (kbd_mode_levels[i] == state->mode_bit) + return i; + return 0; + } + + return -EINVAL; +} + +static int kbd_set_level(struct kbd_state *state, u8 level) +{ + if (kbd_info.levels != 0) { + if (level != 0) + kbd_previous_level = level; + if (state->level == level) + return 0; + state->level = level; + if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF) + state->mode_bit = kbd_previous_mode_bit; + else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) { + kbd_previous_mode_bit = state->mode_bit; + state->mode_bit = KBD_MODE_BIT_OFF; + } + return 0; + } + + if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) { + if (level != 0) + kbd_previous_level = level; + state->mode_bit = kbd_mode_levels[level]; + return 0; + } + + return -EINVAL; +} + +static int kbd_get_state(struct kbd_state *state) +{ + int ret; + + get_buffer(); + + buffer->input[0] = 0x1; + dell_send_request(buffer, 4, 11); + ret = buffer->output[0]; + + if (ret) { + ret = dell_smi_error(ret); + goto out; + } + + state->mode_bit = ffs(buffer->output[1] & 0xFFFF); + if (state->mode_bit != 0) + state->mode_bit--; + + state->triggers = (buffer->output[1] >> 16) & 0xFF; + state->timeout_value = (buffer->output[1] >> 24) & 0x3F; + state->timeout_unit = (buffer->output[1] >> 30) & 0x3; + state->als_setting = buffer->output[2] & 0xFF; + state->als_value = (buffer->output[2] >> 8) & 0xFF; + state->level = (buffer->output[2] >> 16) & 0xFF; + + out: + release_buffer(); + return ret; +} + +static int kbd_set_state(struct kbd_state *state) +{ + int ret; + + get_buffer(); + buffer->input[0] = 0x2; + buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; + buffer->input[1] |= (state->triggers & 0xFF) << 16; + buffer->input[1] |= (state->timeout_value & 0x3F) << 24; + buffer->input[1] |= (state->timeout_unit & 0x3) << 30; + buffer->input[2] = state->als_setting & 0xFF; + buffer->input[2] |= (state->level & 0xFF) << 16; + dell_send_request(buffer, 4, 11); + ret = buffer->output[0]; + release_buffer(); + + return dell_smi_error(ret); +} + +static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) +{ + int ret; + + ret = kbd_set_state(state); + if (ret == 0) + return 0; + + /* + * When setting the new state fails,try to restore the previous one. + * This is needed on some machines where BIOS sets a default state when + * setting a new state fails. This default state could be all off. + */ + + if (kbd_set_state(old)) + pr_err("Setting old previous keyboard state failed\n"); + + return ret; +} + +static int kbd_set_token_bit(u8 bit) +{ + int id; |