diff options
| -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 | |||
| 8 | * 0x2 -> AUTO (also called TIMER) | 8 | * 0x2 -> AUTO (also called TIMER) |
| 9 | * 0x8 -> ON | 9 | * 0x8 -> ON |
| 10 | * 0x10 -> OFF | 10 | * 0x10 -> OFF |
| 11 | Note that the kernel 3.16 onwards this file accepts all listed | 11 | Note that from kernel 3.16 onwards this file accepts all listed |
| 12 | parameters, kernel 3.15 only accepts the first two (FN-Z and | 12 | parameters, kernel 3.15 only accepts the first two (FN-Z and |
| 13 | AUTO). | 13 | AUTO). |
| 14 | Also note that toggling this value on type 1 devices, requires | ||
| 15 | a reboot for changes to take effect. | ||
| 14 | Users: KToshiba | 16 | Users: KToshiba |
| 15 | 17 | ||
| 16 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_timeout | 18 | 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, | |||
| 67 | * 2 -> Type 2, supporting modes TIMER, ON and OFF | 69 | * 2 -> Type 2, supporting modes TIMER, ON and OFF |
| 68 | Users: KToshiba | 70 | Users: KToshiba |
| 69 | 71 | ||
| 72 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_charge | ||
| 73 | Date: January 23, 2015 | ||
| 74 | KernelVersion: 4.0 | ||
| 75 | Contact: Azael Avalos <coproscefalo@gmail.com> | ||
| 76 | Description: This file controls the USB Sleep & Charge charging mode, which | ||
| 77 | can be: | ||
| 78 | * 0 -> Disabled (0x00) | ||
| 79 | * 1 -> Alternate (0x09) | ||
| 80 | * 2 -> Auto (0x21) | ||
| 81 | * 3 -> Typical (0x11) | ||
| 82 | Note that from kernel 4.1 onwards this file accepts all listed | ||
| 83 | values, kernel 4.0 only supports the first three. | ||
| 84 | Note that this feature only works when connected to power, if | ||
| 85 | you want to use it under battery, see the entry named | ||
| 86 | "sleep_functions_on_battery" | ||
| 87 | Users: KToshiba | ||
| 88 | |||
| 89 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/sleep_functions_on_battery | ||
| 90 | Date: January 23, 2015 | ||
| 91 | KernelVersion: 4.0 | ||
| 92 | Contact: Azael Avalos <coproscefalo@gmail.com> | ||
| 93 | Description: This file controls the USB Sleep Functions under battery, and | ||
| 94 | set the level at which point they will be disabled, accepted | ||
| 95 | values can be: | ||
| 96 | * 0 -> Disabled | ||
| 97 | * 1-100 -> Battery level to disable sleep functions | ||
| 98 | Currently it prints two values, the first one indicates if the | ||
| 99 | feature is enabled or disabled, while the second one shows the | ||
| 100 | current battery level set. | ||
| 101 | Note that when the value is set to disabled, the sleep function | ||
| 102 | will only work when connected to power. | ||
| 103 | Users: KToshiba | ||
| 104 | |||
| 105 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_rapid_charge | ||
| 106 | Date: January 23, 2015 | ||
| 107 | KernelVersion: 4.0 | ||
| 108 | Contact: Azael Avalos <coproscefalo@gmail.com> | ||
| 109 | Description: This file controls the USB Rapid Charge state, which can be: | ||
| 110 | * 0 -> Disabled | ||
| 111 | * 1 -> Enabled | ||
| 112 | Note that toggling this value requires a reboot for changes to | ||
| 113 | take effect. | ||
| 114 | Users: KToshiba | ||
| 115 | |||
| 116 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_music | ||
| 117 | Date: January 23, 2015 | ||
| 118 | KernelVersion: 4.0 | ||
| 119 | Contact: Azael Avalos <coproscefalo@gmail.com> | ||
| 120 | Description: This file controls the Sleep & Music state, which values can be: | ||
| 121 | * 0 -> Disabled | ||
| 122 | * 1 -> Enabled | ||
| 123 | Note that this feature only works when connected to power, if | ||
| 124 | you want to use it under battery, see the entry named | ||
| 125 | "sleep_functions_on_battery" | ||
| 126 | Users: KToshiba | ||
| 127 | |||
| 70 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version | 128 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version |
| 71 | Date: February, 2015 | 129 | Date: February 12, 2015 |
| 72 | KernelVersion: 3.20 | 130 | KernelVersion: 4.0 |
| 73 | Contact: Azael Avalos <coproscefalo@gmail.com> | 131 | Contact: Azael Avalos <coproscefalo@gmail.com> |
| 74 | Description: This file shows the current version of the driver | 132 | Description: This file shows the current version of the driver |
| 133 | Users: KToshiba | ||
| 75 | 134 | ||
| 76 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan | 135 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan |
| 77 | Date: February, 2015 | 136 | Date: February 12, 2015 |
| 78 | KernelVersion: 3.20 | 137 | KernelVersion: 4.0 |
| 79 | Contact: Azael Avalos <coproscefalo@gmail.com> | 138 | Contact: Azael Avalos <coproscefalo@gmail.com> |
| 80 | Description: This file controls the state of the internal fan, valid | 139 | Description: This file controls the state of the internal fan, valid |
| 81 | values are: | 140 | values are: |
| @@ -83,8 +142,8 @@ Description: This file controls the state of the internal fan, valid | |||
| 83 | * 1 -> ON | 142 | * 1 -> ON |
| 84 | 143 | ||
| 85 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys | 144 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys |
| 86 | Date: February, 2015 | 145 | Date: February 12, 2015 |
| 87 | KernelVersion: 3.20 | 146 | KernelVersion: 4.0 |
| 88 | Contact: Azael Avalos <coproscefalo@gmail.com> | 147 | Contact: Azael Avalos <coproscefalo@gmail.com> |
| 89 | Description: This file controls the Special Functions (hotkeys) operation | 148 | Description: This file controls the Special Functions (hotkeys) operation |
| 90 | mode, valid values are: | 149 | mode, valid values are: |
| @@ -94,21 +153,29 @@ Description: This file controls the Special Functions (hotkeys) operation | |||
| 94 | and the hotkeys are accessed via FN-F{1-12}. | 153 | and the hotkeys are accessed via FN-F{1-12}. |
| 95 | In the "Special Functions" mode, the F{1-12} keys trigger the | 154 | In the "Special Functions" mode, the F{1-12} keys trigger the |
| 96 | hotkey and the F{1-12} keys are accessed via FN-F{1-12}. | 155 | hotkey and the F{1-12} keys are accessed via FN-F{1-12}. |
| 156 | Note that toggling this value requires a reboot for changes to | ||
| 157 | take effect. | ||
| 158 | Users: KToshiba | ||
| 97 | 159 | ||
| 98 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on | 160 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on |
| 99 | Date: February, 2015 | 161 | Date: February 12, 2015 |
| 100 | KernelVersion: 3.20 | 162 | KernelVersion: 4.0 |
| 101 | Contact: Azael Avalos <coproscefalo@gmail.com> | 163 | Contact: Azael Avalos <coproscefalo@gmail.com> |
| 102 | Description: This file controls whether the laptop should turn ON whenever | 164 | Description: This file controls whether the laptop should turn ON whenever |
| 103 | the LID is opened, valid values are: | 165 | the LID is opened, valid values are: |
| 104 | * 0 -> Disabled | 166 | * 0 -> Disabled |
| 105 | * 1 -> Enabled | 167 | * 1 -> Enabled |
| 168 | Note that toggling this value requires a reboot for changes to | ||
| 169 | take effect. | ||
| 170 | Users: KToshiba | ||
| 106 | 171 | ||
| 107 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three | 172 | What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three |
| 108 | Date: February, 2015 | 173 | Date: February 12, 2015 |
| 109 | KernelVersion: 3.20 | 174 | KernelVersion: 4.0 |
| 110 | Contact: Azael Avalos <coproscefalo@gmail.com> | 175 | Contact: Azael Avalos <coproscefalo@gmail.com> |
| 111 | Description: This file controls whether the USB 3 functionality, valid | 176 | Description: This file controls the USB 3 functionality, valid values are: |
| 112 | values are: | ||
| 113 | * 0 -> Disabled (Acts as a regular USB 2) | 177 | * 0 -> Disabled (Acts as a regular USB 2) |
| 114 | * 1 -> Enabled (Full USB 3 functionality) | 178 | * 1 -> Enabled (Full USB 3 functionality) |
| 179 | Note that toggling this value requires a reboot for changes to | ||
| 180 | take effect. | ||
| 181 | 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 @@ | |||
| 1 | What: /sys/class/leds/dell::kbd_backlight/als_enabled | ||
| 2 | Date: December 2014 | ||
| 3 | KernelVersion: 3.19 | ||
| 4 | Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, | ||
| 5 | Pali Rohár <pali.rohar@gmail.com> | ||
| 6 | Description: | ||
| 7 | This file allows to control the automatic keyboard | ||
| 8 | illumination mode on some systems that have an ambient | ||
| 9 | light sensor. Write 1 to this file to enable the auto | ||
| 10 | mode, 0 to disable it. | ||
| 11 | |||
| 12 | What: /sys/class/leds/dell::kbd_backlight/als_setting | ||
| 13 | Date: December 2014 | ||
| 14 | KernelVersion: 3.19 | ||
| 15 | Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, | ||
| 16 | Pali Rohár <pali.rohar@gmail.com> | ||
| 17 | Description: | ||
| 18 | This file allows to specifiy the on/off threshold value, | ||
| 19 | as reported by the ambient light sensor. | ||
| 20 | |||
| 21 | What: /sys/class/leds/dell::kbd_backlight/start_triggers | ||
| 22 | Date: December 2014 | ||
| 23 | KernelVersion: 3.19 | ||
| 24 | Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, | ||
| 25 | Pali Rohár <pali.rohar@gmail.com> | ||
| 26 | Description: | ||
| 27 | This file allows to control the input triggers that | ||
| 28 | turn on the keyboard backlight illumination that is | ||
| 29 | disabled because of inactivity. | ||
| 30 | Read the file to see the triggers available. The ones | ||
| 31 | enabled are preceded by '+', those disabled by '-'. | ||
| 32 | |||
| 33 | To enable a trigger, write its name preceded by '+' to | ||
| 34 | this file. To disable a trigger, write its name preceded | ||
| 35 | by '-' instead. | ||
| 36 | |||
| 37 | For example, to enable the keyboard as trigger run: | ||
| 38 | echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers | ||
| 39 | To disable it: | ||
| 40 | echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers | ||
| 41 | |||
| 42 | Note that not all the available triggers can be configured. | ||
| 43 | |||
| 44 | What: /sys/class/leds/dell::kbd_backlight/stop_timeout | ||
| 45 | Date: December 2014 | ||
| 46 | KernelVersion: 3.19 | ||
| 47 | Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, | ||
| 48 | Pali Rohár <pali.rohar@gmail.com> | ||
| 49 | Description: | ||
| 50 | This file allows to specify the interval after which the | ||
| 51 | keyboard illumination is disabled because of inactivity. | ||
| 52 | The timeouts are expressed in seconds, minutes, hours and | ||
| 53 | days, for which the symbols are 's', 'm', 'h' and 'd' | ||
| 54 | respectively. | ||
| 55 | |||
| 56 | To configure the timeout, write to this file a value along | ||
| 57 | with any the above units. If no unit is specified, the value | ||
| 58 | is assumed to be expressed in seconds. | ||
| 59 | |||
| 60 | For example, to set the timeout to 10 minutes run: | ||
| 61 | echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout | ||
| 62 | |||
| 63 | Note that when this file is read, the returned value might be | ||
| 64 | expressed in a different unit than the one used when the timeout | ||
| 65 | was set. | ||
| 66 | |||
| 67 | Also note that only some timeouts are supported and that | ||
| 68 | some systems might fall back to a specific timeout in case | ||
| 69 | 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: | |||
| 1355 | rfkill controller switch "tpacpi_uwb_sw": refer to | 1355 | rfkill controller switch "tpacpi_uwb_sw": refer to |
| 1356 | Documentation/rfkill.txt for details. | 1356 | Documentation/rfkill.txt for details. |
| 1357 | 1357 | ||
| 1358 | Adaptive keyboard | ||
| 1359 | ----------------- | ||
| 1360 | |||
| 1361 | sysfs device attribute: adaptive_kbd_mode | ||
| 1362 | |||
| 1363 | This sysfs attribute controls the keyboard "face" that will be shown on the | ||
| 1364 | Lenovo X1 Carbon 2nd gen (2014)'s adaptive keyboard. The value can be read | ||
| 1365 | and set. | ||
| 1366 | |||
| 1367 | 1 = Home mode | ||
| 1368 | 2 = Web-browser mode | ||
| 1369 | 3 = Web-conference mode | ||
| 1370 | 4 = Function mode | ||
| 1371 | 5 = Layflat mode | ||
| 1372 | |||
| 1373 | For more details about which buttons will appear depending on the mode, please | ||
| 1374 | review the laptop's user guide: | ||
| 1375 | http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf | ||
| 1358 | 1376 | ||
| 1359 | Multiple Commands, Module Parameters | 1377 | Multiple Commands, Module Parameters |
| 1360 | ------------------------------------ | 1378 | ------------------------------------ |
diff --git a/MAINTAINERS b/MAINTAINERS index 62cd43e7f56f..2b38266d592a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -3066,10 +3066,16 @@ F: drivers/net/fddi/defxx.* | |||
| 3066 | 3066 | ||
| 3067 | DELL LAPTOP DRIVER | 3067 | DELL LAPTOP DRIVER |
| 3068 | M: Matthew Garrett <mjg59@srcf.ucam.org> | 3068 | M: Matthew Garrett <mjg59@srcf.ucam.org> |
| 3069 | M: Pali Rohár <pali.rohar@gmail.com> | ||
| 3069 | L: platform-driver-x86@vger.kernel.org | 3070 | L: platform-driver-x86@vger.kernel.org |
| 3070 | S: Maintained | 3071 | S: Maintained |
| 3071 | F: drivers/platform/x86/dell-laptop.c | 3072 | F: drivers/platform/x86/dell-laptop.c |
| 3072 | 3073 | ||
| 3074 | DELL LAPTOP FREEFALL DRIVER | ||
| 3075 | M: Pali Rohár <pali.rohar@gmail.com> | ||
| 3076 | S: Maintained | ||
| 3077 | F: drivers/platform/x86/dell-smo8800.c | ||
| 3078 | |||
| 3073 | DELL LAPTOP SMM DRIVER | 3079 | DELL LAPTOP SMM DRIVER |
| 3074 | M: Guenter Roeck <linux@roeck-us.net> | 3080 | M: Guenter Roeck <linux@roeck-us.net> |
| 3075 | S: Maintained | 3081 | S: Maintained |
| @@ -3084,6 +3090,7 @@ F: drivers/firmware/dcdbas.* | |||
| 3084 | 3090 | ||
| 3085 | DELL WMI EXTRAS DRIVER | 3091 | DELL WMI EXTRAS DRIVER |
| 3086 | M: Matthew Garrett <mjg59@srcf.ucam.org> | 3092 | M: Matthew Garrett <mjg59@srcf.ucam.org> |
| 3093 | M: Pali Rohár <pali.rohar@gmail.com> | ||
| 3087 | S: Maintained | 3094 | S: Maintained |
| 3088 | F: drivers/platform/x86/dell-wmi.c | 3095 | F: drivers/platform/x86/dell-wmi.c |
| 3089 | 3096 | ||
| @@ -9949,10 +9956,23 @@ S: Maintained | |||
| 9949 | F: drivers/platform/x86/topstar-laptop.c | 9956 | F: drivers/platform/x86/topstar-laptop.c |
| 9950 | 9957 | ||
| 9951 | TOSHIBA ACPI EXTRAS DRIVER | 9958 | TOSHIBA ACPI EXTRAS DRIVER |
| 9959 | M: Azael Avalos <coproscefalo@gmail.com> | ||
| 9952 | L: platform-driver-x86@vger.kernel.org | 9960 | L: platform-driver-x86@vger.kernel.org |
| 9953 | S: Orphan | 9961 | S: Maintained |
| 9954 | F: drivers/platform/x86/toshiba_acpi.c | 9962 | F: drivers/platform/x86/toshiba_acpi.c |
| 9955 | 9963 | ||
| 9964 | TOSHIBA BLUETOOTH DRIVER | ||
| 9965 | M: Azael Avalos <coproscefalo@gmail.com> | ||
| 9966 | L: platform-driver-x86@vger.kernel.org | ||
| 9967 | S: Maintained | ||
| 9968 | F: drivers/platform/x86/toshiba_bluetooth.c | ||
| 9969 | |||
| 9970 | TOSHIBA HDD ACTIVE PROTECTION SENSOR DRIVER | ||
| 9971 | M: Azael Avalos <coproscefalo@gmail.com> | ||
| 9972 | L: platform-driver-x86@vger.kernel.org | ||
| 9973 | S: Maintained | ||
| 9974 | F: drivers/platform/x86/toshiba_haps.c | ||
| 9975 | |||
| 9956 | TOSHIBA SMM DRIVER | 9976 | TOSHIBA SMM DRIVER |
| 9957 | M: Jonathan Buzzard <jonathan@buzzard.org.uk> | 9977 | M: Jonathan Buzzard <jonathan@buzzard.org.uk> |
| 9958 | L: tlinux-users@tce.toshiba-dme.co.jp | 9978 | 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 | |||
| 614 | depends on INPUT | 614 | depends on INPUT |
| 615 | depends on RFKILL || RFKILL = n | 615 | depends on RFKILL || RFKILL = n |
| 616 | depends on SERIO_I8042 || SERIO_I8042 = n | 616 | depends on SERIO_I8042 || SERIO_I8042 = n |
| 617 | depends on ACPI_VIDEO || ACPI_VIDEO = n | ||
| 617 | select INPUT_POLLDEV | 618 | select INPUT_POLLDEV |
| 618 | select INPUT_SPARSEKMAP | 619 | select INPUT_SPARSEKMAP |
| 619 | ---help--- | 620 | ---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 @@ | |||
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
| 24 | #include <linux/vga_switcheroo.h> | 24 | #include <linux/vga_switcheroo.h> |
| 25 | #include <linux/vgaarb.h> | ||
| 25 | #include <acpi/video.h> | 26 | #include <acpi/video.h> |
| 26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| 27 | 28 | ||
| @@ -31,6 +32,7 @@ struct apple_gmux_data { | |||
| 31 | bool indexed; | 32 | bool indexed; |
| 32 | struct mutex index_lock; | 33 | struct mutex index_lock; |
| 33 | 34 | ||
| 35 | struct pci_dev *pdev; | ||
| 34 | struct backlight_device *bdev; | 36 | struct backlight_device *bdev; |
| 35 | 37 | ||
| 36 | /* switcheroo data */ | 38 | /* switcheroo data */ |
| @@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev) | |||
| 415 | return 0; | 417 | return 0; |
| 416 | } | 418 | } |
| 417 | 419 | ||
| 420 | static struct pci_dev *gmux_get_io_pdev(void) | ||
| 421 | { | ||
| 422 | struct pci_dev *pdev = NULL; | ||
| 423 | |||
| 424 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { | ||
| 425 | u16 cmd; | ||
| 426 | |||
| 427 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | ||
| 428 | if (!(cmd & PCI_COMMAND_IO)) | ||
| 429 | continue; | ||
| 430 | |||
| 431 | return pdev; | ||
| 432 | } | ||
| 433 | |||
| 434 | return NULL; | ||
| 435 | } | ||
| 436 | |||
| 418 | static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | 437 | static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) |
| 419 | { | 438 | { |
| 420 | struct apple_gmux_data *gmux_data; | 439 | struct apple_gmux_data *gmux_data; |
| @@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
| 425 | int ret = -ENXIO; | 444 | int ret = -ENXIO; |
| 426 | acpi_status status; | 445 | acpi_status status; |
| 427 | unsigned long long gpe; | 446 | unsigned long long gpe; |
| 447 | struct pci_dev *pdev = NULL; | ||
| 428 | 448 | ||
| 429 | if (apple_gmux_data) | 449 | if (apple_gmux_data) |
| 430 | return -EBUSY; | 450 | return -EBUSY; |
| @@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
| 475 | ver_minor = (version >> 16) & 0xff; | 495 | ver_minor = (version >> 16) & 0xff; |
| 476 | ver_release = (version >> 8) & 0xff; | 496 | ver_release = (version >> 8) & 0xff; |
| 477 | } else { | 497 | } else { |
| 478 | pr_info("gmux device not present\n"); | 498 | pr_info("gmux device not present or IO disabled\n"); |
| 479 | ret = -ENODEV; | 499 | ret = -ENODEV; |
| 480 | goto err_release; | 500 | goto err_release; |
| 481 | } | 501 | } |
| @@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
| 483 | pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, | 503 | pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, |
| 484 | ver_release, (gmux_data->indexed ? "indexed" : "classic")); | 504 | ver_release, (gmux_data->indexed ? "indexed" : "classic")); |
| 485 | 505 | ||
| 506 | /* | ||
| 507 | * Apple systems with gmux are EFI based and normally don't use | ||
| 508 | * VGA. In addition changing IO+MEM ownership between IGP and dGPU | ||
| 509 | * disables IO/MEM used for backlight control on some systems. | ||
| 510 | * Lock IO+MEM to GPU with active IO to prevent switch. | ||
| 511 | */ | ||
| 512 | pdev = gmux_get_io_pdev(); | ||
| 513 | if (pdev && vga_tryget(pdev, | ||
| 514 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) { | ||
| 515 | pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n", | ||
| 516 | pci_name(pdev)); | ||
| 517 | ret = -EBUSY; | ||
| 518 | goto err_release; | ||
| 519 | } else if (pdev) | ||
| 520 | pr_info("locked IO for PCI:%s\n", pci_name(pdev)); | ||
| 521 | gmux_data->pdev = pdev; | ||
| 522 | |||
| 486 | memset(&props, 0, sizeof(props)); | 523 | memset(&props, 0, sizeof(props)); |
| 487 | props.type = BACKLIGHT_PLATFORM; | 524 | props.type = BACKLIGHT_PLATFORM; |
| 488 | props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); | 525 | props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); |
| @@ -574,6 +611,10 @@ err_enable_gpe: | |||
| 574 | err_notify: | 611 | err_notify: |
| 575 | backlight_device_unregister(bdev); | 612 | backlight_device_unregister(bdev); |
| 576 | err_release: | 613 | err_release: |
| 614 | if (gmux_data->pdev) | ||
| 615 | vga_put(gmux_data->pdev, | ||
| 616 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); | ||
| 617 | pci_dev_put(pdev); | ||
| 577 | release_region(gmux_data->iostart, gmux_data->iolen); | 618 | release_region(gmux_data->iostart, gmux_data->iolen); |
| 578 | err_free: | 619 | err_free: |
| 579 | kfree(gmux_data); | 620 | kfree(gmux_data); |
| @@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp) | |||
| 593 | &gmux_notify_handler); | 634 | &gmux_notify_handler); |
| 594 | } | 635 | } |
| 595 | 636 | ||
| 637 | if (gmux_data->pdev) { | ||
| 638 | vga_put(gmux_data->pdev, | ||
| 639 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); | ||
| 640 | pci_dev_put(gmux_data->pdev); | ||
| 641 | } | ||
| 596 | backlight_device_unregister(gmux_data->bdev); | 642 | backlight_device_unregister(gmux_data->bdev); |
| 597 | 643 | ||
| 598 | release_region(gmux_data->iostart, gmux_data->iolen); | 644 | 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 @@ | |||
| 2 | * Driver for Dell laptop extras | 2 | * Driver for Dell laptop extras |
| 3 | * | 3 | * |
| 4 | * Copyright (c) Red Hat <mjg@redhat.com> | 4 | * Copyright (c) Red Hat <mjg@redhat.com> |
| 5 | * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> | ||
| 6 | * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> | ||
| 5 | * | 7 | * |
| 6 | * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell | 8 | * Based on documentation in the libsmbios package: |
| 7 | * Inc. | 9 | * Copyright (C) 2005-2014 Dell Inc. |
| 8 | * | 10 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
| @@ -32,6 +34,13 @@ | |||
| 32 | #include "../../firmware/dcdbas.h" | 34 | #include "../../firmware/dcdbas.h" |
| 33 | 35 | ||
| 34 | #define BRIGHTNESS_TOKEN 0x7d | 36 | #define BRIGHTNESS_TOKEN 0x7d |
| 37 | #define KBD_LED_OFF_TOKEN 0x01E1 | ||
| 38 | #define KBD_LED_ON_TOKEN 0x01E2 | ||
| 39 | #define KBD_LED_AUTO_TOKEN 0x01E3 | ||
| 40 | #define KBD_LED_AUTO_25_TOKEN 0x02EA | ||
| 41 | #define KBD_LED_AUTO_50_TOKEN 0x02EB | ||
| 42 | #define KBD_LED_AUTO_75_TOKEN 0x02EC | ||
| 43 | #define KBD_LED_AUTO_100_TOKEN 0x02F6 | ||
| 35 | 44 | ||
| 36 | /* This structure will be modified by the firmware when we enter | 45 | /* This structure will be modified by the firmware when we enter |
| 37 | * system management mode, hence the volatiles */ | 46 | * system management mode, hence the volatiles */ |
| @@ -62,6 +71,13 @@ struct calling_interface_structure { | |||
| 62 | 71 | ||
| 63 | struct quirk_entry { | 72 | struct quirk_entry { |
| 64 | u8 touchpad_led; | 73 | u8 touchpad_led; |
| 74 | |||
| 75 | int needs_kbd_timeouts; | ||
| 76 | /* | ||
| 77 | * Ordered list of timeouts expressed in seconds. | ||
| 78 | * The list must end with -1 | ||
| 79 | */ | ||
| 80 | int kbd_timeouts[]; | ||
| 65 | }; | 81 | }; |
| 66 | 82 | ||
| 67 | static struct quirk_entry *quirks; | 83 | static struct quirk_entry *quirks; |
| @@ -76,6 +92,15 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) | |||
| 76 | return 1; | 92 | return 1; |
| 77 | } | 93 | } |
| 78 | 94 | ||
| 95 | /* | ||
| 96 | * These values come from Windows utility provided by Dell. If any other value | ||
| 97 | * is used then BIOS silently set timeout to 0 without any error message. | ||
| 98 | */ | ||
| 99 | static struct quirk_entry quirk_dell_xps13_9333 = { | ||
| 100 | .needs_kbd_timeouts = 1, | ||
| 101 | .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, | ||
| 102 | }; | ||
| 103 | |||
| 79 | static int da_command_address; | 104 | static int da_command_address; |
| 80 | static int da_command_code; | 105 | static int da_command_code; |
| 81 | static int da_num_tokens; | 106 | static int da_num_tokens; |
| @@ -267,6 +292,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = { | |||
| 267 | }, | 292 | }, |
| 268 | .driver_data = &quirk_dell_vostro_v130, | 293 | .driver_data = &quirk_dell_vostro_v130, |
| 269 | }, | 294 | }, |
| 295 | { | ||
| 296 | .callback = dmi_matched, | ||
| 297 | .ident = "Dell XPS13 9333", | ||
| 298 | .matches = { | ||
| 299 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 300 | DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"), | ||
| 301 | }, | ||
| 302 | .driver_data = &quirk_dell_xps13_9333, | ||
| 303 | }, | ||
| 270 | { } | 304 | { } |
| 271 | }; | 305 | }; |
| 272 | 306 | ||
| @@ -331,17 +365,29 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy) | |||
| 331 | } | 365 | } |
| 332 | } | 366 | } |
| 333 | 367 | ||
| 334 | static int find_token_location(int tokenid) | 368 | static int find_token_id(int tokenid) |
| 335 | { | 369 | { |
| 336 | int i; | 370 | int i; |
| 371 | |||
| 337 | for (i = 0; i < da_num_tokens; i++) { | 372 | for (i = 0; i < da_num_tokens; i++) { |
| 338 | if (da_tokens[i].tokenID == tokenid) | 373 | if (da_tokens[i].tokenID == tokenid) |
| 339 | return da_tokens[i].location; | 374 | return i; |
| 340 | } | 375 | } |
| 341 | 376 | ||
| 342 | return -1; | 377 | return -1; |
| 343 | } | 378 | } |
| 344 | 379 | ||
| 380 | static int find_token_location(int tokenid) | ||
| 381 | { | ||
| 382 | int id; | ||
| 383 | |||
| 384 | id = find_token_id(tokenid); | ||
| 385 | if (id == -1) | ||
| 386 | return -1; | ||
| 387 | |||
| 388 | return da_tokens[id].location; | ||
| 389 | } | ||
| 390 | |||
| 345 | static struct calling_interface_buffer * | 391 | static struct calling_interface_buffer * |
| 346 | dell_send_request(struct calling_interface_buffer *buffer, int class, | 392 | dell_send_request(struct calling_interface_buffer *buffer, int class, |
| 347 | int select) | 393 | int select) |
| @@ -362,6 +408,20 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
| 362 | return buffer; | 408 | return buffer; |
| 363 | } | 409 | } |
| 364 | 410 | ||
| 411 | static inline int dell_smi_error(int value) | ||
| 412 | { | ||
| 413 | switch (value) { | ||
| 414 | case 0: /* Completed successfully */ | ||
| 415 | return 0; | ||
| 416 | case -1: /* Completed with error */ | ||
| 417 | return -EIO; | ||
| 418 | case -2: /* Function not supported */ | ||
| 419 | return -ENXIO; | ||
| 420 | default: /* Unknown error */ | ||
| 421 | return -EINVAL; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 365 | /* Derived from information in DellWirelessCtl.cpp: | 425 | /* Derived from information in DellWirelessCtl.cpp: |
| 366 | Class 17, select 11 is radio control. It returns an array of 32-bit values. | 426 | Class 17, select 11 is radio control. It returns an array of 32-bit values. |
| 367 | 427 | ||
| @@ -716,7 +776,7 @@ static int dell_send_intensity(struct backlight_device *bd) | |||
| 716 | else | 776 | else |
| 717 | dell_send_request(buffer, 1, 1); | 777 | dell_send_request(buffer, 1, 1); |
| 718 | 778 | ||
| 719 | out: | 779 | out: |
| 720 | release_buffer(); | 780 | release_buffer(); |
| 721 | return ret; | 781 | return ret; |
| 722 | } | 782 | } |
| @@ -740,7 +800,7 @@ static int dell_get_intensity(struct backlight_device *bd) | |||
| 740 | 800 | ||
| 741 | ret = buffer->output[1]; | 801 | ret = buffer->output[1]; |
| 742 | 802 | ||
| 743 | out: | 803 | out: |
| 744 | release_buffer(); | 804 | release_buffer(); |
| 745 | return ret; | 805 | return ret; |
| 746 | } | 806 | } |
| @@ -789,6 +849,1018 @@ static void touchpad_led_exit(void) | |||
| 789 | led_classdev_unregister(&touchpad_led); | 849 | led_classdev_unregister(&touchpad_led); |
| 790 | } | 850 | } |
| 791 | 851 | ||
| 852 | /* | ||
| 853 | * Derived from information in smbios-keyboard-ctl: | ||
| 854 | * | ||
| 855 | * cbClass 4 | ||
| 856 | * cbSelect 11 | ||
| 857 | * Keyboard illumination | ||
| 858 | * cbArg1 determines the function to be performed | ||
| 859 | * | ||
| 860 | * cbArg1 0x0 = Get Feature Information | ||
| 861 | * cbRES1 Standard return codes (0, -1, -2) | ||
| 862 | * cbRES2, word0 Bitmap of user-selectable modes | ||
| 863 | * bit 0 Always off (All systems) | ||
| 864 | * bit 1 Always on (Travis ATG, Siberia) | ||
| 865 | * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) | ||
| 866 | * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off | ||
| 867 | * bit 4 Auto: Input-activity-based On; input-activity based Off | ||
| 868 | * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off | ||
| 869 | * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off | ||
| 870 | * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off | ||
| 871 | * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off | ||
| 872 | * bits 9-15 Reserved for future use | ||
| 873 | * cbRES2, byte2 Reserved for future use | ||
| 874 | * cbRES2, byte3 Keyboard illumination type | ||
| 875 | * 0 Reserved | ||
| 876 | * 1 Tasklight | ||
| 877 | * 2 Backlight | ||
| 878 | * 3-255 Reserved for future use | ||
| 879 | * cbRES3, byte0 Supported auto keyboard illumination trigger bitmap. | ||
| 880 | * bit 0 Any keystroke | ||
| 881 | * bit 1 Touchpad activity | ||
| 882 | * bit 2 Pointing stick | ||
| 883 | * bit 3 Any mouse | ||
| 884 | * bits 4-7 Reserved for future use | ||
| 885 | * cbRES3, byte1 Supported timeout unit bitmap | ||
| 886 | * bit 0 Seconds | ||
| 887 | * bit 1 Minutes | ||
| 888 | * bit 2 Hours | ||
| 889 | * bit 3 Days | ||
| 890 | * bits 4-7 Reserved for future use | ||
| 891 | * cbRES3, byte2 Number of keyboard light brightness levels | ||
| 892 | * cbRES4, byte0 Maximum acceptable seconds value (0 if seconds not supported). | ||
| 893 | * cbRES4, byte1 Maximum acceptable minutes value (0 if minutes not supported). | ||
| 894 | * cbRES4, byte2 Maximum acceptable hours value (0 if hours not supported). | ||
| 895 | * cbRES4, byte3 Maximum acceptable days value (0 if days not supported) | ||
| 896 | * | ||
| 897 | * cbArg1 0x1 = Get Current State | ||
| 898 | * cbRES1 Standard return codes (0, -1, -2) | ||
| 899 | * cbRES2, word0 Bitmap of current mode state | ||
| 900 | * bit 0 Always off (All systems) | ||
| 901 | * bit 1 Always on (Travis ATG, Siberia) | ||
| 902 | * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) | ||
| 903 | * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off | ||
| 904 | * bit 4 Auto: Input-activity-based On; input-activity based Off | ||
| 905 | * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off | ||
| 906 | * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off | ||
| 907 | * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off | ||
| 908 | * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off | ||
| 909 | * bits 9-15 Reserved for future use | ||
| 910 | * Note: Only One bit can be set | ||
| 911 | * cbRES2, byte2 Currently active auto keyboard illumination triggers. | ||
| 912 | * bit 0 Any keystroke | ||
| 913 | * bit 1 Touchpad activity | ||
| 914 | * bit 2 Pointing stick | ||
| 915 | * bit 3 Any mouse | ||
| 916 | * bits 4-7 Reserved for future use | ||
| 917 | * cbRES2, byte3 Current Timeout | ||
| 918 | * bits 7:6 Timeout units indicator: | ||
| 919 | * 00b Seconds | ||
| 920 | * 01b Minutes | ||
| 921 | * 10b Hours | ||
| 922 | * 11b Days | ||
| 923 | * bits 5:0 Timeout value (0-63) in sec/min/hr/day | ||
| 924 | * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte | ||
| 925 | * are set upon return from the [Get feature information] call. | ||
| 926 | * cbRES3, byte0 Current setting of ALS value that turns the light on or off. | ||
| 927 | * cbRES3, byte1 Current ALS reading | ||
| 928 | * cbRES3, byte2 Current keyboard light level. | ||
| 929 | * | ||
| 930 | * cbArg1 0x2 = Set New State | ||
| 931 | * cbRES1 Standard return codes (0, -1, -2) | ||
| 932 | * cbArg2, word0 Bitmap of current mode state | ||
| 933 | * bit 0 Always off (All systems) | ||
| 934 | * bit 1 Always on (Travis ATG, Siberia) | ||
| 935 | * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) | ||
| 936 | * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off | ||
| 937 | * bit 4 Auto: Input-activity-based On; input-activity based Off | ||
| 938 | * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off | ||
| 939 | * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off | ||
| 940 | * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off | ||
| 941 | * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off | ||
| 942 | * bits 9-15 Reserved for future use | ||
| 943 | * Note: Only One bit can be set | ||
| 944 | * cbArg2, byte2 Desired auto keyboard illumination triggers. Must remain inactive to allow | ||
| 945 | * keyboard to turn off automatically. | ||
| 946 | * bit 0 Any keystroke | ||
| 947 | * bit 1 Touchpad activity | ||
| 948 | * bit 2 Pointing stick | ||
| 949 | * bit 3 Any mouse | ||
| 950 | * bits 4-7 Reserved for future use | ||
| 951 | * cbArg2, byte3 Desired Timeout | ||
| 952 | * bits 7:6 Timeout units indicator: | ||
| 953 | * 00b Seconds | ||
| 954 | * 01b Minutes | ||
| 955 | * 10b Hours | ||
| 956 | * 11b Days | ||
| 957 | * bits 5:0 Timeout value (0-63) in sec/min/hr/day | ||
| 958 | * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. | ||
| 959 | * cbArg3, byte2 Desired keyboard light level. | ||
| 960 | */ | ||
| 961 | |||
| 962 | |||
| 963 | enum kbd_timeout_unit { | ||
| 964 | KBD_TIMEOUT_SECONDS = 0, | ||
| 965 | KBD_TIMEOUT_MINUTES, | ||
| 966 | KBD_TIMEOUT_HOURS, | ||
| 967 | KBD_TIMEOUT_DAYS, | ||
| 968 | }; | ||
| 969 | |||
| 970 | enum kbd_mode_bit { | ||
| 971 | KBD_MODE_BIT_OFF = 0, | ||
| 972 | KBD_MODE_BIT_ON, | ||
| 973 | KBD_MODE_BIT_ALS, | ||
| 974 | KBD_MODE_BIT_TRIGGER_ALS, | ||
| 975 | KBD_MODE_BIT_TRIGGER, | ||
| 976 | KBD_MODE_BIT_TRIGGER_25, | ||
| 977 | KBD_MODE_BIT_TRIGGER_50, | ||
| 978 | KBD_MODE_BIT_TRIGGER_75, | ||
| 979 | KBD_MODE_BIT_TRIGGER_100, | ||
| 980 | }; | ||
| 981 | |||
| 982 | #define kbd_is_als_mode_bit(bit) \ | ||
| 983 | ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS) | ||
| 984 | #define kbd_is_trigger_mode_bit(bit) \ | ||
| 985 | ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100) | ||
| 986 | #define kbd_is_level_mode_bit(bit) \ | ||
| 987 | ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100) | ||
| 988 | |||
| 989 | struct kbd_info { | ||
| 990 | u16 modes; | ||
| 991 | u8 type; | ||
| 992 | u8 triggers; | ||
| 993 | u8 levels; | ||
| 994 | u8 seconds; | ||
| 995 | u8 minutes; | ||
| 996 | u8 hours; | ||
| 997 | u8 days; | ||
| 998 | }; | ||
| 999 | |||
| 1000 | struct kbd_state { | ||
| 1001 | u8 mode_bit; | ||
| 1002 | u8 triggers; | ||
| 1003 | u8 timeout_value; | ||
| 1004 | u8 timeout_unit; | ||
| 1005 | u8 als_setting; | ||
| 1006 | u8 als_value; | ||
| 1007 | u8 level; | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | static const int kbd_tokens[] = { | ||
| 1011 | KBD_LED_OFF_TOKEN, | ||
| 1012 | KBD_LED_AUTO_25_TOKEN, | ||
| 1013 | KBD_LED_AUTO_50_TOKEN, | ||
| 1014 | KBD_LED_AUTO_75_TOKEN, | ||
| 1015 | KBD_LED_AUTO_100_TOKEN, | ||
| 1016 | KBD_LED_ON_TOKEN, | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | static u16 kbd_token_bits; | ||
| 1020 | |||
| 1021 | static struct kbd_info kbd_info; | ||
| 1022 | static bool kbd_als_supported; | ||
| 1023 | static bool kbd_triggers_supported; | ||
| 1024 | |||
| 1025 | static u8 kbd_mode_levels[16]; | ||
| 1026 | static int kbd_mode_levels_count; | ||
| 1027 | |||
| 1028 | static u8 kbd_previous_level; | ||
| 1029 | static u8 kbd_previous_mode_bit; | ||
| 1030 | |||
| 1031 | static bool kbd_led_present; | ||
| 1032 | |||
| 1033 | /* | ||
| 1034 | * NOTE: there are three ways to set the keyboard backlight level. | ||
| 1035 | * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value). | ||
| 1036 | * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels). | ||
| 1037 | * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens) | ||
| 1038 | * | ||
| 1039 | * There are laptops which support only one of these methods. If we want to | ||
| 1040 | * support as many machines as possible we need to implement all three methods. | ||
| 1041 | * The first two methods use the kbd_state structure. The third uses SMBIOS | ||
| 1042 | * tokens. If kbd_info.levels == 0, the machine does not support setting the | ||
| 1043 | * keyboard backlight level via kbd_state.level. | ||
| 1044 | */ | ||
| 1045 | |||
| 1046 | static int kbd_get_info(struct kbd_info *info) | ||
| 1047 | { | ||
| 1048 | u8 units; | ||
| 1049 | int ret; | ||
| 1050 | |||
| 1051 | get_buffer(); | ||
| 1052 | |||
| 1053 | buffer->input[0] = 0x0; | ||
| 1054 | dell_send_request(buffer, 4, 11); | ||
| 1055 | ret = buffer->output[0]; | ||
| 1056 | |||
| 1057 | if (ret) { | ||
| 1058 | ret = dell_smi_error(ret); | ||
| 1059 | goto out; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | info->modes = buffer->output[1] & 0xFFFF; | ||
| 1063 | info->type = (buffer->output[1] >> 24) & 0xFF; | ||
| 1064 | info->triggers = buffer->output[2] & 0xFF; | ||
| 1065 | units = (buffer->output[2] >> 8) & 0xFF; | ||
| 1066 | info->levels = (buffer->output[2] >> 16) & 0xFF; | ||
| 1067 | |||
| 1068 | if (units & BIT(0)) | ||
| 1069 | info->seconds = (buffer->output[3] >> 0) & 0xFF; | ||
| 1070 | if (units & BIT(1)) | ||
| 1071 | info->minutes = (buffer->output[3] >> 8) & 0xFF; | ||
| 1072 | if (units & BIT(2)) | ||
| 1073 | info->hours = (buffer->output[3] >> 16) & 0xFF; | ||
| 1074 | if (units & BIT(3)) | ||
| 1075 | info->days = (buffer->output[3] >> 24) & 0xFF; | ||
| 1076 | |||
| 1077 | out: | ||
| 1078 | release_buffer(); | ||
| 1079 | return ret; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | static unsigned int kbd_get_max_level(void) | ||
| 1083 | { | ||
| 1084 | if (kbd_info.levels != 0) | ||
| 1085 | return kbd_info.levels; | ||
| 1086 | if (kbd_mode_levels_count > 0) | ||
| 1087 | return kbd_mode_levels_count - 1; | ||
| 1088 | return 0; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | static int kbd_get_level(struct kbd_state *state) | ||
| 1092 | { | ||
| 1093 | int i; | ||
| 1094 | |||
| 1095 | if (kbd_info.levels != 0) | ||
| 1096 | return state->level; | ||
| 1097 | |||
| 1098 | if (kbd_mode_levels_count > 0) { | ||
| 1099 | for (i = 0; i < kbd_mode_levels_count; ++i) | ||
| 1100 | if (kbd_mode_levels[i] == state->mode_bit) | ||
| 1101 | return i; | ||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | return -EINVAL; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | static int kbd_set_level(struct kbd_state *state, u8 level) | ||
| 1109 | { | ||
| 1110 | if (kbd_info.levels != 0) { | ||
| 1111 | if (level != 0) | ||
| 1112 | kbd_previous_level = level; | ||
| 1113 | if (state->level == level) | ||
| 1114 | return 0; | ||
| 1115 | state->level = level; | ||
| 1116 | if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF) | ||
| 1117 | state->mode_bit = kbd_previous_mode_bit; | ||
| 1118 | else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) { | ||
| 1119 | kbd_previous_mode_bit = state->mode_bit; | ||
| 1120 | state->mode_bit = KBD_MODE_BIT_OFF; | ||
| 1121 | } | ||
| 1122 | return 0; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) { | ||
| 1126 | if (level != 0) | ||
| 1127 | kbd_previous_level = level; | ||
| 1128 | state->mode_bit = kbd_mode_levels[level]; | ||
| 1129 | return 0; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | return -EINVAL; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | static int kbd_get_state(struct kbd_state *state) | ||
| 1136 | { | ||
| 1137 | int ret; | ||
| 1138 | |||
| 1139 | get_buffer(); | ||
| 1140 | |||
| 1141 | buffer->input[0] = 0x1; | ||
| 1142 | dell_send_request(buffer, 4, 11); | ||
| 1143 | ret = buffer->output[0]; | ||
| 1144 | |||
| 1145 | if (ret) { | ||
| 1146 | ret = dell_smi_error(ret); | ||
| 1147 | goto out; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | state->mode_bit = ffs(buffer->output[1] & 0xFFFF); | ||
| 1151 | if (state->mode_bit != 0) | ||
| 1152 | state->mode_bit--; | ||
| 1153 | |||
| 1154 | state->triggers = (buffer->output[1] >> 16) & 0xFF; | ||
| 1155 | state->timeout_value = (buffer->output[1] >> 24) & 0x3F; | ||
| 1156 | state->timeout_unit = (buffer->output[1] >> 30) & 0x3; | ||
| 1157 | state->als_setting = buffer->output[2] & 0xFF; | ||
| 1158 | state->als_value = (buffer->output[2] >> 8) & 0xFF; | ||
| 1159 | state->level = (buffer->output[2] >> 16) & 0xFF; | ||
| 1160 | |||
| 1161 | out: | ||
| 1162 | release_buffer(); | ||
| 1163 | return ret; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static int kbd_set_state(struct kbd_state *state) | ||
| 1167 | { | ||
| 1168 | int ret; | ||
| 1169 | |||
| 1170 | get_buffer(); | ||
| 1171 | buffer->input[0] = 0x2; | ||
| 1172 | buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; | ||
| 1173 | buffer->input[1] |= (state->triggers & 0xFF) << 16; | ||
| 1174 | buffer->input[1] |= (state->timeout_value & 0x3F) << 24; | ||
| 1175 | buffer->input[1] |= (state->timeout_unit & 0x3) << 30; | ||
| 1176 | buffer->input[2] = state->als_setting & 0xFF; | ||
| 1177 | buffer->input[2] |= (state->level & 0xFF) << 16; | ||
| 1178 | dell_send_request(buffer, 4, 11); | ||
| 1179 | ret = buffer->output[0]; | ||
| 1180 | release_buffer(); | ||
| 1181 | |||
| 1182 | return dell_smi_error(ret); | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) | ||
| 1186 | { | ||
| 1187 | int ret; | ||
| 1188 | |||
| 1189 | ret = kbd_set_state(state); | ||
| 1190 | if (ret == 0) | ||
| 1191 | return 0; | ||
| 1192 | |||
| 1193 | /* | ||
| 1194 | * When setting the new state fails,try to restore the previous one. | ||
| 1195 | * This is needed on some machines where BIOS sets a default state when | ||
| 1196 | * setting a new state fails. This default state could be all off. | ||
| 1197 | */ | ||
| 1198 | |||
| 1199 | if (kbd_set_state(old)) | ||
| 1200 | pr_err("Setting old previous keyboard state failed\n"); | ||
| 1201 | |||
| 1202 | return ret; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | static int kbd_set_token_bit(u8 bit) | ||
| 1206 | { | ||
| 1207 | int id; | ||
| 1208 | int ret; | ||
| 1209 | |||
| 1210 | if (bit >= ARRAY_SIZE(kbd_tokens)) | ||
| 1211 | return -EINVAL; | ||
| 1212 | |||
| 1213 | id = find_token_id(kbd_tokens[bit]); | ||
| 1214 | if (id == -1) | ||
| 1215 | return -EINVAL; | ||
| 1216 | |||
| 1217 | get_buffer(); | ||
| 1218 | buffer->input[0] = da_tokens[id].location; | ||
| 1219 | buffer->input[1] = da_tokens[id].value; | ||
| 1220 | dell_send_request(buffer, 1, 0); | ||
| 1221 | ret = buffer->output[0]; | ||
| 1222 | release_buffer(); | ||
| 1223 | |||
| 1224 | return dell_smi_error(ret); | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static int kbd_get_token_bit(u8 bit) | ||
| 1228 | { | ||
| 1229 | int id; | ||
| 1230 | int ret; | ||
| 1231 | int val; | ||
| 1232 | |||
| 1233 | if (bit >= ARRAY_SIZE(kbd_tokens)) | ||
| 1234 | return -EINVAL; | ||
| 1235 | |||
| 1236 | id = find_token_id(kbd_tokens[bit]); | ||
| 1237 | if (id == -1) | ||
| 1238 | return -EINVAL; | ||
| 1239 | |||
| 1240 | get_buffer(); | ||
| 1241 | buffer->input[0] = da_tokens[id].location; | ||
| 1242 | dell_send_request(buffer, 0, 0); | ||
| 1243 | ret = buffer->output[0]; | ||
| 1244 | val = buffer->output[1]; | ||
| 1245 | release_buffer(); | ||
| 1246 | |||
| 1247 | if (ret) | ||
| 1248 | return dell_smi_error(ret); | ||
| 1249 | |||
| 1250 | return (val == da_tokens[id].value); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | static int kbd_get_first_active_token_bit(void) | ||
| 1254 | { | ||
| 1255 | int i; | ||
| 1256 | int ret; | ||
| 1257 | |||
| 1258 | for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) { | ||
| 1259 | ret = kbd_get_token_bit(i); | ||
| 1260 | if (ret == 1) | ||
| 1261 | return i; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | return ret; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static int kbd_get_valid_token_counts(void) | ||
| 1268 | { | ||
| 1269 | return hweight16(kbd_token_bits); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | static inline int kbd_init_info(void) | ||
| 1273 | { | ||
| 1274 | struct kbd_state state; | ||
| 1275 | int ret; | ||
| 1276 | int i; | ||
| 1277 | |||
| 1278 | ret = kbd_get_info(&kbd_info); | ||
| 1279 | if (ret) | ||
| 1280 | return ret; | ||
| 1281 | |||
| 1282 | kbd_get_state(&state); | ||
| 1283 | |||
| 1284 | /* NOTE: timeout value is stored in 6 bits so max value is 63 */ | ||
| 1285 | if (kbd_info.seconds > 63) | ||
| 1286 | kbd_info.seconds = 63; | ||
| 1287 | if (kbd_info.minutes > 63) | ||
| 1288 | kbd_info.minutes = 63; | ||
| 1289 | if (kbd_info.hours > 63) | ||
| 1290 | kbd_info.hours = 63; | ||
| 1291 | if (kbd_info.days > 63) | ||
| 1292 | kbd_info.days = 63; | ||
| 1293 | |||
| 1294 | /* NOTE: On tested machines ON mode did not work and caused | ||
| 1295 | * problems (turned backlight off) so do not use it | ||
| 1296 | */ | ||
| 1297 | kbd_info.modes &= ~BIT(KBD_MODE_BIT_ON); | ||
| 1298 | |||
| 1299 | kbd_previous_level = kbd_get_level(&state); | ||
| 1300 | kbd_previous_mode_bit = state.mode_bit; | ||
| 1301 | |||
| 1302 | if (kbd_previous_level == 0 && kbd_get_max_level() != 0) | ||
| 1303 | kbd_previous_level = 1; | ||
| 1304 | |||
| 1305 | if (kbd_previous_mode_bit == KBD_MODE_BIT_OFF) { | ||
| 1306 | kbd_previous_mode_bit = | ||
| 1307 | ffs(kbd_info.modes & ~BIT(KBD_MODE_BIT_OFF)); | ||
| 1308 | if (kbd_previous_mode_bit != 0) | ||
| 1309 | kbd_previous_mode_bit--; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | if (kbd_info.modes & (BIT(KBD_MODE_BIT_ALS) | | ||
| 1313 | BIT(KBD_MODE_BIT_TRIGGER_ALS))) | ||
| 1314 | kbd_als_supported = true; | ||
| 1315 | |||
| 1316 | if (kbd_info.modes & ( | ||
| 1317 | BIT(KBD_MODE_BIT_TRIGGER_ALS) | BIT(KBD_MODE_BIT_TRIGGER) | | ||
| 1318 | BIT(KBD_MODE_BIT_TRIGGER_25) | BIT(KBD_MODE_BIT_TRIGGER_50) | | ||
| 1319 | BIT(KBD_MODE_BIT_TRIGGER_75) | BIT(KBD_MODE_BIT_TRIGGER_100) | ||
| 1320 | )) | ||
| 1321 | kbd_triggers_supported = true; | ||
| 1322 | |||
| 1323 | /* kbd_mode_levels[0] is reserved, see below */ | ||
| 1324 | for (i = 0; i < 16; ++i) | ||
| 1325 | if (kbd_is_level_mode_bit(i) && (BIT(i) & kbd_info.modes)) | ||
| 1326 | kbd_mode_levels[1 + kbd_mode_levels_count++] = i; | ||
| 1327 | |||
| 1328 | /* | ||
| 1329 | * Find the first supported mode and assign to kbd_mode_levels[0]. | ||
| 1330 | * This should be 0 (off), but we cannot depend on the BIOS to | ||
| 1331 | * support 0. | ||
| 1332 | */ | ||
| 1333 | if (kbd_mode_levels_count > 0) { | ||
| 1334 | for (i = 0; i < 16; ++i) { | ||
| 1335 | if (BIT(i) & kbd_info.modes) { | ||
| 1336 | kbd_mode_levels[0] = i; | ||
| 1337 | break; | ||
| 1338 | } | ||
| 1339 | } | ||
| 1340 | kbd_mode_levels_count++; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | return 0; | ||
| 1344 | |||
| 1345 | } | ||
| 1346 | |||
| 1347 | static inline void kbd_init_tokens(void) | ||
| 1348 | { | ||
| 1349 | int i; | ||
| 1350 | |||
| 1351 | for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) | ||
| 1352 | if (find_token_id(kbd_tokens[i]) != -1) | ||
| 1353 | kbd_token_bits |= BIT(i); | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | static void kbd_init(void) | ||
| 1357 | { | ||
| 1358 | int ret; | ||
| 1359 | |||
| 1360 | ret = kbd_init_info(); | ||
| 1361 | kbd_init_tokens(); | ||
| 1362 | |||
| 1363 | if (kbd_token_bits != 0 || ret == 0) | ||
| 1364 | kbd_led_present = true; | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | static ssize_t kbd_led_timeout_store(struct device *dev, | ||
| 1368 | struct device_attribute *attr, | ||
| 1369 | const char *buf, size_t count) | ||
| 1370 | { | ||
| 1371 | struct kbd_state new_state; | ||
| 1372 | struct kbd_state state; | ||
| 1373 | bool convert; | ||
| 1374 | int value; | ||
| 1375 | int ret; | ||
| 1376 | char ch; | ||
| 1377 | u8 unit; | ||
| 1378 | int i; | ||
| 1379 | |||
| 1380 | ret = sscanf(buf, "%d %c", &value, &ch); | ||
| 1381 | if (ret < 1) | ||
| 1382 | return -EINVAL; | ||
| 1383 | else if (ret == 1) | ||
| 1384 | ch = 's'; | ||
| 1385 | |||
| 1386 | if (value < 0) | ||
| 1387 | return -EINVAL; | ||
| 1388 | |||
| 1389 | convert = false; | ||
| 1390 | |||
| 1391 | switch (ch) { | ||
| 1392 | case 's': | ||
| 1393 | if (value > kbd_info.seconds) | ||
| 1394 | convert = true; | ||
| 1395 | unit = KBD_TIMEOUT_SECONDS; | ||
| 1396 | break; | ||
| 1397 | case 'm': | ||
| 1398 | if (value > kbd_info.minutes) | ||
| 1399 | convert = true; | ||
| 1400 | unit = KBD_TIMEOUT_MINUTES; | ||
| 1401 | break; | ||
| 1402 | case 'h': | ||
| 1403 | if (value > kbd_info.hours) | ||
| 1404 | convert = true; | ||
| 1405 | unit = KBD_TIMEOUT_HOURS; | ||
| 1406 | break; | ||
| 1407 | case 'd': | ||
| 1408 | if (value > kbd_info.days) | ||
| 1409 | convert = true; | ||
| 1410 | unit = KBD_TIMEOUT_DAYS; | ||
| 1411 | break; | ||
| 1412 | default: | ||
| 1413 | return -EINVAL; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | if (quirks && quirks->needs_kbd_timeouts) | ||
| 1417 | convert = true; | ||
| 1418 | |||
| 1419 | if (convert) { | ||
| 1420 | /* Convert value from current units to seconds */ | ||
| 1421 | switch (unit) { | ||
| 1422 | case KBD_TIMEOUT_DAYS: | ||
| 1423 | value *= 24; | ||
| 1424 | case KBD_TIMEOUT_HOURS: | ||
| 1425 | value *= 60; | ||
| 1426 | case KBD_TIMEOUT_MINUTES: | ||
| 1427 | value *= 60; | ||
| 1428 | unit = KBD_TIMEOUT_SECONDS; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | if (quirks && quirks->needs_kbd_timeouts) { | ||
| 1432 | for (i = 0; quirks->kbd_timeouts[i] != -1; i++) { | ||
| 1433 | if (value <= quirks->kbd_timeouts[i]) { | ||
| 1434 | value = quirks->kbd_timeouts[i]; | ||
| 1435 | break; | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | if (value <= kbd_info.seconds && kbd_info.seconds) { | ||
| 1441 | unit = KBD_TIMEOUT_SECONDS; | ||
| 1442 | } else if (value / 60 <= kbd_info.minutes && kbd_info.minutes) { | ||
| 1443 | value /= 60; | ||
| 1444 | unit = KBD_TIMEOUT_MINUTES; | ||
| 1445 | } else if (value / (60 * 60) <= kbd_info.hours && kbd_info.hours) { | ||
| 1446 | value /= (60 * 60); | ||
| 1447 | unit = KBD_TIMEOUT_HOURS; | ||
| 1448 | } else if (value / (60 * 60 * 24) <= kbd_info.days && kbd_info.days) { | ||
| 1449 | value /= (60 * 60 * 24); | ||
| 1450 | unit = KBD_TIMEOUT_DAYS; | ||
| 1451 | } else { | ||
| 1452 | return -EINVAL; | ||
| 1453 | } | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | ret = kbd_get_state(&state); | ||
| 1457 | if (ret) | ||
| 1458 | return ret; | ||
| 1459 | |||
| 1460 | new_state = state; | ||
| 1461 | new_state.timeout_value = value; | ||
| 1462 | new_state.timeout_unit = unit; | ||
| 1463 | |||
| 1464 | ret = kbd_set_state_safe(&new_state, &state); | ||
| 1465 | if (ret) | ||
| 1466 | return ret; | ||
| 1467 | |||
| 1468 | return count; | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | static ssize_t kbd_led_timeout_show(struct device *dev, | ||
| 1472 | struct device_attribute *attr, char *buf) | ||
| 1473 | { | ||
| 1474 | struct kbd_state state; | ||
| 1475 | int ret; | ||
| 1476 | int len; | ||
| 1477 | |||
| 1478 | ret = kbd_get_state(&state); | ||
| 1479 | if (ret) | ||
| 1480 | return ret; | ||
| 1481 | |||
| 1482 | len = sprintf(buf, "%d", state.timeout_value); | ||
| 1483 | |||
| 1484 | switch (state.timeout_unit) { | ||
| 1485 | case KBD_TIMEOUT_SECONDS: | ||
| 1486 | return len + sprintf(buf+len, "s\n"); | ||
| 1487 | case KBD_TIMEOUT_MINUTES: | ||
| 1488 | return len + sprintf(buf+len, "m\n"); | ||
| 1489 | case KBD_TIMEOUT_HOURS: | ||
| 1490 | return len + sprintf(buf+len, "h\n"); | ||
| 1491 | case KBD_TIMEOUT_DAYS: | ||
| 1492 | return len + sprintf(buf+len, "d\n"); | ||
| 1493 | default: | ||
| 1494 | return -EINVAL; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | return len; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR, | ||
| 1501 | kbd_led_timeout_show, kbd_led_timeout_store); | ||
| 1502 | |||
| 1503 | static const char * const kbd_led_triggers[] = { | ||
| 1504 | "keyboard", | ||
| 1505 | "touchpad", | ||
| 1506 | /*"trackstick"*/ NULL, /* NOTE: trackstick is just alias for touchpad */ | ||
| 1507 | "mouse", | ||
| 1508 | }; | ||
| 1509 | |||
| 1510 | static ssize_t kbd_led_triggers_store(struct device *dev, | ||
| 1511 | struct device_attribute *attr, | ||
| 1512 | const char *buf, size_t count) | ||
| 1513 | { | ||
| 1514 | struct kbd_state new_state; | ||
| 1515 | struct kbd_state state; | ||
| 1516 | bool triggers_enabled = false; | ||
| 1517 | int trigger_bit = -1; | ||
| 1518 | char trigger[21]; | ||
| 1519 | int i, ret; | ||
| 1520 | |||
| 1521 | ret = sscanf(buf, "%20s", trigger); | ||
| 1522 | if (ret != 1) | ||
| 1523 | return -EINVAL; | ||
| 1524 | |||
| 1525 | if (trigger[0] != '+' && trigger[0] != '-') | ||
| 1526 | return -EINVAL; | ||
| 1527 | |||
| 1528 | ret = kbd_get_state(&state); | ||
| 1529 | if (ret) | ||
| 1530 | return ret; | ||
| 1531 | |||
| 1532 | if (kbd_triggers_supported) | ||
| 1533 | triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); | ||
| 1534 | |||
| 1535 | if (kbd_triggers_supported) { | ||
| 1536 | for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { | ||
| 1537 | if (!(kbd_info.triggers & BIT(i))) | ||
| 1538 | continue; | ||
| 1539 | if (!kbd_led_triggers[i]) | ||
| 1540 | continue; | ||
| 1541 | if (strcmp(trigger+1, kbd_led_triggers[i]) != 0) | ||
| 1542 | continue; | ||
| 1543 | if (trigger[0] == '+' && | ||
| 1544 | triggers_enabled && (state.triggers & BIT(i))) | ||
| 1545 | return count; | ||
| 1546 | if (trigger[0] == '-' && | ||
| 1547 | (!triggers_enabled || !(state.triggers & BIT(i)))) | ||
| 1548 | return count; | ||
| 1549 | trigger_bit = i; | ||
| 1550 | break; | ||
| 1551 | } | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | if (trigger_bit != -1) { | ||
| 1555 | new_state = state; | ||
| 1556 | if (trigger[0] == '+') | ||
| 1557 | new_state.triggers |= BIT(trigger_bit); | ||
| 1558 | else { | ||
| 1559 | new_state.triggers &= ~BIT(trigger_bit); | ||
| 1560 | /* NOTE: trackstick bit (2) must be disabled when | ||
| 1561 | * disabling touchpad bit (1), otherwise touchpad | ||
| 1562 | * bit (1) will not be disabled */ | ||
| 1563 | if (trigger_bit == 1) | ||
| 1564 | new_state.triggers &= ~BIT(2); | ||
| 1565 | } | ||
| 1566 | if ((kbd_info.triggers & new_state.triggers) != | ||
| 1567 | new_state.triggers) | ||
| 1568 | return -EINVAL; | ||
| 1569 | if (new_state.triggers && !triggers_enabled) { | ||
| 1570 | new_state.mode_bit = KBD_MODE_BIT_TRIGGER; | ||
| 1571 | kbd_set_level(&new_state, kbd_previous_level); | ||
| 1572 | } else if (new_state.triggers == 0) { | ||
| 1573 | kbd_set_level(&new_state, 0); | ||
| 1574 | } | ||
| 1575 | if (!(kbd_info.modes & BIT(new_state.mode_bit))) | ||
| 1576 | return -EINVAL; | ||
| 1577 | ret = kbd_set_state_safe(&new_state, &state); | ||
| 1578 | if (ret) | ||
| 1579 | return ret; | ||
| 1580 | if (new_state.mode_bit != KBD_MODE_BIT_OFF) | ||
| 1581 | kbd_previous_mode_bit = new_state.mode_bit; | ||
| 1582 | return count; | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | return -EINVAL; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | static ssize_t kbd_led_triggers_show(struct device *dev, | ||
| 1589 | struct device_attribute *attr, char *buf) | ||
| 1590 | { | ||
| 1591 | struct kbd_state state; | ||
| 1592 | bool triggers_enabled; | ||
| 1593 | int level, i, ret; | ||
| 1594 | int len = 0; | ||
| 1595 | |||
| 1596 | ret = kbd_get_state(&state); | ||
| 1597 | if (ret) | ||
| 1598 | return ret; | ||
| 1599 | |||
| 1600 | len = 0; | ||
| 1601 | |||
| 1602 | if (kbd_triggers_supported) { | ||
| 1603 | triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); | ||
| 1604 | level = kbd_get_level(&state); | ||
| 1605 | for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { | ||
| 1606 | if (!(kbd_info.triggers & BIT(i))) | ||
| 1607 | continue; | ||
| 1608 | if (!kbd_led_triggers[i]) | ||
| 1609 | continue; | ||
| 1610 | if ((triggers_enabled || level <= 0) && | ||
| 1611 | (state.triggers & BIT(i))) | ||
| 1612 | buf[len++] = '+'; | ||
| 1613 | else | ||
| 1614 | buf[len++] = '-'; | ||
| 1615 | len += sprintf(buf+len, "%s ", kbd_led_triggers[i]); | ||
| 1616 | } | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | if (len) | ||
| 1620 | buf[len - 1] = '\n'; | ||
| 1621 | |||
| 1622 | return len; | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR, | ||
| 1626 | kbd_led_triggers_show, kbd_led_triggers_store); | ||
| 1627 | |||
| 1628 | static ssize_t kbd_led_als_enabled_store(struct device *dev, | ||
| 1629 | struct device_attribute *attr, | ||
| 1630 | const char *buf, size_t count) | ||
| 1631 | { | ||
| 1632 | struct kbd_state new_state; | ||
| 1633 | struct kbd_state state; | ||
| 1634 | bool triggers_enabled = false; | ||
| 1635 | int enable; | ||
| 1636 | int ret; | ||
| 1637 | |||
| 1638 | ret = kstrtoint(buf, 0, &enable); | ||
| 1639 | if (ret) | ||
| 1640 | return ret; | ||
| 1641 | |||
| 1642 | ret = kbd_get_state(&state); | ||
| 1643 | if (ret) | ||
| 1644 | return ret; | ||
| 1645 | |||
| 1646 | if (enable == kbd_is_als_mode_bit(state.mode_bit)) | ||
| 1647 | return count; | ||
| 1648 | |||
| 1649 | new_state = state; | ||
| 1650 | |||
| 1651 | if (kbd_triggers_supported) | ||
| 1652 | triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); | ||
| 1653 | |||
| 1654 | if (enable) { | ||
| 1655 | if (triggers_enabled) | ||
| 1656 | new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS; | ||
| 1657 | else | ||
| 1658 | new_state.mode_bit = KBD_MODE_BIT_ALS; | ||
| 1659 | } else { | ||
| 1660 | if (triggers_enabled) { | ||
| 1661 | new_state.mode_bit = KBD_MODE_BIT_TRIGGER; | ||
| 1662 | kbd_set_level(&new_state, kbd_previous_level); | ||
| 1663 | } else { | ||
| 1664 | new_state.mode_bit = KBD_MODE_BIT_ON; | ||
| 1665 | } | ||
| 1666 | } | ||
| 1667 | if (!(kbd_info.modes & BIT(new_state.mode_bit))) | ||
| 1668 | return -EINVAL; | ||
| 1669 | |||
| 1670 | ret = kbd_set_state_safe(&new_state, &state); | ||
| 1671 | if (ret) | ||
| 1672 | return ret; | ||
| 1673 | kbd_previous_mode_bit = new_state.mode_bit; | ||
| 1674 | |||
| 1675 | return count; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | static ssize_t kbd_led_als_enabled_show(struct device *dev, | ||
| 1679 | struct device_attribute *attr, | ||
| 1680 | char *buf) | ||
| 1681 | { | ||
| 1682 | struct kbd_state state; | ||
| 1683 | bool enabled = false; | ||
| 1684 | int ret; | ||
| 1685 | |||
| 1686 | ret = kbd_get_state(&state); | ||
| 1687 | if (ret) | ||
| 1688 | return ret; | ||
| 1689 | enabled = kbd_is_als_mode_bit(state.mode_bit); | ||
| 1690 | |||
| 1691 | return sprintf(buf, "%d\n", enabled ? 1 : 0); | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | static DEVICE_ATTR(als_enabled, S_IRUGO | S_IWUSR, | ||
| 1695 | kbd_led_als_enabled_show, kbd_led_als_enabled_store); | ||
| 1696 | |||
| 1697 | static ssize_t kbd_led_als_setting_store(struct device *dev, | ||
| 1698 | struct device_attribute *attr, | ||
| 1699 | const char *buf, size_t count) | ||
| 1700 | { | ||
| 1701 | struct kbd_state state; | ||
| 1702 | struct kbd_state new_state; | ||
| 1703 | u8 setting; | ||
| 1704 | int ret; | ||
| 1705 | |||
| 1706 | ret = kstrtou8(buf, 10, &setting); | ||
| 1707 | if (ret) | ||
| 1708 | return ret; | ||
| 1709 | |||
| 1710 | ret = kbd_get_state(&state); | ||
| 1711 | if (ret) | ||
| 1712 | return ret; | ||
| 1713 | |||
| 1714 | new_state = state; | ||
| 1715 | new_state.als_setting = setting; | ||
| 1716 | |||
| 1717 | ret = kbd_set_state_safe(&new_state, &state); | ||
| 1718 | if (ret) | ||
| 1719 | return ret; | ||
| 1720 | |||
| 1721 | return count; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | static ssize_t kbd_led_als_setting_show(struct device *dev, | ||
| 1725 | struct device_attribute *attr, | ||
| 1726 | char *buf) | ||
| 1727 | { | ||
| 1728 | struct kbd_state state; | ||
| 1729 | int ret; | ||
| 1730 | |||
| 1731 | ret = kbd_get_state(&state); | ||
| 1732 | if (ret) | ||
| 1733 | return ret; | ||
| 1734 | |||
| 1735 | return sprintf(buf, "%d\n", state.als_setting); | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR, | ||
| 1739 | kbd_led_als_setting_show, kbd_led_als_setting_store); | ||
| 1740 | |||
| 1741 | static struct attribute *kbd_led_attrs[] = { | ||
| 1742 | &dev_attr_stop_timeout.attr, | ||
| 1743 | &dev_attr_start_triggers.attr, | ||
| 1744 | NULL, | ||
| 1745 | }; | ||
| 1746 | |||
| 1747 | static const struct attribute_group kbd_led_group = { | ||
| 1748 | .attrs = kbd_led_attrs, | ||
| 1749 | }; | ||
| 1750 | |||
| 1751 | static struct attribute *kbd_led_als_attrs[] = { | ||
| 1752 | &dev_attr_als_enabled.attr, | ||
| 1753 | &dev_attr_als_setting.attr, | ||
| 1754 | NULL, | ||
| 1755 | }; | ||
| 1756 | |||
| 1757 | static const struct attribute_group kbd_led_als_group = { | ||
| 1758 | .attrs = kbd_led_als_attrs, | ||
| 1759 | }; | ||
| 1760 | |||
| 1761 | static const struct attribute_group *kbd_led_groups[] = { | ||
| 1762 | &kbd_led_group, | ||
| 1763 | &kbd_led_als_group, | ||
| 1764 | NULL, | ||
| 1765 | }; | ||
| 1766 | |||
| 1767 | static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) | ||
| 1768 | { | ||
| 1769 | int ret; | ||
| 1770 | u16 num; | ||
| 1771 | struct kbd_state state; | ||
| 1772 | |||
| 1773 | if (kbd_get_max_level()) { | ||
| 1774 | ret = kbd_get_state(&state); | ||
| 1775 | if (ret) | ||
| 1776 | return 0; | ||
| 1777 | ret = kbd_get_level(&state); | ||
| 1778 | if (ret < 0) | ||
| 1779 | return 0; | ||
| 1780 | return ret; | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | if (kbd_get_valid_token_counts()) { | ||
| 1784 | ret = kbd_get_first_active_token_bit(); | ||
| 1785 | if (ret < 0) | ||
| 1786 | return 0; | ||
| 1787 | for (num = kbd_token_bits; num != 0 && ret > 0; --ret) | ||
| 1788 | num &= num - 1; /* clear the first bit set */ | ||
| 1789 | if (num == 0) | ||
| 1790 | return 0; | ||
| 1791 | return ffs(num) - 1; | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | pr_warn("Keyboard brightness level control not supported\n"); | ||
| 1795 | return 0; | ||
| 1796 | } | ||
| 1797 | |||
| 1798 | static void kbd_led_level_set(struct led_classdev *led_cdev, | ||
| 1799 | enum led_brightness value) | ||
| 1800 | { | ||
| 1801 | struct kbd_state state; | ||
| 1802 | struct kbd_state new_state; | ||
| 1803 | u16 num; | ||
| 1804 | |||
| 1805 | if (kbd_get_max_level()) { | ||
| 1806 | if (kbd_get_state(&state)) | ||
| 1807 | return; | ||
| 1808 | new_state = state; | ||
| 1809 | if (kbd_set_level(&new_state, value)) | ||
| 1810 | return; | ||
| 1811 | kbd_set_state_safe(&new_state, &state); | ||
| 1812 | return; | ||
| 1813 | } | ||
| 1814 | |||
| 1815 | if (kbd_get_valid_token_counts()) { | ||
| 1816 | for (num = kbd_token_bits; num != 0 && value > 0; --value) | ||
| 1817 | num &= num - 1; /* clear the first bit set */ | ||
| 1818 | if (num == 0) | ||
| 1819 | return; | ||
| 1820 | kbd_set_token_bit(ffs(num) - 1); | ||
| 1821 | return; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | pr_warn("Keyboard brightness level control not supported\n"); | ||
| 1825 | } | ||
| 1826 | |||
| 1827 | static struct led_classdev kbd_led = { | ||
| 1828 | .name = "dell::kbd_backlight", | ||
| 1829 | .brightness_set = kbd_led_level_set, | ||
| 1830 | .brightness_get = kbd_led_level_get, | ||
| 1831 | .groups = kbd_led_groups, | ||
| 1832 | }; | ||
| 1833 | |||
| 1834 | static int __init kbd_led_init(struct device *dev) | ||
| 1835 | { | ||
| 1836 | kbd_init(); | ||
| 1837 | if (!kbd_led_present) | ||
| 1838 | return -ENODEV; | ||
| 1839 | if (!kbd_als_supported) | ||
| 1840 | kbd_led_groups[1] = NULL; | ||
| 1841 | kbd_led.max_brightness = kbd_get_max_level(); | ||
| 1842 | if (!kbd_led.max_brightness) { | ||
| 1843 | kbd_led.max_brightness = kbd_get_valid_token_counts(); | ||
| 1844 | if (kbd_led.max_brightness) | ||
| 1845 | kbd_led.max_brightness--; | ||
| 1846 | } | ||
| 1847 | return led_classdev_register(dev, &kbd_led); | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | static void brightness_set_exit(struct led_classdev *led_cdev, | ||
| 1851 | enum led_brightness value) | ||
| 1852 | { | ||
| 1853 | /* Don't change backlight level on exit */ | ||
| 1854 | }; | ||
| 1855 | |||
| 1856 | static void kbd_led_exit(void) | ||
| 1857 | { | ||
| 1858 | if (!kbd_led_present) | ||
| 1859 | return; | ||
| 1860 | kbd_led.brightness_set = brightness_set_exit; | ||
| 1861 | led_classdev_unregister(&kbd_led); | ||
| 1862 | } | ||
| 1863 | |||
| 792 | static int __init dell_init(void) | 1864 | static int __init dell_init(void) |
| 793 | { | 1865 | { |
| 794 | int max_intensity = 0; | 1866 | int max_intensity = 0; |
| @@ -841,6 +1913,8 @@ static int __init dell_init(void) | |||
| 841 | if (quirks && quirks->touchpad_led) | 1913 | if (quirks && quirks->touchpad_led) |
| 842 | touchpad_led_init(&platform_device->dev); | 1914 | touchpad_led_init(&platform_device->dev); |
| 843 | 1915 | ||
| 1916 | kbd_led_init(&platform_device->dev); | ||
| 1917 | |||
| 844 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); | 1918 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); |
| 845 | if (dell_laptop_dir != NULL) | 1919 | if (dell_laptop_dir != NULL) |
| 846 | debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, | 1920 | debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, |
| @@ -908,6 +1982,7 @@ static void __exit dell_exit(void) | |||
| 908 | debugfs_remove_recursive(dell_laptop_dir); | 1982 | debugfs_remove_recursive(dell_laptop_dir); |
| 909 | if (quirks && quirks->touchpad_led) | 1983 | if (quirks && quirks->touchpad_led) |
| 910 | touchpad_led_exit(); | 1984 | touchpad_led_exit(); |
| 1985 | kbd_led_exit(); | ||
| 911 | i8042_remove_filter(dell_laptop_i8042_filter); | 1986 | i8042_remove_filter(dell_laptop_i8042_filter); |
| 912 | cancel_delayed_work_sync(&dell_rfkill_work); | 1987 | cancel_delayed_work_sync(&dell_rfkill_work); |
| 913 | backlight_device_unregister(dell_backlight_device); | 1988 | backlight_device_unregister(dell_backlight_device); |
| @@ -924,5 +1999,7 @@ module_init(dell_init); | |||
| 924 | module_exit(dell_exit); | 1999 | module_exit(dell_exit); |
| 925 | 2000 | ||
| 926 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | 2001 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |
| 2002 | MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>"); | ||
| 2003 | MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); | ||
| 927 | MODULE_DESCRIPTION("Dell laptop driver"); | 2004 | MODULE_DESCRIPTION("Dell laptop driver"); |
| 928 | MODULE_LICENSE("GPL"); | 2005 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index a4a4258f6134..8037c8b46241 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c | |||
| @@ -62,7 +62,7 @@ | |||
| 62 | * (1 << 1): Bluetooth enable/disable, RW. | 62 | * (1 << 1): Bluetooth enable/disable, RW. |
| 63 | * (1 << 2): GPS enable/disable, RW. | 63 | * (1 << 2): GPS enable/disable, RW. |
| 64 | * (1 << 3): WiFi enable/disable, RW. | 64 | * (1 << 3): WiFi enable/disable, RW. |
| 65 | * (1 << 4): WWAN (3G) enable/disalbe, RW. | 65 | * (1 << 4): WWAN (3G) enable/disable, RW. |
| 66 | * (1 << 5): Touchscreen enable/disable, Read Only. | 66 | * (1 << 5): Touchscreen enable/disable, Read Only. |
| 67 | */ | 67 | */ |
| 68 | #define OT_EC_DEVICE_STATE_ADDRESS 0xD6 | 68 | #define OT_EC_DEVICE_STATE_ADDRESS 0xD6 |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 3b8ceee7c5cb..7769575345d8 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -319,6 +319,7 @@ static struct { | |||
| 319 | u32 sensors_pdrv_attrs_registered:1; | 319 | u32 sensors_pdrv_attrs_registered:1; |
| 320 | u32 sensors_pdev_attrs_registered:1; | 320 | u32 sensors_pdev_attrs_registered:1; |
| 321 | u32 hotkey_poll_active:1; | 321 | u32 hotkey_poll_active:1; |
| 322 | u32 has_adaptive_kbd:1; | ||
| 322 | } tp_features; | 323 | } tp_features; |
| 323 | 324 | ||
| 324 | static struct { | 325 | static struct { |
| @@ -1911,6 +1912,27 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ | |||
| 1911 | TP_ACPI_HOTKEYSCAN_UNK7, | 1912 | TP_ACPI_HOTKEYSCAN_UNK7, |
| 1912 | TP_ACPI_HOTKEYSCAN_UNK8, | 1913 | TP_ACPI_HOTKEYSCAN_UNK8, |
| 1913 | 1914 | ||
| 1915 | TP_ACPI_HOTKEYSCAN_MUTE2, | ||
| 1916 | TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO, | ||
| 1917 | TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL, | ||
| 1918 | TP_ACPI_HOTKEYSCAN_CLOUD, | ||
| 1919 | TP_ACPI_HOTKEYSCAN_UNK9, | ||
| 1920 | TP_ACPI_HOTKEYSCAN_VOICE, | ||
| 1921 | TP_ACPI_HOTKEYSCAN_UNK10, | ||
| 1922 | TP_ACPI_HOTKEYSCAN_GESTURES, | ||
| 1923 | TP_ACPI_HOTKEYSCAN_UNK11, | ||
| 1924 | TP_ACPI_HOTKEYSCAN_UNK12, | ||
| 1925 | TP_ACPI_HOTKEYSCAN_UNK13, | ||
| 1926 | TP_ACPI_HOTKEYSCAN_CONFIG, | ||
| 1927 | TP_ACPI_HOTKEYSCAN_NEW_TAB, | ||
| 1928 | TP_ACPI_HOTKEYSCAN_RELOAD, | ||
| 1929 | TP_ACPI_HOTKEYSCAN_BACK, | ||
| 1930 | TP_ACPI_HOTKEYSCAN_MIC_DOWN, | ||
| 1931 | TP_ACPI_HOTKEYSCAN_MIC_UP, | ||
| 1932 | TP_ACPI_HOTKEYSCAN_MIC_CANCELLATION, | ||
| 1933 | TP_ACPI_HOTKEYSCAN_CAMERA_MODE, | ||
| 1934 | TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY, | ||
| 1935 | |||
| 1914 | /* Hotkey keymap size */ | 1936 | /* Hotkey keymap size */ |
| 1915 | TPACPI_HOTKEY_MAP_LEN | 1937 | TPACPI_HOTKEY_MAP_LEN |
| 1916 | }; | 1938 | }; |
| @@ -2647,9 +2669,7 @@ static ssize_t hotkey_enable_store(struct device *dev, | |||
| 2647 | return count; | 2669 | return count; |
| 2648 | } | 2670 | } |
| 2649 | 2671 | ||
| 2650 | static struct device_attribute dev_attr_hotkey_enable = | 2672 | static DEVICE_ATTR_RW(hotkey_enable); |
| 2651 | __ATTR(hotkey_enable, S_IWUSR | S_IRUGO, | ||
| 2652 | hotkey_enable_show, hotkey_enable_store); | ||
| 2653 | 2673 | ||
| 2654 | /* sysfs hotkey mask --------------------------------------------------- */ | 2674 | /* sysfs hotkey mask --------------------------------------------------- */ |
| 2655 | static ssize_t hotkey_mask_show(struct device *dev, | 2675 | static ssize_t hotkey_mask_show(struct device *dev, |
| @@ -2685,9 +2705,7 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
| 2685 | return (res) ? res : count; | 2705 | return (res) ? res : count; |
| 2686 | } | 2706 | } |
| 2687 | 2707 | ||
| 2688 | static struct device_attribute dev_attr_hotkey_mask = | 2708 | static DEVICE_ATTR_RW(hotkey_mask); |
| 2689 | __ATTR(hotkey_mask, S_IWUSR | S_IRUGO, | ||
| 2690 | hotkey_mask_show, hotkey_mask_store); | ||
| 2691 | 2709 | ||
| 2692 | /* sysfs hotkey bios_enabled ------------------------------------------- */ | 2710 | /* sysfs hotkey bios_enabled ------------------------------------------- */ |
| 2693 | static ssize_t hotkey_bios_enabled_show(struct device *dev, | 2711 | static ssize_t hotkey_bios_enabled_show(struct device *dev, |
| @@ -2697,8 +2715,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev, | |||
| 2697 | return sprintf(buf, "0\n"); | 2715 | return sprintf(buf, "0\n"); |
| 2698 | } | 2716 | } |
| 2699 | 2717 | ||
| 2700 | static struct device_attribute dev_attr_hotkey_bios_enabled = | 2718 | static DEVICE_ATTR_RO(hotkey_bios_enabled); |
| 2701 | __ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); | ||
| 2702 | 2719 | ||
| 2703 | /* sysfs hotkey bios_mask ---------------------------------------------- */ | 2720 | /* sysfs hotkey bios_mask ---------------------------------------------- */ |
| 2704 | static ssize_t hotkey_bios_mask_show(struct device *dev, | 2721 | static ssize_t hotkey_bios_mask_show(struct device *dev, |
| @@ -2710,8 +2727,7 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, | |||
| 2710 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); | 2727 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); |
| 2711 | } | 2728 | } |
| 2712 | 2729 | ||
| 2713 | static struct device_attribute dev_attr_hotkey_bios_mask = | 2730 | static DEVICE_ATTR_RO(hotkey_bios_mask); |
| 2714 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); | ||
| 2715 | 2731 | ||
| 2716 | /* sysfs hotkey all_mask ----------------------------------------------- */ | 2732 | /* sysfs hotkey all_mask ----------------------------------------------- */ |
| 2717 | static ssize_t hotkey_all_mask_show(struct device *dev, | 2733 | static ssize_t hotkey_all_mask_show(struct device *dev, |
| @@ -2722,8 +2738,7 @@ static ssize_t hotkey_all_mask_show(struct device *dev, | |||
| 2722 | hotkey_all_mask | hotkey_source_mask); | 2738 | hotkey_all_mask | hotkey_source_mask); |
| 2723 | } | 2739 | } |
| 2724 | 2740 | ||
| 2725 | static struct device_attribute dev_attr_hotkey_all_mask = | 2741 | static DEVICE_ATTR_RO(hotkey_all_mask); |
| 2726 | __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); | ||
| 2727 | 2742 | ||
| 2728 | /* sysfs hotkey recommended_mask --------------------------------------- */ | 2743 | /* sysfs hotkey recommended_mask --------------------------------------- */ |
| 2729 | static ssize_t hotkey_recommended_mask_show(struct device *dev, | 2744 | static ssize_t hotkey_recommended_mask_show(struct device *dev, |
| @@ -2735,9 +2750,7 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev, | |||
| 2735 | & ~hotkey_reserved_mask); | 2750 | & ~hotkey_reserved_mask); |
| 2736 | } | 2751 | } |
| 2737 | 2752 | ||
| 2738 | static struct device_attribute dev_attr_hotkey_recommended_mask = | 2753 | static DEVICE_ATTR_RO(hotkey_recommended_mask); |
| 2739 | __ATTR(hotkey_recommended_mask, S_IRUGO, | ||
| 2740 | hotkey_recommended_mask_show, NULL); | ||
| 2741 | 2754 | ||
| 2742 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2755 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
| 2743 | 2756 | ||
| @@ -2792,9 +2805,7 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
| 2792 | return (rc < 0) ? rc : count; | 2805 | return (rc < 0) ? rc : count; |
| 2793 | } | 2806 | } |
| 2794 | 2807 | ||
| 2795 | static struct device_attribute dev_attr_hotkey_source_mask = | 2808 | static DEVICE_ATTR_RW(hotkey_source_mask); |
| 2796 | __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO, | ||
| 2797 | hotkey_source_mask_show, hotkey_source_mask_store); | ||
| 2798 | 2809 | ||
| 2799 | /* sysfs hotkey hotkey_poll_freq --------------------------------------- */ | 2810 | /* sysfs hotkey hotkey_poll_freq --------------------------------------- */ |
| 2800 | static ssize_t hotkey_poll_freq_show(struct device *dev, | 2811 | static ssize_t hotkey_poll_freq_show(struct device *dev, |
| @@ -2826,9 +2837,7 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, | |||
| 2826 | return count; | 2837 | return count; |
| 2827 | } | 2838 | } |
| 2828 | 2839 | ||
| 2829 | static struct device_attribute dev_attr_hotkey_poll_freq = | 2840 | static DEVICE_ATTR_RW(hotkey_poll_freq); |
| 2830 | __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO, | ||
| 2831 | hotkey_poll_freq_show, hotkey_poll_freq_store); | ||
| 2832 | 2841 | ||
| 2833 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 2842 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
| 2834 | 2843 | ||
| @@ -2849,8 +2858,7 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, | |||
| 2849 | (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); | 2858 | (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); |
| 2850 | } | 2859 | } |
| 2851 | 2860 | ||
| 2852 | static struct device_attribute dev_attr_hotkey_radio_sw = | 2861 | static DEVICE_ATTR_RO(hotkey_radio_sw); |
| 2853 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | ||
| 2854 | 2862 | ||
| 2855 | static void hotkey_radio_sw_notify_change(void) | 2863 | static void hotkey_radio_sw_notify_change(void) |
| 2856 | { | 2864 | { |
| @@ -2872,8 +2880,7 @@ static ssize_t hotkey_tablet_mode_show(struct device *dev, | |||
| 2872 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | 2880 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); |
| 2873 | } | 2881 | } |
| 2874 | 2882 | ||
| 2875 | static struct device_attribute dev_attr_hotkey_tablet_mode = | 2883 | static DEVICE_ATTR_RO(hotkey_tablet_mode); |
| 2876 | __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL); | ||
| 2877 | 2884 | ||
| 2878 | static void hotkey_tablet_mode_notify_change(void) | 2885 | static void hotkey_tablet_mode_notify_change(void) |
| 2879 | { | 2886 | { |
| @@ -2890,8 +2897,7 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev, | |||
| 2890 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); | 2897 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); |
| 2891 | } | 2898 | } |
| 2892 | 2899 | ||
| 2893 | static struct device_attribute dev_attr_hotkey_wakeup_reason = | 2900 | static DEVICE_ATTR_RO(hotkey_wakeup_reason); |
| 2894 | __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); | ||
| 2895 | 2901 | ||
| 2896 | static void hotkey_wakeup_reason_notify_change(void) | 2902 | static void hotkey_wakeup_reason_notify_change(void) |
| 2897 | { | 2903 | { |
| @@ -2907,9 +2913,7 @@ static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, | |||
| 2907 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); | 2913 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); |
| 2908 | } | 2914 | } |
| 2909 | 2915 | ||
| 2910 | static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = | 2916 | static DEVICE_ATTR_RO(hotkey_wakeup_hotunplug_complete); |
| 2911 | __ATTR(wakeup_hotunplug_complete, S_IRUGO, | ||
| 2912 | hotkey_wakeup_hotunplug_complete_show, NULL); | ||
| 2913 | 2917 | ||
| 2914 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) | 2918 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) |
| 2915 | { | 2919 | { |
| @@ -2917,6 +2921,57 @@ static void hotkey_wakeup_hotunplug_complete_notify_change(void) | |||
| 2917 | "wakeup_hotunplug_complete"); | 2921 | "wakeup_hotunplug_complete"); |
| 2918 | } | 2922 | } |
| 2919 | 2923 | ||
| 2924 | /* sysfs adaptive kbd mode --------------------------------------------- */ | ||
| 2925 | |||
| 2926 | static int adaptive_keyboard_get_mode(void); | ||
| 2927 | static int adaptive_keyboard_set_mode(int new_mode); | ||
| 2928 | |||
| 2929 | enum ADAPTIVE_KEY_MODE { | ||
| 2930 | HOME_MODE, | ||
| 2931 | WEB_BROWSER_MODE, | ||
| 2932 | WEB_CONFERENCE_MODE, | ||
| 2933 | FUNCTION_MODE, | ||
| 2934 | LAYFLAT_MODE | ||
| 2935 | }; | ||
| 2936 | |||
| 2937 | static ssize_t adaptive_kbd_mode_show(struct device *dev, | ||
| 2938 | struct device_attribute *attr, | ||
| 2939 | char *buf) | ||
| 2940 | { | ||
| 2941 | int current_mode; | ||
| 2942 | |||
| 2943 | current_mode = adaptive_keyboard_get_mode(); | ||
| 2944 | if (current_mode < 0) | ||
| 2945 | return current_mode; | ||
| 2946 | |||
| 2947 | return snprintf(buf, PAGE_SIZE, "%d\n", current_mode); | ||
| 2948 | } | ||
| 2949 | |||
| 2950 | static ssize_t adaptive_kbd_mode_store(struct device *dev, | ||
| 2951 | struct device_attribute *attr, | ||
| 2952 | const char *buf, size_t count) | ||
| 2953 | { | ||
| 2954 | unsigned long t; | ||
| 2955 | int res; | ||
| 2956 | |||
| 2957 | if (parse_strtoul(buf, LAYFLAT_MODE, &t)) | ||
| 2958 | return -EINVAL; | ||
| 2959 | |||
| 2960 | res = adaptive_keyboard_set_mode(t); | ||
| 2961 | return (res < 0) ? res : count; | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | static DEVICE_ATTR_RW(adaptive_kbd_mode); | ||
| 2965 | |||
| 2966 | static struct attribute *adaptive_kbd_attributes[] = { | ||
| 2967 | &dev_attr_adaptive_kbd_mode.attr, | ||
| 2968 | NULL | ||
| 2969 | }; | ||
| 2970 | |||
| 2971 | static const struct attribute_group adaptive_kbd_attr_group = { | ||
| 2972 | .attrs = adaptive_kbd_attributes, | ||
| 2973 | }; | ||
| 2974 | |||
| 2920 | /* --------------------------------------------------------------------- */ | 2975 | /* --------------------------------------------------------------------- */ |
| 2921 | 2976 | ||
| 2922 | static struct attribute *hotkey_attributes[] __initdata = { | 2977 | static struct attribute *hotkey_attributes[] __initdata = { |
| @@ -3118,6 +3173,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3118 | /* (assignments unknown, please report if found) */ | 3173 | /* (assignments unknown, please report if found) */ |
| 3119 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 3174 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
| 3120 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 3175 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
| 3176 | |||
| 3177 | /* No assignments, only used for Adaptive keyboards. */ | ||
| 3178 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3179 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3180 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3181 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3182 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3121 | }, | 3183 | }, |
| 3122 | 3184 | ||
| 3123 | /* Generic keymap for Lenovo ThinkPads */ | 3185 | /* Generic keymap for Lenovo ThinkPads */ |
| @@ -3174,6 +3236,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3174 | 3236 | ||
| 3175 | /* Extra keys in use since the X240 / T440 / T540 */ | 3237 | /* Extra keys in use since the X240 / T440 / T540 */ |
| 3176 | KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE, | 3238 | KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE, |
| 3239 | |||
| 3240 | /* | ||
| 3241 | * These are the adaptive keyboard keycodes for Carbon X1 2014. | ||
| 3242 | * The first item in this list is the Mute button which is | ||
| 3243 | * emitted with 0x103 through | ||
| 3244 | * adaptive_keyboard_hotkey_notify_hotkey() when the sound | ||
| 3245 | * symbol is held. | ||
| 3246 | * We'll need to offset those by 0x20. | ||
| 3247 | */ | ||
| 3248 | KEY_RESERVED, /* Mute held, 0x103 */ | ||
| 3249 | KEY_BRIGHTNESS_MIN, /* Backlight off */ | ||
| 3250 | KEY_RESERVED, /* Clipping tool */ | ||
| 3251 | KEY_RESERVED, /* Cloud */ | ||
| 3252 | KEY_RESERVED, | ||
| 3253 | KEY_VOICECOMMAND, /* Voice */ | ||
| 3254 | KEY_RESERVED, | ||
| 3255 | KEY_RESERVED, /* Gestures */ | ||
| 3256 | KEY_RESERVED, | ||
| 3257 | KEY_RESERVED, | ||
| 3258 | KEY_RESERVED, | ||
| 3259 | KEY_CONFIG, /* Settings */ | ||
| 3260 | KEY_RESERVED, /* New tab */ | ||
| 3261 | KEY_REFRESH, /* Reload */ | ||
| 3262 | KEY_BACK, /* Back */ | ||
| 3263 | KEY_RESERVED, /* Microphone down */ | ||
| 3264 | KEY_RESERVED, /* Microphone up */ | ||
| 3265 | KEY_RESERVED, /* Microphone cancellation */ | ||
| 3266 | KEY_RESERVED, /* Camera mode */ | ||
| 3267 | KEY_RESERVED, /* Rotate display, 0x116 */ | ||
| 3177 | }, | 3268 | }, |
| 3178 | }; | 3269 | }; |
| 3179 | 3270 | ||
| @@ -3227,6 +3318,20 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3227 | if (!tp_features.hotkey) | 3318 | if (!tp_features.hotkey) |
| 3228 | return 1; | 3319 | return 1; |
| 3229 | 3320 | ||
| 3321 | /* | ||
| 3322 | * Check if we have an adaptive keyboard, like on the | ||
| 3323 | * Lenovo Carbon X1 2014 (2nd Gen). | ||
| 3324 | */ | ||
| 3325 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | ||
| 3326 | if ((hkeyv >> 8) == 2) { | ||
| 3327 | tp_features.has_adaptive_kbd = true; | ||
| 3328 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
| 3329 | &adaptive_kbd_attr_group); | ||
| 3330 | if (res) | ||
| 3331 | goto err_exit; | ||
| 3332 | } | ||
| 3333 | } | ||
| 3334 | |||
| 3230 | quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, | 3335 | quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, |
| 3231 | ARRAY_SIZE(tpacpi_hotkey_qtable)); | 3336 | ARRAY_SIZE(tpacpi_hotkey_qtable)); |
| 3232 | 3337 | ||
| @@ -3437,6 +3542,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3437 | 3542 | ||
| 3438 | err_exit: | 3543 | err_exit: |
| 3439 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); | 3544 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); |
| 3545 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | ||
| 3546 | &adaptive_kbd_attr_group); | ||
| 3547 | |||
| 3440 | hotkey_dev_attributes = NULL; | 3548 | hotkey_dev_attributes = NULL; |
| 3441 | 3549 | ||
| 3442 | return (res < 0) ? res : 1; | 3550 | return (res < 0) ? res : 1; |
| @@ -3449,14 +3557,6 @@ err_exit: | |||
| 3449 | * Will consider support rest of modes in future. | 3557 | * Will consider support rest of modes in future. |
| 3450 | * | 3558 | * |
| 3451 | */ | 3559 | */ |
| 3452 | enum ADAPTIVE_KEY_MODE { | ||
| 3453 | HOME_MODE, | ||
| 3454 | WEB_BROWSER_MODE, | ||
| 3455 | WEB_CONFERENCE_MODE, | ||
| 3456 | FUNCTION_MODE, | ||
| 3457 | LAYFLAT_MODE | ||
| 3458 | }; | ||
| 3459 | |||
| 3460 | static const int adaptive_keyboard_modes[] = { | 3560 | static const int adaptive_keyboard_modes[] = { |
| 3461 | HOME_MODE, | 3561 | HOME_MODE, |
| 3462 | /* WEB_BROWSER_MODE = 2, | 3562 | /* WEB_BROWSER_MODE = 2, |
| @@ -3466,6 +3566,8 @@ static const int adaptive_keyboard_modes[] = { | |||
| 3466 | 3566 | ||
| 3467 | #define DFR_CHANGE_ROW 0x101 | 3567 | #define DFR_CHANGE_ROW 0x101 |
| 3468 | #define DFR_SHOW_QUICKVIEW_ROW 0x102 | 3568 | #define DFR_SHOW_QUICKVIEW_ROW 0x102 |
| 3569 | #define FIRST_ADAPTIVE_KEY 0x103 | ||
| 3570 | #define ADAPTIVE_KEY_OFFSET 0x020 | ||
| 3469 | 3571 | ||
| 3470 | /* press Fn key a while second, it will switch to Function Mode. Then | 3572 | /* press Fn key a while second, it will switch to Function Mode. Then |
| 3471 | * release Fn key, previous mode be restored. | 3573 | * release Fn key, previous mode be restored. |
| @@ -3473,6 +3575,32 @@ static const int adaptive_keyboard_modes[] = { | |||
| 3473 | static bool adaptive_keyboard_mode_is_saved; | 3575 | static bool adaptive_keyboard_mode_is_saved; |
| 3474 | static int adaptive_keyboard_prev_mode; | 3576 | static int adaptive_keyboard_prev_mode; |
| 3475 | 3577 | ||
| 3578 | static int adaptive_keyboard_get_mode(void) | ||
| 3579 | { | ||
| 3580 | int mode = 0; | ||
| 3581 | |||
| 3582 | if (!acpi_evalf(hkey_handle, &mode, "GTRW", "dd", 0)) { | ||
| 3583 | pr_err("Cannot read adaptive keyboard mode\n"); | ||
| 3584 | return -EIO; | ||
| 3585 | } | ||
| 3586 | |||
| 3587 | return mode; | ||
| 3588 | } | ||
| 3589 | |||
| 3590 | static int adaptive_keyboard_set_mode(int new_mode) | ||
| 3591 | { | ||
| 3592 | if (new_mode < 0 || | ||
| 3593 | new_mode > LAYFLAT_MODE) | ||
| 3594 | return -EINVAL; | ||
| 3595 | |||
| 3596 | if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) { | ||
| 3597 | pr_err("Cannot set adaptive keyboard mode\n"); | ||
| 3598 | return -EIO; | ||
| 3599 | } | ||
| 3600 | |||
| 3601 | return 0; | ||
| 3602 | } | ||
| 3603 | |||
| 3476 | static int adaptive_keyboard_get_next_mode(int mode) | 3604 | static int adaptive_keyboard_get_next_mode(int mode) |
| 3477 | { | 3605 | { |
| 3478 | size_t i; | 3606 | size_t i; |
| @@ -3493,8 +3621,9 @@ static int adaptive_keyboard_get_next_mode(int mode) | |||
| 3493 | 3621 | ||
| 3494 | static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) | 3622 | static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) |
| 3495 | { | 3623 | { |
| 3496 | u32 current_mode = 0; | 3624 | int current_mode = 0; |
| 3497 | int new_mode = 0; | 3625 | int new_mode = 0; |
| 3626 | int keycode; | ||
| 3498 | 3627 | ||
| 3499 | switch (scancode) { | 3628 | switch (scancode) { |
| 3500 | case DFR_CHANGE_ROW: | 3629 | case DFR_CHANGE_ROW: |
| @@ -3502,43 +3631,51 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) | |||
| 3502 | new_mode = adaptive_keyboard_prev_mode; | 3631 | new_mode = adaptive_keyboard_prev_mode; |
| 3503 | adaptive_keyboard_mode_is_saved = false; | 3632 | adaptive_keyboard_mode_is_saved = false; |
| 3504 | } else { | 3633 | } else { |
| 3505 | if (!acpi_evalf( | 3634 | current_mode = adaptive_keyboard_get_mode(); |
| 3506 | hkey_handle, ¤t_mode, | 3635 | if (current_mode < 0) |
| 3507 | "GTRW", "dd", 0)) { | ||
| 3508 | pr_err("Cannot read adaptive keyboard mode\n"); | ||
| 3509 | return false; | 3636 | return false; |
| 3510 | } else { | 3637 | new_mode = adaptive_keyboard_get_next_mode( |
| 3511 | new_mode = adaptive_keyboard_get_next_mode( | 3638 | current_mode); |
| 3512 | current_mode); | ||
| 3513 | } | ||
| 3514 | } | 3639 | } |
| 3515 | 3640 | ||
| 3516 | if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) { | 3641 | if (adaptive_keyboard_set_mode(new_mode) < 0) |
| 3517 | pr_err("Cannot set adaptive keyboard mode\n"); | ||
| 3518 | return false; | 3642 | return false; |
| 3519 | } | ||
| 3520 | 3643 | ||
| 3521 | return true; | 3644 | return true; |
| 3522 | 3645 | ||
| 3523 | case DFR_SHOW_QUICKVIEW_ROW: | 3646 | case DFR_SHOW_QUICKVIEW_ROW: |
| 3524 | if (!acpi_evalf(hkey_handle, | 3647 | current_mode = adaptive_keyboard_get_mode(); |
| 3525 | &adaptive_keyboard_prev_mode, | 3648 | if (current_mode < 0) |
| 3526 | "GTRW", "dd", 0)) { | ||
| 3527 | pr_err("Cannot read adaptive keyboard mode\n"); | ||
| 3528 | return false; | 3649 | return false; |
| 3529 | } else { | ||
| 3530 | adaptive_keyboard_mode_is_saved = true; | ||
| 3531 | 3650 | ||
| 3532 | if (!acpi_evalf(hkey_handle, | 3651 | adaptive_keyboard_prev_mode = current_mode; |
| 3533 | NULL, "STRW", "vd", FUNCTION_MODE)) { | 3652 | adaptive_keyboard_mode_is_saved = true; |
| 3534 | pr_err("Cannot set adaptive keyboard mode\n"); | 3653 | |
| 3535 | return false; | 3654 | if (adaptive_keyboard_set_mode (FUNCTION_MODE) < 0) |
| 3536 | } | 3655 | return false; |
| 3537 | } | ||
| 3538 | return true; | 3656 | return true; |
| 3539 | 3657 | ||
| 3540 | default: | 3658 | default: |
| 3541 | return false; | 3659 | if (scancode < FIRST_ADAPTIVE_KEY || |
| 3660 | scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN - | ||
| 3661 | ADAPTIVE_KEY_OFFSET) { | ||
| 3662 | pr_info("Unhandled adaptive keyboard key: 0x%x\n", | ||
| 3663 | scancode); | ||
| 3664 | return false; | ||
| 3665 | } | ||
| 3666 | keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + ADAPTIVE_KEY_OFFSET]; | ||
| 3667 | if (keycode != KEY_RESERVED) { | ||
| 3668 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
| 3669 | |||
| 3670 | input_report_key(tpacpi_inputdev, keycode, 1); | ||
| 3671 | input_sync(tpacpi_inputdev); | ||
| 3672 | |||
| 3673 | input_report_key(tpacpi_inputdev, keycode, 0); | ||
| 3674 | input_sync(tpacpi_inputdev); | ||
| 3675 | |||
| 3676 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
| 3677 | } | ||
| 3678 | return true; | ||
| 3542 | } | 3679 | } |
| 3543 | } | 3680 | } |
| 3544 | 3681 | ||
| @@ -3836,28 +3973,21 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
| 3836 | 3973 | ||
| 3837 | static void hotkey_suspend(void) | 3974 | static void hotkey_suspend(void) |
| 3838 | { | 3975 | { |
| 3839 | int hkeyv; | ||
| 3840 | |||
| 3841 | /* Do these on suspend, we get the events on early resume! */ | 3976 | /* Do these on suspend, we get the events on early resume! */ |
| 3842 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; | 3977 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; |
| 3843 | hotkey_autosleep_ack = 0; | 3978 | hotkey_autosleep_ack = 0; |
| 3844 | 3979 | ||
| 3845 | /* save previous mode of adaptive keyboard of X1 Carbon */ | 3980 | /* save previous mode of adaptive keyboard of X1 Carbon */ |
| 3846 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | 3981 | if (tp_features.has_adaptive_kbd) { |
| 3847 | if ((hkeyv >> 8) == 2) { | 3982 | if (!acpi_evalf(hkey_handle, &adaptive_keyboard_prev_mode, |
| 3848 | if (!acpi_evalf(hkey_handle, | 3983 | "GTRW", "dd", 0)) { |
| 3849 | &adaptive_keyboard_prev_mode, | 3984 | pr_err("Cannot read adaptive keyboard mode.\n"); |
| 3850 | "GTRW", "dd", 0)) { | ||
| 3851 | pr_err("Cannot read adaptive keyboard mode.\n"); | ||
| 3852 | } | ||
| 3853 | } | 3985 | } |
| 3854 | } | 3986 | } |
| 3855 | } | 3987 | } |
| 3856 | 3988 | ||
| 3857 | static void hotkey_resume(void) | 3989 | static void hotkey_resume(void) |
| 3858 | { | 3990 | { |
| 3859 | int hkeyv; | ||
| 3860 | |||
| 3861 | tpacpi_disable_brightness_delay(); | 3991 | tpacpi_disable_brightness_delay(); |
| 3862 | 3992 | ||
| 3863 | if (hotkey_status_set(true) < 0 || | 3993 | if (hotkey_status_set(true) < 0 || |
| @@ -3872,14 +4002,10 @@ static void hotkey_resume(void) | |||
| 3872 | hotkey_poll_setup_safe(false); | 4002 | hotkey_poll_setup_safe(false); |
| 3873 | 4003 | ||
| 3874 | /* restore previous mode of adapive keyboard of X1 Carbon */ | 4004 | /* restore previous mode of adapive keyboard of X1 Carbon */ |
| 3875 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | 4005 | if (tp_features.has_adaptive_kbd) { |
| 3876 | if ((hkeyv >> 8) == 2) { | 4006 | if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", |
| 3877 | if (!acpi_evalf(hkey_handle, | 4007 | adaptive_keyboard_prev_mode)) { |
| 3878 | NULL, | 4008 | pr_err("Cannot set adaptive keyboard mode.\n"); |
| 3879 | "STRW", "vd", | ||
| 3880 | adaptive_keyboard_prev_mode)) { | ||
| 3881 | pr_err("Cannot set adaptive keyboard mode.\n"); | ||
| 3882 | } | ||
| 3883 | } | 4009 | } |
| 3884 | } | 4010 | } |
| 3885 | } | 4011 | } |
| @@ -4079,9 +4205,7 @@ static ssize_t bluetooth_enable_store(struct device *dev, | |||
| 4079 | attr, buf, count); | 4205 | attr, buf, count); |
| 4080 | } | 4206 | } |
| 4081 | 4207 | ||
| 4082 | static struct device_attribute dev_attr_bluetooth_enable = | 4208 | static DEVICE_ATTR_RW(bluetooth_enable); |
| 4083 | __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO, | ||
| 4084 | bluetooth_enable_show, bluetooth_enable_store); | ||
| 4085 | 4209 | ||
| 4086 | /* --------------------------------------------------------------------- */ | 4210 | /* --------------------------------------------------------------------- */ |
| 4087 | 4211 | ||
| @@ -4269,9 +4393,7 @@ static ssize_t wan_enable_store(struct device *dev, | |||
| 4269 | attr, buf, count); | 4393 | attr, buf, count); |
| 4270 | } | 4394 | } |
| 4271 | 4395 | ||
| 4272 | static struct device_attribute dev_attr_wan_enable = | 4396 | static DEVICE_ATTR_RW(wan_enable); |
| 4273 | __ATTR(wwan_enable, S_IWUSR | S_IRUGO, | ||
| 4274 | wan_enable_show, wan_enable_store); | ||
| 4275 | 4397 | ||
| 4276 | /* --------------------------------------------------------------------- */ | 4398 | /* --------------------------------------------------------------------- */ |
| 4277 | 4399 | ||
| @@ -5048,8 +5170,7 @@ static ssize_t cmos_command_store(struct device *dev, | |||
| 5048 | return (res) ? res : count; | 5170 | return (res) ? res : count; |
| 5049 | } | 5171 | } |
| 5050 | 5172 | ||
| 5051 | static struct device_attribute dev_attr_cmos_command = | 5173 | static DEVICE_ATTR_WO(cmos_command); |
| 5052 | __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store); | ||
| 5053 | 5174 | ||
| 5054 | /* --------------------------------------------------------------------- */ | 5175 | /* --------------------------------------------------------------------- */ |
| 5055 | 5176 | ||
| @@ -8017,9 +8138,7 @@ static ssize_t fan_pwm1_enable_store(struct device *dev, | |||
| 8017 | return count; | 8138 | return count; |
| 8018 | } | 8139 | } |
| 8019 | 8140 | ||
| 8020 | static struct device_attribute dev_attr_fan_pwm1_enable = | 8141 | static DEVICE_ATTR_RW(fan_pwm1_enable); |
| 8021 | __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | ||
| 8022 | fan_pwm1_enable_show, fan_pwm1_enable_store); | ||
| 8023 | 8142 | ||
| 8024 | /* sysfs fan pwm1 ------------------------------------------------------ */ | 8143 | /* sysfs fan pwm1 ------------------------------------------------------ */ |
| 8025 | static ssize_t fan_pwm1_show(struct device *dev, | 8144 | static ssize_t fan_pwm1_show(struct device *dev, |
| @@ -8079,9 +8198,7 @@ static ssize_t fan_pwm1_store(struct device *dev, | |||
| 8079 | return (rc) ? rc : count; | 8198 | return (rc) ? rc : count; |
| 8080 | } | 8199 | } |
| 8081 | 8200 | ||
| 8082 | static struct device_attribute dev_attr_fan_pwm1 = | 8201 | static DEVICE_ATTR_RW(fan_pwm1); |
| 8083 | __ATTR(pwm1, S_IWUSR | S_IRUGO, | ||
| 8084 | fan_pwm1_show, fan_pwm1_store); | ||
| 8085 | 8202 | ||
| 8086 | /* sysfs fan fan1_input ------------------------------------------------ */ | 8203 | /* sysfs fan fan1_input ------------------------------------------------ */ |
| 8087 | static ssize_t fan_fan1_input_show(struct device *dev, | 8204 | static ssize_t fan_fan1_input_show(struct device *dev, |
| @@ -8098,9 +8215,7 @@ static ssize_t fan_fan1_input_show(struct device *dev, | |||
| 8098 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); | 8215 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); |
| 8099 | } | 8216 | } |
| 8100 | 8217 | ||
| 8101 | static struct device_attribute dev_attr_fan_fan1_input = | 8218 | static DEVICE_ATTR_RO(fan_fan1_input); |
| 8102 | __ATTR(fan1_input, S_IRUGO, | ||
| 8103 | fan_fan1_input_show, NULL); | ||
| 8104 | 8219 | ||
| 8105 | /* sysfs fan fan2_input ------------------------------------------------ */ | 8220 | /* sysfs fan fan2_input ------------------------------------------------ */ |
| 8106 | static ssize_t fan_fan2_input_show(struct device *dev, | 8221 | static ssize_t fan_fan2_input_show(struct device *dev, |
| @@ -8117,9 +8232,7 @@ static ssize_t fan_fan2_input_show(struct device *dev, | |||
| 8117 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); | 8232 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); |
| 8118 | } | 8233 | } |
| 8119 | 8234 | ||
| 8120 | static struct device_attribute dev_attr_fan_fan2_input = | 8235 | static DEVICE_ATTR_RO(fan_fan2_input); |
| 8121 | __ATTR(fan2_input, S_IRUGO, | ||
| 8122 | fan_fan2_input_show, NULL); | ||
| 8123 | 8236 | ||
| 8124 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ | 8237 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
| 8125 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 8238 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
| @@ -8735,8 +8848,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, | |||
| 8735 | return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); | 8848 | return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); |
| 8736 | } | 8849 | } |
| 8737 | 8850 | ||
| 8738 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | 8851 | static DEVICE_ATTR_RO(thinkpad_acpi_pdev_name); |
| 8739 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); | ||
| 8740 | 8852 | ||
| 8741 | /* --------------------------------------------------------------------- */ | 8853 | /* --------------------------------------------------------------------- */ |
| 8742 | 8854 | ||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index dbcb7a8915b8..9956b9902bb4 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include <linux/acpi.h> | 51 | #include <linux/acpi.h> |
| 52 | #include <linux/dmi.h> | 52 | #include <linux/dmi.h> |
| 53 | #include <linux/uaccess.h> | 53 | #include <linux/uaccess.h> |
| 54 | #include <acpi/video.h> | ||
| 54 | 55 | ||
| 55 | MODULE_AUTHOR("John Belmonte"); | 56 | MODULE_AUTHOR("John Belmonte"); |
| 56 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); | 57 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); |
| @@ -116,6 +117,7 @@ MODULE_LICENSE("GPL"); | |||
| 116 | #define HCI_KBD_ILLUMINATION 0x0095 | 117 | #define HCI_KBD_ILLUMINATION 0x0095 |
| 117 | #define HCI_ECO_MODE 0x0097 | 118 | #define HCI_ECO_MODE 0x0097 |
| 118 | #define HCI_ACCELEROMETER2 0x00a6 | 119 | #define HCI_ACCELEROMETER2 0x00a6 |
| 120 | #define HCI_SYSTEM_INFO 0xc000 | ||
| 119 | #define SCI_PANEL_POWER_ON 0x010d | 121 | #define SCI_PANEL_POWER_ON 0x010d |
| 120 | #define SCI_ILLUMINATION 0x014e | 122 | #define SCI_ILLUMINATION 0x014e |
| 121 | #define SCI_USB_SLEEP_CHARGE 0x0150 | 123 | #define SCI_USB_SLEEP_CHARGE 0x0150 |
| @@ -129,10 +131,13 @@ MODULE_LICENSE("GPL"); | |||
| 129 | #define HCI_ACCEL_MASK 0x7fff | 131 | #define HCI_ACCEL_MASK 0x7fff |
| 130 | #define HCI_HOTKEY_DISABLE 0x0b | 132 | #define HCI_HOTKEY_DISABLE 0x0b |
| 131 | #define HCI_HOTKEY_ENABLE 0x09 | 133 | #define HCI_HOTKEY_ENABLE 0x09 |
| 134 | #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 | ||
| 132 | #define HCI_LCD_BRIGHTNESS_BITS 3 | 135 | #define HCI_LCD_BRIGHTNESS_BITS 3 |
| 133 | #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) | 136 | #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) |
| 134 | #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) | 137 | #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) |
| 135 | #define HCI_MISC_SHIFT 0x10 | 138 | #define HCI_MISC_SHIFT 0x10 |
| 139 | #define HCI_SYSTEM_TYPE1 0x10 | ||
| 140 | #define HCI_SYSTEM_TYPE2 0x11 | ||
| 136 | #define HCI_VIDEO_OUT_LCD 0x1 | 141 | #define HCI_VIDEO_OUT_LCD 0x1 |
| 137 | #define HCI_VIDEO_OUT_CRT 0x2 | 142 | #define HCI_VIDEO_OUT_CRT 0x2 |
| 138 | #define HCI_VIDEO_OUT_TV 0x4 | 143 | #define HCI_VIDEO_OUT_TV 0x4 |
| @@ -147,9 +152,10 @@ MODULE_LICENSE("GPL"); | |||
| 147 | #define SCI_KBD_MODE_OFF 0x10 | 152 | #define SCI_KBD_MODE_OFF 0x10 |
| 148 | #define SCI_KBD_TIME_MAX 0x3c001a | 153 | #define SCI_KBD_TIME_MAX 0x3c001a |
| 149 | #define SCI_USB_CHARGE_MODE_MASK 0xff | 154 | #define SCI_USB_CHARGE_MODE_MASK 0xff |
| 150 | #define SCI_USB_CHARGE_DISABLED 0x30000 | 155 | #define SCI_USB_CHARGE_DISABLED 0x00 |
| 151 | #define SCI_USB_CHARGE_ALTERNATE 0x30009 | 156 | #define SCI_USB_CHARGE_ALTERNATE 0x09 |
| 152 | #define SCI_USB_CHARGE_AUTO 0x30021 | 157 | #define SCI_USB_CHARGE_TYPICAL 0x11 |
| 158 | #define SCI_USB_CHARGE_AUTO 0x21 | ||
| 153 | #define SCI_USB_CHARGE_BAT_MASK 0x7 | 159 | #define SCI_USB_CHARGE_BAT_MASK 0x7 |
| 154 | #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 | 160 | #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 |
| 155 | #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 | 161 | #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 |
| @@ -174,6 +180,8 @@ struct toshiba_acpi_dev { | |||
| 174 | int kbd_mode; | 180 | int kbd_mode; |
| 175 | int kbd_time; | 181 | int kbd_time; |
| 176 | int usbsc_bat_level; | 182 | int usbsc_bat_level; |
| 183 | int usbsc_mode_base; | ||
| 184 | int hotkey_event_type; | ||
| 177 | 185 | ||
| 178 | unsigned int illumination_supported:1; | 186 | unsigned int illumination_supported:1; |
| 179 | unsigned int video_supported:1; | 187 | unsigned int video_supported:1; |
| @@ -243,29 +251,6 @@ static const struct key_entry toshiba_acpi_keymap[] = { | |||
| 243 | { KE_END, 0 }, | 251 | { KE_END, 0 }, |
| 244 | }; | 252 | }; |
| 245 | 253 | ||
| 246 | /* alternative keymap */ | ||
| 247 | static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { | ||
| 248 | { | ||
| 249 | .matches = { | ||
| 250 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 251 | DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), | ||
| 252 | }, | ||
| 253 | }, | ||
| 254 | { | ||
| 255 | .matches = { | ||
| 256 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 257 | DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"), | ||
| 258 | }, | ||
| 259 | }, | ||
| 260 | { | ||
| 261 | .matches = { | ||
| 262 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 263 | DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"), | ||
| 264 | }, | ||
| 265 | }, | ||
| 266 | {} | ||
| 267 | }; | ||
| 268 | |||
| 269 | static const struct key_entry toshiba_acpi_alt_keymap[] = { | 254 | static const struct key_entry toshiba_acpi_alt_keymap[] = { |
| 270 | { KE_KEY, 0x157, { KEY_MUTE } }, | 255 | { KE_KEY, 0x157, { KEY_MUTE } }, |
| 271 | { KE_KEY, 0x102, { KEY_ZOOMOUT } }, | 256 | { KE_KEY, 0x102, { KEY_ZOOMOUT } }, |
| @@ -281,6 +266,14 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = { | |||
| 281 | }; | 266 | }; |
| 282 | 267 | ||
| 283 | /* | 268 | /* |
| 269 | * List of models which have a broken acpi-video backlight interface and thus | ||
| 270 | * need to use the toshiba (vendor) interface instead. | ||
| 271 | */ | ||
| 272 | static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { | ||
| 273 | {} | ||
| 274 | }; | ||
| 275 | |||
| 276 | /* | ||
| 284 | * Utility | 277 | * Utility |
| 285 | */ | 278 | */ |
| 286 | 279 | ||
| @@ -819,6 +812,54 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, | |||
| 819 | } | 812 | } |
| 820 | 813 | ||
| 821 | /* Sleep (Charge and Music) utilities support */ | 814 | /* Sleep (Charge and Music) utilities support */ |
| 815 | static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) | ||
| 816 | { | ||
| 817 | u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; | ||
| 818 | u32 out[TCI_WORDS]; | ||
| 819 | acpi_status status; | ||
| 820 | |||
| 821 | /* Set the feature to "not supported" in case of error */ | ||
| 822 | dev->usb_sleep_charge_supported = 0; | ||
| 823 | |||
| 824 | if (!sci_open(dev)) | ||
| 825 | return; | ||
| 826 | |||
| 827 | status = tci_raw(dev, in, out); | ||
| 828 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { | ||
| 829 | pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); | ||
| 830 | sci_close(dev); | ||
| 831 | return; | ||
| 832 | } else if (out[0] == TOS_NOT_SUPPORTED) { | ||
| 833 | pr_info("USB Sleep and Charge not supported\n"); | ||
| 834 | sci_close(dev); | ||
| 835 | return; | ||
| 836 | } else if (out[0] == TOS_SUCCESS) { | ||
| 837 | dev->usbsc_mode_base = out[4]; | ||
| 838 | } | ||
| 839 | |||
| 840 | in[5] = SCI_USB_CHARGE_BAT_LVL; | ||
| 841 | status = tci_raw(dev, in, out); | ||
| 842 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { | ||
| 843 | pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); | ||
| 844 | sci_close(dev); | ||
| 845 | return; | ||
| 846 | } else if (out[0] == TOS_NOT_SUPPORTED) { | ||
| 847 | pr_info("USB Sleep and Charge not supported\n"); | ||
| 848 | sci_close(dev); | ||
| 849 | return; | ||
| 850 | } else if (out[0] == TOS_SUCCESS) { | ||
| 851 | dev->usbsc_bat_level = out[2]; | ||
| 852 | /* | ||
| 853 | * If we reach this point, it means that the laptop has support | ||
| 854 | * for this feature and all values are initialized. | ||
| 855 | * Set it as supported. | ||
| 856 | */ | ||
| 857 | dev->usb_sleep_charge_supported = 1; | ||
| 858 | } | ||
| 859 | |||
| 860 | sci_close(dev); | ||
| 861 | } | ||
| 862 | |||
| 822 | static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, | 863 | static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, |
| 823 | u32 *mode) | 864 | u32 *mode) |
| 824 | { | 865 | { |
| @@ -934,11 +975,11 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, | |||
| 934 | status = tci_raw(dev, in, out); | 975 | status = tci_raw(dev, in, out); |
| 935 | sci_close(dev); | 976 | sci_close(dev); |
| 936 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { | 977 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { |
| 937 | pr_err("ACPI call to get USB S&C battery level failed\n"); | 978 | pr_err("ACPI call to get USB Rapid Charge failed\n"); |
| 938 | return -EIO; | 979 | return -EIO; |
| 939 | } else if (out[0] == TOS_NOT_SUPPORTED || | 980 | } else if (out[0] == TOS_NOT_SUPPORTED || |
| 940 | out[0] == TOS_INPUT_DATA_ERROR) { | 981 | out[0] == TOS_INPUT_DATA_ERROR) { |
| 941 | pr_info("USB Sleep and Charge not supported\n"); | 982 | pr_info("USB Rapid Charge not supported\n"); |
| 942 | return -ENODEV; | 983 | return -ENODEV; |
| 943 | } | 984 | } |
| 944 | 985 | ||
| @@ -962,10 +1003,10 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, | |||
| 962 | status = tci_raw(dev, in, out); | 1003 | status = tci_raw(dev, in, out); |
| 963 | sci_close(dev); | 1004 | sci_close(dev); |
| 964 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { | 1005 | if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { |
| 965 | pr_err("ACPI call to set USB S&C battery level failed\n"); | 1006 | pr_err("ACPI call to set USB Rapid Charge failed\n"); |
| 966 | return -EIO; | 1007 | return -EIO; |
| 967 | } else if (out[0] == TOS_NOT_SUPPORTED) { | 1008 | } else if (out[0] == TOS_NOT_SUPPORTED) { |
| 968 | pr_info("USB Sleep and Charge not supported\n"); | 1009 | pr_info("USB Rapid Charge not supported\n"); |
| 969 | return -ENODEV; | 1010 | return -ENODEV; |
| 970 | } else if (out[0] == TOS_INPUT_DATA_ERROR) { | 1011 | } else if (out[0] == TOS_INPUT_DATA_ERROR) { |
| 971 | return -EIO; | 1012 | return -EIO; |
| @@ -984,10 +1025,10 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) | |||
| 984 | result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); | 1025 | result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); |
| 985 | sci_close(dev); | 1026 | sci_close(dev); |
| 986 | if (result == TOS_FAILURE) { | 1027 | if (result == TOS_FAILURE) { |
| 987 | pr_err("ACPI call to set USB S&C mode failed\n"); | 1028 | pr_err("ACPI call to get Sleep and Music failed\n"); |
| 988 | return -EIO; | 1029 | return -EIO; |
| 989 | } else if (result == TOS_NOT_SUPPORTED) { | 1030 | } else if (result == TOS_NOT_SUPPORTED) { |
| 990 | pr_info("USB Sleep and Charge not supported\n"); | 1031 | pr_info("Sleep and Music not supported\n"); |
| 991 | return -ENODEV; | 1032 | return -ENODEV; |
| 992 | } else if (result == TOS_INPUT_DATA_ERROR) { | 1033 | } else if (result == TOS_INPUT_DATA_ERROR) { |
| 993 | return -EIO; | 1034 | return -EIO; |
| @@ -1006,10 +1047,10 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) | |||
| 1006 | result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); | 1047 | result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); |
| 1007 | sci_close(dev); | 1048 | sci_close(dev); |
| 1008 | if (result == TOS_FAILURE) { | 1049 | if (result == TOS_FAILURE) { |
| 1009 | pr_err("ACPI call to set USB S&C mode failed\n"); | 1050 | pr_err("ACPI call to set Sleep and Music failed\n"); |
| 1010 | return -EIO; | 1051 | return -EIO; |
| 1011 | } else if (result == TOS_NOT_SUPPORTED) { | 1052 | } else if (result == TOS_NOT_SUPPORTED) { |
| 1012 | pr_info("USB Sleep and Charge not supported\n"); | 1053 | pr_info("Sleep and Music not supported\n"); |
| 1013 | return -ENODEV; | 1054 | return -ENODEV; |
| 1014 | } else if (result == TOS_INPUT_DATA_ERROR) { | 1055 | } else if (result == TOS_INPUT_DATA_ERROR) { |
| 1015 | return -EIO; | 1056 | return -EIO; |
| @@ -1149,6 +1190,28 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) | |||
| 1149 | return 0; | 1190 | return 0; |
| 1150 | } | 1191 | } |
| 1151 | 1192 | ||
| 1193 | /* Hotkey Event type */ | ||
| 1194 | static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, | ||
| 1195 | u32 *type) | ||
| 1196 | { | ||
| 1197 | u32 val1 = 0x03; | ||
| 1198 | u32 val2 = 0; | ||
| 1199 | u32 result; | ||
| 1200 | |||
| 1201 | result = hci_read2(dev, HCI_SYSTEM_INFO, &val1, &val2); | ||
| 1202 | if (result == TOS_FAILURE) { | ||
| 1203 | pr_err("ACPI call to get System type failed\n"); | ||
| 1204 | return -EIO; | ||
| 1205 | } else if (result == TOS_NOT_SUPPORTED) { | ||
| 1206 | pr_info("System type not supported\n"); | ||
| 1207 | return -ENODEV; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | *type = val2; | ||
| 1211 | |||
| 1212 | return 0; | ||
| 1213 | } | ||
| 1214 | |||
| 1152 | /* Bluetooth rfkill handlers */ | 1215 | /* Bluetooth rfkill handlers */ |
| 1153 | 1216 | ||
| 1154 | static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) | 1217 | static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) |
| @@ -1973,17 +2036,21 @@ static ssize_t usb_sleep_charge_store(struct device *dev, | |||
| 1973 | * 0 - Disabled | 2036 | * 0 - Disabled |
| 1974 | * 1 - Alternate (Non USB conformant devices that require more power) | 2037 | * 1 - Alternate (Non USB conformant devices that require more power) |
| 1975 | * 2 - Auto (USB conformant devices) | 2038 | * 2 - Auto (USB conformant devices) |
| 2039 | * 3 - Typical | ||
| 1976 | */ | 2040 | */ |
| 1977 | if (state != 0 && state != 1 && state != 2) | 2041 | if (state != 0 && state != 1 && state != 2 && state != 3) |
| 1978 | return -EINVAL; | 2042 | return -EINVAL; |
| 1979 | 2043 | ||
| 1980 | /* Set the USB charging mode to internal value */ | 2044 | /* Set the USB charging mode to internal value */ |
| 2045 | mode = toshiba->usbsc_mode_base; | ||
| 1981 | if (state == 0) | 2046 | if (state == 0) |
| 1982 | mode = SCI_USB_CHARGE_DISABLED; | 2047 | mode |= SCI_USB_CHARGE_DISABLED; |
| 1983 | else if (state == 1) | 2048 | else if (state == 1) |
| 1984 | mode = SCI_USB_CHARGE_ALTERNATE; | 2049 | mode |= SCI_USB_CHARGE_ALTERNATE; |
| 1985 | else if (state == 2) | 2050 | else if (state == 2) |
| 1986 | mode = SCI_USB_CHARGE_AUTO; | 2051 | mode |= SCI_USB_CHARGE_AUTO; |
| 2052 | else if (state == 3) | ||
| 2053 | mode |= SCI_USB_CHARGE_TYPICAL; | ||
| 1987 | 2054 | ||
| 1988 | ret = toshiba_usb_sleep_charge_set(toshiba, mode); | 2055 | ret = toshiba_usb_sleep_charge_set(toshiba, mode); |
| 1989 | if (ret) | 2056 | if (ret) |
| @@ -2333,6 +2400,20 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) | |||
| 2333 | return 0; | 2400 | return 0; |
| 2334 | } | 2401 | } |
| 2335 | 2402 | ||
| 2403 | static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) | ||
| 2404 | { | ||
| 2405 | u32 result; | ||
| 2406 | |||
| 2407 | /* | ||
| 2408 | * Re-activate the hotkeys, but this time, we are using the | ||
| 2409 | * "Special Functions" mode. | ||
| 2410 | */ | ||
| 2411 | result = hci_write1(dev, HCI_HOTKEY_EVENT, | ||
| 2412 | HCI_HOTKEY_SPECIAL_FUNCTIONS); | ||
| 2413 | if (result != TOS_SUCCESS) | ||
| 2414 | pr_err("Could not enable the Special Function mode\n"); | ||
| 2415 | } | ||
| 2416 | |||
| 2336 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, | 2417 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, |
| 2337 | struct serio *port) | 2418 | struct serio *port) |
| 2338 | { | 2419 | { |
| @@ -2434,10 +2515,22 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) | |||
| 2434 | 2515 | ||
| 2435 | static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | 2516 | static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) |
| 2436 | { | 2517 | { |
| 2518 | const struct key_entry *keymap = toshiba_acpi_keymap; | ||
| 2437 | acpi_handle ec_handle; | 2519 | acpi_handle ec_handle; |
| 2438 | int error; | 2520 | u32 events_type; |
| 2439 | u32 hci_result; | 2521 | u32 hci_result; |
| 2440 | const struct key_entry *keymap = toshiba_acpi_keymap; | 2522 | int error; |
| 2523 | |||
| 2524 | error = toshiba_acpi_enable_hotkeys(dev); | ||
| 2525 | if (error) | ||
| 2526 | return error; | ||
| 2527 | |||
| 2528 | error = toshiba_hotkey_event_type_get(dev, &events_type); | ||
| 2529 | if (error) { | ||
| 2530 | pr_err("Unable to query Hotkey Event Type\n"); | ||
| 2531 | return error; | ||
| 2532 | } | ||
| 2533 | dev->hotkey_event_type = events_type; | ||
| 2441 | 2534 | ||
| 2442 | dev->hotkey_dev = input_allocate_device(); | 2535 | dev->hotkey_dev = input_allocate_device(); |
| 2443 | if (!dev->hotkey_dev) | 2536 | if (!dev->hotkey_dev) |
| @@ -2447,8 +2540,14 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 2447 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; | 2540 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; |
| 2448 | dev->hotkey_dev->id.bustype = BUS_HOST; | 2541 | dev->hotkey_dev->id.bustype = BUS_HOST; |
| 2449 | 2542 | ||
| 2450 | if (dmi_check_system(toshiba_alt_keymap_dmi)) | 2543 | if (events_type == HCI_SYSTEM_TYPE1 || |
| 2544 | !dev->kbd_function_keys_supported) | ||
| 2545 | keymap = toshiba_acpi_keymap; | ||
| 2546 | else if (events_type == HCI_SYSTEM_TYPE2 || | ||
| 2547 | dev->kbd_function_keys_supported) | ||
| 2451 | keymap = toshiba_acpi_alt_keymap; | 2548 | keymap = toshiba_acpi_alt_keymap; |
| 2549 | else | ||
| 2550 | pr_info("Unknown event type received %x\n", events_type); | ||
| 2452 | error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); | 2551 | error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); |
| 2453 | if (error) | 2552 | if (error) |
| 2454 | goto err_free_dev; | 2553 | goto err_free_dev; |
| @@ -2490,12 +2589,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 2490 | goto err_remove_filter; | 2589 | goto err_remove_filter; |
| 2491 | } | 2590 | } |
| 2492 | 2591 | ||
| 2493 | error = toshiba_acpi_enable_hotkeys(dev); | ||
| 2494 | if (error) { | ||
| 2495 | pr_info("Unable to enable hotkeys\n"); | ||
| 2496 | goto err_remove_filter; | ||
| 2497 | } | ||
| 2498 | |||
| 2499 | error = input_register_device(dev->hotkey_dev); | 2592 | error = input_register_device(dev->hotkey_dev); |
| 2500 | if (error) { | 2593 | if (error) { |
| 2501 | pr_info("Unable to register input device\n"); | 2594 | pr_info("Unable to register input device\n"); |
| @@ -2541,6 +2634,20 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) | |||
| 2541 | ret = get_tr_backlight_status(dev, &enabled); | 2634 | ret = get_tr_backlight_status(dev, &enabled); |
| 2542 | dev->tr_backlight_supported = !ret; | 2635 | dev->tr_backlight_supported = !ret; |
| 2543 | 2636 | ||
| 2637 | /* | ||
| 2638 | * Tell acpi-video-detect code to prefer vendor backlight on all | ||
| 2639 | * systems with transflective backlight and on dmi matched systems. | ||
| 2640 | */ | ||
| 2641 | if (dev->tr_backlight_supported || | ||
| 2642 | dmi_check_system(toshiba_vendor_backlight_dmi)) | ||
| 2643 | acpi_video_dmi_promote_vendor(); | ||
| 2644 | |||
| 2645 | if (acpi_video_backlight_support()) | ||
| 2646 | return 0; | ||
| 2647 | |||
| 2648 | /* acpi-video may have loaded before we called dmi_promote_vendor() */ | ||
| 2649 | acpi_video_unregister_backlight(); | ||
| 2650 | |||
| 2544 | memset(&props, 0, sizeof(props)); | 2651 | memset(&props, 0, sizeof(props)); |
| 2545 | props.type = BACKLIGHT_PLATFORM; | 2652 | props.type = BACKLIGHT_PLATFORM; |
| 2546 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; | 2653 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; |
| @@ -2624,6 +2731,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 2624 | { | 2731 | { |
| 2625 | struct toshiba_acpi_dev *dev; | 2732 | struct toshiba_acpi_dev *dev; |
| 2626 | const char *hci_method; | 2733 | const char *hci_method; |
| 2734 | u32 special_functions; | ||
| 2627 | u32 dummy; | 2735 | u32 dummy; |
| 2628 | bool bt_present; | 2736 | bool bt_present; |
| 2629 | int ret = 0; | 2737 | int ret = 0; |
| @@ -2648,6 +2756,16 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 2648 | acpi_dev->driver_data = dev; | 2756 | acpi_dev->driver_data = dev; |
| 2649 | dev_set_drvdata(&acpi_dev->dev, dev); | 2757 | dev_set_drvdata(&acpi_dev->dev, dev); |
| 2650 | 2758 | ||
| 2759 | /* Query the BIOS for supported features */ | ||
| 2760 | |||
| 2761 | /* | ||
| 2762 | * The "Special Functions" are always supported by the laptops | ||
| 2763 | * with the new keyboard layout, query for its presence to help | ||
| 2764 | * determine the keymap layout to use. | ||
| 2765 | */ | ||
| 2766 | ret = toshiba_function_keys_get(dev, &special_functions); | ||
| 2767 | dev->kbd_function_keys_supported = !ret; | ||
| 2768 | |||
| 2651 | if (toshiba_acpi_setup_keyboard(dev)) | 2769 | if (toshiba_acpi_setup_keyboard(dev)) |
| 2652 | pr_info("Unable to activate hotkeys\n"); | 2770 | pr_info("Unable to activate hotkeys\n"); |
| 2653 | 2771 | ||
| @@ -2716,8 +2834,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 2716 | ret = toshiba_accelerometer_supported(dev); | 2834 | ret = toshiba_accelerometer_supported(dev); |
| 2717 | dev->accelerometer_supported = !ret; | 2835 | dev->accelerometer_supported = !ret; |
| 2718 | 2836 | ||
| 2719 | ret = toshiba_usb_sleep_charge_get(dev, &dummy); | 2837 | toshiba_usb_sleep_charge_available(dev); |
| 2720 | dev->usb_sleep_charge_supported = !ret; | ||
| 2721 | 2838 | ||
| 2722 | ret = toshiba_usb_rapid_charge_get(dev, &dummy); | 2839 | ret = toshiba_usb_rapid_charge_get(dev, &dummy); |
| 2723 | dev->usb_rapid_charge_supported = !ret; | 2840 | dev->usb_rapid_charge_supported = !ret; |
| @@ -2725,23 +2842,25 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 2725 | ret = toshiba_usb_sleep_music_get(dev, &dummy); | 2842 | ret = toshiba_usb_sleep_music_get(dev, &dummy); |
| 2726 | dev->usb_sleep_music_supported = !ret; | 2843 | dev->usb_sleep_music_supported = !ret; |
| 2727 | 2844 | ||
| 2728 | ret = toshiba_function_keys_get(dev, &dummy); | ||
| 2729 | dev->kbd_function_keys_supported = !ret; | ||
| 2730 | |||
| 2731 | ret = toshiba_panel_power_on_get(dev, &dummy); | 2845 | ret = toshiba_panel_power_on_get(dev, &dummy); |
| 2732 | dev->panel_power_on_supported = !ret; | 2846 | dev->panel_power_on_supported = !ret; |
| 2733 | 2847 | ||
| 2734 | ret = toshiba_usb_three_get(dev, &dummy); | 2848 | ret = toshiba_usb_three_get(dev, &dummy); |
| 2735 | dev->usb_three_supported = !ret; | 2849 | dev->usb_three_supported = !ret; |
| 2736 | 2850 | ||
| 2737 | /* Determine whether or not BIOS supports fan and video interfaces */ | ||
| 2738 | |||
| 2739 | ret = get_video_status(dev, &dummy); | 2851 | ret = get_video_status(dev, &dummy); |
| 2740 | dev->video_supported = !ret; | 2852 | dev->video_supported = !ret; |
| 2741 | 2853 | ||
| 2742 | ret = get_fan_status(dev, &dummy); | 2854 | ret = get_fan_status(dev, &dummy); |
| 2743 | dev->fan_supported = !ret; | 2855 | dev->fan_supported = !ret; |
| 2744 | 2856 | ||
| 2857 | /* | ||
| 2858 | * Enable the "Special Functions" mode only if they are | ||
| 2859 | * supported and if they are activated. | ||
| 2860 | */ | ||
| 2861 | if (dev->kbd_function_keys_supported && special_functions) | ||
| 2862 | toshiba_acpi_enable_special_functions(dev); | ||
| 2863 | |||
| 2745 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, | 2864 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, |
| 2746 | &toshiba_attr_group); | 2865 | &toshiba_attr_group); |
| 2747 | if (ret) { | 2866 | if (ret) { |
| @@ -2770,6 +2889,21 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) | |||
| 2770 | case 0x80: /* Hotkeys and some system events */ | 2889 | case 0x80: /* Hotkeys and some system events */ |
| 2771 | toshiba_acpi_process_hotkeys(dev); | 2890 | toshiba_acpi_process_hotkeys(dev); |
| 2772 | break; | 2891 | break; |
| 2892 | case 0x81: /* Dock events */ | ||
| 2893 | case 0x82: | ||
| 2894 | case 0x83: | ||
| 2895 | pr_info("Dock event received %x\n", event); | ||
| 2896 | break; | ||
| 2897 | case 0x88: /* Thermal events */ | ||
| 2898 | pr_info("Thermal event received\n"); | ||
| 2899 | break; | ||
| 2900 | case 0x8f: /* LID closed */ | ||
| 2901 | case 0x90: /* LID is closed and Dock has been ejected */ | ||
| 2902 | break; | ||
| 2903 | case 0x8c: /* SATA power events */ | ||
| 2904 | case 0x8b: | ||
| 2905 | pr_info("SATA power event received %x\n", event); | ||
| 2906 | break; | ||
| 2773 | case 0x92: /* Keyboard backlight mode changed */ | 2907 | case 0x92: /* Keyboard backlight mode changed */ |
| 2774 | /* Update sysfs entries */ | 2908 | /* Update sysfs entries */ |
| 2775 | ret = sysfs_update_group(&acpi_dev->dev.kobj, | 2909 | ret = sysfs_update_group(&acpi_dev->dev.kobj, |
| @@ -2777,17 +2911,19 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) | |||
| 2777 | if (ret) | 2911 | if (ret) |
| 2778 | pr_err("Unable to update sysfs entries\n"); | 2912 | pr_err("Unable to update sysfs entries\n"); |
| 2779 | break; | 2913 | break; |
| 2780 | case 0x81: /* Unknown */ | 2914 | case 0x85: /* Unknown */ |
| 2781 | case 0x82: /* Unknown */ | 2915 | case 0x8d: /* Unknown */ |
| 2782 | case 0x83: /* Unknown */ | ||
| 2783 | case 0x8c: /* Unknown */ | ||
| 2784 | case 0x8e: /* Unknown */ | 2916 | case 0x8e: /* Unknown */ |
| 2785 | case 0x8f: /* Unknown */ | 2917 | case 0x94: /* Unknown */ |
| 2786 | case 0x90: /* Unknown */ | 2918 | case 0x95: /* Unknown */ |
| 2787 | default: | 2919 | default: |
| 2788 | pr_info("Unknown event received %x\n", event); | 2920 | pr_info("Unknown event received %x\n", event); |
| 2789 | break; | 2921 | break; |
| 2790 | } | 2922 | } |
| 2923 | |||
| 2924 | acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, | ||
| 2925 | dev_name(&acpi_dev->dev), | ||
| 2926 | event, 0); | ||
| 2791 | } | 2927 | } |
| 2792 | 2928 | ||
| 2793 | #ifdef CONFIG_PM_SLEEP | 2929 | #ifdef CONFIG_PM_SLEEP |
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index 2cb1ea62b4a7..249800763362 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * Toshiba Bluetooth Enable Driver | 2 | * Toshiba Bluetooth Enable Driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com> | 4 | * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com> |
| 5 | * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com> | ||
| 5 | * | 6 | * |
| 6 | * Thanks to Matthew Garrett for background info on ACPI innards which | 7 | * Thanks to Matthew Garrett for background info on ACPI innards which |
| 7 | * normal people aren't meant to understand :-) | 8 | * normal people aren't meant to understand :-) |
| @@ -25,6 +26,10 @@ | |||
| 25 | #include <linux/types.h> | 26 | #include <linux/types.h> |
| 26 | #include <linux/acpi.h> | 27 | #include <linux/acpi.h> |
| 27 | 28 | ||
| 29 | #define BT_KILLSWITCH_MASK 0x01 | ||
| 30 | #define BT_PLUGGED_MASK 0x40 | ||
| 31 | #define BT_POWER_MASK 0x80 | ||
| 32 | |||
| 28 | MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>"); | 33 | MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>"); |
| 29 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); | 34 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); |
| 30 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
| @@ -57,32 +62,107 @@ static struct acpi_driver toshiba_bt_rfkill_driver = { | |||
| 57 | .drv.pm = &toshiba_bt_pm, | 62 | .drv.pm = &toshiba_bt_pm, |
| 58 | }; | 63 | }; |
| 59 | 64 | ||
| 65 | static int toshiba_bluetooth_present(acpi_handle handle) | ||
| 66 | { | ||
| 67 | acpi_status result; | ||
| 68 | u64 bt_present; | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Some Toshiba laptops may have a fake TOS6205 device in | ||
| 72 | * their ACPI BIOS, so query the _STA method to see if there | ||
| 73 | * is really anything there. | ||
| 74 | */ | ||
| 75 | result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present); | ||
| 76 | if (ACPI_FAILURE(result)) { | ||
| 77 | pr_err("ACPI call to query Bluetooth presence failed"); | ||
| 78 | return -ENXIO; | ||
| 79 | } else if (!bt_present) { | ||
| 80 | pr_info("Bluetooth device not present\n"); | ||
| 81 | return -ENODEV; | ||
| 82 | } | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int toshiba_bluetooth_status(acpi_handle handle) | ||
| 88 | { | ||
| 89 | acpi_status result; | ||
| 90 | u64 status; | ||
| 91 | |||
| 92 | result = acpi_evaluate_integer(handle, "BTST", NULL, &status); | ||
| 93 | if (ACPI_FAILURE(result)) { | ||
| 94 | pr_err("Could not get Bluetooth device status\n"); | ||
| 95 | return -ENXIO; | ||
| 96 | } | ||
| 97 | |||
| 98 | pr_info("Bluetooth status %llu\n", status); | ||
| 99 | |||
| 100 | return status; | ||
| 101 | } | ||
| 60 | 102 | ||
| 61 | static int toshiba_bluetooth_enable(acpi_handle handle) | 103 | static int toshiba_bluetooth_enable(acpi_handle handle) |
| 62 | { | 104 | { |
| 63 | acpi_status res1, res2; | 105 | acpi_status result; |
| 64 | u64 result; | 106 | bool killswitch; |
| 107 | bool powered; | ||
| 108 | bool plugged; | ||
| 109 | int status; | ||
| 65 | 110 | ||
| 66 | /* | 111 | /* |
| 67 | * Query ACPI to verify RFKill switch is set to 'on'. | 112 | * Query ACPI to verify RFKill switch is set to 'on'. |
| 68 | * If not, we return silently, no need to report it as | 113 | * If not, we return silently, no need to report it as |
| 69 | * an error. | 114 | * an error. |
| 70 | */ | 115 | */ |
| 71 | res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result); | 116 | status = toshiba_bluetooth_status(handle); |
| 72 | if (ACPI_FAILURE(res1)) | 117 | if (status < 0) |
| 73 | return res1; | 118 | return status; |
| 74 | if (!(result & 0x01)) | 119 | |
| 75 | return 0; | 120 | killswitch = (status & BT_KILLSWITCH_MASK) ? true : false; |
| 121 | powered = (status & BT_POWER_MASK) ? true : false; | ||
| 122 | plugged = (status & BT_PLUGGED_MASK) ? true : false; | ||
| 76 | 123 | ||
| 77 | pr_info("Re-enabling Toshiba Bluetooth\n"); | 124 | if (!killswitch) |
| 78 | res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL); | ||
| 79 | res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL); | ||
| 80 | if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2)) | ||
| 81 | return 0; | 125 | return 0; |
| 126 | /* | ||
| 127 | * This check ensures to only enable the device if it is powered | ||
| 128 | * off or detached, as some recent devices somehow pass the killswitch | ||
| 129 | * test, causing a loop enabling/disabling the device, see bug 93911. | ||
| 130 | */ | ||
| 131 | if (powered || plugged) | ||
| 132 | return 0; | ||
| 133 | |||
| 134 | result = acpi_evaluate_object(handle, "AUSB", NULL, NULL); | ||
| 135 | if (ACPI_FAILURE(result)) { | ||
| 136 | pr_err("Could not attach USB Bluetooth device\n"); | ||
| 137 | return -ENXIO; | ||
| 138 | } | ||
| 139 | |||
| 140 | result = acpi_evaluate_object(handle, "BTPO", NULL, NULL); | ||
| 141 | if (ACPI_FAILURE(result)) { | ||
| 142 | pr_err("Could not power ON Bluetooth device\n"); | ||
| 143 | return -ENXIO; | ||
| 144 | } | ||
| 145 | |||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | static int toshiba_bluetooth_disable(acpi_handle handle) | ||
| 150 | { | ||
| 151 | acpi_status result; | ||
| 152 | |||
| 153 | result = acpi_evaluate_object(handle, "BTPF", NULL, NULL); | ||
| 154 | if (ACPI_FAILURE(result)) { | ||
| 155 | pr_err("Could not power OFF Bluetooth device\n"); | ||
| 156 | return -ENXIO; | ||
| 157 | } | ||
| 82 | 158 | ||
| 83 | pr_warn("Failed to re-enable Toshiba Bluetooth\n"); | 159 | result = acpi_evaluate_object(handle, "DUSB", NULL, NULL); |
| 160 | if (ACPI_FAILURE(result)) { | ||
| 161 | pr_err("Could not detach USB Bluetooth device\n"); | ||
| 162 | return -ENXIO; | ||
| 163 | } | ||
| 84 | 164 | ||
| 85 | return -ENODEV; | 165 | return 0; |
| 86 | } | 166 | } |
| 87 | 167 | ||
| 88 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) | 168 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) |
| @@ -99,23 +179,18 @@ static int toshiba_bt_resume(struct device *dev) | |||
| 99 | 179 | ||
| 100 | static int toshiba_bt_rfkill_add(struct acpi_device *device) | 180 | static int toshiba_bt_rfkill_add(struct acpi_device *device) |
| 101 | { | 181 | { |
| 102 | acpi_status status; | 182 | int result; |
| 103 | u64 bt_present; | ||
| 104 | int result = -ENODEV; | ||
| 105 | 183 | ||
| 106 | /* | 184 | result = toshiba_bluetooth_present(device->handle); |
| 107 | * Some Toshiba laptops may have a fake TOS6205 device in | 185 | if (result) |
| 108 | * their ACPI BIOS, so query the _STA method to see if there | 186 | return result; |
| 109 | * is really anything there, before trying to enable it. | ||
| 110 | */ | ||
| 111 | status = acpi_evaluate_integer(device->handle, "_STA", NULL, | ||
| 112 | &bt_present); | ||
| 113 | 187 | ||
| 114 | if (!ACPI_FAILURE(status) && bt_present) { | 188 | pr_info("Toshiba ACPI Bluetooth device driver\n"); |
| 115 | pr_info("Detected Toshiba ACPI Bluetooth device - " | 189 | |
| 116 | "installing RFKill handler\n"); | 190 | /* Enable the BT device */ |
| 117 | result = toshiba_bluetooth_enable(device->handle); | 191 | result = toshiba_bluetooth_enable(device->handle); |
| 118 | } | 192 | if (result) |
| 193 | return result; | ||
| 119 | 194 | ||
| 120 | return result; | 195 | return result; |
| 121 | } | 196 | } |
| @@ -123,7 +198,7 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) | |||
| 123 | static int toshiba_bt_rfkill_remove(struct acpi_device *device) | 198 | static int toshiba_bt_rfkill_remove(struct acpi_device *device) |
| 124 | { | 199 | { |
| 125 | /* clean up */ | 200 | /* clean up */ |
| 126 | return 0; | 201 | return toshiba_bluetooth_disable(device->handle); |
| 127 | } | 202 | } |
| 128 | 203 | ||
| 129 | module_acpi_driver(toshiba_bt_rfkill_driver); | 204 | module_acpi_driver(toshiba_bt_rfkill_driver); |
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 737e56d46f61..aac47573f9ed 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
| @@ -45,7 +45,6 @@ MODULE_LICENSE("GPL"); | |||
| 45 | 45 | ||
| 46 | #define ACPI_WMI_CLASS "wmi" | 46 | #define ACPI_WMI_CLASS "wmi" |
| 47 | 47 | ||
| 48 | static DEFINE_MUTEX(wmi_data_lock); | ||
| 49 | static LIST_HEAD(wmi_block_list); | 48 | static LIST_HEAD(wmi_block_list); |
| 50 | 49 | ||
| 51 | struct guid_block { | 50 | struct guid_block { |
| @@ -240,10 +239,10 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) | |||
| 240 | if (memcmp(block->guid, guid_input, 16) == 0) { | 239 | if (memcmp(block->guid, guid_input, 16) == 0) { |
| 241 | if (out) | 240 | if (out) |
| 242 | *out = wblock; | 241 | *out = wblock; |
| 243 | return 1; | 242 | return true; |
| 244 | } | 243 | } |
| 245 | } | 244 | } |
| 246 | return 0; | 245 | return false; |
| 247 | } | 246 | } |
| 248 | 247 | ||
| 249 | static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) | 248 | static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) |
